Changes in dcc.c [dce3903:2c2df7d]
Legend:
- Unmodified
- Added
- Removed
-
dcc.c
rdce3903 r2c2df7d 28 28 #include <poll.h> 29 29 #include <netinet/tcp.h> 30 #include <regex.h>31 30 32 31 /* … … 61 60 unsigned int receivedchunks=0, receiveddata=0; 62 61 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 63 70 int max_packet_size = 0; 71 #endif 64 72 65 73 static void dcc_finish( file_transfer_t *file ); … … 68 76 gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_ptr ); 69 77 int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr ); 70 gboolean dccs_recv_start( file_transfer_t *ft );71 gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond);72 gboolean dccs_recv_write_request( file_transfer_t *ft );73 78 74 79 /* As defined in ft.h */ … … 94 99 95 100 /* As defined in ft.h */ 96 gboolean imcb_file_recv_start( file_transfer_t *ft ) 97 { 98 return dccs_recv_start( ft ); 99 } 100 101 dcc_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); 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); 105 119 file->file_size = file_size; 106 120 file->file_name = g_strdup( file_name ); … … 109 123 df->ft = file; 110 124 111 return df; 112 } 113 114 /* This is where the sending magic starts... */ 115 file_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 ) 125 /* listen and request */ 126 if( !dcc_listen( df, saddr ) || 127 !dccs_send_request( df, user_nick, *saddr ) ) 122 128 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 129 /* listen and request */ 130 if( !dcc_listen( df, &saddr ) || 131 !dccs_send_request( df, user_nick, saddr ) ) 132 return NULL; 133 134 g_free( saddr ); 129 130 g_free( *saddr ); 135 131 136 132 /* watch */ … … 182 178 struct sockaddr_in *saddr_ipv4 = ( struct sockaddr_in *) saddr; 183 179 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 */ 184 185 sprintf( ipaddr, "%d", 185 ntohl( saddr_ipv4->sin_addr.s_addr ) );186 htonl( saddr_ipv4->sin_addr.s_addr ) ); 186 187 port = saddr_ipv4->sin_port; 187 188 } else … … 208 209 209 210 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 ); 210 214 211 215 return TRUE; … … 257 261 258 262 /* 259 * Checks poll(), same for receiving and sending 260 */ 261 gboolean dcc_poll( dcc_file_transfer_t *df, int fd, short *revents ) 262 { 263 * After setup, the transfer itself is handled entirely by this function. 264 * There are basically four things to handle: connect, receive, send, and error. 265 */ 266 gboolean dccs_send_proto( gpointer data, gint fd, b_input_condition cond ) 267 { 268 dcc_file_transfer_t *df = data; 269 file_transfer_t *file = df->ft; 263 270 struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT }; 264 265 ASSERTSOCKOP( poll( &pfd, 1, 0 ), "poll()" ) 266 267 if( pfd.revents & POLLERR ) 271 short revents; 272 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 ) 268 282 { 269 283 int sockerror; … … 276 290 } 277 291 278 if( pfd.revents & POLLHUP )292 if( revents & POLLHUP ) 279 293 return dcc_abort( df, "Remote end closed connection" ); 280 294 281 *revents = pfd.revents;282 283 return TRUE;284 }285 286 /*287 * fills max_packet_size with twice the TCP maximum segment size288 */289 gboolean 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 /*305 * After setup, the transfer itself is handled entirely by this function.306 * There are basically four things to handle: connect, receive, send, and error.307 */308 gboolean dccs_send_proto( gpointer data, gint fd, b_input_condition cond )309 {310 dcc_file_transfer_t *df = data;311 file_transfer_t *file = df->ft;312 short revents;313 314 if( !dcc_poll( df, fd, &revents) )315 return FALSE;316 317 295 if( ( revents & POLLIN ) && 318 296 ( file->status & FT_STATUS_LISTENING ) ) … … 327 305 closesocket( fd ); 328 306 fd = df->fd; 329 file->status = FT_STATUS_TRANSFER RING;307 file->status = FT_STATUS_TRANSFERING; 330 308 sock_make_nonblocking( fd ); 331 309 332 if ( !dcc_check_maxseg( df, fd ) ) 333 return FALSE; 334 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 335 322 /* IM protocol callback */ 323 336 324 if( file->accept ) 337 325 file->accept( file ); 338 339 326 /* reschedule for reading on new fd */ 340 327 df->watch_in = b_input_add( fd, GAIM_INPUT_READ, dccs_send_proto, df ); … … 380 367 } 381 368 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 ); 375 } 376 #endif 382 377 return TRUE; 383 378 } 384 379 385 return TRUE; 386 } 387 388 gboolean 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 416 gboolean 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 ) ) 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; 430 392 return FALSE; 431 432 //df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df ); 393 } 394 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 } 433 445 434 446 df->watch_out = 0; … … 436 448 } 437 449 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 ); 461 } 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; 472 return FALSE; 473 } 474 475 df->watch_in = 0; 476 return FALSE; 477 } 450 /* Send buffer full, come back later */ 478 451 479 452 return TRUE; 480 453 } 481 454 482 gboolean 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 494 gboolean 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;501 }502 503 455 /* 504 * Incoming data. 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. 505 458 * 506 * /507 gboolean dccs_send_write( file_transfer_t *file, char *data, unsigned int data_len)459 * */ 460 gboolean dccs_send_write( file_transfer_t *file, gpointer data, unsigned int data_size ) 508 461 { 509 462 dcc_file_transfer_t *df = file->priv; 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;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; 532 485 } 533 486 … … 550 503 b_event_remove( df->watch_out ); 551 504 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 552 519 df->ic->irc->file_transfers = g_slist_remove( df->ic->irc->file_transfers, file ); 553 520 … … 566 533 dcc_close( file ); 567 534 } 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 */576 file_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 } else609 {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 } else622 {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
Note: See TracChangeset
for help on using the changeset viewer.