- Timestamp:
- 2007-12-03T14:28:45Z (16 years ago)
- Branches:
- master
- Children:
- dce3903
- Parents:
- 2c2df7d
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
dcc.c
r2c2df7d r2ff2076 28 28 #include <poll.h> 29 29 #include <netinet/tcp.h> 30 #include <regex.h> 30 31 31 32 /* … … 76 77 gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_ptr ); 77 78 int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr ); 79 gboolean dccs_recv_start( file_transfer_t *ft ); 80 gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond); 81 void dccs_recv_out_of_data( file_transfer_t *ft ); 78 82 79 83 /* As defined in ft.h */ … … 104 108 } 105 109 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); 110 /* As defined in ft.h */ 111 gboolean imcb_file_recv_start( file_transfer_t *ft ) 112 { 113 return dccs_recv_start( ft ); 114 } 115 116 dcc_file_transfer_t *dcc_alloc_transfer( char *file_name, size_t file_size, struct im_connection *ic ) 117 { 118 file_transfer_t *file = g_new0( file_transfer_t, 1 ); 119 dcc_file_transfer_t *df = file->priv = g_new0( dcc_file_transfer_t, 1); 119 120 file->file_size = file_size; 120 121 file->file_name = g_strdup( file_name ); … … 123 124 df->ft = file; 124 125 126 return df; 127 } 128 129 /* This is where the sending magic starts... */ 130 file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size ) 131 { 132 file_transfer_t *file; 133 dcc_file_transfer_t *df; 134 struct sockaddr_storage *saddr; 135 136 if( file_size > global.conf->max_filetransfer_size ) 137 return NULL; 138 139 df = dcc_alloc_transfer( file_name, file_size, ic ); 140 file = df->ft; 141 125 142 /* listen and request */ 126 if( !dcc_listen( df, saddr ) ||127 !dccs_send_request( df, user_nick, *saddr ) )143 if( !dcc_listen( df, &saddr ) || 144 !dccs_send_request( df, user_nick, saddr ) ) 128 145 return NULL; 129 146 130 g_free( *saddr );147 g_free( saddr ); 131 148 132 149 /* watch */ … … 261 278 262 279 /* 280 * Checks poll(), same for receiving and sending 281 */ 282 gboolean dcc_poll( dcc_file_transfer_t *df, int fd, short *revents ) 283 { 284 struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT }; 285 286 ASSERTSOCKOP( poll( &pfd, 1, 0 ), "poll()" ) 287 288 if( pfd.revents & POLLERR ) 289 { 290 int sockerror; 291 socklen_t errlen = sizeof( sockerror ); 292 293 if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen ) ) 294 return dcc_abort( df, "getsockopt() failed, unknown socket error (weird!)" ); 295 296 return dcc_abort( df, "Socket error: %s", strerror( sockerror ) ); 297 } 298 299 if( pfd.revents & POLLHUP ) 300 return dcc_abort( df, "Remote end closed connection" ); 301 302 *revents = pfd.revents; 303 304 return TRUE; 305 } 306 307 gboolean dcc_check_maxseg( dcc_file_transfer_t *df, int fd ) 308 { 309 #ifdef DCC_SEND_AHEAD 310 /* 311 * use twice the maximum segment size as a maximum for calls to send(). 312 */ 313 if( max_packet_size == 0 ) 314 { 315 unsigned int mpslen = sizeof( max_packet_size ); 316 if( getsockopt( fd, IPPROTO_TCP, TCP_MAXSEG, &max_packet_size, &mpslen ) ) 317 return dcc_abort( df, "getsockopt() failed" ); 318 max_packet_size *= 2; 319 } 320 #endif 321 return TRUE; 322 } 323 324 /* 263 325 * After setup, the transfer itself is handled entirely by this function. 264 326 * There are basically four things to handle: connect, receive, send, and error. … … 268 330 dcc_file_transfer_t *df = data; 269 331 file_transfer_t *file = df->ft; 270 struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT };271 332 short revents; 272 333 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 334 if( !dcc_poll( df, fd, &revents) ) 335 return FALSE; 336 295 337 if( ( revents & POLLIN ) && 296 338 ( file->status & FT_STATUS_LISTENING ) ) … … 305 347 closesocket( fd ); 306 348 fd = df->fd; 307 file->status = FT_STATUS_TRANSFER ING;349 file->status = FT_STATUS_TRANSFERRING; 308 350 sock_make_nonblocking( fd ); 309 351 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 352 if ( !dcc_check_maxseg( df, fd ) ) 353 return FALSE; 354 322 355 /* IM protocol callback */ 323 356 … … 453 486 } 454 487 488 gboolean dccs_recv_start( file_transfer_t *ft ) 489 { 490 dcc_file_transfer_t *df = ft->priv; 491 struct sockaddr_storage *saddr = &df->saddr; 492 int fd; 493 socklen_t sa_len = saddr->ss_family == AF_INET ? 494 sizeof( struct sockaddr_in ) : sizeof( struct sockaddr_in6 ); 495 496 if( !ft->write ) 497 return dcc_abort( df, "Protocol didn't register write()" ); 498 499 ASSERTSOCKOP( fd = df->fd = socket( saddr->ss_family, SOCK_STREAM, 0 ) , "Opening Socket" ); 500 501 sock_make_nonblocking( fd ); 502 503 if( ( connect( fd, (struct sockaddr *)saddr, sa_len ) == -1 ) && 504 ( errno != EINPROGRESS ) ) 505 return dcc_abort( df, "Connecting" ); 506 507 ft->status = FT_STATUS_CONNECTING; 508 509 /* watch */ 510 df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_recv_proto, df ); 511 ft->out_of_data = dccs_recv_out_of_data; 512 513 return TRUE; 514 } 515 516 gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond) 517 { 518 dcc_file_transfer_t *df = data; 519 file_transfer_t *ft = df->ft; 520 short revents; 521 522 if( !dcc_poll( df, fd, &revents ) ) 523 return FALSE; 524 525 if( ( revents & POLLOUT ) && 526 ( ft->status & FT_STATUS_CONNECTING ) ) 527 { 528 ft->status = FT_STATUS_TRANSFERRING; 529 if ( !dcc_check_maxseg( df, fd ) ) 530 return FALSE; 531 532 //df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df ); 533 534 df->watch_out = 0; 535 return FALSE; 536 } 537 538 if( revents & POLLIN ) 539 { 540 char *buffer = g_malloc( 65536 ); 541 int ret, done; 542 543 ASSERTSOCKOP( ret = recv( fd, buffer, 65536, 0 ), "Receiving" ); 544 545 if( ret == 0 ) 546 return dcc_abort( df, "Remote end closed connection" ); 547 548 buffer = g_realloc( buffer, ret ); 549 550 df->bytes_sent += ret; 551 552 done = df->bytes_sent >= ft->file_size; 553 554 if( ( ( df->bytes_sent - ft->bytes_transferred ) > DCC_PACKET_SIZE ) || 555 done ) 556 { 557 int ack, ackret; 558 ack = htonl( ft->bytes_transferred = df->bytes_sent ); 559 560 ASSERTSOCKOP( ackret = send( fd, &ack, 4, 0 ), "Sending DCC ACK" ); 561 562 if ( ackret != 4 ) 563 return dcc_abort( df, "Error sending DCC ACK, sent %d instead of 4 bytes", ret ); 564 } 565 566 if( !ft->write( df->ft, buffer, ret ) && !done ) 567 { 568 df->watch_in = 0; 569 return FALSE; 570 } 571 572 if( done ) 573 { 574 closesocket( fd ); 575 dcc_finish( ft ); 576 577 df->watch_in = 0; 578 return FALSE; 579 } 580 581 return TRUE; 582 } 583 584 return TRUE; 585 } 586 587 void dccs_recv_out_of_data( file_transfer_t *ft ) 588 { 589 dcc_file_transfer_t *df = ft->priv; 590 591 if( !df->watch_in ) 592 df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df ); 593 } 594 455 595 /* 456 596 * Incoming data. Note that the buffer MUST NOT be freed by the caller! … … 472 612 df->queued_bytes += data_size; 473 613 474 if( ( file->status & FT_STATUS_TRANSFER ING ) &&614 if( ( file->status & FT_STATUS_TRANSFERRING ) && 475 615 #ifndef DCC_SEND_AHEAD 476 616 ( file->bytes_transferred >= df->bytes_sent ) && … … 533 673 dcc_close( file ); 534 674 } 675 676 /* 677 * DCC SEND <filename> <IP> <port> <filesize> 678 * 679 * filename can be in "" or not. If it is, " can probably be escaped... 680 * IP can be an unsigned int (IPV4) or something else (IPV6) 681 * 682 */ 683 file_transfer_t *dcc_request( struct im_connection *ic, char *line ) 684 { 685 char *pattern = "SEND" 686 " (([^\"][^ ]*)|\"([^\"]|\\\")*\")" 687 " (([0-9]*)|([^ ]*))" 688 " ([0-9]*)" 689 " ([0-9]*)\001"; 690 regmatch_t pmatch[9]; 691 regex_t re; 692 file_transfer_t *ft; 693 dcc_file_transfer_t *df; 694 695 if( regcomp( &re, pattern, REG_EXTENDED ) ) 696 return NULL; 697 if( regexec( &re, line, 9, pmatch, 0 ) ) 698 return NULL; 699 700 if( ( pmatch[1].rm_so > 0 ) && 701 ( pmatch[4].rm_so > 0 ) && 702 ( pmatch[7].rm_so > 0 ) && 703 ( pmatch[8].rm_so > 0 ) ) 704 { 705 char *input = g_strdup( line ); 706 char *filename, *host, *port; 707 size_t filesize; 708 struct addrinfo hints, *rp; 709 710 /* "filename" or filename */ 711 if ( pmatch[2].rm_so > 0 ) 712 { 713 input[pmatch[2].rm_eo] = '\0'; 714 filename = input + pmatch[2].rm_so; 715 } else 716 { 717 input[pmatch[3].rm_eo] = '\0'; 718 filename = input + pmatch[3].rm_so; 719 } 720 721 input[pmatch[4].rm_eo] = '\0'; 722 723 /* number means ipv4, something else means ipv6 */ 724 if ( pmatch[5].rm_so > 0 ) 725 { 726 struct in_addr ipaddr = { htonl( atoi( input + pmatch[5].rm_so ) ) }; 727 host = inet_ntoa( ipaddr ); 728 } else 729 { 730 /* Contains non-numbers, hopefully an IPV6 address */ 731 host = input + pmatch[6].rm_so; 732 } 733 734 input[pmatch[7].rm_eo] = '\0'; 735 input[pmatch[8].rm_eo] = '\0'; 736 737 port = input + pmatch[7].rm_so; 738 filesize = atoll( input + pmatch[8].rm_so ); 739 740 memset( &hints, 0, sizeof ( struct addrinfo ) ); 741 if ( getaddrinfo( host, port, &hints, &rp ) ) 742 { 743 g_free( input ); 744 return NULL; 745 } 746 747 df = dcc_alloc_transfer( filename, filesize, ic ); 748 ft = df->ft; 749 ft->sending = TRUE; 750 memcpy( &df->saddr, rp->ai_addr, rp->ai_addrlen ); 751 752 freeaddrinfo( rp ); 753 g_free( input ); 754 755 df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, ft ); 756 757 return ft; 758 } 759 760 return NULL; 761 } 762
Note: See TracChangeset
for help on using the changeset viewer.