Changeset fa30fa5


Ignore:
Timestamp:
2007-12-04T00:53:04Z (16 years ago)
Author:
ulim <a.sporto+bee@…>
Branches:
master
Children:
08135df
Parents:
2c2df7d (diff), dce3903 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Jabber file transfer now also with sending! You can't use a proxy yet when
sending, that's my next task. You can use proxies when receiving though!

I also changed the buffering strategy. Previously receiving continued till some
buffer limit was reached, now only one message is received and receiving stops
till it is delivered. This keeps the buffering space per file transfer to a
minimum(currently 4k). Makes sense when used on a public server. For public
servers a throughput maximum would also be interesting...

Files:
1 added
1 deleted
12 edited

Legend:

Unmodified
Added
Removed
  • dcc.c

    r2c2df7d rfa30fa5  
    2828#include <poll.h>
    2929#include <netinet/tcp.h>
     30#include <regex.h>
    3031
    3132/*
     
    6061unsigned int receivedchunks=0, receiveddata=0;
    6162
    62 /*
    63  * If using DCC SEND AHEAD this value will be set before the first transfer starts.
    64  * Not that in this case it degenerates to the maximum message size to send() and
    65  * has nothing to do with packets.
    66  */
    67 #ifdef DCC_SEND_AHEAD
    68 int max_packet_size = DCC_PACKET_SIZE;
    69 #else
    7063int max_packet_size = 0;
    71 #endif
    7264
    7365static void dcc_finish( file_transfer_t *file );
     
    7668gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_ptr );
    7769int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr );
     70gboolean dccs_recv_start( file_transfer_t *ft );
     71gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond);
     72gboolean dccs_recv_write_request( file_transfer_t *ft );
    7873
    7974/* As defined in ft.h */
     
    9994
    10095/* As defined in ft.h */
    101 gboolean imcb_file_write( file_transfer_t *file, gpointer data, size_t data_size )
    102 {
    103         return dccs_send_write( file, data, data_size );
    104 }
    105 
    106 /* This is where the sending magic starts... */
    107 file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size )
    108 {
    109         file_transfer_t *file;
    110         dcc_file_transfer_t *df;
    111         struct sockaddr_storage **saddr;
    112 
    113         if( file_size > global.conf->max_filetransfer_size )
    114                 return NULL;
    115        
    116         /* alloc stuff */
    117         file = g_new0( file_transfer_t, 1 );
    118         file->priv = df = g_new0( dcc_file_transfer_t, 1);
     96gboolean imcb_file_recv_start( file_transfer_t *ft )
     97{
     98        return dccs_recv_start( ft );
     99}
     100
     101dcc_file_transfer_t *dcc_alloc_transfer( char *file_name, size_t file_size, struct im_connection *ic )
     102{
     103        file_transfer_t *file = g_new0( file_transfer_t, 1 );
     104        dcc_file_transfer_t *df = file->priv = g_new0( dcc_file_transfer_t, 1);
    119105        file->file_size = file_size;
    120106        file->file_name = g_strdup( file_name );
     
    123109        df->ft = file;
    124110       
     111        return df;
     112}
     113
     114/* This is where the sending magic starts... */
     115file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size )
     116{
     117        file_transfer_t *file;
     118        dcc_file_transfer_t *df;
     119        struct sockaddr_storage *saddr;
     120
     121        if( file_size > global.conf->max_filetransfer_size )
     122                return NULL;
     123       
     124        df = dcc_alloc_transfer( file_name, file_size, ic );
     125        file = df->ft;
     126        file->write = dccs_send_write;
     127        file->sending = TRUE;
     128
    125129        /* listen and request */
    126         if( !dcc_listen( df, saddr ) ||
    127             !dccs_send_request( df, user_nick, *saddr ) )
     130        if( !dcc_listen( df, &saddr ) ||
     131            !dccs_send_request( df, user_nick, saddr ) )
    128132                return NULL;
    129133
    130         g_free( *saddr );
     134        g_free( saddr );
    131135
    132136        /* watch */
     
    178182                struct sockaddr_in *saddr_ipv4 = ( struct sockaddr_in *) saddr;
    179183
    180                 /*
    181                  * this is so ridiculous. We're supposed to convert the address to
    182                  * host byte order!!! Let's exclude anyone running big endian just
    183                  * for the fun of it...
    184                  */
    185184                sprintf( ipaddr, "%d",
    186                          htonl( saddr_ipv4->sin_addr.s_addr ) );
     185                         ntohl( saddr_ipv4->sin_addr.s_addr ) );
    187186                port = saddr_ipv4->sin_port;
    188187        } else
     
    209208
    210209        g_free( cmd );
    211 
    212         /* message is sortof redundant cause the users client probably informs him about that. remove? */
    213         imcb_log( df->ic, "Transferring file %s: Chose local address %s for DCC connection", df->ft->file_name, ipaddr );
    214210
    215211        return TRUE;
     
    261257
    262258/*
     259 * Checks poll(), same for receiving and sending
     260 */
     261gboolean dcc_poll( dcc_file_transfer_t *df, int fd, short *revents )
     262{
     263        struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT };
     264
     265        ASSERTSOCKOP( poll( &pfd, 1, 0 ), "poll()" )
     266
     267        if( pfd.revents & POLLERR )
     268        {
     269                int sockerror;
     270                socklen_t errlen = sizeof( sockerror );
     271
     272                if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen ) )
     273                        return dcc_abort( df, "getsockopt() failed, unknown socket error (weird!)" );
     274
     275                return dcc_abort( df, "Socket error: %s", strerror( sockerror ) );
     276        }
     277       
     278        if( pfd.revents & POLLHUP )
     279                return dcc_abort( df, "Remote end closed connection" );
     280       
     281        *revents = pfd.revents;
     282
     283        return TRUE;
     284}
     285
     286/*
     287 * fills max_packet_size with twice the TCP maximum segment size
     288 */
     289gboolean  dcc_check_maxseg( dcc_file_transfer_t *df, int fd )
     290{
     291        /*
     292         * use twice the maximum segment size as a maximum for calls to send().
     293         */
     294        if( max_packet_size == 0 )
     295        {
     296                unsigned int mpslen = sizeof( max_packet_size );
     297                if( getsockopt( fd, IPPROTO_TCP, TCP_MAXSEG, &max_packet_size, &mpslen ) )
     298                        return dcc_abort( df, "getsockopt() failed" );
     299                max_packet_size *= 2;
     300        }
     301        return TRUE;
     302}
     303
     304/*
    263305 * After setup, the transfer itself is handled entirely by this function.
    264306 * There are basically four things to handle: connect, receive, send, and error.
     
    268310        dcc_file_transfer_t *df = data;
    269311        file_transfer_t *file = df->ft;
    270         struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT };
    271312        short revents;
    272313       
    273         if ( poll( &pfd, 1, 0 ) == -1 )
    274         {
    275                 imcb_log( df->ic, "poll() failed, weird!" );
    276                 revents = 0;
    277         };
    278 
    279         revents = pfd.revents;
    280 
    281         if( revents & POLLERR )
    282         {
    283                 int sockerror;
    284                 socklen_t errlen = sizeof( sockerror );
    285 
    286                 if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen ) )
    287                         return dcc_abort( df, "getsockopt() failed, unknown socket error (weird!)" );
    288 
    289                 return dcc_abort( df, "Socket error: %s", strerror( sockerror ) );
    290         }
    291        
    292         if( revents & POLLHUP )
    293                 return dcc_abort( df, "Remote end closed connection" );
    294        
     314        if( !dcc_poll( df, fd, &revents) )
     315                return FALSE;
     316
    295317        if( ( revents & POLLIN ) &&
    296318            ( file->status & FT_STATUS_LISTENING ) )
     
    305327                closesocket( fd );
    306328                fd = df->fd;
    307                 file->status = FT_STATUS_TRANSFERING;
     329                file->status = FT_STATUS_TRANSFERRING;
    308330                sock_make_nonblocking( fd );
    309331
    310 #ifdef DCC_SEND_AHEAD
    311                 /*
    312                  * use twice the maximum segment size as a maximum for calls to send().
    313                  */
    314                 if( max_packet_size == 0 )
    315                 {
    316                         unsigned int mpslen = sizeof( max_packet_size );
    317                         if( getsockopt( fd, IPPROTO_TCP, TCP_MAXSEG, &max_packet_size, &mpslen ) )
    318                                 return dcc_abort( df, "getsockopt() failed" );
    319                         max_packet_size *= 2;
    320                 }
    321 #endif
     332                if ( !dcc_check_maxseg( df, fd ) )
     333                        return FALSE;
     334
    322335                /* IM protocol callback */
    323 
    324336                if( file->accept )
    325337                        file->accept( file );
     338
    326339                /* reschedule for reading on new fd */
    327340                df->watch_in = b_input_add( fd, GAIM_INPUT_READ, dccs_send_proto, df );
     
    367380                }
    368381       
    369 #ifndef DCC_SEND_AHEAD
    370                 /* reschedule writer if neccessary */
    371                 if( file->bytes_transferred >= df->bytes_sent &&
    372                     df->watch_out == 0 &&
    373                     df->queued_bytes > 0 ) {
    374                         df->watch_out = b_input_add( fd, GAIM_INPUT_WRITE, dcc_send_proto, df );
     382                return TRUE;
     383        }
     384
     385        return TRUE;
     386}
     387
     388gboolean dccs_recv_start( file_transfer_t *ft )
     389{
     390        dcc_file_transfer_t *df = ft->priv;
     391        struct sockaddr_storage *saddr = &df->saddr;
     392        int fd;
     393        socklen_t sa_len = saddr->ss_family == AF_INET ?
     394                sizeof( struct sockaddr_in ) : sizeof( struct sockaddr_in6 );
     395       
     396        if( !ft->write )
     397                return dcc_abort( df, "Protocol didn't register write()" );
     398       
     399        ASSERTSOCKOP( fd = df->fd = socket( saddr->ss_family, SOCK_STREAM, 0 ) , "Opening Socket" );
     400
     401        sock_make_nonblocking( fd );
     402
     403        if( ( connect( fd, (struct sockaddr *)saddr, sa_len ) == -1 ) &&
     404            ( errno != EINPROGRESS ) )
     405                return dcc_abort( df, "Connecting" );
     406
     407        ft->status = FT_STATUS_CONNECTING;
     408
     409        /* watch */
     410        df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_recv_proto, df );
     411        ft->write_request = dccs_recv_write_request;
     412
     413        return TRUE;
     414}
     415
     416gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond)
     417{
     418        dcc_file_transfer_t *df = data;
     419        file_transfer_t *ft = df->ft;
     420        short revents;
     421
     422        if( !dcc_poll( df, fd, &revents ) )
     423                return FALSE;
     424       
     425        if( ( revents & POLLOUT ) &&
     426            ( ft->status & FT_STATUS_CONNECTING ) )
     427        {
     428                ft->status = FT_STATUS_TRANSFERRING;
     429                if ( !dcc_check_maxseg( df, fd ) )
     430                        return FALSE;
     431
     432                //df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df );
     433
     434                df->watch_out = 0;
     435                return FALSE;
     436        }
     437
     438        if( revents & POLLIN )
     439        {
     440                int ret, done;
     441
     442                ASSERTSOCKOP( ret = recv( fd, ft->buffer, sizeof( ft->buffer ), 0 ), "Receiving" );
     443
     444                if( ret == 0 )
     445                        return dcc_abort( df, "Remote end closed connection" );
     446
     447                df->bytes_sent += ret;
     448
     449                done = df->bytes_sent >= ft->file_size;
     450
     451                if( ( ( df->bytes_sent - ft->bytes_transferred ) > DCC_PACKET_SIZE ) ||
     452                    done )
     453                {
     454                        int ack, ackret;
     455                        ack = htonl( ft->bytes_transferred = df->bytes_sent );
     456
     457                        ASSERTSOCKOP( ackret = send( fd, &ack, 4, 0 ), "Sending DCC ACK" );
     458                       
     459                        if ( ackret != 4 )
     460                                return dcc_abort( df, "Error sending DCC ACK, sent %d instead of 4 bytes", ackret );
    375461                }
    376 #endif
    377                 return TRUE;
    378         }
    379 
    380         if( revents & POLLOUT )
    381         {
    382                 struct dcc_buffer *dccb;
    383                 int ret;
    384                 char *msg;
    385 
    386                 if( df->queued_bytes == 0 )
    387                 {
    388                         /* shouldn't happen */
    389                         imcb_log( df->ic, "WARNING: DCC SEND: write called with empty queue" );
    390 
    391                         df->watch_out = 0;
     462               
     463                if( !ft->write( df->ft, ft->buffer, ret ) )
     464                        return FALSE;
     465
     466                if( done )
     467                {
     468                        closesocket( fd );
     469                        dcc_finish( ft );
     470
     471                        df->watch_in = 0;
    392472                        return FALSE;
    393473                }
    394474
    395                 /* start where we left off */
    396                 if( !( df->queued_buffers ) ||
    397                     !( dccb = df->queued_buffers->data ) )
    398                         return dcc_abort( df, "BUG in DCC SEND: queued data but no buffers" );
    399 
    400                 msg = dccb->b + df->buffer_pos;
    401 
    402                 int msgsize = MIN(
    403 #ifndef DCC_SEND_AHEAD
    404                                   file->bytes_transferred + MAX_PACKET_SIZE - df->bytes_sent,
    405 #else
    406                                   max_packet_size,
    407 #endif
    408                                   dccb->len - df->buffer_pos );
    409 
    410                 if ( msgsize == 0 )
    411                 {
    412                         df->watch_out = 0;
    413                         return FALSE;
    414                 }
    415 
    416                 ASSERTSOCKOP( ret = send( fd, msg, msgsize, 0 ), "Sending data" );
    417 
    418                 if( ret == 0 )
    419                         return dcc_abort( df, "Remote end closed connection" );
    420 
    421                 df->bytes_sent += ret;
    422                 df->queued_bytes -= ret;
    423                 df->buffer_pos += ret;
    424 
    425                 if( df->buffer_pos == dccb->len )
    426                 {
    427                         df->buffer_pos = 0;
    428                         df->queued_buffers = g_slist_remove( df->queued_buffers, dccb );
    429                         g_free( dccb->b );
    430                         g_free( dccb );
    431                 }
    432 
    433                 if( ( df->queued_bytes < DCC_QUEUE_THRESHOLD_LOW ) && file->out_of_data )
    434                         file->out_of_data( file );
    435        
    436                 if( df->queued_bytes > 0 )
    437                 {
    438                         /* Who knows how long the event loop cycle will take,
    439                          * let's just try to send some more now. */
    440 #ifndef DCC_SEND_AHEAD
    441                         if( df->bytes_sent < ( file->bytes_transferred + max_packet_size ) )
    442 #endif
    443                                 return dccs_send_proto( df, fd, cond );
    444                 }
    445 
    446                 df->watch_out = 0;
     475                df->watch_in = 0;
    447476                return FALSE;
    448477        }
    449478
    450         /* Send buffer full, come back later */
    451 
    452         return TRUE;
     479        return TRUE;
     480}
     481
     482gboolean dccs_recv_write_request( file_transfer_t *ft )
     483{
     484        dcc_file_transfer_t *df = ft->priv;
     485
     486        if( df->watch_in )
     487                return dcc_abort( df, "BUG: write_request() called while watching" );
     488
     489        df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df );
     490
     491        return TRUE;
     492}
     493
     494gboolean dccs_send_can_write( gpointer data, gint fd, b_input_condition cond )
     495{
     496        struct dcc_file_transfer *df = data;
     497        df->watch_out = 0;
     498
     499        df->ft->write_request( df->ft );
     500        return FALSE;
    453501}
    454502
    455503/*
    456  * Incoming data. Note that the buffer MUST NOT be freed by the caller!
    457  * We don't copy the buffer but put it in our queue.
     504 * Incoming data.
    458505 *
    459  * */
    460 gboolean dccs_send_write( file_transfer_t *file, gpointer data, unsigned int data_size )
     506 */
     507gboolean dccs_send_write( file_transfer_t *file, char *data, unsigned int data_len )
    461508{
    462509        dcc_file_transfer_t *df = file->priv;
    463         struct dcc_buffer *dccb = g_new0( struct dcc_buffer, 1 );
    464 
    465         receivedchunks++; receiveddata += data_size;
    466 
    467         dccb->b = data;
    468         dccb->len = data_size;
    469 
    470         df->queued_buffers = g_slist_append( df->queued_buffers, dccb );
    471 
    472         df->queued_bytes += data_size;
    473 
    474         if( ( file->status & FT_STATUS_TRANSFERING ) &&
    475 #ifndef DCC_SEND_AHEAD
    476             ( file->bytes_transferred >= df->bytes_sent ) &&
    477 #endif
    478             ( df->watch_out == 0 ) &&
    479             ( df->queued_bytes > 0 ) )
    480         {
    481                 df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_send_proto, df );
    482         }
    483        
    484         return df->queued_bytes > DCC_QUEUE_THRESHOLD_HIGH;
     510        int ret;
     511
     512        receivedchunks++; receiveddata += data_len;
     513
     514        if( df->watch_out )
     515                return dcc_abort( df, "BUG: write() called while watching" );
     516
     517        ASSERTSOCKOP( ret = send( df->fd, data, data_len, 0 ), "Sending data" );
     518
     519        if( ret == 0 )
     520                return dcc_abort( df, "Remote end closed connection" );
     521
     522        /* TODO: this should really not be fatal */
     523        if( ret < data_len )
     524                return dcc_abort( df, "send() sent %d instead of %d", ret, data_len );
     525
     526        df->bytes_sent += ret;
     527
     528        if( df->bytes_sent < df->ft->file_size )
     529                df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_send_can_write, df );
     530
     531        return TRUE;
    485532}
    486533
     
    503550                b_event_remove( df->watch_out );
    504551       
    505         if( df->queued_buffers )
    506         {
    507                 struct dcc_buffer *dccb;
    508                 GSList *gslist = df->queued_buffers;
    509 
    510                 for( ; gslist ; gslist = g_slist_next( gslist ) )
    511                 {
    512                         dccb = gslist->data;
    513                         g_free( dccb->b );
    514                         g_free( dccb );
    515                 }
    516                 g_slist_free( df->queued_buffers );
    517         }
    518 
    519552        df->ic->irc->file_transfers = g_slist_remove( df->ic->irc->file_transfers, file );
    520553       
     
    533566        dcc_close( file );
    534567}
     568
     569/*
     570 * DCC SEND <filename> <IP> <port> <filesize>
     571 *
     572 * filename can be in "" or not. If it is, " can probably be escaped...
     573 * IP can be an unsigned int (IPV4) or something else (IPV6)
     574 *
     575 */
     576file_transfer_t *dcc_request( struct im_connection *ic, char *line )
     577{
     578        char *pattern = "SEND"
     579                " (([^\"][^ ]*)|\"([^\"]|\\\")*\")"
     580                " (([0-9]*)|([^ ]*))"
     581                " ([0-9]*)"
     582                " ([0-9]*)\001";
     583        regmatch_t pmatch[9];
     584        regex_t re;
     585        file_transfer_t *ft;
     586        dcc_file_transfer_t *df;
     587
     588        if( regcomp( &re, pattern, REG_EXTENDED ) )
     589                return NULL;
     590        if( regexec( &re, line, 9, pmatch, 0 ) )
     591                return NULL;
     592
     593        if( ( pmatch[1].rm_so > 0 ) &&
     594            ( pmatch[4].rm_so > 0 ) &&
     595            ( pmatch[7].rm_so > 0 ) &&
     596            ( pmatch[8].rm_so > 0 ) )
     597        {
     598                char *input = g_strdup( line );
     599                char *filename, *host, *port;
     600                size_t filesize;
     601                struct addrinfo hints, *rp;
     602
     603                /* "filename" or filename */
     604                if ( pmatch[2].rm_so > 0 )
     605                {
     606                        input[pmatch[2].rm_eo] = '\0';
     607                        filename = input + pmatch[2].rm_so;
     608                } else
     609                {
     610                        input[pmatch[3].rm_eo] = '\0';
     611                        filename = input + pmatch[3].rm_so;
     612                }
     613                       
     614                input[pmatch[4].rm_eo] = '\0';
     615
     616                /* number means ipv4, something else means ipv6 */
     617                if ( pmatch[5].rm_so > 0 )
     618                {
     619                        struct in_addr ipaddr = { htonl( atoi( input + pmatch[5].rm_so ) ) };
     620                        host = inet_ntoa( ipaddr );
     621                } else
     622                {
     623                        /* Contains non-numbers, hopefully an IPV6 address */
     624                        host = input + pmatch[6].rm_so;
     625                }
     626
     627                input[pmatch[7].rm_eo] = '\0';
     628                input[pmatch[8].rm_eo] = '\0';
     629
     630                port = input + pmatch[7].rm_so;
     631                filesize = atoll( input + pmatch[8].rm_so );
     632
     633                memset( &hints, 0, sizeof ( struct addrinfo ) );
     634                if ( getaddrinfo( host, port, &hints, &rp ) )
     635                {
     636                        g_free( input );
     637                        return NULL;
     638                }
     639
     640                df = dcc_alloc_transfer( filename, filesize, ic );
     641                ft = df->ft;
     642                ft->sending = TRUE;
     643                memcpy( &df->saddr, rp->ai_addr, rp->ai_addrlen );
     644
     645                freeaddrinfo( rp );
     646                g_free( input );
     647
     648                df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, ft );
     649
     650                return ft;
     651        }
     652
     653        return NULL;
     654}
     655
  • dcc.h

    r2c2df7d rfa30fa5  
    4444#define _DCC_H
    4545
    46 /* don't wait for acknowledgments */
    47 #define DCC_SEND_AHEAD
    48 
    49 /* This multiplier specifies how many bytes we
    50  * can go ahead within one event loop cycle. Notice that all in all,
    51  * we can easily be more ahead if the event loop shoots often enough.
    52  * (or the receiver processes slow enough)
    53  *
    54  * Setting this value too high will cause send buffer overflows.
    55  */
    56 #define DCC_SEND_AHEAD_MUL 10
    57 
    58 /*
    59  * queue thresholds for the out of data and overflow conditions
    60  */
    61 #define DCC_QUEUE_THRESHOLD_LOW 2048
    62 #define DCC_QUEUE_THRESHOLD_HIGH 65536
    63 
    64 /* only used in non-ahead mode */
     46/* Send an ACK after receiving this amount of data */
    6547#define DCC_PACKET_SIZE 1024
    66 
    67 /* stores buffers handed over by IM protocols */
    68 struct dcc_buffer {
    69         char *b;
    70         int len;
    71 };
    7248
    7349typedef struct dcc_file_transfer {
     
    8965       
    9066        /*
    91          * The total number of queued bytes. The following equality should always hold:
    92          *
    93          *      queued_bytes = sum(queued_buffers.len) - buffer_pos
    94          */
    95         unsigned int queued_bytes;
    96 
    97         /*
    98          * A list of dcc_buffer structures.
    99          * These are provided by the protocols directly so that no copying is neccessary.
    100          */
    101         GSList *queued_buffers;
    102        
    103         /*
    104          * current position within the first buffer.
    105          * Is non-null if the whole buffer couldn't be sent at once.
    106          */
    107         int buffer_pos;
    108 
    109         /*
    11067         * The total amount of bytes that have been sent to the irc client.
    11168         */
    11269        size_t bytes_sent;
    11370       
    114         /* imcb's handle */
     71        /* imc's handle */
    11572        file_transfer_t *ft;
     73
     74        /* if we're receiving, this is the sender's socket address */
     75        struct sockaddr_storage saddr;
    11676
    11777} dcc_file_transfer_t;
     
    12181void dcc_canceled( file_transfer_t *file, char *reason );
    12282
    123 gboolean dccs_send_write( file_transfer_t *file, gpointer data, unsigned int data_size );
     83gboolean dccs_send_write( file_transfer_t *file, char *data, unsigned int data_size );
    12484
     85file_transfer_t *dcc_request( struct im_connection *ic, char *line );
    12586#endif
  • doc/user-guide/commands.xml

    r2c2df7d rfa30fa5  
    861861
    862862        </bitlbee-command>
     863       
     864        <bitlbee-command name="transfers">
     865                <short-description>Monitor, cancel, or reject file transfers</short-description>
     866                <syntax>transfers [&lt;cancel&gt; id | &lt;reject&gt;]</syntax>
     867               
     868                <description>
     869                        <para>
     870                                Without parameters the currently pending file transfers and their status will be listed. Available actions are <emphasis>cancel</emphasis> and <emphasis>reject</emphasis>. See <emphasis>help transfers &lt;action&gt;</emphasis> for more information.
     871                        </para>
     872
     873                        <ircexample>
     874                                <ircline nick="ulim">transfers</ircline>
     875                        </ircexample>
     876                </description>
     877               
     878                <bitlbee-command name="cancel">
     879                        <short-description>Cancels the file transfer with the given id</short-description>
     880                        <syntax>transfers &lt;cancel&gt; id</syntax>
     881
     882                        <description>
     883                                <para>Cancels the file transfer with the given id</para>
     884                        </description>
     885
     886                        <ircexample>
     887                                <ircline nick="ulim">transfers cancel 1</ircline>
     888                                <ircline nick="root">Canceling file transfer for test</ircline>
     889                        </ircexample>
     890                </bitlbee-command>
     891
     892                <bitlbee-command name="reject">
     893                        <short-description>Rejects all incoming transfers</short-description>
     894                        <syntax>transfers &lt;reject&gt;</syntax>
     895
     896                        <description>
     897                                <para>Rejects all incoming (not already transferring) file transfers. Since you probably have only one incoming transfer at a time, no id is neccessary. Or is it?</para>
     898                        </description>
     899
     900                        <ircexample>
     901                                <ircline nick="ulim">transfers reject</ircline>
     902                        </ircexample>
     903                </bitlbee-command>
     904        </bitlbee-command>
     905       
    863906</chapter>
  • irc.c

    r2c2df7d rfa30fa5  
    2828#include "crypting.h"
    2929#include "ipc.h"
     30#include "dcc.h"
     31
     32#include <regex.h>
     33#include <netinet/in.h>
    3034
    3135static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
     
    981985                        return( 1 );
    982986                }
     987                else if( g_strncasecmp( s + 1, "DCC", 3 ) == 0 )
     988                {
     989                        if( u && u->ic && u->ic->acc->prpl->transfer_request )
     990                        {
     991                                file_transfer_t *ft = dcc_request( u->ic, s + 5 );
     992                                if ( ft )
     993                                        u->ic->acc->prpl->transfer_request( u->ic, ft, u->handle );
     994                        }
     995                        return( 1 );
     996                }               
    983997                else
    984998                {
    985                         irc_usermsg( irc, "Non-ACTION CTCP's aren't supported" );
     999                        irc_usermsg( irc, "Supported CTCPs are ACTION, VERSION, PING, TYPING, DCC" );
    9861000                        return( 0 );
    9871001                }
  • protocols/ft.h

    r2c2df7d rfa30fa5  
    2727#define _FT_H
    2828
     29/*
     30 * One buffer is needed for each transfer. The receiver stores a message
     31 * in it and gives it to the sender. The sender will stall the receiver
     32 * till the buffer has been sent out.
     33 */
     34#define FT_BUFFER_SIZE 2048
     35
    2936typedef enum {
    3037        FT_STATUS_LISTENING     = 1,
    31         FT_STATUS_TRANSFERING   = 2,
     38        FT_STATUS_TRANSFERRING  = 2,
    3239        FT_STATUS_FINISHED      = 4,
    33         FT_STATUS_CANCELED      = 8
     40        FT_STATUS_CANCELED      = 8,
     41        FT_STATUS_CONNECTING    = 16
    3442} file_status_t;
    3543
     
    6169 */
    6270typedef struct file_transfer {
     71
     72        /* Are we sending something? */
     73        int sending;
     74
    6375        /*
    6476         * The current status of this file transfer.
     
    126138       
    127139        /*
    128          * If set, called when the transfer queue is running empty and
    129          * more data can be added.
     140         * called by the sending side to indicate that it is writable.
     141         * The callee should check if data is available and call the
     142         * function(as seen below) if that is the case.
    130143         */
    131         void (*out_of_data) ( struct file_transfer *file );
     144        gboolean (*write_request) ( struct file_transfer *file );
     145
     146        /*
     147         * When sending files, protocols register this function to receive data.
     148         * This should only be called once after write_request is called. The caller
     149         * should not read more data until write_request is called again. This technique
     150         * avoids buffering.
     151         */
     152        gboolean (*write) (struct file_transfer *file, char *buffer, unsigned int len );
     153
     154        /* The send buffer associated with this transfer.
     155         * Since receivers always wait for a write_request call one is enough.
     156         */
     157        char buffer[FT_BUFFER_SIZE];
    132158
    133159} file_transfer_t;
     
    144170void imcb_file_canceled( file_transfer_t *file, char *reason );
    145171
    146 /*
    147  * The given buffer is queued for transfer and MUST NOT be freed by the caller.
    148  * When the method returns false the caller should not invoke this method again
    149  * until out_of_data has been called.
    150  */
    151 gboolean imcb_file_write( file_transfer_t *file, gpointer data, size_t data_size );
    152 
     172gboolean imcb_file_recv_start( file_transfer_t *ft );
    153173#endif
  • protocols/jabber/Makefile

    r2c2df7d rfa30fa5  
    1010
    1111# [SH] Program variables
    12 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o si.o stream.o
     12objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o si.o s5bytestream.o
    1313
    1414CFLAGS += -Wall
  • protocols/jabber/iq.c

    r2c2df7d rfa30fa5  
    168168                {
    169169                        /* Bytestream Request (stage 2 of file transfer) */
    170                         return jabber_bs_request( ic, node, c );
     170                        return jabber_bs_recv_request( ic, node, c );
    171171                } else
    172172                {
  • protocols/jabber/jabber.c

    r2c2df7d rfa30fa5  
    502502        ret->send_typing = jabber_send_typing;
    503503        ret->handle_cmp = g_strcasecmp;
     504        ret->transfer_request = jabber_si_transfer_request;
    504505
    505506        register_protocol( ret );
  • protocols/jabber/jabber.h

    r2c2df7d rfa30fa5  
    146146
    147147        size_t bytesread, byteswritten;
    148         int receiver_overflow;
    149148        int fd;
     149        struct sockaddr_storage saddr;
    150150};
    151151
     
    201201
    202202/* si.c */
    203 int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode);
    204 
    205 /* stream.c */
    206 int jabber_bs_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
     203int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode );
     204void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
     205void jabber_si_free_transfer( file_transfer_t *ft);
     206
     207/* s5bytestream.c */
     208int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
     209gboolean jabber_bs_send_start( struct jabber_transfer *tf );
     210gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len );
    207211
    208212/* message.c */
  • protocols/jabber/jabber_util.c

    r2c2df7d rfa30fa5  
    265265        new = g_new( char, len + 1 );
    266266        for( i = 0; i < len; i ++ )
     267        {
     268                /* don't normalize the resource */
     269                if( orig[i] == '/' )
     270                        break;
    267271                new[i] = tolower( orig[i] );
     272        }
     273        for( ; i < len; i ++ )
     274                new[i] = orig[i];
    268275       
    269276        new[i] = 0;
  • protocols/jabber/si.c

    r2c2df7d rfa30fa5  
    2626
    2727void jabber_si_answer_request( file_transfer_t *ft );
    28 
    29 /* imcb callback */
     28int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf );
     29
     30/* file_transfer free() callback */
    3031void jabber_si_free_transfer( file_transfer_t *ft)
    3132{
     
    5051}
    5152
    52 /* imcb callback */
     53/* file_transfer finished() callback */
    5354void jabber_si_finished( file_transfer_t *ft )
    5455{
     
    5859}
    5960
    60 /* imcb callback */
     61/* file_transfer canceled() callback */
    6162void jabber_si_canceled( file_transfer_t *ft, char *reason )
    6263{
     
    7677        xt_free_node( reply );
    7778
     79}
     80
     81void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who )
     82{
     83        struct jabber_transfer *tf;
     84        struct jabber_data *jd = ic->proto_data;
     85
     86        imcb_log( ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who );
     87
     88        tf = g_new0( struct jabber_transfer, 1 );
     89
     90        tf->ic = ic;
     91        tf->ft = ft;
     92        tf->ft->data = tf;
     93        tf->ft->free = jabber_si_free_transfer;
     94        tf->ft->finished = jabber_si_finished;
     95        ft->write = jabber_bs_send_write;
     96
     97        jd->filetransfers = g_slist_prepend( jd->filetransfers, tf );
     98
     99        jabber_si_send_request( ic, who, tf );
     100
     101        imcb_file_recv_start( ft );
    78102}
    79103
     
    136160                                break;
    137161                        }
     162
     163                if ( !requestok )
     164                        imcb_log( ic, "WARNING: Unsupported file transfer request from %s", ini_jid);
    138165        }
    139166       
     
    160187
    161188                *s = '/';
    162         } else
    163                 imcb_log( ic, "WARNING: Unsupported file transfer request from %s", ini_jid);
     189        }
    164190
    165191        if ( !requestok )
     
    198224
    199225/*
    200  * imcb called the accept callback which probably means that the user accepted this file transfer.
     226 * imc called the accept callback which probably means that the user accepted this file transfer.
    201227 * We send our response to the initiator.
    202228 * In the next step, the initiator will send us a request for the given stream type.
     
    245271        xt_free_node( reply );
    246272}
     273
     274static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     275{
     276        struct xt_node *c, *d;
     277        char *ini_jid, *tgt_jid, *iq_id;
     278        GSList *tflist;
     279        struct jabber_transfer *tf=NULL;
     280        struct jabber_data *jd = ic->proto_data;
     281
     282        if( !( tgt_jid = xt_find_attr( node, "from" ) ) ||
     283            !( ini_jid = xt_find_attr( node, "to" ) ) )
     284        {
     285                imcb_log( ic, "Invalid SI response from=%s to=%s", tgt_jid, ini_jid );
     286                return XT_HANDLED;
     287        }
     288       
     289        /* All this means we expect something like this: ( I think )
     290         * <iq from=... to=... id=...>
     291         *      <si xmlns=si>
     292         *      [       <file xmlns=ft/>    ] <-- not neccessary
     293         *              <feature xmlns=feature>
     294         *                      <x xmlns=xdata type=submit>
     295         *                              <field var=stream-method>
     296         *                                      <value>
     297         */
     298        if( !( tgt_jid = xt_find_attr( node, "from" ) ) ||
     299            !( ini_jid = xt_find_attr( node, "to" ) ) ||
     300            !( iq_id   = xt_find_attr( node, "id" ) ) ||
     301            !( c = xt_find_node( node->children, "si" ) ) ||
     302            !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_SI ) == 0 ) ||
     303/*          !( d = xt_find_node( c->children, "file" ) ) ||
     304            !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FILETRANSFER ) == 0 ) || */
     305            !( d = xt_find_node( c->children, "feature" ) ) ||
     306            !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FEATURE ) == 0 ) ||
     307            !( d = xt_find_node( d->children, "x" ) ) ||
     308            !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_XDATA ) == 0 ) ||
     309            !( strcmp( xt_find_attr( d, "type" ), "submit" ) == 0 ) ||
     310            !( d = xt_find_node( d->children, "field" ) ) ||
     311            !( strcmp( xt_find_attr( d, "var" ), "stream-method" ) == 0 ) ||
     312            !( d = xt_find_node( d->children, "value" ) ) )
     313        {
     314                imcb_log( ic, "WARNING: Received incomplete Stream Initiation response" );
     315                return XT_HANDLED;
     316        }
     317
     318        if( !( strcmp( d->text, XMLNS_BYTESTREAMS ) == 0 ) ) {
     319                /* since we should only have advertised what we can do and the peer should
     320                 * only have chosen what we offered, this should never happen */
     321                imcb_log( ic, "WARNING: Received invalid Stream Initiation response, method %s", d->text );
     322                       
     323                return XT_HANDLED;
     324        }
     325       
     326        /* Let's see if we can find out what this bytestream should be for... */
     327
     328        for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) )
     329        {
     330                struct jabber_transfer *tft = tflist->data;
     331                if( ( strcmp( tft->iq_id, iq_id ) == 0 ) )
     332                {
     333                        tf = tft;
     334                        break;
     335                }
     336        }
     337
     338        if (!tf)
     339        {
     340                imcb_log( ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid );
     341                return XT_HANDLED;
     342        }
     343
     344        tf->ini_jid = g_strdup( ini_jid );
     345        tf->tgt_jid = g_strdup( tgt_jid );
     346
     347        imcb_log( ic, "File %s: %s accepted the transfer!", tf->ft->file_name, tgt_jid );
     348
     349        jabber_bs_send_start( tf );
     350
     351        return XT_HANDLED;
     352}
     353
     354int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf )
     355{
     356        struct xt_node *node, *sinode;
     357        struct jabber_buddy *bud;
     358
     359        /* who knows how many bits the future holds :) */
     360        char filesizestr[ 1 + ( int ) ( 0.301029995663981198f * sizeof( size_t ) * 8 ) ];
     361
     362        const char *methods[] =
     363        {       
     364                XMLNS_BYTESTREAMS,
     365                //XMLNS_IBB,
     366                NULL
     367        };
     368        const char **m;
     369        char *s;
     370
     371        /* Maybe we should hash this? */
     372        tf->sid = g_strdup_printf( "BitlBeeJabberSID%d", tf->ft->local_id );
     373       
     374        if( ( s = strchr( who, '=' ) ) && jabber_chat_by_name( ic, s + 1 ) )
     375                bud = jabber_buddy_by_ext_jid( ic, who, 0 );
     376        else
     377                bud = jabber_buddy_by_jid( ic, who, 0 );
     378
     379        /* start with the SI tag */
     380        sinode = xt_new_node( "si", NULL, NULL );
     381        xt_add_attr( sinode, "xmlns", XMLNS_SI );
     382        xt_add_attr( sinode, "profile", XMLNS_FILETRANSFER );
     383        xt_add_attr( sinode, "id", tf->sid );
     384
     385/*      if( mimetype )
     386                xt_add_attr( node, "mime-type", mimetype ); */
     387
     388        /* now the file tag */
     389/*      if( desc )
     390                node = xt_new_node( "desc", descr, NULL ); */
     391        node = xt_new_node( "range", NULL, NULL );
     392
     393        sprintf( filesizestr, "%zd", tf->ft->file_size );
     394        node = xt_new_node( "file", NULL, node );
     395        xt_add_attr( node, "xmlns", XMLNS_FILETRANSFER );
     396        xt_add_attr( node, "name", tf->ft->file_name );
     397        xt_add_attr( node, "size", filesizestr );
     398/*      if (hash)
     399                xt_add_attr( node, "hash", hash );
     400        if (date)
     401                xt_add_attr( node, "date", date ); */
     402
     403        xt_add_child( sinode, node );
     404
     405        /* and finally the feature tag */
     406        node = xt_new_node( "field", NULL, NULL );
     407        xt_add_attr( node, "var", "stream-method" );
     408        xt_add_attr( node, "type", "list-single" );
     409
     410        for ( m = methods ; *m ; m ++ )
     411                xt_add_child( node, xt_new_node( "option", NULL, xt_new_node( "value", (char *)*m, NULL ) ) );
     412
     413        node = xt_new_node( "x", NULL, node );
     414        xt_add_attr( node, "xmlns", XMLNS_XDATA );
     415        xt_add_attr( node, "type", "form" );
     416
     417        node = xt_new_node( "feature", NULL, node );
     418        xt_add_attr( node, "xmlns", XMLNS_FEATURE );
     419
     420        xt_add_child( sinode, node );
     421
     422        /* and we are there... */
     423        node = jabber_make_packet( "iq", "set", bud ? bud->full_jid : who, sinode );
     424        jabber_cache_add( ic, node, jabber_si_handle_response );
     425        tf->iq_id = g_strdup( xt_find_attr( node, "id" ) );
     426       
     427        return jabber_write_packet( ic, node );
     428}
  • protocols/nogaim.h

    r2c2df7d rfa30fa5  
    229229         * - Most protocols will just want to set this to g_strcasecmp().*/
    230230        int (* handle_cmp) (const char *who1, const char *who2);
     231
     232        /* Incoming transfer request */
     233        void (* transfer_request) (struct im_connection *, file_transfer_t *ft, char *handle );
    231234};
    232235
Note: See TracChangeset for help on using the changeset viewer.