Changeset fa30fa5 for protocols


Ignore:
Timestamp:
2007-12-04T00:53:04Z (17 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...

Location:
protocols
Files:
1 added
1 deleted
8 edited

Legend:

Unmodified
Added
Removed
  • 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.