summaryrefslogtreecommitdiffstats
path: root/src/plugins/abrt-retrace-client.c
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2011-01-19 18:21:22 +0100
committerKarel Klic <kklic@redhat.com>2011-01-19 18:21:22 +0100
commit139975f2369015d6ca02f4291ab4b953b1e41ce5 (patch)
tree0e1a3908583c6dda4b26a59958d7646467273a01 /src/plugins/abrt-retrace-client.c
parent67aee159ada8c1f971273c4d8599109dd5f72a57 (diff)
downloadabrt-139975f2369015d6ca02f4291ab4b953b1e41ce5.tar.gz
abrt-139975f2369015d6ca02f4291ab4b953b1e41ce5.tar.xz
abrt-139975f2369015d6ca02f4291ab4b953b1e41ce5.zip
Retrace client more work in progress
Diffstat (limited to 'src/plugins/abrt-retrace-client.c')
-rw-r--r--src/plugins/abrt-retrace-client.c322
1 files changed, 205 insertions, 117 deletions
diff --git a/src/plugins/abrt-retrace-client.c b/src/plugins/abrt-retrace-client.c
index 834c22d3..28b8543f 100644
--- a/src/plugins/abrt-retrace-client.c
+++ b/src/plugins/abrt-retrace-client.c
@@ -14,11 +14,10 @@
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-http://www.mail-archive.com/dev-tech-crypto@lists.mozilla.org/msg01921.html
*/
#include "abrtlib.h"
#include "parse_options.h"
+#include "strbuf.h"
#include <nspr.h>
#include <nss.h>
#include <pk11pub.h>
@@ -42,10 +41,14 @@ static struct options abrt_retrace_client_options[] = {
OPT_END()
};
-void add_if_exists(struct dump_dir *dd,
- const char *name,
- const char *args[],
- int *argindex)
+/* Add an entry name to the args array if the entry name exists in a
+ * dump directory. The entry is added to argindex offset to the array,
+ * and the argindex is then increased.
+ */
+void args_add_if_exists(const char *args[],
+ struct dump_dir *dd,
+ const char *name,
+ int *argindex)
{
if (dd_exist(dd, name))
{
@@ -54,190 +57,275 @@ void add_if_exists(struct dump_dir *dd,
}
}
-int main(int argc, char **argv)
+/* Create an archive with files required for retrace server and return
+ * a file descriptor. Returns -1 if it fails.
+ */
+int create_archive(const char *dump_dir_name)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
-
- unsigned opts = parse_opts(argc, argv, abrt_retrace_client_options,
- abrt_retrace_client_usage);
-
- if (opts & OPT_s)
- {
- openlog(msg_prefix, 0, LOG_DAEMON);
- logmode = LOGMODE_SYSLOG;
- }
-
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
- return 1;
-
- const char *args[10];
- args[0] = "tar";
- args[1] = "cJvO";
- int argindex = 2;
- args[argindex++] = xasprintf("--directory=%s", dump_dir_name);
- args[argindex++] = FILENAME_COREDUMP;
- add_if_exists(dd, FILENAME_ANALYZER, args, &argindex);
- add_if_exists(dd, FILENAME_ARCHITECTURE, args, &argindex);
- add_if_exists(dd, FILENAME_EXECUTABLE, args, &argindex);
- add_if_exists(dd, FILENAME_PACKAGE, args, &argindex);
- add_if_exists(dd, FILENAME_RELEASE, args, &argindex);
- args[argindex] = NULL;
-
- int tempfd = mkstemp("/tmp/abrt-retrace-client-archive.tar.xz.XXXXXX");
+ return -1;
+
+ /* Open a temporary file. */
+ char *filename = xstrdup("/tmp/abrt-retrace-client-archive-XXXXXX.tar.xz");
+ int tempfd = mkstemps(filename, /*suffixlen:*/7);
if (tempfd == -1)
perror_msg_and_die("Cannot open temporary file");
-
- int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT;
- int pipeout[2];
- pid_t child = fork_execv_on_steroids(flags, (char**)args,
- pipeout, NULL, NULL, 0);
-
- while (1)
+ //xunlink(filename);
+ free(filename);
+
+ /* Run xz:
+ * - xz reads input from a pipe
+ * - xz writes output to the temporary file.
+ */
+ const char *xz_args[4];
+ xz_args[0] = "xz";
+ xz_args[1] = "-2";
+ xz_args[2] = "-";
+ xz_args[3] = NULL;
+
+ int tar_xz_pipe[2];
+ xpipe(tar_xz_pipe);
+ pid_t xz_child = fork();
+ if (xz_child == -1)
+ perror_msg_and_die("fork");
+ else if (xz_child == 0)
{
- struct pollfd pfd;
- pfd.fd = pipeout[0];
- pfd.events = POLLIN;
- poll(&pfd, 1, 1000);
+ close(tar_xz_pipe[1]);
+ xmove_fd(tar_xz_pipe[0], STDIN_FILENO);
+ xdup2(tempfd, STDOUT_FILENO);
+ execvp(xz_args[0], (char * const*)xz_args);
+ perror_msg("Can't execute '%s'", xz_args[0]);
+ }
- char buf[32768];
- int r = read(pipeout[0], buf, sizeof(buf));
- if (r <= 0)
- {
- if (r == -1)
- {
- if (EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno)
- continue;
- perror_msg_and_die("Failed to read from a pipe");
- }
- break;
- }
+ close(tar_xz_pipe[0]);
+
+ /* Run tar, and set output to a pipe with xz waiting on the other
+ * end.
+ */
+ const char *tar_args[10];
+ tar_args[0] = "tar";
+ tar_args[1] = "cO";
+ tar_args[2] = xasprintf("--directory=%s", dump_dir_name);
+ int argindex = 3;
+ tar_args[argindex++] = FILENAME_COREDUMP;
+ args_add_if_exists(tar_args, dd, FILENAME_ANALYZER, &argindex);
+ args_add_if_exists(tar_args, dd, FILENAME_ARCHITECTURE, &argindex);
+ args_add_if_exists(tar_args, dd, FILENAME_EXECUTABLE, &argindex);
+ args_add_if_exists(tar_args, dd, FILENAME_PACKAGE, &argindex);
+ args_add_if_exists(tar_args, dd, FILENAME_RELEASE, &argindex);
+ tar_args[argindex] = NULL;
- int w = 0;
- while (r)
- {
- w += write(tempfd, buf + w, r);
- if (w == -1)
- {
- if (EINTR == errno)
- continue;
+ dd_close(dd);
- perror_msg_and_die("Failed to write to a temp file");
- }
- if (w < r)
- {
- r -= w;
- continue;
- }
- }
+ pid_t tar_child = fork();
+ if (tar_child == -1)
+ perror_msg_and_die("fork");
+ else if (tar_child == 0)
+ {
+ xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO);
+ xmove_fd(tar_xz_pipe[1], STDOUT_FILENO);
+ execvp(tar_args[0], (char * const*)tar_args);
+ perror_msg("Can't execute '%s'", tar_args[0]);
}
- close(pipeout[0]);
- close(tempfd);
+ close(tar_xz_pipe[1]);
- /* Prevent having zombie child process, and maybe collect status
- * (note that status == NULL is ok too) */
+ /* Prevent having zombie child process. */
int status;
- waitpid(child, &status, 0);
- free((void*)args[2]);
-
- dd_close(dd);
-
+ VERB1 log_msg("Waiting for tar...");
+ waitpid(tar_child, &status, 0);
+ free((void*)tar_args[2]);
+ VERB1 log_msg("Waiting for xz...");
+ waitpid(xz_child, &status, 0);
+ VERB1 log_msg("Done...");
+
+ return tempfd;
+}
- /* Upload the archive. */
-#define HOST "coding.debuntu.org"
-#define PAGE "/"
-#define PORT 443
-#define USERAGENT "HTMLGET 1.0"
-
- NSS_Init("path");
- PRFileDesc *tcp_sock = PR_NewTCPSocket();
- if (!sock)
+void ssl_connect(const char *host, PRFileDesc **tcp_sock, PRFileDesc **ssl_sock)
+{
+ NSS_Init("/etc/ssl");
+ *tcp_sock = PR_NewTCPSocket();
+ if (!*tcp_sock)
error_msg_and_die("Failed to create a TCP socket");
PRSocketOptionData sock_option;
sock_option.option = PR_SockOpt_Nonblocking;
sock_option.value.non_blocking = PR_FALSE;
- PRStatus pr_status = PR_SetSocketOption(tcp_sock, &sock_option);
+ PRStatus pr_status = PR_SetSocketOption(*tcp_sock, &sock_option);
if (PR_SUCCESS != pr_status)
{
- PR_Close(tcp_sock);
+ PR_Close(*tcp_sock);
error_msg_and_die("Failed to set socket blocking mode.");
}
- PRFileDesc *ssl_sock = SSL_ImportFD(NULL, tcp_sock);
- if (!ssl_sock)
+ *ssl_sock = SSL_ImportFD(NULL, *tcp_sock);
+ if (!*ssl_sock)
{
- PR_Close(tcp_sock);
+ PR_Close(*tcp_sock);
error_msg_and_die("Failed to wrap TCP socket by SSL");
}
- SECStatus sec_status = SSL_OptionSet(ssl_sock, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
+ SECStatus sec_status = SSL_OptionSet(*ssl_sock, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
if (SECSuccess != sec_status)
{
- PR_Close(ssl_sock);
+ PR_Close(*ssl_sock);
error_msg_and_die("Failed to enable client handshake to SSL socket.");
}
- sec_status = SSL_OptionSet(ssl_sock, SSL_ENABLE_FDX, PR_TRUE);
+ sec_status = SSL_OptionSet(*ssl_sock, SSL_ENABLE_FDX, PR_TRUE);
if (SECSuccess != sec_status)
{
- PR_Close(ssl_sock);
+ PR_Close(*ssl_sock);
error_msg_and_die("Failed to set full duplex to SSL socket.");
}
- sec_status = SSL_SetURL(ssl_sock, HOST);
+ sec_status = SSL_SetURL(*ssl_sock, host);
if (SECSuccess != sec_status)
{
- PR_Close(ssl_sock);
+ PR_Close(*ssl_sock);
error_msg_and_die("Failed to set URL to SSL socket.");
}
- char buffer[256];
+ char buffer[PR_NETDB_BUF_SIZE];
PRHostEnt host_entry;
- pr_status = PR_GetHostByName(HOST, buffer, sizeof(buffer), &host_entry);
+ pr_status = PR_GetHostByName(host, buffer, sizeof(buffer), &host_entry);
if (PR_SUCCESS != pr_status)
{
- PR_Close(ssl_sock);
- error_msg_and_die("Failed to get host by name.");
+ char *error = xmalloc(PR_GetErrorTextLength());
+ PRInt32 count = PR_GetErrorText(error);
+ PR_Close(*ssl_sock);
+ if (count)
+ error_msg_and_die("Failed to get host by name: %s", error);
+ else
+ error_msg_and_die("Failed to get host by name: pr_status == %d, pr_error == %d", pr_status, PR_GetError());
}
PRNetAddr addr;
- PRInt32 rv = PR_EnumerateHostEnt(0, &host_entry, PORT, &addr);
+ PRInt32 rv = PR_EnumerateHostEnt(0, &host_entry, /*port:*/443, &addr);
if (rv < 0)
{
- PR_Close(ssl_sock);
+ PR_Close(*ssl_sock);
error_msg_and_die("Failed to enumerate host ent.");
}
- pr_status = PR_Connect(ssl_sock, &addr, PR_INTERVAL_NO_TIMEOUT);
+ pr_status = PR_Connect(*ssl_sock, &addr, PR_INTERVAL_NO_TIMEOUT);
if (PR_SUCCESS != pr_status)
{
- PR_Close(ssl_sock);
- error_msg_and_die("Failed to connect SSL address");
+ PR_Close(*ssl_sock);
+ error_msg_and_die("Failed to connect SSL address.");
}
- sec_status = SSL_ResetHandshake(ssl_sock, PR_FALSE);
+ sec_status = SSL_ResetHandshake(*ssl_sock, PR_FALSE);
if (SECSuccess != sec_status)
{
- PR_Close(ssl_sock);
+ PR_Close(*ssl_sock);
error_msg_and_die("Failed to reset handshake.");
}
- pr_status = PR_Close(ssl_sock);
+ sec_status = SSL_ForceHandshake(*ssl_sock);
+ if (SECSuccess != sec_status)
+ {
+ PR_Close(*ssl_sock);
+ error_msg_and_die("Failed to force handshake.");
+ }
+}
+
+void ssl_disconnect(PRFileDesc *ssl_sock)
+{
+ PRStatus pr_status = PR_Close(ssl_sock);
if (PR_SUCCESS != pr_status)
error_msg("Failed to close SSL socket.");
SSL_ClearSessionCache();
- sec_status = NSS_Shutdown();
+ SECStatus sec_status = NSS_Shutdown();
if (SECSuccess != sec_status)
error_msg("Failed to shutdown NSS.");
PR_Cleanup();
+}
+
+int main(int argc, char **argv)
+{
+ char *env_verbose = getenv("ABRT_VERBOSE");
+ if (env_verbose)
+ g_verbose = atoi(env_verbose);
+
+ unsigned opts = parse_opts(argc, argv, abrt_retrace_client_options,
+ abrt_retrace_client_usage);
+
+ if (opts & OPT_s)
+ {
+ openlog(msg_prefix, 0, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
+ }
+
+ int tempfd = create_archive(dump_dir_name);
+
+ /* Get the file size. */
+ struct stat tempfd_buf;
+ fstat(tempfd, &tempfd_buf);
+
+ PRFileDesc *tcp_sock, *ssl_sock;
+ ssl_connect("retrace01.fedoraproject.org", &tcp_sock, &ssl_sock);
+ /* Upload the archive. */
+ struct strbuf *request = strbuf_new();
+ strbuf_append_strf(request,
+ "POST /create HTTP/1.1\r\n"
+ "Host: retrace01.fedoraproject.org\r\n"
+ "Content-Type: application/x-xz-compressed-tar\r\n"
+ "Content-Length: %lld\r\n"
+ "Connection: close\r\n"
+ "\r\n", (long long)tempfd_buf.st_size);
+
+ PRInt32 written = PR_Send(tcp_sock, request->buf, request->len,
+ /*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
+ if (written == -1)
+ {
+ char *error = xmalloc(PR_GetErrorTextLength());
+ PRInt32 count = PR_GetErrorText(error);
+ PR_Close(ssl_sock);
+ if (count)
+ error_msg_and_die("Failed to send HTTP header of length %d: %s", request->len, error);
+ else
+ error_msg_and_die("Failed to send HTTP header of length %d: pr_error == %d",
+ request->len, PR_GetError());
+ }
+
+ xlseek(tempfd, 0, SEEK_SET);
+
+ while (1)
+ {
+ char buf[32768];
+ int r = read(tempfd, buf, sizeof(buf));
+ if (r <= 0)
+ {
+ if (r == -1)
+ {
+ if (EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno)
+ continue;
+ perror_msg_and_die("Failed to read from a pipe");
+ }
+ break;
+ }
+
+ written = PR_Send(tcp_sock, buf, r,
+ /*flags:*/0, PR_INTERVAL_NO_TIMEOUT);
+ if (written == -1)
+ {
+ PR_Close(ssl_sock);
+ error_msg_and_die("Failed to send data.");
+ }
+ }
+
+ //PRInt32 received = PR_Recv(tcp_sock, buf, amount, /*flags:*/0,
+ // PR_INTERVAL_NO_TIMEOUT);
+
+ ssl_disconnect(ssl_sock);
+ close(tempfd);
return 0;
}