Changeset 5125
Legend:
- Unmodified
- Added
- Removed
-
trunk/gtk/ipc.c
r5123 r5125 91 91 }; 92 92 93 static void 94 serv_bind(struct constate *con); 95 static void 96 rmsock(void); 93 /* this is only used on the server */ 94 static char *gl_sockpath = NULL; 95 97 96 static gboolean 98 client_connect(char *path, struct constate *con); 99 static void 100 srv_io_accept(GSource *source, int fd, struct sockaddr *sa, socklen_t len, 101 void *vdata); 97 simpleresp( struct constate * con, int64_t tag, enum ipc_msg id ) 98 { 99 uint8_t * buf; 100 size_t size; 101 102 buf = ipc_mkempty( con->ipc, &size, id, tag ); 103 if( NULL == buf ) 104 { 105 return FALSE; 106 } 107 108 io_send_keepdata( con->source, buf, size ); 109 110 return TRUE; 111 } 112 113 static void 114 all_default( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag, void * arg ) 115 { 116 switch( id ) 117 { 118 case IPC_MSG_FAIL: 119 case IPC_MSG_NOTSUP: 120 case IPC_MSG_BAD: 121 case IPC_MSG_OK: 122 break; 123 default: 124 simpleresp( arg, tag, IPC_MSG_NOTSUP ); 125 break; 126 } 127 } 128 129 static void 130 destroycon(struct constate *con) { 131 con->source = NULL; 132 133 if(0 <= con->fd) 134 EVUTIL_CLOSESOCKET(con->fd); 135 con->fd = -1; 136 ipc_freecon( con->ipc ); 137 138 switch(con->type) { 139 case CON_SERV: 140 break; 141 case CON_CLIENT: 142 ipc_freemsgs( con->msgs ); 143 freestrlist(con->u.client.files); 144 g_main_loop_quit(con->u.client.loop); 145 break; 146 } 147 } 148 149 static void 150 cli_io_sent( GSource * source UNUSED, size_t id, void *vdata ) 151 { 152 struct constate_client *cli = &((struct constate*)vdata)->u.client; 153 154 if(0 < id && cli->msgid == id) { 155 *(cli->succeeded) = TRUE; 156 destroycon(vdata); 157 } 158 } 159 160 static void 161 client_sendmsg( struct constate * con ) 162 { 163 struct constate_client * cli = &con->u.client; 164 GList * ii; 165 uint8_t * buf; 166 size_t size; 167 benc_val_t packet, * val; 168 int saved; 169 170 switch( cli->msg ) 171 { 172 case IPC_MSG_ADDMANYFILES: 173 val = ipc_initval( con->ipc, cli->msg, -1, &packet, TYPE_LIST ); 174 if( NULL == val || 175 tr_bencListReserve( val, g_list_length( cli->files ) ) ) 176 { 177 perror( "malloc" ); 178 destroycon( con ); 179 return; 180 } 181 for( ii = cli->files; NULL != ii; ii = ii->next ) 182 { 183 tr_bencInitStr( tr_bencListAdd( val ), ii->data, -1, 0 ); 184 } 185 buf = ipc_mkval( &packet, &size ); 186 saved = errno; 187 tr_bencFree( &packet ); 188 g_list_free( cli->files ); 189 cli->files = NULL; 190 break; 191 case IPC_MSG_QUIT: 192 buf = ipc_mkempty( con->ipc, &size, cli->msg, -1 ); 193 saved = errno; 194 break; 195 default: 196 g_assert_not_reached(); 197 return; 198 } 199 200 if( NULL == buf ) 201 { 202 errno = saved; 203 perror( "malloc" ); 204 destroycon( con ); 205 return; 206 } 207 208 cli->msgid = io_send_keepdata( con->source, buf, size ); 209 } 210 102 211 static size_t 103 srv_io_received( GSource * source, void * data, size_t len, void * vdata ); 212 cli_io_received( GSource * source UNUSED, void * data, size_t len, 213 void * vdata ) 214 { 215 struct constate * con = vdata; 216 struct constate_client * cli = &con->u.client; 217 ssize_t res; 218 219 if( IPC_MIN_MSG_LEN > len ) 220 { 221 return 0; 222 } 223 224 res = ipc_parse( con->ipc, data, len, con ); 225 226 if( 0 > res ) 227 { 228 switch( errno ) 229 { 230 case EPERM: 231 g_message( _("Bad IPC protocol version") ); 232 break; 233 case EINVAL: 234 g_message( _("IPC protocol parse error") ); 235 break; 236 default: 237 g_message( _("IPC parsing failed: %s"), g_strerror( errno ) ); 238 break; 239 } 240 destroycon( con ); 241 return 0; 242 } 243 244 if( HASVERS( con->ipc ) && 0 == cli->msgid ) 245 { 246 client_sendmsg( con ); 247 } 248 249 return res; 250 } 251 252 static void 253 all_io_closed(GSource *source UNUSED, void *vdata) { 254 struct constate *con = vdata; 255 256 destroycon(con); 257 } 258 259 static gboolean 260 client_connect(char *path, struct constate *con) { 261 struct sockaddr_un addr; 262 uint8_t * buf; 263 size_t size; 264 265 if(0 > (con->fd = socket(AF_UNIX, SOCK_STREAM, 0))) { 266 g_message( _("Failed to create socket: %s"), g_strerror(errno)); 267 return FALSE; 268 } 269 270 memset(&addr, 0, sizeof(addr)); 271 addr.sun_family = AF_UNIX; 272 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); 273 274 if(0 > connect(con->fd, (struct sockaddr*)&addr, SUN_LEN(&addr))) { 275 g_message( _("Failed to connect to %s: %s"), path, g_strerror(errno)); 276 return FALSE; 277 } 278 279 con->source = io_new(con->fd, cli_io_sent, cli_io_received, 280 all_io_closed, con); 281 if( NULL == con->source ) 282 { 283 EVUTIL_CLOSESOCKET( con->fd ); 284 return FALSE; 285 } 286 287 buf = ipc_mkvers( &size, "Transmission GTK+ " LONG_VERSION_STRING ); 288 if( NULL == buf ) 289 { 290 EVUTIL_CLOSESOCKET( con->fd ); 291 return FALSE; 292 } 293 294 io_send_keepdata( con->source, buf, size ); 295 296 return TRUE; 297 } 298 299 static gboolean 300 blocking_client( enum ipc_msg msgid, GList * files ) 301 { 302 303 struct constate *con; 304 char *path; 305 gboolean ret = FALSE; 306 307 con = g_new0(struct constate, 1); 308 con->source = NULL; 309 con->fd = -1; 310 con->type = CON_CLIENT; 311 312 con->msgs = ipc_initmsgs(); 313 if( NULL == con->msgs ) 314 { 315 g_message( _("Failed to set up IPC: %s"), g_strerror( errno ) ); 316 g_free( con ); 317 return FALSE; 318 } 319 320 con->ipc = ipc_newcon( con->msgs ); 321 if( NULL == con->ipc ) 322 { 323 ipc_freemsgs( con->msgs ); 324 g_free( con ); 325 return FALSE; 326 } 327 328 ipc_setdefmsg( con->msgs, all_default ); 329 330 con->u.client.loop = g_main_loop_new(NULL, TRUE); 331 con->u.client.msg = msgid; 332 con->u.client.files = files; 333 con->u.client.succeeded = &ret; 334 con->u.client.msgid = 0; 335 336 path = cf_sockname(); 337 if(!client_connect(path, con)) { 338 g_free(path); 339 destroycon(con); 340 return FALSE; 341 } 342 343 g_main_loop_run(con->u.client.loop); 344 345 return ret; 346 } 347 348 gboolean 349 ipc_sendfiles_blocking( GList * files ) 350 { 351 return blocking_client( IPC_MSG_ADDMANYFILES, files ); 352 } 353 354 gboolean 355 ipc_sendquit_blocking( void ) 356 { 357 return blocking_client( IPC_MSG_QUIT, NULL ); 358 } 359 360 static void 361 rmsock(void) { 362 if(NULL != gl_sockpath) { 363 unlink(gl_sockpath); 364 g_free(gl_sockpath); 365 } 366 } 367 104 368 static size_t 105 cli_io_received( GSource * source, void * data, size_t len, void * vdata ); 106 static void 107 client_sendmsg( struct constate * con ); 108 static void 109 destroycon(struct constate *con); 110 static void 111 all_io_closed(GSource *source, void *vdata); 112 static void 113 cli_io_sent( GSource * source, size_t id, void * vdata ); 114 static void 115 smsg_add( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 116 static void 117 smsg_addone( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 118 static void 119 smsg_quit( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 120 static void 121 smsg_noop( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 122 static void 123 smsg_info( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 124 static void 125 smsg_infoall( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 369 srv_io_received( GSource * source UNUSED, void * data, size_t len, 370 void * vdata ) 371 { 372 struct constate * con = vdata; 373 struct constate_serv * srv = &con->u.serv; 374 ssize_t res; 375 376 if( IPC_MIN_MSG_LEN > len ) 377 { 378 return 0; 379 } 380 381 if( NULL == srv->core ) 382 { 383 destroycon( con ); 384 } 385 386 res = ipc_parse( con->ipc, data, len, con ); 387 388 if( 0 > res ) 389 { 390 switch( errno ) 391 { 392 case EPERM: 393 errmsg( con->u.serv.wind, _("Bad IPC protocol version") ); 394 break; 395 case EINVAL: 396 errmsg( con->u.serv.wind, _("IPC protocol parse error") ); 397 break; 398 default: 399 errmsg( con->u.serv.wind, _("IPC parsing failed: %s"), 400 g_strerror( errno ) ); 401 } 402 destroycon( con ); 403 return 0; 404 } 405 406 return res; 407 } 408 409 static void 410 srv_io_accept(GSource *source UNUSED, int fd, struct sockaddr *sa UNUSED, 411 socklen_t len UNUSED, void *vdata) { 412 struct constate *con = vdata; 413 struct constate *newcon; 414 uint8_t * buf; 415 size_t size; 416 417 newcon = g_new(struct constate, 1); 418 memcpy(newcon, con, sizeof(*newcon)); 419 newcon->fd = fd; 420 421 newcon->ipc = ipc_newcon( con->msgs ); 422 if( NULL == newcon->ipc ) 423 { 424 g_free( newcon ); 425 EVUTIL_CLOSESOCKET( fd ); 426 return; 427 } 428 429 newcon->source = io_new(fd, NULL, srv_io_received, all_io_closed, newcon); 430 if( NULL == newcon->source ) 431 { 432 ipc_freecon( newcon->ipc ); 433 g_free( newcon ); 434 EVUTIL_CLOSESOCKET( fd ); 435 return; 436 } 437 438 buf = ipc_mkvers( &size, "Transmission GTK+ " LONG_VERSION_STRING ); 439 if( NULL == buf ) 440 { 441 ipc_freecon( newcon->ipc ); 442 g_free( newcon ); 443 EVUTIL_CLOSESOCKET( fd ); 444 return; 445 } 446 447 io_send_keepdata( newcon->source, buf, size ); 448 } 449 450 /* open a local socket for clients connections */ 451 static void 452 serv_bind(struct constate *con) { 453 struct sockaddr_un sa; 454 455 rmsock(); 456 gl_sockpath = cf_sockname(); 457 458 if(0 > (con->fd = socket(AF_LOCAL, SOCK_STREAM, 0))) 459 goto fail; 460 461 memset(&sa, 0, sizeof(sa)); 462 sa.sun_family = AF_LOCAL; 463 strncpy(sa.sun_path, gl_sockpath, sizeof(sa.sun_path) - 1); 464 465 /* unlink any existing socket file before trying to create ours */ 466 unlink(gl_sockpath); 467 if(0 > bind(con->fd, (struct sockaddr *)&sa, SUN_LEN(&sa))) { 468 /* bind may fail if there was already a socket, so try twice */ 469 unlink(gl_sockpath); 470 if(0 > bind(con->fd, (struct sockaddr *)&sa, SUN_LEN(&sa))) 471 goto fail; 472 } 473 474 if(0 > listen(con->fd, 5)) 475 goto fail; 476 477 con->source = io_new_listening(con->fd, sizeof(struct sockaddr_un), 478 srv_io_accept, all_io_closed, con); 479 480 g_atexit(rmsock); 481 482 return; 483 484 fail: 485 errmsg(con->u.serv.wind, _("Failed to set up socket: %s"), 486 g_strerror(errno)); 487 if(0 <= con->fd) 488 EVUTIL_CLOSESOCKET(con->fd); 489 con->fd = -1; 490 rmsock(); 491 } 492 493 static void 494 smsg_add( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg ) 495 { 496 struct constate * con = arg; 497 struct constate_serv * srv = &con->u.serv; 498 benc_val_t * path; 499 int ii; 500 tr_ctor * ctor; 501 GList * list = NULL; 502 503 if( NULL == val || TYPE_LIST != val->type ) 504 { 505 simpleresp( con, tag, IPC_MSG_BAD ); 506 return; 507 } 508 509 ctor = tr_ctorNew( srv->core ); 510 511 for( ii = 0; ii < val->val.l.count; ii++ ) 512 { 513 path = val->val.l.vals + ii; 514 if( TYPE_STR == path->type && 515 /* XXX somehow escape invalid utf-8 */ 516 g_utf8_validate( path->val.s.s, path->val.s.i, NULL ) ) 517 { 518 list = g_list_append( list, g_strndup( path->val.s.s, path->val.s.i ) ); 519 } 520 } 521 522 if( list ) { 523 tr_core_add_list( srv->core, list, ctor ); 524 tr_core_torrents_added( TR_CORE( srv->core ) ); 525 } 526 527 /* XXX should send info response back with torrent ids */ 528 simpleresp( con, tag, IPC_MSG_OK ); 529 } 530 531 static void 532 smsg_addone( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, 533 void * arg ) 534 { 535 struct constate * con = arg; 536 struct constate_serv * srv = &con->u.serv; 537 benc_val_t * file, * data, * dir, * start; 538 tr_ctor * ctor; 539 540 if( NULL == val || TYPE_DICT != val->type ) 541 { 542 simpleresp( con, tag, IPC_MSG_BAD ); 543 return; 544 } 545 546 file = tr_bencDictFind( val, "file" ); 547 data = tr_bencDictFind( val, "data" ); 548 dir = tr_bencDictFind( val, "directory" ); 549 start = tr_bencDictFind( val, "autostart" ); 550 551 if( ( NULL != file && TYPE_STR != file->type ) || 552 ( NULL != data && TYPE_STR != data->type ) || 553 ( NULL != dir && TYPE_STR != dir->type ) || 554 ( NULL != start && TYPE_INT != start->type ) ) 555 { 556 simpleresp( con, tag, IPC_MSG_BAD ); 557 return; 558 } 559 560 ctor = tr_ctorNew( tr_core_handle( srv->core ) ); 561 if( dir ) 562 tr_ctorSetDestination( ctor, TR_FORCE, dir->val.s.s ); 563 if( file ) 564 tr_ctorSetMetainfoFromFile( ctor, file->val.s.s ); 565 if( data ) 566 tr_ctorSetMetainfo( ctor, (uint8_t*)data->val.s.s, data->val.s.i ); 567 if( start ) 568 tr_ctorSetPaused( ctor, TR_FORCE, !start->val.i ); 569 570 tr_core_add_ctor( TR_CORE( srv->core ), ctor ); 571 572 tr_core_torrents_added( TR_CORE( srv->core ) ); 573 574 /* XXX should send info response back with torrent ids */ 575 simpleresp( con, tag, IPC_MSG_OK ); 576 } 577 578 static void 579 smsg_quit( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag UNUSED, 580 void * arg UNUSED ) 581 { 582 struct constate * con = arg; 583 struct constate_serv * srv = &con->u.serv; 584 585 tr_core_quit( srv->core ); 586 } 587 588 static void 589 smsg_noop( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag, 590 void * arg ) 591 { 592 simpleresp( arg, tag, IPC_MSG_OK ); 593 } 594 595 static TrTorrent * 596 findtorid( TrCore * core, int id, GtkTreeIter * iter ) 597 { 598 GtkTreeModel * model; 599 GtkTreeIter myiter; 600 int rowid; 601 TrTorrent * tor; 602 603 if( NULL == iter ) 604 { 605 iter = &myiter; 606 } 607 608 model = tr_core_model( core ); 609 if( gtk_tree_model_get_iter_first( model, iter ) ) 610 { 611 do 612 { 613 gtk_tree_model_get( model, iter, MC_ID, &rowid, -1 ); 614 if( rowid == id ) 615 { 616 gtk_tree_model_get( model, iter, MC_TORRENT, &tor, -1 ); 617 g_object_unref( tor ); 618 return tor; 619 } 620 } 621 while( gtk_tree_model_iter_next( model, iter ) ); 622 } 623 624 return NULL; 625 } 626 126 627 static int 127 628 addinfo( TrTorrent * tor, enum ipc_msg msgid, int torid, int types, 128 benc_val_t * val ); 129 static void 130 smsg_look( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 131 static void 132 smsg_tor( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 133 static void 134 smsg_torall( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 135 static void 136 smsg_pref( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 137 static void 138 smsg_int( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 139 static void 140 smsg_str( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 141 static void 142 smsg_sup( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 143 static void 144 all_default( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ); 145 static gboolean 146 simpleresp( struct constate * con, int64_t tag, enum ipc_msg id ); 629 benc_val_t * val ) 630 { 631 if( IPC_MSG_INFO == msgid ) 632 { 633 const tr_info * inf = tr_torrent_info( tor ); 634 return ipc_addinfo( val, torid, inf, types ); 635 } 636 else 637 { 638 const tr_stat * st = tr_torrent_stat( tor ); 639 return ipc_addstat( val, torid, st, types ); 640 } 641 } 642 643 static void 644 smsg_info( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ) 645 { 646 struct constate * con = arg; 647 struct constate_serv * srv = &con->u.serv; 648 enum ipc_msg respid; 649 benc_val_t * ids, * types, * idval, packet, * pkval; 650 int typeflags, ii; 651 TrTorrent * tor; 652 uint8_t * buf; 653 size_t size; 654 655 if( NULL == val || TYPE_DICT != val->type ) 656 { 657 simpleresp( con, tag, IPC_MSG_BAD ); 658 return; 659 } 660 661 respid = ( IPC_MSG_GETINFO == id ? IPC_MSG_INFO : IPC_MSG_STAT ); 662 ids = tr_bencDictFind( val, "id" ); 663 types = tr_bencDictFind( val, "types" ); 664 if( NULL == ids || TYPE_LIST != ids->type || 665 NULL == types || TYPE_LIST != types->type ) 666 { 667 simpleresp( con, tag, IPC_MSG_BAD ); 668 return; 669 } 670 typeflags = ipc_infotypes( respid, types ); 671 672 pkval = ipc_initval( con->ipc, respid, tag, &packet, TYPE_LIST ); 673 if( NULL == pkval ) 674 { 675 simpleresp( con, tag, IPC_MSG_FAIL ); 676 return; 677 } 678 for( ii = 0; ids->val.l.count > ii; ii++ ) 679 { 680 idval = &ids->val.l.vals[ii]; 681 if( TYPE_INT != idval->type || !TORRENT_ID_VALID( idval->val.i ) || 682 NULL == ( tor = findtorid( srv->core, idval->val.i, NULL ) ) ) 683 { 684 continue; 685 } 686 if( 0 > addinfo( tor, respid, idval->val.i, typeflags, pkval ) ) 687 { 688 tr_bencFree( &packet ); 689 simpleresp( con, tag, IPC_MSG_FAIL ); 690 return; 691 } 692 } 693 694 buf = ipc_mkval( &packet, &size ); 695 tr_bencFree( &packet ); 696 if( NULL == buf ) 697 { 698 simpleresp( con, tag, IPC_MSG_FAIL ); 699 } 700 else 701 { 702 io_send_keepdata( con->source, buf, size ); 703 } 704 } 705 706 static void 707 smsg_infoall( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ) 708 { 709 struct constate * con = arg; 710 struct constate_serv * srv = &con->u.serv; 711 enum ipc_msg respid; 712 benc_val_t packet, * pkval; 713 int typeflags; 714 GtkTreeModel * model; 715 GtkTreeIter iter; 716 int rowid; 717 TrTorrent * tor; 718 uint8_t * buf; 719 size_t size; 720 721 if( NULL == val || TYPE_LIST != val->type ) 722 { 723 simpleresp( con, tag, IPC_MSG_BAD ); 724 return; 725 } 726 727 respid = ( IPC_MSG_GETINFOALL == id ? IPC_MSG_INFO : IPC_MSG_STAT ); 728 typeflags = ipc_infotypes( respid, val ); 729 730 pkval = ipc_initval( con->ipc, respid, tag, &packet, TYPE_LIST ); 731 if( NULL == pkval ) 732 { 733 simpleresp( con, tag, IPC_MSG_FAIL ); 734 return; 735 } 736 737 model = tr_core_model( srv->core ); 738 if( gtk_tree_model_get_iter_first( model, &iter ) ) 739 { 740 do 741 { 742 gtk_tree_model_get( model, &iter, MC_ID, &rowid, 743 MC_TORRENT, &tor, -1 ); 744 g_object_unref( tor ); 745 if( 0 > addinfo( tor, respid, rowid, typeflags, pkval ) ) 746 { 747 tr_bencFree( &packet ); 748 simpleresp( con, tag, IPC_MSG_FAIL ); 749 return; 750 } 751 } 752 while( gtk_tree_model_iter_next( model, &iter ) ); 753 } 754 755 buf = ipc_mkval( &packet, &size ); 756 tr_bencFree( &packet ); 757 if( NULL == buf ) 758 { 759 simpleresp( con, tag, IPC_MSG_FAIL ); 760 } 761 else 762 { 763 io_send_keepdata( con->source, buf, size ); 764 } 765 } 766 147 767 static TrTorrent * 148 findtorid( TrCore * core, int id, GtkTreeIter * iter ); 149 static TrTorrent * 150 findtorhash( TrCore * core, const char * hash, int * id ); 151 152 /* this is only used on the server */ 153 static char *gl_sockpath = NULL; 768 findtorhash( TrCore * core, const char * hash, int * torid ) 769 { 770 GtkTreeModel * model; 771 GtkTreeIter iter; 772 char * rowhash; 773 TrTorrent * tor; 774 775 model = tr_core_model( core ); 776 if( gtk_tree_model_get_iter_first( model, &iter ) ) 777 { 778 do 779 { 780 gtk_tree_model_get( model, &iter, MC_HASH, &rowhash, -1 ); 781 if( 0 == strcmp( hash, rowhash ) ) 782 { 783 gtk_tree_model_get( model, &iter, MC_ID, torid, 784 MC_TORRENT, &tor, -1 ); 785 g_object_unref( tor ); 786 return tor; 787 } 788 } 789 while( gtk_tree_model_iter_next( model, &iter ) ); 790 } 791 792 return NULL; 793 } 794 795 static void 796 smsg_look( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, 797 void * arg ) 798 { 799 struct constate * con = arg; 800 struct constate_serv * srv = &con->u.serv; 801 benc_val_t packet, * pkval, * hash; 802 int ii, torid; 803 TrTorrent * tor; 804 const tr_info * inf; 805 uint8_t * buf; 806 size_t size; 807 808 if( NULL == val || TYPE_LIST != val->type ) 809 { 810 simpleresp( con, tag, IPC_MSG_BAD ); 811 return; 812 } 813 814 pkval = ipc_initval( con->ipc, IPC_MSG_INFO, tag, &packet, TYPE_LIST ); 815 if( NULL == pkval ) 816 { 817 simpleresp( con, tag, IPC_MSG_FAIL ); 818 return; 819 } 820 821 for( ii = 0; val->val.l.count > ii; ii++ ) 822 { 823 hash = &val->val.l.vals[ii]; 824 if( NULL == hash || TYPE_STR != hash->type || 825 SHA_DIGEST_LENGTH * 2 != hash->val.s.i || 826 NULL == ( tor = findtorhash( srv->core, hash->val.s.s, &torid ) ) ) 827 { 828 continue; 829 } 830 inf = tr_torrent_info( tor ); 831 if( 0 > ipc_addinfo( pkval, torid, inf, IPC_INF_HASH ) ) 832 { 833 tr_bencFree( &packet ); 834 simpleresp( con, tag, IPC_MSG_FAIL ); 835 return; 836 } 837 } 838 839 buf = ipc_mkval( &packet, &size ); 840 tr_bencFree( &packet ); 841 if( NULL == buf ) 842 { 843 simpleresp( con, tag, IPC_MSG_FAIL ); 844 } 845 else 846 { 847 io_send_keepdata( con->source, buf, size ); 848 } 849 } 850 851 static void 852 smsg_tor( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ) 853 { 854 struct constate * con = arg; 855 struct constate_serv * srv = &con->u.serv; 856 benc_val_t * idval; 857 TrTorrent * tor; 858 GtkTreeIter iter; 859 int ii; 860 861 if( NULL == val || TYPE_LIST != val->type ) 862 { 863 simpleresp( con, tag, IPC_MSG_BAD ); 864 return; 865 } 866 867 for( ii = 0; val->val.l.count > ii; ii++ ) 868 { 869 idval = &val->val.l.vals[ii]; 870 if( TYPE_INT != idval->type || !TORRENT_ID_VALID( idval->val.i ) || 871 NULL == ( tor = findtorid( srv->core, idval->val.i, &iter ) ) ) 872 { 873 continue; 874 } 875 switch( id ) 876 { 877 case IPC_MSG_REMOVE: 878 tr_core_delete_torrent( srv->core, &iter ); 879 break; 880 case IPC_MSG_START: 881 tr_torrent_start( tor ); 882 break; 883 case IPC_MSG_STOP: 884 tr_torrent_stop( tor ); 885 break; 886 default: 887 g_assert_not_reached(); 888 break; 889 } 890 } 891 892 tr_core_update( srv->core ); 893 894 /* XXX this is a lie */ 895 simpleresp( con, tag, IPC_MSG_OK ); 896 } 897 898 static void 899 smsg_torall( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag, 900 void * arg ) 901 { 902 struct constate * con = arg; 903 struct constate_serv * srv = &con->u.serv; 904 TrTorrent * tor; 905 GtkTreeModel * model; 906 GtkTreeIter iter; 907 908 model = tr_core_model( srv->core ); 909 if( gtk_tree_model_get_iter_first( model, &iter ) ) 910 { 911 do 912 { 913 gtk_tree_model_get( model, &iter, MC_TORRENT, &tor, -1 ); 914 switch( id ) 915 { 916 case IPC_MSG_REMOVEALL: 917 tr_core_delete_torrent( srv->core, &iter ); 918 break; 919 case IPC_MSG_STARTALL: 920 tr_torrent_start( tor ); 921 break; 922 case IPC_MSG_STOPALL: 923 tr_torrent_stop( tor ); 924 break; 925 default: 926 g_assert_not_reached(); 927 break; 928 } 929 g_object_unref( tor ); 930 } 931 while( gtk_tree_model_iter_next( model, &iter ) ); 932 } 933 934 tr_core_update( srv->core ); 935 936 /* XXX this is a lie */ 937 simpleresp( con, tag, IPC_MSG_OK ); 938 } 939 940 #define TR_NAT_TRAVERSAL_IS_DISABLED( st ) \ 941 ( TR_NAT_TRAVERSAL_UNMAPPED == (st) || TR_NAT_TRAVERSAL_UNMAPPING == (st) ) 942 943 static void 944 smsg_pref( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag, void * arg ) 945 { 946 struct constate * con = arg; 947 struct constate_serv * srv = &con->u.serv; 948 uint8_t * buf; 949 size_t size; 950 const tr_handle_status * hstat; 951 const char * pref; 952 int num; 953 954 switch( id ) 955 { 956 case IPC_MSG_GETAUTOMAP: 957 hstat = tr_handleStatus( tr_core_handle( srv->core ) ); 958 buf = ipc_mkint( con->ipc, &size, IPC_MSG_AUTOMAP, tag, 959 !TR_NAT_TRAVERSAL_IS_DISABLED( 960 hstat->natTraversalStatus ) ); 961 break; 962 case IPC_MSG_GETAUTOSTART: 963 buf = ipc_mkint( con->ipc, &size, IPC_MSG_AUTOSTART, tag, 1 ); 964 break; 965 case IPC_MSG_GETDIR: 966 /* XXX sending back "" when we're prompting is kind of bogus */ 967 pref = pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) ? "" : getdownloaddir(); 968 buf = ipc_mkstr( con->ipc, &size, IPC_MSG_DIR, tag, pref ); 969 break; 970 case IPC_MSG_GETDOWNLIMIT: 971 num = pref_flag_get( PREF_KEY_DL_LIMIT_ENABLED ) 972 ? pref_int_get( PREF_KEY_DL_LIMIT ) 973 : -1; 974 buf = ipc_mkint( con->ipc, &size, IPC_MSG_DOWNLIMIT, tag, num ); 975 break; 976 case IPC_MSG_GETPEX: 977 buf = ipc_mkint( con->ipc, &size, IPC_MSG_PEX, tag, 978 pref_flag_get( PREF_KEY_PEX ) ); 979 break; 980 case IPC_MSG_GETPORT: 981 buf = ipc_mkint( con->ipc, &size, IPC_MSG_PORT, tag, 982 pref_flag_get( PREF_KEY_PORT ) ); 983 break; 984 case IPC_MSG_GETUPLIMIT: 985 num = pref_flag_get( PREF_KEY_UL_LIMIT_ENABLED ) 986 ? pref_int_get( PREF_KEY_UL_LIMIT ) 987 : -1; 988 buf = ipc_mkint( con->ipc, &size, IPC_MSG_UPLIMIT, tag, num ); 989 break; 990 default: 991 g_assert_not_reached(); 992 return; 993 } 994 995 if( NULL != buf ) 996 { 997 io_send_keepdata( con->source, buf, size ); 998 } 999 } 1000 1001 static void 1002 smsg_int( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ) 1003 { 1004 struct constate * con = arg; 1005 struct constate_serv * srv = &con->u.serv; 1006 1007 if( NULL == val || TYPE_INT != val->type || INT_MAX < val->val.i ) 1008 { 1009 simpleresp( con, tag, IPC_MSG_BAD ); 1010 return; 1011 } 1012 1013 switch( id ) 1014 { 1015 case IPC_MSG_AUTOMAP: 1016 tr_core_set_pref_bool( srv->core, PREF_KEY_NAT, val->val.i ); 1017 break; 1018 case IPC_MSG_AUTOSTART: 1019 simpleresp( con, tag, IPC_MSG_BAD ); 1020 return; 1021 case IPC_MSG_DOWNLIMIT: 1022 if( 0 > val->val.i ) 1023 { 1024 tr_core_set_pref_bool( srv->core, PREF_KEY_DL_LIMIT_ENABLED, 0 ); 1025 } 1026 else 1027 { 1028 tr_core_set_pref_int( srv->core, PREF_KEY_DL_LIMIT, val->val.i ); 1029 tr_core_set_pref_bool( srv->core, PREF_KEY_DL_LIMIT_ENABLED, 1 ); 1030 } 1031 break; 1032 case IPC_MSG_PEX: 1033 tr_core_set_pref_bool( srv->core, PREF_KEY_PEX, val->val.i ); 1034 break; 1035 case IPC_MSG_PORT: 1036 tr_core_set_pref_int( srv->core, PREF_KEY_PORT, val->val.i ); 1037 break; 1038 case IPC_MSG_UPLIMIT: 1039 if( 0 > val->val.i ) 1040 { 1041 tr_core_set_pref_bool( srv->core, PREF_KEY_UL_LIMIT_ENABLED, 0 ); 1042 } 1043 else 1044 { 1045 tr_core_set_pref_int( srv->core, PREF_KEY_UL_LIMIT, val->val.i ); 1046 tr_core_set_pref_bool( srv->core, PREF_KEY_UL_LIMIT_ENABLED, 1 ); 1047 } 1048 break; 1049 default: 1050 g_assert_not_reached(); 1051 return; 1052 } 1053 } 1054 1055 static void 1056 smsg_str( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg ) 1057 { 1058 struct constate * con = arg; 1059 struct constate_serv * srv = &con->u.serv; 1060 1061 if( NULL == val || TYPE_STR != val->type ) 1062 { 1063 simpleresp( con, tag, IPC_MSG_BAD ); 1064 return; 1065 } 1066 1067 switch( id ) 1068 { 1069 case IPC_MSG_DIR: 1070 tr_core_set_pref( srv->core, PREF_KEY_DIR_DEFAULT, val->val.s.s ); 1071 break; 1072 default: 1073 g_assert_not_reached(); 1074 return; 1075 } 1076 } 1077 1078 static void 1079 smsg_sup( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg ) 1080 { 1081 struct constate * con = arg; 1082 benc_val_t packet, * pkval, * name; 1083 int ii; 1084 enum ipc_msg found; 1085 uint8_t * buf; 1086 size_t size; 1087 1088 if( NULL == val || TYPE_LIST != val->type ) 1089 { 1090 simpleresp( con, tag, IPC_MSG_BAD ); 1091 return; 1092 } 1093 1094 pkval = ipc_initval( con->ipc, IPC_MSG_SUP, tag, &packet, TYPE_LIST ); 1095 if( NULL == pkval ) 1096 { 1097 simpleresp( con, tag, IPC_MSG_FAIL ); 1098 return; 1099 } 1100 if( tr_bencListReserve( pkval, val->val.l.count ) ) 1101 { 1102 tr_bencFree( &packet ); 1103 simpleresp( con, tag, IPC_MSG_FAIL ); 1104 return; 1105 } 1106 1107 for( ii = 0; val->val.l.count > ii; ii++ ) 1108 { 1109 name = &val->val.l.vals[ii]; 1110 if( NULL == name || TYPE_STR != name->type ) 1111 { 1112 continue; 1113 } 1114 found = ipc_msgid( con->ipc, name->val.s.s ); 1115 if( IPC__MSG_COUNT == found || !ipc_ishandled( con->ipc, found ) ) 1116 { 1117 continue; 1118 } 1119 tr_bencInitStr( tr_bencListAdd( pkval ), 1120 name->val.s.s, name->val.s.i, 1 ); 1121 } 1122 1123 buf = ipc_mkval( &packet, &size ); 1124 tr_bencFree( &packet ); 1125 if( NULL == buf ) 1126 { 1127 simpleresp( con, tag, IPC_MSG_FAIL ); 1128 } 1129 else 1130 { 1131 io_send_keepdata( con->source, buf, size ); 1132 } 1133 } 154 1134 155 1135 void … … 211 1191 serv_bind(con); 212 1192 } 213 214 static gboolean215 blocking_client( enum ipc_msg msgid, GList * files )216 {217 218 struct constate *con;219 char *path;220 gboolean ret = FALSE;221 222 con = g_new0(struct constate, 1);223 con->source = NULL;224 con->fd = -1;225 con->type = CON_CLIENT;226 227 con->msgs = ipc_initmsgs();228 if( NULL == con->msgs )229 {230 g_message( _("Failed to set up IPC: %s"), g_strerror( errno ) );231 g_free( con );232 return FALSE;233 }234 235 con->ipc = ipc_newcon( con->msgs );236 if( NULL == con->ipc )237 {238 ipc_freemsgs( con->msgs );239 g_free( con );240 return FALSE;241 }242 243 ipc_setdefmsg( con->msgs, all_default );244 245 con->u.client.loop = g_main_loop_new(NULL, TRUE);246 con->u.client.msg = msgid;247 con->u.client.files = files;248 con->u.client.succeeded = &ret;249 con->u.client.msgid = 0;250 251 path = cf_sockname();252 if(!client_connect(path, con)) {253 g_free(path);254 destroycon(con);255 return FALSE;256 }257 258 g_main_loop_run(con->u.client.loop);259 260 return ret;261 }262 263 gboolean264 ipc_sendfiles_blocking( GList * files )265 {266 return blocking_client( IPC_MSG_ADDMANYFILES, files );267 }268 269 gboolean270 ipc_sendquit_blocking( void )271 {272 return blocking_client( IPC_MSG_QUIT, NULL );273 }274 275 /* open a local socket for clients connections */276 static void277 serv_bind(struct constate *con) {278 struct sockaddr_un sa;279 280 rmsock();281 gl_sockpath = cf_sockname();282 283 if(0 > (con->fd = socket(AF_LOCAL, SOCK_STREAM, 0)))284 goto fail;285 286 memset(&sa, 0, sizeof(sa));287 sa.sun_family = AF_LOCAL;288 strncpy(sa.sun_path, gl_sockpath, sizeof(sa.sun_path) - 1);289 290 /* unlink any existing socket file before trying to create ours */291 unlink(gl_sockpath);292 if(0 > bind(con->fd, (struct sockaddr *)&sa, SUN_LEN(&sa))) {293 /* bind may fail if there was already a socket, so try twice */294 unlink(gl_sockpath);295 if(0 > bind(con->fd, (struct sockaddr *)&sa, SUN_LEN(&sa)))296 goto fail;297 }298 299 if(0 > listen(con->fd, 5))300 goto fail;301 302 con->source = io_new_listening(con->fd, sizeof(struct sockaddr_un),303 srv_io_accept, all_io_closed, con);304 305 g_atexit(rmsock);306 307 return;308 309 fail:310 errmsg(con->u.serv.wind, _("Failed to set up socket: %s"),311 g_strerror(errno));312 if(0 <= con->fd)313 EVUTIL_CLOSESOCKET(con->fd);314 con->fd = -1;315 rmsock();316 }317 318 static void319 rmsock(void) {320 if(NULL != gl_sockpath) {321 unlink(gl_sockpath);322 g_free(gl_sockpath);323 }324 }325 326 static gboolean327 client_connect(char *path, struct constate *con) {328 struct sockaddr_un addr;329 uint8_t * buf;330 size_t size;331 332 if(0 > (con->fd = socket(AF_UNIX, SOCK_STREAM, 0))) {333 g_message( _("Failed to create socket: %s"), g_strerror(errno));334 return FALSE;335 }336 337 memset(&addr, 0, sizeof(addr));338 addr.sun_family = AF_UNIX;339 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);340 341 if(0 > connect(con->fd, (struct sockaddr*)&addr, SUN_LEN(&addr))) {342 g_message( _("Failed to connect to %s: %s"), path, g_strerror(errno));343 return FALSE;344 }345 346 con->source = io_new(con->fd, cli_io_sent, cli_io_received,347 all_io_closed, con);348 if( NULL == con->source )349 {350 EVUTIL_CLOSESOCKET( con->fd );351 return FALSE;352 }353 354 buf = ipc_mkvers( &size, "Transmission GTK+ " LONG_VERSION_STRING );355 if( NULL == buf )356 {357 EVUTIL_CLOSESOCKET( con->fd );358 return FALSE;359 }360 361 io_send_keepdata( con->source, buf, size );362 363 return TRUE;364 }365 366 static void367 srv_io_accept(GSource *source UNUSED, int fd, struct sockaddr *sa UNUSED,368 socklen_t len UNUSED, void *vdata) {369 struct constate *con = vdata;370 struct constate *newcon;371 uint8_t * buf;372 size_t size;373 374 newcon = g_new(struct constate, 1);375 memcpy(newcon, con, sizeof(*newcon));376 newcon->fd = fd;377 378 newcon->ipc = ipc_newcon( con->msgs );379 if( NULL == newcon->ipc )380 {381 g_free( newcon );382 EVUTIL_CLOSESOCKET( fd );383 return;384 }385 386 newcon->source = io_new(fd, NULL, srv_io_received, all_io_closed, newcon);387 if( NULL == newcon->source )388 {389 ipc_freecon( newcon->ipc );390 g_free( newcon );391 EVUTIL_CLOSESOCKET( fd );392 return;393 }394 395 buf = ipc_mkvers( &size, "Transmission GTK+ " LONG_VERSION_STRING );396 if( NULL == buf )397 {398 ipc_freecon( newcon->ipc );399 g_free( newcon );400 EVUTIL_CLOSESOCKET( fd );401 return;402 }403 404 io_send_keepdata( newcon->source, buf, size );405 }406 407 static size_t408 srv_io_received( GSource * source UNUSED, void * data, size_t len,409 void * vdata )410 {411 struct constate * con = vdata;412 struct constate_serv * srv = &con->u.serv;413 ssize_t res;414 415 if( IPC_MIN_MSG_LEN > len )416 {417 return 0;418 }419 420 if( NULL == srv->core )421 {422 destroycon( con );423 }424 425 res = ipc_parse( con->ipc, data, len, con );426 427 if( 0 > res )428 {429 switch( errno )430 {431 case EPERM:432 errmsg( con->u.serv.wind, _("Bad IPC protocol version") );433 break;434 case EINVAL:435 errmsg( con->u.serv.wind, _("IPC protocol parse error") );436 break;437 default:438 errmsg( con->u.serv.wind, _("IPC parsing failed: %s"),439 g_strerror( errno ) );440 }441 destroycon( con );442 return 0;443 }444 445 return res;446 }447 448 static size_t449 cli_io_received( GSource * source UNUSED, void * data, size_t len,450 void * vdata )451 {452 struct constate * con = vdata;453 struct constate_client * cli = &con->u.client;454 ssize_t res;455 456 if( IPC_MIN_MSG_LEN > len )457 {458 return 0;459 }460 461 res = ipc_parse( con->ipc, data, len, con );462 463 if( 0 > res )464 {465 switch( errno )466 {467 case EPERM:468 g_message( _("Bad IPC protocol version") );469 break;470 case EINVAL:471 g_message( _("IPC protocol parse error") );472 break;473 default:474 g_message( _("IPC parsing failed: %s"), g_strerror( errno ) );475 break;476 }477 destroycon( con );478 return 0;479 }480 481 if( HASVERS( con->ipc ) && 0 == cli->msgid )482 {483 client_sendmsg( con );484 }485 486 return res;487 }488 489 static void490 client_sendmsg( struct constate * con )491 {492 struct constate_client * cli = &con->u.client;493 GList * ii;494 uint8_t * buf;495 size_t size;496 benc_val_t packet, * val;497 int saved;498 499 switch( cli->msg )500 {501 case IPC_MSG_ADDMANYFILES:502 val = ipc_initval( con->ipc, cli->msg, -1, &packet, TYPE_LIST );503 if( NULL == val ||504 tr_bencListReserve( val, g_list_length( cli->files ) ) )505 {506 perror( "malloc" );507 destroycon( con );508 return;509 }510 for( ii = cli->files; NULL != ii; ii = ii->next )511 {512 tr_bencInitStr( tr_bencListAdd( val ), ii->data, -1, 0 );513 }514 buf = ipc_mkval( &packet, &size );515 saved = errno;516 tr_bencFree( &packet );517 g_list_free( cli->files );518 cli->files = NULL;519 break;520 case IPC_MSG_QUIT:521 buf = ipc_mkempty( con->ipc, &size, cli->msg, -1 );522 saved = errno;523 break;524 default:525 g_assert_not_reached();526 return;527 }528 529 if( NULL == buf )530 {531 errno = saved;532 perror( "malloc" );533 destroycon( con );534 return;535 }536 537 cli->msgid = io_send_keepdata( con->source, buf, size );538 }539 540 static void541 destroycon(struct constate *con) {542 con->source = NULL;543 544 if(0 <= con->fd)545 EVUTIL_CLOSESOCKET(con->fd);546 con->fd = -1;547 ipc_freecon( con->ipc );548 549 switch(con->type) {550 case CON_SERV:551 break;552 case CON_CLIENT:553 ipc_freemsgs( con->msgs );554 freestrlist(con->u.client.files);555 g_main_loop_quit(con->u.client.loop);556 break;557 }558 }559 560 static void561 all_io_closed(GSource *source UNUSED, void *vdata) {562 struct constate *con = vdata;563 564 destroycon(con);565 }566 567 static void568 cli_io_sent( GSource * source UNUSED, size_t id, void *vdata )569 {570 struct constate_client *cli = &((struct constate*)vdata)->u.client;571 572 if(0 < id && cli->msgid == id) {573 *(cli->succeeded) = TRUE;574 destroycon(vdata);575 }576 }577 578 static void579 smsg_add( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )580 {581 struct constate * con = arg;582 struct constate_serv * srv = &con->u.serv;583 benc_val_t * path;584 int ii;585 tr_ctor * ctor;586 GList * list = NULL;587 588 if( NULL == val || TYPE_LIST != val->type )589 {590 simpleresp( con, tag, IPC_MSG_BAD );591 return;592 }593 594 ctor = tr_ctorNew( srv->core );595 596 for( ii = 0; ii < val->val.l.count; ii++ )597 {598 path = val->val.l.vals + ii;599 if( TYPE_STR == path->type &&600 /* XXX somehow escape invalid utf-8 */601 g_utf8_validate( path->val.s.s, path->val.s.i, NULL ) )602 {603 list = g_list_append( list, g_strndup( path->val.s.s, path->val.s.i ) );604 }605 }606 607 if( list ) {608 tr_core_add_list( srv->core, list, ctor );609 tr_core_torrents_added( TR_CORE( srv->core ) );610 }611 612 /* XXX should send info response back with torrent ids */613 simpleresp( con, tag, IPC_MSG_OK );614 }615 616 static void617 smsg_addone( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag,618 void * arg )619 {620 struct constate * con = arg;621 struct constate_serv * srv = &con->u.serv;622 benc_val_t * file, * data, * dir, * start;623 tr_ctor * ctor;624 625 if( NULL == val || TYPE_DICT != val->type )626 {627 simpleresp( con, tag, IPC_MSG_BAD );628 return;629 }630 631 file = tr_bencDictFind( val, "file" );632 data = tr_bencDictFind( val, "data" );633 dir = tr_bencDictFind( val, "directory" );634 start = tr_bencDictFind( val, "autostart" );635 636 if( ( NULL != file && TYPE_STR != file->type ) ||637 ( NULL != data && TYPE_STR != data->type ) ||638 ( NULL != dir && TYPE_STR != dir->type ) ||639 ( NULL != start && TYPE_INT != start->type ) )640 {641 simpleresp( con, tag, IPC_MSG_BAD );642 return;643 }644 645 ctor = tr_ctorNew( tr_core_handle( srv->core ) );646 if( dir )647 tr_ctorSetDestination( ctor, TR_FORCE, dir->val.s.s );648 if( file )649 tr_ctorSetMetainfoFromFile( ctor, file->val.s.s );650 if( data )651 tr_ctorSetMetainfo( ctor, (uint8_t*)data->val.s.s, data->val.s.i );652 if( start )653 tr_ctorSetPaused( ctor, TR_FORCE, !start->val.i );654 655 tr_core_add_ctor( TR_CORE( srv->core ), ctor );656 657 tr_core_torrents_added( TR_CORE( srv->core ) );658 659 /* XXX should send info response back with torrent ids */660 simpleresp( con, tag, IPC_MSG_OK );661 }662 663 static void664 smsg_quit( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag UNUSED,665 void * arg UNUSED )666 {667 struct constate * con = arg;668 struct constate_serv * srv = &con->u.serv;669 670 tr_core_quit( srv->core );671 }672 673 static void674 smsg_noop( enum ipc_msg id UNUSED, benc_val_t * val UNUSED, int64_t tag,675 void * arg )676 {677 simpleresp( arg, tag, IPC_MSG_OK );678 }679 680 static void681 smsg_info( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )682 {683 struct constate * con = arg;684 struct constate_serv * srv = &con->u.serv;685 enum ipc_msg respid;686 benc_val_t * ids, * types, * idval, packet, * pkval;687 int typeflags, ii;688 TrTorrent * tor;689 uint8_t * buf;690 size_t size;691 692 if( NULL == val || TYPE_DICT != val->type )693 {694 simpleresp( con, tag, IPC_MSG_BAD );695 return;696 }697 698 respid = ( IPC_MSG_GETINFO == id ? IPC_MSG_INFO : IPC_MSG_STAT );699 ids = tr_bencDictFind( val, "id" );700 types = tr_bencDictFind( val, "types" );701 if( NULL == ids || TYPE_LIST != ids->type ||702 NULL == types || TYPE_LIST != types->type )703 {704 simpleresp( con, tag, IPC_MSG_BAD );705 return;706 }707 typeflags = ipc_infotypes( respid, types );708 709 pkval = ipc_initval( con->ipc, respid, tag, &packet, TYPE_LIST );710 if( NULL == pkval )711 {712 simpleresp( con, tag, IPC_MSG_FAIL );713 return;714 }715 for( ii = 0; ids->val.l.count > ii; ii++ )716 {717 idval = &ids->val.l.vals[ii];718 if( TYPE_INT != idval->type || !TORRENT_ID_VALID( idval->val.i ) ||719 NULL == ( tor = findtorid( srv->core, idval->val.i, NULL ) ) )720 {721 continue;722 }723 if( 0 > addinfo( tor, respid, idval->val.i, typeflags, pkval ) )724 {725 tr_bencFree( &packet );726 simpleresp( con, tag, IPC_MSG_FAIL );727 return;728 }729 }730 731 buf = ipc_mkval( &packet, &size );732 tr_bencFree( &packet );733 if( NULL == buf )734 {735 simpleresp( con, tag, IPC_MSG_FAIL );736 }737 else738 {739 io_send_keepdata( con->source, buf, size );740 }741 }742 743 static void744 smsg_infoall( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )745 {746 struct constate * con = arg;747 struct constate_serv * srv = &con->u.serv;748 enum ipc_msg respid;749 benc_val_t packet, * pkval;750 int typeflags;751 GtkTreeModel * model;752 GtkTreeIter iter;753 int rowid;754 TrTorrent * tor;755 uint8_t * buf;756 size_t size;757 758 if( NULL == val || TYPE_LIST != val->type )759 {760 simpleresp( con, tag, IPC_MSG_BAD );761 return;762 }763 764 respid = ( IPC_MSG_GETINFOALL == id ? IPC_MSG_INFO : IPC_MSG_STAT );765 typeflags = ipc_infotypes( respid, val );766 767 pkval = ipc_initval( con->ipc, respid, tag, &packet, TYPE_LIST );768 if( NULL == pkval )769 {770 simpleresp( con, tag, IPC_MSG_FAIL );771 return;772 }773 774 model = tr_core_model( srv->core );775 if( gtk_tree_model_get_iter_first( model, &iter ) )776 {777 do778 {779 gtk_tree_model_get( model, &iter, MC_ID, &rowid,780 MC_TORRENT, &tor, -1 );781 g_object_unref( tor );782 if( 0 > addinfo( tor, respid, rowid, typeflags, pkval ) )783 {784 tr_bencFree( &packet );785 simpleresp( con, tag, IPC_MSG_FAIL );786 return;787 }788 }789 while( gtk_tree_model_iter_next( model, &iter ) );790 }791 792 buf = ipc_mkval( &packet, &size );793 tr_bencFree( &packet );794 if( NULL == buf )795 {796 simpleresp( con, tag, IPC_MSG_FAIL );797 }798 else799 {800 io_send_keepdata( con->source, buf, size );801 }802 }803 804 static int805 addinfo( TrTorrent * tor, enum ipc_msg msgid, int torid, int types,806 benc_val_t * val )807 {808 if( IPC_MSG_INFO == msgid )809 {810 const tr_info * inf = tr_torrent_info( tor );811 return ipc_addinfo( val, torid, inf, types );812 }813 else814 {815 const tr_stat * st = tr_torrent_stat( tor );816 return ipc_addstat( val, torid, st, types );817 }818 }819 820 static void821 smsg_look( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag,822 void * arg )823 {824 struct constate * con = arg;825 struct constate_serv * srv = &con->u.serv;826 benc_val_t packet, * pkval, * hash;827 int ii, torid;828 TrTorrent * tor;829 const tr_info * inf;830 uint8_t * buf;831 size_t size;832 833 if( NULL == val || TYPE_LIST != val->type )834 {835 simpleresp( con, tag, IPC_MSG_BAD );836 return;837 }838 839 pkval = ipc_initval( con->ipc, IPC_MSG_INFO, tag, &packet, TYPE_LIST );840 if( NULL == pkval )841 {842 simpleresp( con, tag, IPC_MSG_FAIL );843 return;844 }845 846 for( ii = 0; val->val.l.count > ii; ii++ )847 {848 hash = &val->val.l.vals[ii];849 if( NULL == hash || TYPE_STR != hash->type ||850 SHA_DIGEST_LENGTH * 2 != hash->val.s.i ||851 NULL == ( tor = findtorhash( srv->core, hash->val.s.s, &torid ) ) )852 {853 continue;854 }855 inf = tr_torrent_info( tor );856 if( 0 > ipc_addinfo( pkval, torid, inf, IPC_INF_HASH ) )857 {858 tr_bencFree( &packet );859 simpleresp( con, tag, IPC_MSG_FAIL );860 return;861 }862 }863 864 buf = ipc_mkval( &packet, &size );865 tr_bencFree( &packet );866 if( NULL == buf )867 {868 simpleresp( con, tag, IPC_MSG_FAIL );869 }870 else871 {872 io_send_keepdata( con->source, buf, size );873 }874 }875 876 static void877 smsg_tor( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )878 {879 struct constate * con = arg;880 struct constate_serv * srv = &con->u.serv;881 benc_val_t * idval;882 TrTorrent * tor;883 GtkTreeIter iter;884 int ii;885 886 if( NULL == val || TYPE_LIST != val->type )887 {888 simpleresp( con, tag, IPC_MSG_BAD );889 return;890 }891 892 for( ii = 0; val->val.l.count > ii; ii++ )893 {894 idval = &val->val.l.vals[ii];895 if( TYPE_INT != idval->type || !TORRENT_ID_VALID( idval->val.i ) ||896 NULL == ( tor = findtorid( srv->core, idval->val.i, &iter ) ) )897 {898 continue;899 }900 switch( id )901 {902 case IPC_MSG_REMOVE:903 tr_core_delete_torrent( srv->core, &iter );904 break;905 case IPC_MSG_START:906 tr_torrent_start( tor );907 break;908 case IPC_MSG_STOP:909 tr_torrent_stop( tor );910 break;911 default:912 g_assert_not_reached();913 break;914 }915 }916 917 tr_core_update( srv->core );918 919 /* XXX this is a lie */920 simpleresp( con, tag, IPC_MSG_OK );921 }922 923 static void924 smsg_torall( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag,925 void * arg )926 {927 struct constate * con = arg;928 struct constate_serv * srv = &con->u.serv;929 TrTorrent * tor;930 GtkTreeModel * model;931 GtkTreeIter iter;932 933 model = tr_core_model( srv->core );934 if( gtk_tree_model_get_iter_first( model, &iter ) )935 {936 do937 {938 gtk_tree_model_get( model, &iter, MC_TORRENT, &tor, -1 );939 switch( id )940 {941 case IPC_MSG_REMOVEALL:942 tr_core_delete_torrent( srv->core, &iter );943 break;944 case IPC_MSG_STARTALL:945 tr_torrent_start( tor );946 break;947 case IPC_MSG_STOPALL:948 tr_torrent_stop( tor );949 break;950 default:951 g_assert_not_reached();952 break;953 }954 g_object_unref( tor );955 }956 while( gtk_tree_model_iter_next( model, &iter ) );957 }958 959 tr_core_update( srv->core );960 961 /* XXX this is a lie */962 simpleresp( con, tag, IPC_MSG_OK );963 }964 965 #define TR_NAT_TRAVERSAL_IS_DISABLED( st ) \966 ( TR_NAT_TRAVERSAL_UNMAPPED == (st) || TR_NAT_TRAVERSAL_UNMAPPING == (st) )967 968 static void969 smsg_pref( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag, void * arg )970 {971 struct constate * con = arg;972 struct constate_serv * srv = &con->u.serv;973 uint8_t * buf;974 size_t size;975 const tr_handle_status * hstat;976 const char * pref;977 int num;978 979 switch( id )980 {981 case IPC_MSG_GETAUTOMAP:982 hstat = tr_handleStatus( tr_core_handle( srv->core ) );983 buf = ipc_mkint( con->ipc, &size, IPC_MSG_AUTOMAP, tag,984 !TR_NAT_TRAVERSAL_IS_DISABLED(985 hstat->natTraversalStatus ) );986 break;987 case IPC_MSG_GETAUTOSTART:988 buf = ipc_mkint( con->ipc, &size, IPC_MSG_AUTOSTART, tag, 1 );989 break;990 case IPC_MSG_GETDIR:991 /* XXX sending back "" when we're prompting is kind of bogus */992 pref = pref_flag_get( PREF_KEY_OPTIONS_PROMPT ) ? "" : getdownloaddir();993 buf = ipc_mkstr( con->ipc, &size, IPC_MSG_DIR, tag, pref );994 break;995 case IPC_MSG_GETDOWNLIMIT:996 num = pref_flag_get( PREF_KEY_DL_LIMIT_ENABLED )997 ? pref_int_get( PREF_KEY_DL_LIMIT )998 : -1;999 buf = ipc_mkint( con->ipc, &size, IPC_MSG_DOWNLIMIT, tag, num );1000 break;1001 case IPC_MSG_GETPEX:1002 buf = ipc_mkint( con->ipc, &size, IPC_MSG_PEX, tag,1003 pref_flag_get( PREF_KEY_PEX ) );1004 break;1005 case IPC_MSG_GETPORT:1006 buf = ipc_mkint( con->ipc, &size, IPC_MSG_PORT, tag,1007 pref_flag_get( PREF_KEY_PORT ) );1008 break;1009 case IPC_MSG_GETUPLIMIT:1010 num = pref_flag_get( PREF_KEY_UL_LIMIT_ENABLED )1011 ? pref_int_get( PREF_KEY_UL_LIMIT )1012 : -1;1013 buf = ipc_mkint( con->ipc, &size, IPC_MSG_UPLIMIT, tag, num );1014 break;1015 default:1016 g_assert_not_reached();1017 return;1018 }1019 1020 if( NULL != buf )1021 {1022 io_send_keepdata( con->source, buf, size );1023 }1024 }1025 1026 static void1027 smsg_int( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )1028 {1029 struct constate * con = arg;1030 struct constate_serv * srv = &con->u.serv;1031 1032 if( NULL == val || TYPE_INT != val->type || INT_MAX < val->val.i )1033 {1034 simpleresp( con, tag, IPC_MSG_BAD );1035 return;1036 }1037 1038 switch( id )1039 {1040 case IPC_MSG_AUTOMAP:1041 tr_core_set_pref_bool( srv->core, PREF_KEY_NAT, val->val.i );1042 break;1043 case IPC_MSG_AUTOSTART:1044 simpleresp( con, tag, IPC_MSG_BAD );1045 return;1046 case IPC_MSG_DOWNLIMIT:1047 if( 0 > val->val.i )1048 {1049 tr_core_set_pref_bool( srv->core, PREF_KEY_DL_LIMIT_ENABLED, 0 );1050 }1051 else1052 {1053 tr_core_set_pref_int( srv->core, PREF_KEY_DL_LIMIT, val->val.i );1054 tr_core_set_pref_bool( srv->core, PREF_KEY_DL_LIMIT_ENABLED, 1 );1055 }1056 break;1057 case IPC_MSG_PEX:1058 tr_core_set_pref_bool( srv->core, PREF_KEY_PEX, val->val.i );1059 break;1060 case IPC_MSG_PORT:1061 tr_core_set_pref_int( srv->core, PREF_KEY_PORT, val->val.i );1062 break;1063 case IPC_MSG_UPLIMIT:1064 if( 0 > val->val.i )1065 {1066 tr_core_set_pref_bool( srv->core, PREF_KEY_UL_LIMIT_ENABLED, 0 );1067 }1068 else1069 {1070 tr_core_set_pref_int( srv->core, PREF_KEY_UL_LIMIT, val->val.i );1071 tr_core_set_pref_bool( srv->core, PREF_KEY_UL_LIMIT_ENABLED, 1 );1072 }1073 break;1074 default:1075 g_assert_not_reached();1076 return;1077 }1078 }1079 1080 static void1081 smsg_str( enum ipc_msg id, benc_val_t * val, int64_t tag, void * arg )1082 {1083 struct constate * con = arg;1084 struct constate_serv * srv = &con->u.serv;1085 1086 if( NULL == val || TYPE_STR != val->type )1087 {1088 simpleresp( con, tag, IPC_MSG_BAD );1089 return;1090 }1091 1092 switch( id )1093 {1094 case IPC_MSG_DIR:1095 tr_core_set_pref( srv->core, PREF_KEY_DIR_DEFAULT, val->val.s.s );1096 break;1097 default:1098 g_assert_not_reached();1099 return;1100 }1101 }1102 1103 static void1104 smsg_sup( enum ipc_msg id UNUSED, benc_val_t * val, int64_t tag, void * arg )1105 {1106 struct constate * con = arg;1107 benc_val_t packet, * pkval, * name;1108 int ii;1109 enum ipc_msg found;1110 uint8_t * buf;1111 size_t size;1112 1113 if( NULL == val || TYPE_LIST != val->type )1114 {1115 simpleresp( con, tag, IPC_MSG_BAD );1116 return;1117 }1118 1119 pkval = ipc_initval( con->ipc, IPC_MSG_SUP, tag, &packet, TYPE_LIST );1120 if( NULL == pkval )1121 {1122 simpleresp( con, tag, IPC_MSG_FAIL );1123 return;1124 }1125 if( tr_bencListReserve( pkval, val->val.l.count ) )1126 {1127 tr_bencFree( &packet );1128 simpleresp( con, tag, IPC_MSG_FAIL );1129 return;1130 }1131 1132 for( ii = 0; val->val.l.count > ii; ii++ )1133 {1134 name = &val->val.l.vals[ii];1135 if( NULL == name || TYPE_STR != name->type )1136 {1137 continue;1138 }1139 found = ipc_msgid( con->ipc, name->val.s.s );1140 if( IPC__MSG_COUNT == found || !ipc_ishandled( con->ipc, found ) )1141 {1142 continue;1143 }1144 tr_bencInitStr( tr_bencListAdd( pkval ),1145 name->val.s.s, name->val.s.i, 1 );1146 }1147 1148 buf = ipc_mkval( &packet, &size );1149 tr_bencFree( &packet );1150 if( NULL == buf )1151 {1152 simpleresp( con, tag, IPC_MSG_FAIL );1153 }1154 else1155 {1156 io_send_keepdata( con->source, buf, size );1157 }1158 }1159 1160 static void1161 all_default( enum ipc_msg id, benc_val_t * val UNUSED, int64_t tag, void * arg )1162 {1163 switch( id )1164 {1165 case IPC_MSG_FAIL:1166 case IPC_MSG_NOTSUP:1167 case IPC_MSG_BAD:1168 case IPC_MSG_OK:1169 break;1170 default:1171 simpleresp( arg, tag, IPC_MSG_NOTSUP );1172 break;1173 }1174 }1175 1176 static gboolean1177 simpleresp( struct constate * con, int64_t tag, enum ipc_msg id )1178 {1179 uint8_t * buf;1180 size_t size;1181 1182 buf = ipc_mkempty( con->ipc, &size, id, tag );1183 if( NULL == buf )1184 {1185 return FALSE;1186 }1187 1188 io_send_keepdata( con->source, buf, size );1189 1190 return TRUE;1191 }1192 1193 static TrTorrent *1194 findtorid( TrCore * core, int id, GtkTreeIter * iter )1195 {1196 GtkTreeModel * model;1197 GtkTreeIter myiter;1198 int rowid;1199 TrTorrent * tor;1200 1201 if( NULL == iter )1202 {1203 iter = &myiter;1204 }1205 1206 model = tr_core_model( core );1207 if( gtk_tree_model_get_iter_first( model, iter ) )1208 {1209 do1210 {1211 gtk_tree_model_get( model, iter, MC_ID, &rowid, -1 );1212 if( rowid == id )1213 {1214 gtk_tree_model_get( model, iter, MC_TORRENT, &tor, -1 );1215 g_object_unref( tor );1216 return tor;1217 }1218 }1219 while( gtk_tree_model_iter_next( model, iter ) );1220 }1221 1222 return NULL;1223 }1224 1225 static TrTorrent *1226 findtorhash( TrCore * core, const char * hash, int * torid )1227 {1228 GtkTreeModel * model;1229 GtkTreeIter iter;1230 char * rowhash;1231 TrTorrent * tor;1232 1233 model = tr_core_model( core );1234 if( gtk_tree_model_get_iter_first( model, &iter ) )1235 {1236 do1237 {1238 gtk_tree_model_get( model, &iter, MC_HASH, &rowhash, -1 );1239 if( 0 == strcmp( hash, rowhash ) )1240 {1241 gtk_tree_model_get( model, &iter, MC_ID, torid,1242 MC_TORRENT, &tor, -1 );1243 g_object_unref( tor );1244 return tor;1245 }1246 }1247 while( gtk_tree_model_iter_next( model, &iter ) );1248 }1249 1250 return NULL;1251 } -
trunk/gtk/tr-io.c
r5124 r5125 61 61 }; 62 62 63 static struct iosource *64 newsource(void);65 static void66 freeoutbuf(struct iooutbuf *buf);67 63 static gboolean 68 io_prepare(GSource *source, gint *timeout_); 64 io_prepare(GSource *source UNUSED, gint *timeout_) { 65 *timeout_ = -1; 66 return FALSE; 67 } 68 69 69 static gboolean 70 io_check(GSource *source); 70 io_check(GSource *source) { 71 struct iosource *io = (struct iosource*)source; 72 73 if(io->infd.revents) 74 return TRUE; 75 if(NULL != io->outbufs && io->outfd.revents) 76 return TRUE; 77 else 78 return FALSE; 79 } 80 81 static void 82 io_disconnect(struct iosource *io, int err) { 83 if(NULL != io->closed) { 84 errno = err; 85 io->closed((GSource*)io, io->cbdata); 86 } 87 88 if(NULL != io->outbufs) 89 g_source_remove_poll((GSource*)io, &io->outfd); 90 91 g_source_remove_poll((GSource*)io, &io->infd); 92 g_source_remove(g_source_get_id((GSource*)io)); 93 g_source_unref((GSource*)io); 94 } 95 96 static void 97 io_biggify(char **buf, size_t used, size_t *max) { 98 if(used + IO_BLOCKSIZE > *max) { 99 *max += IO_BLOCKSIZE; 100 *buf = g_renew(char, *buf, *max); 101 } 102 } 103 104 static void 105 io_read(struct iosource *io) { 106 ssize_t res = 0; 107 gboolean newdata = FALSE; 108 size_t used; 109 int err = 0; 110 111 g_source_ref((GSource*)io); 112 113 do { 114 if(!newdata && 0 < res) 115 newdata = TRUE; 116 io->inused += res; 117 io_biggify(&io->inbuf, io->inused, &io->inmax); 118 errno = 0; 119 res = read(io->infd.fd, io->inbuf + io->inused, io->inmax - io->inused); 120 if(0 > res) 121 err = errno; 122 } while(0 < res); 123 124 if(NULL == io->received) 125 io->inused = 0; 126 else if(newdata) { 127 used = io->received((GSource*)io, io->inbuf, io->inused, io->cbdata); 128 if(used > io->inused) 129 used = io->inused; 130 if(0 < used) { 131 if(used < io->inused) 132 memmove(io->inbuf, io->inbuf + used, io->inused - used); 133 io->inused -= used; 134 } 135 } 136 137 if(0 != err && EAGAIN != err) 138 io_disconnect(io, err); 139 else if(0 == res) 140 io_disconnect(io, 0); 141 g_source_unref((GSource*)io); 142 } 143 144 static void 145 io_accept(struct iosource *io) { 146 int fd; 147 socklen_t len; 148 149 len = io->inmax; 150 if(0 > (fd = accept(io->infd.fd, (struct sockaddr*)io->inbuf, &len))) { 151 if(EAGAIN == errno || ECONNABORTED == errno || EWOULDBLOCK == errno) 152 return; 153 io_disconnect(io, errno); 154 } 155 156 io->accepted((GSource*)io, fd, (struct sockaddr*)io->inbuf, len, io->cbdata); 157 } 158 159 static void 160 freeoutbuf(struct iooutbuf *buf) { 161 if(NULL != buf->data) 162 g_free(buf->data); 163 g_free(buf); 164 } 165 166 static void 167 io_write(struct iosource *io) { 168 struct iooutbuf *buf; 169 ssize_t res = 1; 170 int err = 0; 171 172 g_source_ref((GSource*)io); 173 174 while(NULL != io->outbufs && 0 == err) { 175 buf = io->outbufs->data; 176 while(buf->off < buf->len && 0 < res) { 177 errno = 0; 178 res = write(io->outfd.fd, buf->data + buf->off, buf->len - buf->off); 179 if(0 > res) 180 err = errno; 181 else 182 buf->off += res; 183 } 184 185 if(buf->off >= buf->len) { 186 io->outbufs = g_list_remove(io->outbufs, buf); 187 if(NULL == io->outbufs) 188 g_source_remove_poll((GSource*)io, &io->outfd); 189 if(NULL != io->sent) 190 io->sent((GSource*)io, buf->id, io->cbdata); 191 freeoutbuf(buf); 192 } 193 } 194 195 if(0 != err && EAGAIN != err) 196 io_disconnect(io, err); 197 198 g_source_unref((GSource*)io); 199 } 200 71 201 static gboolean 72 io_dispatch(GSource *source, GSourceFunc callback, gpointer gdata); 73 static void 74 io_finalize(GSource *source); 75 static void 76 io_accept(struct iosource *io); 77 static void 78 io_read(struct iosource *io); 79 static void 80 io_write(struct iosource *io); 81 static void 82 io_disconnect(struct iosource *io, int err); 202 io_dispatch(GSource *source, GSourceFunc callback UNUSED, 203 gpointer gdata UNUSED) { 204 struct iosource *io = (struct iosource*)source; 205 206 if(io->infd.revents & (G_IO_ERR | G_IO_HUP) || 207 io->outfd.revents & G_IO_ERR) 208 io_disconnect(io, 0 /* XXX how do I get errors here? */ ); 209 else if(io->infd.revents & G_IO_IN) 210 (NULL == io->accepted ? io_read : io_accept)(io); 211 else if(io->outfd.revents & G_IO_OUT) 212 io_write(io); 213 else 214 return FALSE; 215 216 return TRUE; 217 } 218 219 static void 220 io_finalize(GSource *source UNUSED) { 221 struct iosource *io = (struct iosource*)source; 222 223 if(NULL != io->outbufs) { 224 g_list_foreach(io->outbufs, (GFunc)freeoutbuf, NULL); 225 g_list_free(io->outbufs); 226 } 227 228 if(NULL != io->inbuf) 229 g_free(io->inbuf); 230 } 83 231 84 232 static GSourceFuncs sourcefuncs = { … … 90 238 NULL 91 239 }; 92 93 static int94 nonblock(int fd)95 {96 const int err = evutil_make_socket_nonblocking( fd );97 return err;98 }99 100 GSource *101 io_new(int fd, ioidfunc_t sent, iodatafunc_t received,102 iofunc_t closed, void *cbdata) {103 struct iosource *io;104 105 if( nonblock( fd ) )106 return NULL;107 108 io = newsource();109 io->sent = sent;110 io->received = received;111 io->closed = closed;112 io->cbdata = cbdata;113 io->infd.fd = fd;114 io->infd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;115 io->infd.revents = 0;116 io->outfd.fd = fd;117 io->outfd.events = G_IO_OUT | G_IO_ERR;118 io->outfd.revents = 0;119 120 g_source_add_poll((GSource*)io, &io->infd);121 g_source_attach((GSource*)io, NULL);122 123 return (GSource*)io;124 }125 126 GSource *127 io_new_listening(int fd, socklen_t len, ionewfunc_t accepted,128 iofunc_t closed, void *cbdata) {129 struct iosource *io;130 131 g_assert(NULL != accepted);132 133 if( nonblock( fd ) )134 return NULL;135 136 io = newsource();137 io->accepted = accepted;138 io->closed = closed;139 io->cbdata = cbdata;140 io->infd.fd = fd;141 io->infd.events = G_IO_IN | G_IO_ERR;142 io->infd.revents = 0;143 io->inbuf = g_new(char, len);144 io->inmax = len;145 146 g_source_add_poll((GSource*)io, &io->infd);147 g_source_attach((GSource*)io, NULL);148 149 return (GSource*)io;150 }151 240 152 241 static struct iosource * … … 173 262 } 174 263 264 GSource * 265 io_new(int fd, ioidfunc_t sent, iodatafunc_t received, 266 iofunc_t closed, void *cbdata) { 267 struct iosource *io; 268 269 if( evutil_make_socket_nonblocking( fd ) ) 270 return NULL; 271 272 io = newsource(); 273 io->sent = sent; 274 io->received = received; 275 io->closed = closed; 276 io->cbdata = cbdata; 277 io->infd.fd = fd; 278 io->infd.events = G_IO_IN | G_IO_HUP | G_IO_ERR; 279 io->infd.revents = 0; 280 io->outfd.fd = fd; 281 io->outfd.events = G_IO_OUT | G_IO_ERR; 282 io->outfd.revents = 0; 283 284 g_source_add_poll((GSource*)io, &io->infd); 285 g_source_attach((GSource*)io, NULL); 286 287 return (GSource*)io; 288 } 289 290 GSource * 291 io_new_listening(int fd, socklen_t len, ionewfunc_t accepted, 292 iofunc_t closed, void *cbdata) { 293 struct iosource *io; 294 295 g_assert(NULL != accepted); 296 297 if( evutil_make_socket_nonblocking( fd ) ) 298 return NULL; 299 300 io = newsource(); 301 io->accepted = accepted; 302 io->closed = closed; 303 io->cbdata = cbdata; 304 io->infd.fd = fd; 305 io->infd.events = G_IO_IN | G_IO_ERR; 306 io->infd.revents = 0; 307 io->inbuf = g_new(char, len); 308 io->inmax = len; 309 310 g_source_add_poll((GSource*)io, &io->infd); 311 g_source_attach((GSource*)io, NULL); 312 313 return (GSource*)io; 314 } 315 175 316 unsigned int 176 317 io_send_keepdata(GSource *source, void *data, size_t len) { … … 193 334 return io->lastid; 194 335 } 195 196 static void197 freeoutbuf(struct iooutbuf *buf) {198 if(NULL != buf->data)199 g_free(buf->data);200 g_free(buf);201 }202 203 static gboolean204 io_prepare(GSource *source UNUSED, gint *timeout_) {205 *timeout_ = -1;206 return FALSE;207 }208 209 static gboolean210 io_check(GSource *source) {211 struct iosource *io = (struct iosource*)source;212 213 if(io->infd.revents)214 return TRUE;215 if(NULL != io->outbufs && io->outfd.revents)216 return TRUE;217 else218 return FALSE;219 }220 221 static gboolean222 io_dispatch(GSource *source, GSourceFunc callback UNUSED,223 gpointer gdata UNUSED) {224 struct iosource *io = (struct iosource*)source;225 226 if(io->infd.revents & (G_IO_ERR | G_IO_HUP) ||227 io->outfd.revents & G_IO_ERR)228 io_disconnect(io, 0 /* XXX how do I get errors here? */ );229 else if(io->infd.revents & G_IO_IN)230 (NULL == io->accepted ? io_read : io_accept)(io);231 else if(io->outfd.revents & G_IO_OUT)232 io_write(io);233 else234 return FALSE;235 236 return TRUE;237 }238 239 240 static void241 io_finalize(GSource *source UNUSED) {242 struct iosource *io = (struct iosource*)source;243 244 if(NULL != io->outbufs) {245 g_list_foreach(io->outbufs, (GFunc)freeoutbuf, NULL);246 g_list_free(io->outbufs);247 }248 249 if(NULL != io->inbuf)250 g_free(io->inbuf);251 }252 253 static void254 io_biggify(char **buf, size_t used, size_t *max) {255 if(used + IO_BLOCKSIZE > *max) {256 *max += IO_BLOCKSIZE;257 *buf = g_renew(char, *buf, *max);258 }259 }260 261 static void262 io_accept(struct iosource *io) {263 int fd;264 socklen_t len;265 266 len = io->inmax;267 if(0 > (fd = accept(io->infd.fd, (struct sockaddr*)io->inbuf, &len))) {268 if(EAGAIN == errno || ECONNABORTED == errno || EWOULDBLOCK == errno)269 return;270 io_disconnect(io, errno);271 }272 273 io->accepted((GSource*)io, fd, (struct sockaddr*)io->inbuf, len, io->cbdata);274 }275 276 static void277 io_read(struct iosource *io) {278 ssize_t res = 0;279 gboolean newdata = FALSE;280 size_t used;281 int err = 0;282 283 g_source_ref((GSource*)io);284 285 do {286 if(!newdata && 0 < res)287 newdata = TRUE;288 io->inused += res;289 io_biggify(&io->inbuf, io->inused, &io->inmax);290 errno = 0;291 res = read(io->infd.fd, io->inbuf + io->inused, io->inmax - io->inused);292 if(0 > res)293 err = errno;294 } while(0 < res);295 296 if(NULL == io->received)297 io->inused = 0;298 else if(newdata) {299 used = io->received((GSource*)io, io->inbuf, io->inused, io->cbdata);300 if(used > io->inused)301 used = io->inused;302 if(0 < used) {303 if(used < io->inused)304 memmove(io->inbuf, io->inbuf + used, io->inused - used);305 io->inused -= used;306 }307 }308 309 if(0 != err && EAGAIN != err)310 io_disconnect(io, err);311 else if(0 == res)312 io_disconnect(io, 0);313 g_source_unref((GSource*)io);314 }315 316 static void317 io_write(struct iosource *io) {318 struct iooutbuf *buf;319 ssize_t res = 1;320 int err = 0;321 322 g_source_ref((GSource*)io);323 324 while(NULL != io->outbufs && 0 == err) {325 buf = io->outbufs->data;326 while(buf->off < buf->len && 0 < res) {327 errno = 0;328 res = write(io->outfd.fd, buf->data + buf->off, buf->len - buf->off);329 if(0 > res)330 err = errno;331 else332 buf->off += res;333 }334 335 if(buf->off >= buf->len) {336 io->outbufs = g_list_remove(io->outbufs, buf);337 if(NULL == io->outbufs)338 g_source_remove_poll((GSource*)io, &io->outfd);339 if(NULL != io->sent)340 io->sent((GSource*)io, buf->id, io->cbdata);341 freeoutbuf(buf);342 }343 }344 345 if(0 != err && EAGAIN != err)346 io_disconnect(io, err);347 348 g_source_unref((GSource*)io);349 }350 351 static void352 io_disconnect(struct iosource *io, int err) {353 if(NULL != io->closed) {354 errno = err;355 io->closed((GSource*)io, io->cbdata);356 }357 358 if(NULL != io->outbufs)359 g_source_remove_poll((GSource*)io, &io->outfd);360 361 g_source_remove_poll((GSource*)io, &io->infd);362 g_source_remove(g_source_get_id((GSource*)io));363 g_source_unref((GSource*)io);364 }
Note: See TracChangeset
for help on using the changeset viewer.