Mercurial > pidgin.yaz
diff src/protocols/yahoo/yahoo_filexfer.c @ 13200:33bef17125c2
[gaim-migrate @ 15563]
This is the soon-to-be-infamous nonblocking network activity patch that I've been working on. Feel free to yell at me if this makes you unhappy.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Thu, 09 Feb 2006 04:17:56 +0000 |
parents | a1d5f154585b |
children | aaeb6ea63c56 |
line wrap: on
line diff
--- a/src/protocols/yahoo/yahoo_filexfer.c Thu Feb 09 04:14:54 2006 +0000 +++ b/src/protocols/yahoo/yahoo_filexfer.c Thu Feb 09 04:17:56 2006 +0000 @@ -39,16 +39,21 @@ GaimConnection *gc; long expires; gboolean started; + guchar *txbuf; + gsize txbuflen; + gsize txbuf_written; + guint tx_handler; gchar *rxqueue; guint rxlen; }; static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd) { - if (xd->host) - g_free(xd->host); - if (xd->path) - g_free(xd->path); + g_free(xd->host); + g_free(xd->path); + g_free(xd->txbuf); + if (xd->tx_handler) + gaim_input_remove(xd->tx_handler); g_free(xd); } @@ -56,7 +61,7 @@ { GaimXfer *xfer; struct yahoo_xfer_data *xd; - gchar *buf; + int total_len, written; gaim_debug(GAIM_DEBUG_INFO, "yahoo", "AAA - in yahoo_receivefile_connected\n"); @@ -71,29 +76,53 @@ return; } + /* The first time we get here, assemble the tx buffer */ + if (xd->txbuflen == 0) { + xd->txbuf = g_strdup_printf("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", + xd->path, xd->host); + xd->txbuflen = strlen(xd->txbuf); + xd->txbuf_written = 0; + } + + total_len = xd->txbuflen - xd->txbuf_written; + xfer->fd = source; + + written = write(xfer->fd, xd->txbuf + xd->txbuf_written, total_len); + + if (written < 0 && errno == EAGAIN) + written = 0; + else if (written <= 0) { + gaim_debug_error("yahoo", "Unable to write in order to start ft errno = %d\n", errno); + gaim_xfer_cancel_remote(xfer); + return; + } + + if (written < total_len) { + if (!xd->tx_handler) + xd->tx_handler = gaim_input_add(source, GAIM_INPUT_WRITE, + yahoo_receivefile_connected, xfer); + xd->txbuf_written += written; + return; + } + + if (xd->tx_handler) + gaim_input_remove(xd->tx_handler); + xd->tx_handler = 0; + g_free(xd->txbuf); + xd->txbuf = NULL; + xd->txbuflen = 0; + gaim_xfer_start(xfer, source, NULL, 0); - buf = g_strdup_printf("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", - xd->path, xd->host); - write(xfer->fd, buf, strlen(buf)); - g_free(buf); +} - return; -} static void yahoo_sendfile_connected(gpointer data, gint source, GaimInputCondition condition) { GaimXfer *xfer; struct yahoo_xfer_data *xd; - struct yahoo_packet *pkt; - gchar *size, *post, *buf; - const char *host; - int content_length, port; - GaimConnection *gc; - GaimAccount *account; - struct yahoo_data *yd; - char *filename, *encoded_filename; + int written, total_len; gaim_debug(GAIM_DEBUG_INFO, "yahoo", "AAA - in yahoo_sendfile_connected\n"); @@ -102,9 +131,6 @@ if (!(xd = xfer->data)) return; - gc = xd->gc; - account = gaim_connection_get_account(gc); - yd = gc->proto_data; if (source < 0) { gaim_xfer_error(GAIM_XFER_RECEIVE, gaim_xfer_get_account(xfer), @@ -113,43 +139,96 @@ return; } - xfer->fd = source; - gaim_xfer_start(xfer, source, NULL, 0); + /* The first time we get here, assemble the tx buffer */ + if (xd->txbuflen == 0) { + struct yahoo_packet *pkt; + gchar *size, *filename, *encoded_filename, *header; + guchar *pkt_buf; + const char *host; + int port; + gsize content_length, header_len, pkt_buf_len; + GaimConnection *gc; + GaimAccount *account; + struct yahoo_data *yd; - pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER, YAHOO_STATUS_AVAILABLE, yd->session_id); + gc = xd->gc; + account = gaim_connection_get_account(gc); + yd = gc->proto_data; + + pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER, + YAHOO_STATUS_AVAILABLE, yd->session_id); - size = g_strdup_printf("%" G_GSIZE_FORMAT, gaim_xfer_get_size(xfer)); - filename = g_path_get_basename(gaim_xfer_get_local_filename(xfer)); - encoded_filename = yahoo_string_encode(gc, filename, NULL); + size = g_strdup_printf("%" G_GSIZE_FORMAT, gaim_xfer_get_size(xfer)); + filename = g_path_get_basename(gaim_xfer_get_local_filename(xfer)); + encoded_filename = yahoo_string_encode(gc, filename, NULL); + + yahoo_packet_hash(pkt, "sssss", 0, gaim_connection_get_display_name(gc), + 5, xfer->who, 14, "", 27, encoded_filename, 28, size); + g_free(size); + g_free(encoded_filename); + g_free(filename); + + content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); - yahoo_packet_hash(pkt, "sssss", 0, gaim_connection_get_display_name(gc), - 5, xfer->who, 14, "", 27, encoded_filename, 28, size); + pkt_buf_len = yahoo_packet_build(pkt, 8, FALSE, &pkt_buf); + yahoo_packet_free(pkt); - content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); - - buf = g_strdup_printf("Y=%s; T=%s", yd->cookie_y, yd->cookie_t); + host = gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST); + port = gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT); + header = g_strdup_printf( + "POST http://%s:%d/notifyft HTTP/1.0\r\n" + "Content-length: %" G_GSIZE_FORMAT "\r\n" + "Host: %s:%d\r\n" + "Cookie: Y=%s; T=%s\r\n" + "\r\n", + host, port, content_length + 4 + gaim_xfer_get_size(xfer), + host, port, yd->cookie_y, yd->cookie_t); - host = gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST); - port = gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT); - post = g_strdup_printf("POST http://%s:%d/notifyft HTTP/1.0\r\n" - "Content-length: %" G_GSIZE_FORMAT "\r\n" - "Host: %s:%d\r\n" - "Cookie: %s\r\n" - "\r\n", - host, port, content_length + 4 + gaim_xfer_get_size(xfer), - host, port, buf); - write(xfer->fd, post, strlen(post)); + + header_len = strlen(header); + + xd->txbuflen = header_len + pkt_buf_len + 4; + xd->txbuf = g_malloc(xd->txbuflen); + + memcpy(xd->txbuf, header, header_len); + g_free(header); + memcpy(xd->txbuf + header_len, pkt_buf, pkt_buf_len); + g_free(pkt_buf); + memcpy(xd->txbuf + header_len + pkt_buf_len, "29\xc0\x80", 4); + + xd->txbuf_written = 0; + } + + total_len = xd->txbuflen - xd->txbuf_written; + + xfer->fd = source; + + written = write(xfer->fd, xd->txbuf + xd->txbuf_written, total_len); - yahoo_packet_send_special(pkt, xfer->fd, 8); - yahoo_packet_free(pkt); - - write(xfer->fd, "29\xc0\x80", 4); + if (written < 0 && errno == EAGAIN) + written = 0; + else if (written <= 0) { + gaim_debug_error("yahoo", "Unable to write in order to start ft errno = %d\n", errno); + gaim_xfer_cancel_remote(xfer); + return; + } - g_free(size); - g_free(post); - g_free(buf); - g_free(encoded_filename); - g_free(filename); + if (written < total_len) { + if (!xd->tx_handler) + xd->tx_handler = gaim_input_add(source, GAIM_INPUT_WRITE, + yahoo_sendfile_connected, xfer); + xd->txbuf_written += written; + return; + } + + if (xd->tx_handler) + gaim_input_remove(xd->tx_handler); + xd->tx_handler = 0; + g_free(xd->txbuf); + xd->txbuf = NULL; + xd->txbuflen = 0; + + gaim_xfer_start(xfer, source, NULL, 0); } static void yahoo_xfer_init(GaimXfer *xfer)