aboutsummaryrefslogtreecommitdiffstats
path: root/dcc.c
diff options
context:
space:
mode:
authorulim <a.sporto+bee@gmail.com>2007-12-04 01:48:57 +0100
committerulim <a.sporto+bee@gmail.com>2007-12-04 01:48:57 +0100
commitdce390357114e30a424106c99e49cef1e682e1af (patch)
treef238de491573827510c55e29cf80e2fda7ccc793 /dcc.c
parent2ff20765990c756533957e8da9c7c29dd3102e79 (diff)
Send and receive seems to work now! Also adopted the new buffering strategy,
only one buffer of 2k per transfer now.
Diffstat (limited to 'dcc.c')
-rw-r--r--dcc.c207
1 files changed, 50 insertions, 157 deletions
diff --git a/dcc.c b/dcc.c
index a5c77ce8..24673085 100644
--- a/dcc.c
+++ b/dcc.c
@@ -60,16 +60,7 @@ unsigned int local_transfer_id=1;
*/
unsigned int receivedchunks=0, receiveddata=0;
-/*
- * If using DCC SEND AHEAD this value will be set before the first transfer starts.
- * Not that in this case it degenerates to the maximum message size to send() and
- * has nothing to do with packets.
- */
-#ifdef DCC_SEND_AHEAD
-int max_packet_size = DCC_PACKET_SIZE;
-#else
int max_packet_size = 0;
-#endif
static void dcc_finish( file_transfer_t *file );
static void dcc_close( file_transfer_t *file );
@@ -78,7 +69,7 @@ gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_pt
int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr );
gboolean dccs_recv_start( file_transfer_t *ft );
gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond);
-void dccs_recv_out_of_data( file_transfer_t *ft );
+gboolean dccs_recv_write_request( file_transfer_t *ft );
/* As defined in ft.h */
file_transfer_t *imcb_file_send_start( struct im_connection *ic, char *handle, char *file_name, size_t file_size )
@@ -102,12 +93,6 @@ void imcb_file_canceled( file_transfer_t *file, char *reason )
}
/* As defined in ft.h */
-gboolean imcb_file_write( file_transfer_t *file, gpointer data, size_t data_size )
-{
- return dccs_send_write( file, data, data_size );
-}
-
-/* As defined in ft.h */
gboolean imcb_file_recv_start( file_transfer_t *ft )
{
return dccs_recv_start( ft );
@@ -138,6 +123,8 @@ file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, cha
df = dcc_alloc_transfer( file_name, file_size, ic );
file = df->ft;
+ file->write = dccs_send_write;
+ file->sending = TRUE;
/* listen and request */
if( !dcc_listen( df, &saddr ) ||
@@ -194,13 +181,8 @@ int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct soc
{
struct sockaddr_in *saddr_ipv4 = ( struct sockaddr_in *) saddr;
- /*
- * this is so ridiculous. We're supposed to convert the address to
- * host byte order!!! Let's exclude anyone running big endian just
- * for the fun of it...
- */
sprintf( ipaddr, "%d",
- htonl( saddr_ipv4->sin_addr.s_addr ) );
+ ntohl( saddr_ipv4->sin_addr.s_addr ) );
port = saddr_ipv4->sin_port;
} else
{
@@ -226,9 +208,6 @@ int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct soc
g_free( cmd );
- /* message is sortof redundant cause the users client probably informs him about that. remove? */
- imcb_log( df->ic, "Transferring file %s: Chose local address %s for DCC connection", df->ft->file_name, ipaddr );
-
return TRUE;
}
@@ -304,9 +283,11 @@ gboolean dcc_poll( dcc_file_transfer_t *df, int fd, short *revents )
return TRUE;
}
+/*
+ * fills max_packet_size with twice the TCP maximum segment size
+ */
gboolean dcc_check_maxseg( dcc_file_transfer_t *df, int fd )
{
-#ifdef DCC_SEND_AHEAD
/*
* use twice the maximum segment size as a maximum for calls to send().
*/
@@ -317,7 +298,6 @@ gboolean dcc_check_maxseg( dcc_file_transfer_t *df, int fd )
return dcc_abort( df, "getsockopt() failed" );
max_packet_size *= 2;
}
-#endif
return TRUE;
}
@@ -353,9 +333,9 @@ gboolean dccs_send_proto( gpointer data, gint fd, b_input_condition cond )
return FALSE;
/* IM protocol callback */
-
if( file->accept )
file->accept( file );
+
/* reschedule for reading on new fd */
df->watch_in = b_input_add( fd, GAIM_INPUT_READ, dccs_send_proto, df );
@@ -399,89 +379,9 @@ gboolean dccs_send_proto( gpointer data, gint fd, b_input_condition cond )
return FALSE;
}
-#ifndef DCC_SEND_AHEAD
- /* reschedule writer if neccessary */
- if( file->bytes_transferred >= df->bytes_sent &&
- df->watch_out == 0 &&
- df->queued_bytes > 0 ) {
- df->watch_out = b_input_add( fd, GAIM_INPUT_WRITE, dcc_send_proto, df );
- }
-#endif
return TRUE;
}
- if( revents & POLLOUT )
- {
- struct dcc_buffer *dccb;
- int ret;
- char *msg;
-
- if( df->queued_bytes == 0 )
- {
- /* shouldn't happen */
- imcb_log( df->ic, "WARNING: DCC SEND: write called with empty queue" );
-
- df->watch_out = 0;
- return FALSE;
- }
-
- /* start where we left off */
- if( !( df->queued_buffers ) ||
- !( dccb = df->queued_buffers->data ) )
- return dcc_abort( df, "BUG in DCC SEND: queued data but no buffers" );
-
- msg = dccb->b + df->buffer_pos;
-
- int msgsize = MIN(
-#ifndef DCC_SEND_AHEAD
- file->bytes_transferred + MAX_PACKET_SIZE - df->bytes_sent,
-#else
- max_packet_size,
-#endif
- dccb->len - df->buffer_pos );
-
- if ( msgsize == 0 )
- {
- df->watch_out = 0;
- return FALSE;
- }
-
- ASSERTSOCKOP( ret = send( fd, msg, msgsize, 0 ), "Sending data" );
-
- if( ret == 0 )
- return dcc_abort( df, "Remote end closed connection" );
-
- df->bytes_sent += ret;
- df->queued_bytes -= ret;
- df->buffer_pos += ret;
-
- if( df->buffer_pos == dccb->len )
- {
- df->buffer_pos = 0;
- df->queued_buffers = g_slist_remove( df->queued_buffers, dccb );
- g_free( dccb->b );
- g_free( dccb );
- }
-
- if( ( df->queued_bytes < DCC_QUEUE_THRESHOLD_LOW ) && file->out_of_data )
- file->out_of_data( file );
-
- if( df->queued_bytes > 0 )
- {
- /* Who knows how long the event loop cycle will take,
- * let's just try to send some more now. */
-#ifndef DCC_SEND_AHEAD
- if( df->bytes_sent < ( file->bytes_transferred + max_packet_size ) )
-#endif
- return dccs_send_proto( df, fd, cond );
- }
-
- df->watch_out = 0;
- return FALSE;
- }
-
- /* Send buffer full, come back later */
-
return TRUE;
}
@@ -508,7 +408,7 @@ gboolean dccs_recv_start( file_transfer_t *ft )
/* watch */
df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_recv_proto, df );
- ft->out_of_data = dccs_recv_out_of_data;
+ ft->write_request = dccs_recv_write_request;
return TRUE;
}
@@ -537,16 +437,13 @@ gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond)
if( revents & POLLIN )
{
- char *buffer = g_malloc( 65536 );
int ret, done;
- ASSERTSOCKOP( ret = recv( fd, buffer, 65536, 0 ), "Receiving" );
+ ASSERTSOCKOP( ret = recv( fd, ft->buffer, sizeof( ft->buffer ), 0 ), "Receiving" );
if( ret == 0 )
return dcc_abort( df, "Remote end closed connection" );
- buffer = g_realloc( buffer, ret );
-
df->bytes_sent += ret;
done = df->bytes_sent >= ft->file_size;
@@ -560,14 +457,11 @@ gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond)
ASSERTSOCKOP( ackret = send( fd, &ack, 4, 0 ), "Sending DCC ACK" );
if ( ackret != 4 )
- return dcc_abort( df, "Error sending DCC ACK, sent %d instead of 4 bytes", ret );
+ return dcc_abort( df, "Error sending DCC ACK, sent %d instead of 4 bytes", ackret );
}
- if( !ft->write( df->ft, buffer, ret ) && !done )
- {
- df->watch_in = 0;
+ if( !ft->write( df->ft, ft->buffer, ret ) )
return FALSE;
- }
if( done )
{
@@ -578,50 +472,63 @@ gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond)
return FALSE;
}
- return TRUE;
+ df->watch_in = 0;
+ return FALSE;
}
return TRUE;
}
-void dccs_recv_out_of_data( file_transfer_t *ft )
+gboolean dccs_recv_write_request( file_transfer_t *ft )
{
dcc_file_transfer_t *df = ft->priv;
- if( !df->watch_in )
- df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df );
+ if( df->watch_in )
+ return dcc_abort( df, "BUG: write_request() called while watching" );
+
+ df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df );
+
+ return TRUE;
+}
+
+gboolean dccs_send_can_write( gpointer data, gint fd, b_input_condition cond )
+{
+ struct dcc_file_transfer *df = data;
+ df->watch_out = 0;
+
+ df->ft->write_request( df->ft );
+ return FALSE;
}
/*
- * Incoming data. Note that the buffer MUST NOT be freed by the caller!
- * We don't copy the buffer but put it in our queue.
+ * Incoming data.
*
- * */
-gboolean dccs_send_write( file_transfer_t *file, gpointer data, unsigned int data_size )
+ */
+gboolean dccs_send_write( file_transfer_t *file, char *data, unsigned int data_len )
{
dcc_file_transfer_t *df = file->priv;
- struct dcc_buffer *dccb = g_new0( struct dcc_buffer, 1 );
+ int ret;
+
+ receivedchunks++; receiveddata += data_len;
- receivedchunks++; receiveddata += data_size;
+ if( df->watch_out )
+ return dcc_abort( df, "BUG: write() called while watching" );
- dccb->b = data;
- dccb->len = data_size;
+ ASSERTSOCKOP( ret = send( df->fd, data, data_len, 0 ), "Sending data" );
- df->queued_buffers = g_slist_append( df->queued_buffers, dccb );
+ if( ret == 0 )
+ return dcc_abort( df, "Remote end closed connection" );
- df->queued_bytes += data_size;
+ /* TODO: this should really not be fatal */
+ if( ret < data_len )
+ return dcc_abort( df, "send() sent %d instead of %d", ret, data_len );
- if( ( file->status & FT_STATUS_TRANSFERRING ) &&
-#ifndef DCC_SEND_AHEAD
- ( file->bytes_transferred >= df->bytes_sent ) &&
-#endif
- ( df->watch_out == 0 ) &&
- ( df->queued_bytes > 0 ) )
- {
- df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_send_proto, df );
- }
-
- return df->queued_bytes > DCC_QUEUE_THRESHOLD_HIGH;
+ df->bytes_sent += ret;
+
+ if( df->bytes_sent < df->ft->file_size )
+ df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_send_can_write, df );
+
+ return TRUE;
}
/*
@@ -642,20 +549,6 @@ static void dcc_close( file_transfer_t *file )
if( df->watch_out )
b_event_remove( df->watch_out );
- if( df->queued_buffers )
- {
- struct dcc_buffer *dccb;
- GSList *gslist = df->queued_buffers;
-
- for( ; gslist ; gslist = g_slist_next( gslist ) )
- {
- dccb = gslist->data;
- g_free( dccb->b );
- g_free( dccb );
- }
- g_slist_free( df->queued_buffers );
- }
-
df->ic->irc->file_transfers = g_slist_remove( df->ic->irc->file_transfers, file );
g_free( df );