aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dcc.c207
-rw-r--r--dcc.h47
-rw-r--r--protocols/ft.h31
-rw-r--r--protocols/jabber/jabber.h3
-rw-r--r--protocols/jabber/s5bytestream.c137
-rw-r--r--protocols/jabber/si.c23
6 files changed, 160 insertions, 288 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 );
diff --git a/dcc.h b/dcc.h
index d5805a1f..e53823e7 100644
--- a/dcc.h
+++ b/dcc.h
@@ -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 );
}