diff options
author | Karel Klic <kklic@redhat.com> | 2011-01-19 18:21:22 +0100 |
---|---|---|
committer | Karel Klic <kklic@redhat.com> | 2011-01-19 18:21:22 +0100 |
commit | 139975f2369015d6ca02f4291ab4b953b1e41ce5 (patch) | |
tree | 0e1a3908583c6dda4b26a59958d7646467273a01 /src/plugins/abrt-retrace-client.c | |
parent | 67aee159ada8c1f971273c4d8599109dd5f72a57 (diff) | |
download | abrt-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.c | 322 |
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; } |