diff options
| -rw-r--r-- | dcc.c | 207 | ||||
| -rw-r--r-- | dcc.h | 47 | ||||
| -rw-r--r-- | protocols/ft.h | 31 | ||||
| -rw-r--r-- | protocols/jabber/jabber.h | 3 | ||||
| -rw-r--r-- | protocols/jabber/s5bytestream.c | 137 | ||||
| -rw-r--r-- | protocols/jabber/si.c | 23 | 
6 files changed, 160 insertions, 288 deletions
| @@ -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 ); @@ -43,33 +43,9 @@  #ifndef _DCC_H  #define _DCC_H -/* don't wait for acknowledgments */ -#define DCC_SEND_AHEAD - -/* This multiplier specifies how many bytes we - * can go ahead within one event loop cycle. Notice that all in all, - * we can easily be more ahead if the event loop shoots often enough. - * (or the receiver processes slow enough) - * - * Setting this value too high will cause send buffer overflows. - */ -#define DCC_SEND_AHEAD_MUL 10 - -/* - * queue thresholds for the out of data and overflow conditions - */ -#define DCC_QUEUE_THRESHOLD_LOW 2048 -#define DCC_QUEUE_THRESHOLD_HIGH 65536 - -/* only used in non-ahead mode */ +/* Send an ACK after receiving this amount of data */  #define DCC_PACKET_SIZE 1024 -/* stores buffers handed over by IM protocols */ -struct dcc_buffer { -	char *b; -	int len; -}; -  typedef struct dcc_file_transfer {  	struct im_connection *ic; @@ -88,25 +64,6 @@ typedef struct dcc_file_transfer {  	gint watch_out;  /* writable */  	/* -	 * The total number of queued bytes. The following equality should always hold: -	 * -	 * 	queued_bytes = sum(queued_buffers.len) - buffer_pos -	 */ -	unsigned int queued_bytes; - -	/*  -	 * A list of dcc_buffer structures. -	 * These are provided by the protocols directly so that no copying is neccessary. -	 */ -	GSList *queued_buffers; -	 -	/*  -	 * current position within the first buffer. -	 * Is non-null if the whole buffer couldn't be sent at once. -	 */ -	int buffer_pos; - -	/*  	 * The total amount of bytes that have been sent to the irc client.  	 */  	size_t bytes_sent; @@ -123,7 +80,7 @@ file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, cha  void dcc_canceled( file_transfer_t *file, char *reason ); -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_size );  file_transfer_t *dcc_request( struct im_connection *ic, char *line );  #endif diff --git a/protocols/ft.h b/protocols/ft.h index d41eb6c1..d35580d0 100644 --- a/protocols/ft.h +++ b/protocols/ft.h @@ -26,6 +26,13 @@  #ifndef _FT_H  #define _FT_H +/* + * One buffer is needed for each transfer. The receiver stores a message + * in it and gives it to the sender. The sender will stall the receiver + * till the buffer has been sent out. + */ +#define FT_BUFFER_SIZE 2048 +  typedef enum {  	FT_STATUS_LISTENING	= 1,  	FT_STATUS_TRANSFERRING	= 2, @@ -130,15 +137,24 @@ typedef struct file_transfer {  	void (*canceled) ( struct file_transfer *file, char *reason );  	/* -	 * If set, called when the transfer queue is running empty and -	 * more data can be added. +	 * called by the sending side to indicate that it is writable. +	 * The callee should check if data is available and call the  +	 * function(as seen below) if that is the case.  	 */ -	void (*out_of_data) ( struct file_transfer *file ); +	gboolean (*write_request) ( struct file_transfer *file );  	/*  	 * When sending files, protocols register this function to receive data. +	 * This should only be called once after write_request is called. The caller +	 * should not read more data until write_request is called again. This technique +	 * avoids buffering. +	 */ +	gboolean (*write) (struct file_transfer *file, char *buffer, unsigned int len ); + +	/* The send buffer associated with this transfer. +	 * Since receivers always wait for a write_request call one is enough.  	 */ -	gboolean (*write) (struct file_transfer *file, char *buffer, int len ); +	char buffer[FT_BUFFER_SIZE];  } file_transfer_t; @@ -153,12 +169,5 @@ file_transfer_t *imcb_file_send_start( struct im_connection *ic, char *user_nick   */  void imcb_file_canceled( file_transfer_t *file, char *reason ); -/* - * The given buffer is queued for transfer and MUST NOT be freed by the caller. - * When the method returns false the caller should not invoke this method again - * until out_of_data has been called. - */ -gboolean imcb_file_write( file_transfer_t *file, gpointer data, size_t data_size ); -  gboolean imcb_file_recv_start( file_transfer_t *ft );  #endif diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index cb52d396..45082fee 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -145,7 +145,6 @@ struct jabber_transfer  	int accepted;  	size_t bytesread, byteswritten; -	int receiver_overflow;  	int fd;  	struct sockaddr_storage saddr;  }; @@ -208,7 +207,7 @@ void jabber_si_free_transfer( file_transfer_t *ft);  /* s5bytestream.c */  int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);  gboolean jabber_bs_send_start( struct jabber_transfer *tf ); -gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, int len ); +gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len );  /* message.c */  xt_status jabber_pkt_message( struct xt_node *node, gpointer data ); diff --git a/protocols/jabber/s5bytestream.c b/protocols/jabber/s5bytestream.c index e2f32bd0..de173d19 100644 --- a/protocols/jabber/s5bytestream.c +++ b/protocols/jabber/s5bytestream.c @@ -71,8 +71,6 @@ struct socks5_message  	if( (op) == -1 ) \  		return jabber_bs_abort( bt , msg ": %s", strerror( errno ) ); -#define JABBER_BS_BUFSIZE 65536 -  gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ... );  void jabber_bs_canceled( file_transfer_t *ft , char *reason );  void jabber_bs_free_transfer( file_transfer_t *ft); @@ -82,7 +80,7 @@ gboolean jabber_bs_peek( struct bs_transfer *bt, void *buffer, int buflen );  void jabber_bs_recv_answer_request( struct bs_transfer *bt );  gboolean jabber_bs_recv_read( gpointer data, gint fd, b_input_condition cond ); -void jabber_bs_recv_out_of_data( file_transfer_t *ft ); +gboolean jabber_bs_recv_write_request( file_transfer_t *ft );  gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition cond );  gboolean jabber_bs_recv_handshake_abort( struct bs_transfer *bt, char *error );  int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode); @@ -108,7 +106,7 @@ void jabber_bs_free_transfer( file_transfer_t *ft) {  	g_free( bt->pseudoadr );  	xt_free_node( bt->qnode );  	g_free( bt ); -//iq_id +  	jabber_si_free_transfer( ft );  } @@ -325,7 +323,7 @@ gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition con  				sock_make_nonblocking( fd ); -				imcb_log( bt->tf->ic, "Transferring file %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, host, port ); +				imcb_log( bt->tf->ic, "File %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, host, port );  				if( ( connect( fd, rp->ai_addr, rp->ai_addrlen ) == -1 ) &&  				    ( errno != EINPROGRESS ) ) @@ -425,7 +423,6 @@ gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition con  			jabber_bs_recv_answer_request( bt ); -			// reset in answer_request bt->tf->watch_in = 0;  			return FALSE;  		}  	default: @@ -440,8 +437,10 @@ gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition con  /*   * If the handshake failed we can try the next streamhost, if there is one.   * An intelligent sender would probably specify himself as the first streamhost and - * a proxy as the second (Kopete is an example here). That way, a (potentially)  - * slow proxy is only used if neccessary. + * a proxy as the second (Kopete and PSI are examples here). That way, a (potentially)  + * slow proxy is only used if neccessary. This of course also means, that the timeout + * per streamhost should be kept short. If one or two firewalled adresses are specified, + * they have to timeout first before a proxy is tried.   */  gboolean jabber_bs_recv_handshake_abort( struct bs_transfer *bt, char *error )  { @@ -493,15 +492,15 @@ void jabber_bs_recv_answer_request( struct bs_transfer *bt )  	struct jabber_transfer *tf = bt->tf;  	struct xt_node *reply; -	imcb_log( tf->ic, "Transferring file %s: established SOCKS5 connection to %s:%s",  +	imcb_log( tf->ic, "File %s: established SOCKS5 connection to %s:%s",   		  tf->ft->file_name,   		  xt_find_attr( bt->shnode, "host" ),  		  xt_find_attr( bt->shnode, "port" ) );  	tf->ft->data = tf;  	tf->ft->started = time( NULL ); -	tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_recv_read, tf ); -	tf->ft->out_of_data = jabber_bs_recv_out_of_data; +	tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_recv_read, bt ); +	tf->ft->write_request = jabber_bs_recv_write_request;  	reply = xt_new_node( "streamhost-used", NULL, NULL );  	xt_add_attr( reply, "jid", xt_find_attr( bt->shnode, "jid" ) ); @@ -518,90 +517,107 @@ void jabber_bs_recv_answer_request( struct bs_transfer *bt )  	xt_free_node( reply );  } -/* Reads till it is unscheduled or the receiver signifies an overflow. */ +/*  + * This function is called from write_request directly. If no data is available, it will install itself + * as a watcher for input on fd and once that happens, deliver the data and unschedule itself again. + */  gboolean jabber_bs_recv_read( gpointer data, gint fd, b_input_condition cond )  {  	int ret; -	struct jabber_transfer *tf = data; -	struct bs_transfer *bt = tf->streamhandle; -	char *buffer = g_malloc( JABBER_BS_BUFSIZE ); +	struct bs_transfer *bt = data; +	struct jabber_transfer *tf = bt->tf; -	if (tf->receiver_overflow) +	if( fd != 0 ) /* called via event thread */ +	{ +		tf->watch_in = 0; +		ASSERTSOCKOP( ret = recv( fd, tf->ft->buffer, sizeof( tf->ft->buffer ), 0 ) , "Receiving" ); +	} +	else  	{ -		if( tf->watch_in ) +		/* called directly. There might not be any data available. */ +		if( ( ( ret = recv( tf->fd, tf->ft->buffer, sizeof( tf->ft->buffer ), 0 ) ) == -1 ) && +		    ( errno != EAGAIN ) ) +		    return jabber_bs_abort( bt, "Receiving: %s", strerror( errno ) ); + +		if( ( ret == -1 ) && ( errno == EAGAIN ) )  		{ -			/* should never happen, BUG */ -			imcb_file_canceled( tf->ft, "Bug in jabber file transfer code: read while overflow is true. Please report" ); +			tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_recv_read, bt );  			return FALSE;  		}  	} -	ASSERTSOCKOP( ret = recv( fd, buffer, JABBER_BS_BUFSIZE, 0 ) , "Receiving" ); - -	/* that should be all */ +	/* shouldn't happen since we know the file size */  	if( ret == 0 ) -		return FALSE; +		return jabber_bs_abort( bt, "Remote end closed connection" );  	tf->bytesread += ret; -	buffer = g_realloc( buffer, ret ); +	tf->ft->write( tf->ft, tf->ft->buffer, ret );	 -	if ( ( tf->receiver_overflow = imcb_file_write( tf->ft, buffer, ret ) ) ) -	{ -		/* wait for imcb to run out of data */ -		tf->watch_in = 0; -		return FALSE; -	} -		 -	return TRUE; +	return FALSE;  } -/* imcb callback that is invoked when it runs out of data. - * We reschedule jabber_bs_read here if neccessary. */ -void jabber_bs_recv_out_of_data( file_transfer_t *ft ) +/*  + * imc callback that is invoked when it is ready to receive some data. + */ +gboolean jabber_bs_recv_write_request( file_transfer_t *ft )  {  	struct jabber_transfer *tf = ft->data; -	tf->receiver_overflow = FALSE; +	if( tf->watch_in ) +	{ +		imcb_file_canceled( ft, "BUG in jabber file transfer: write_request called when already watching for input" ); +		return FALSE; +	} +	 +	jabber_bs_recv_read( tf->streamhandle, 0 , 0 ); -	if ( !tf->watch_in ) -		tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_recv_read, tf ); +	return TRUE;  } -/* signal ood and be done */ +/*  + * Issues a write_request to imc. + * */  gboolean jabber_bs_send_can_write( gpointer data, gint fd, b_input_condition cond )  {  	struct bs_transfer *bt = data; -	bt->tf->ft->out_of_data( bt->tf->ft ); -  	bt->tf->watch_out = 0; + +	bt->tf->ft->write_request( bt->tf->ft ); +  	return FALSE;  } -/* try to send the stuff. If you can't return false and wait for writable */ -gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, int len ) +/* + * This should only be called if we can write, so just do it. + * Add a write watch so we can write more during the next cycle (if possible). + */ +gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len )  {  	struct jabber_transfer *tf = ft->data;  	struct bs_transfer *bt = tf->streamhandle;  	int ret; -	if ( ( ( ret = send( tf->fd, buffer, len, 0 ) ) == -1 ) && -	     ( errno != EAGAIN ) ) -		return jabber_bs_abort( bt, "send failed on socket with: %s", strerror( errno ) ); +	if( tf->watch_out ) +		return jabber_bs_abort( bt, "BUG: write() called while watching " ); -	if( ret == 0 ) -		return jabber_bs_abort( bt, "Remote end closed connection" ); +	ASSERTSOCKOP( ret = send( tf->fd, buffer, len, 0 ), "Sending" ); + +	tf->byteswritten += ret; -	if( ret == -1 ) -	{ -		bt->tf->watch_out = b_input_add( tf->fd, GAIM_INPUT_WRITE, jabber_bs_send_can_write, bt ); -		return FALSE; -	} +	/* TODO: this should really not be fatal */ +	if( ret < len ) +		return jabber_bs_abort( bt, "send() sent %d instead of %d (send buffer too big!)", ret, len ); + +	bt->tf->watch_out = b_input_add( tf->fd, GAIM_INPUT_WRITE, jabber_bs_send_can_write, bt );  	return TRUE;  } +/* + * Handles the reply by the receiver containing the used streamhost. + */  static xt_status jabber_bs_send_handle_reply(struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) {  	struct jabber_transfer *tf = NULL;  	struct jabber_data *jd = ic->proto_data; @@ -650,12 +666,11 @@ static xt_status jabber_bs_send_handle_reply(struct im_connection *ic, struct xt  	if( bt->phase == BS_PHASE_REPLY )  	{ +		/* handshake went through, let's start transferring */  		tf->ft->started = time( NULL ); -		tf->ft->out_of_data( tf->ft ); +		tf->ft->write_request( tf->ft );  	} -	//bt->tf->watch_out = b_input_add( tf->fd, GAIM_INPUT_WRITE, jabber_bs_send_write, tf ); -  	return XT_HANDLED;  } @@ -680,8 +695,6 @@ gboolean jabber_bs_send_start( struct jabber_transfer *tf )  	bt = g_new0( struct bs_transfer, 1 );  	bt->tf = tf; -	//bt->qnode = xt_dup( qnode ); -	//bt->shnode = bt->qnode->children;  	bt->phase = BS_PHASE_CONNECT;  	bt->pseudoadr = g_strdup( hash_hex );  	tf->streamhandle = bt; @@ -714,8 +727,6 @@ gboolean jabber_bs_send_request( struct jabber_transfer *tf, char *host, char *p  	iq = jabber_make_packet( "iq", "set", tf->tgt_jid, query );  	xt_add_attr( iq, "from", tf->ini_jid ); -	//xt_free_node( query ); -  	jabber_cache_add( tf->ic, iq, jabber_bs_send_handle_reply );  	if( !jabber_write_packet( tf->ic, iq ) ) @@ -884,11 +895,13 @@ gboolean jabber_bs_send_handshake( gpointer data, gint fd, b_input_condition con  			bt->phase = BS_PHASE_REPLY; -			/* don't start sending till the streamhost-used message comes in */ +			imcb_log( tf->ic, "File %s: SOCKS5 handshake successful! Transfer about to start...", tf->ft->file_name ); +  			if( tf->accepted )  			{ +				/* streamhost-used message came already in(possible?), let's start sending */  				tf->ft->started = time( NULL ); -				tf->ft->out_of_data( tf->ft ); +				tf->ft->write_request( tf->ft );  			}  			tf->watch_in = 0; diff --git a/protocols/jabber/si.c b/protocols/jabber/si.c index 598cbd03..ffde6418 100644 --- a/protocols/jabber/si.c +++ b/protocols/jabber/si.c @@ -83,7 +83,7 @@ void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft,  	struct jabber_transfer *tf;  	struct jabber_data *jd = ic->proto_data; -	imcb_log( ic, "Incoming file from %s : %s %zd bytes", ic->irc->nick, ft->file_name, ft->file_size ); +	imcb_log( ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who );  	tf = g_new0( struct jabber_transfer, 1 ); @@ -223,7 +223,7 @@ int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, st  }  /* - * imcb called the accept callback which probably means that the user accepted this file transfer. + * imc called the accept callback which probably means that the user accepted this file transfer.   * We send our response to the initiator.   * In the next step, the initiator will send us a request for the given stream type.   * (currently that can only be a SOCKS5 bytestream) @@ -274,11 +274,10 @@ void jabber_si_answer_request( file_transfer_t *ft ) {  static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig )  {  	struct xt_node *c, *d; -	char *ini_jid, *tgt_jid; +	char *ini_jid, *tgt_jid, *iq_id;  	GSList *tflist;  	struct jabber_transfer *tf=NULL;  	struct jabber_data *jd = ic->proto_data; -	char *sid;  	if( !( tgt_jid = xt_find_attr( node, "from" ) ) ||  	    !( ini_jid = xt_find_attr( node, "to" ) ) ) @@ -287,11 +286,10 @@ static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_n  		return XT_HANDLED;  	} -	imcb_log( ic, "GOT RESPONSE TO FILE" );  	/* All this means we expect something like this: ( I think ) -	 * <iq from=... to=...> +	 * <iq from=... to=... id=...>  	 * 	<si xmlns=si> -	 * 		<file xmlns=ft/> +	 * 	[	<file xmlns=ft/>    ] <-- not neccessary  	 * 		<feature xmlns=feature>  	 * 			<x xmlns=xdata type=submit>  	 * 				<field var=stream-method> @@ -299,11 +297,11 @@ static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_n  	 */  	if( !( tgt_jid = xt_find_attr( node, "from" ) ) ||  	    !( ini_jid = xt_find_attr( node, "to" ) ) || +	    !( iq_id   = xt_find_attr( node, "id" ) ) ||  	    !( c = xt_find_node( node->children, "si" ) ) ||  	    !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_SI ) == 0 ) || -	    !( sid = xt_find_attr( c, "id" ) )|| -	    !( d = xt_find_node( c->children, "file" ) ) || -	    !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FILETRANSFER ) == 0 ) || +/*	    !( d = xt_find_node( c->children, "file" ) ) || +	    !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FILETRANSFER ) == 0 ) || */  	    !( d = xt_find_node( c->children, "feature" ) ) ||  	    !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FEATURE ) == 0 ) ||  	    !( d = xt_find_node( d->children, "x" ) ) || @@ -330,7 +328,7 @@ static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_n  	for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) )  	{  		struct jabber_transfer *tft = tflist->data; -		if( ( strcmp( tft->sid, sid ) == 0 ) ) +		if( ( strcmp( tft->iq_id, iq_id ) == 0 ) )  		{  		    	tf = tft;  			break; @@ -346,6 +344,8 @@ static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_n  	tf->ini_jid = g_strdup( ini_jid );  	tf->tgt_jid = g_strdup( tgt_jid ); +	imcb_log( ic, "File %s: %s accepted the transfer!", tf->ft->file_name, tgt_jid ); +  	jabber_bs_send_start( tf );  	return XT_HANDLED; @@ -422,6 +422,7 @@ int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_tr  	/* and we are there... */  	node = jabber_make_packet( "iq", "set", bud ? bud->full_jid : who, sinode );  	jabber_cache_add( ic, node, jabber_si_handle_response ); +	tf->iq_id = g_strdup( xt_find_attr( node, "id" ) );  	return jabber_write_packet( ic, node );  } | 
