Changeset 11602
- Timestamp:
- Dec 28, 2010, 7:24:10 AM (12 years ago)
- Location:
- trunk/libtransmission
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/fdlimit.c
r11599 r11602 53 53 #include "fdlimit.h" 54 54 #include "net.h" 55 #include "platform.h" /* TR_PATH_MAX, TR_PATH_DELIMITER */56 55 #include "session.h" 57 56 #include "torrent.h" /* tr_isTorrent() */ 58 #include "utils.h"59 57 60 58 #define dbgmsg( ... ) \ … … 63 61 tr_deepLog( __FILE__, __LINE__, NULL, __VA_ARGS__ ); \ 64 62 } while( 0 ) 65 66 /**67 ***68 **/69 70 struct tr_openfile71 {72 tr_bool isWritable;73 int torrentId;74 tr_file_index_t fileNum;75 char filename[TR_PATH_MAX];76 int fd;77 time_t date;78 };79 80 struct tr_fdInfo81 {82 int socketCount;83 int socketLimit;84 int publicSocketLimit;85 int openFileLimit;86 struct tr_openfile * openFiles;87 };88 63 89 64 /*** … … 200 175 And of course they are not thread-safe. */ 201 176 202 /* https://trac.transmissionbt.com/ticket/3826 */ 177 /* don't use pread/pwrite on old versions of uClibc because they're buggy. 178 * https://trac.transmissionbt.com/ticket/3826 */ 203 179 #ifdef __UCLIBC__ 204 180 #define TR_UCLIBC_CHECK_VERSION(major,minor,micro) \ … … 336 312 } 337 313 314 /***** 315 ****** 316 ****** 317 ****** 318 *****/ 319 320 struct tr_cached_file 321 { 322 tr_bool is_writable; 323 int fd; 324 int torrent_id; 325 tr_file_index_t file_index; 326 time_t used_at; 327 }; 328 329 static inline tr_bool 330 cached_file_is_open( const struct tr_cached_file * o ) 331 { 332 assert( o != NULL ); 333 334 return o->fd >= 0; 335 } 336 337 static void 338 cached_file_close( struct tr_cached_file * o ) 339 { 340 assert( cached_file_is_open( o ) ); 341 342 tr_close_file( o->fd ); 343 o->fd = -1; 344 } 345 338 346 /** 339 347 * returns 0 on success, or an errno value on failure. … … 342 350 */ 343 351 static int 344 TrOpenFile( tr_session * session, 345 int i, 346 const char * filename, 347 tr_bool doWrite, 348 tr_preallocation_mode preallocationMode, 349 uint64_t desiredFileSize ) 352 cached_file_open( struct tr_cached_file * o, 353 const char * filename, 354 tr_bool writable, 355 tr_preallocation_mode allocation, 356 uint64_t file_size ) 350 357 { 351 358 int flags; 352 359 struct stat sb; 353 360 tr_bool alreadyExisted; 354 struct tr_openfile * file;355 356 assert( tr_isSession( session ) );357 assert( session->fdInfo != NULL );358 359 file = &session->fdInfo->openFiles[i];360 361 361 362 /* create subfolders, if any */ 362 if( doWrite )363 if( writable ) 363 364 { 364 365 char * dir = tr_dirname( filename ); … … 374 375 alreadyExisted = !stat( filename, &sb ) && S_ISREG( sb.st_mode ); 375 376 376 if( doWrite && !alreadyExisted && ( preallocationMode== TR_PREALLOCATE_FULL ) )377 if( preallocateFileFull( filename, desiredFileSize ) )378 tr_dbg( _( "Preallocated file \"%s\"" ), filename );377 if( writable && !alreadyExisted && ( allocation == TR_PREALLOCATE_FULL ) ) 378 if( preallocateFileFull( filename, file_size ) ) 379 tr_dbg( "Preallocated file \"%s\"", filename ); 379 380 380 381 /* open the file */ 381 flags = doWrite ? ( O_RDWR | O_CREAT ) : O_RDONLY;382 flags = writable ? ( O_RDWR | O_CREAT ) : O_RDONLY; 382 383 #ifdef O_SEQUENTIAL 383 384 flags |= O_SEQUENTIAL; … … 389 390 flags |= O_BINARY; 390 391 #endif 391 file->fd = open( filename, flags, 0666 ); 392 if( file->fd == -1 ) 392 o->fd = open( filename, flags, 0666 ); 393 394 if( o->fd == -1 ) 393 395 { 394 396 const int err = errno; 395 tr_err( _( "Couldn't open \"%1$s\": %2$s" ), filename, tr_strerror( err ) );397 tr_err( ( "Couldn't open \"%1$s\": %2$s" ), filename, tr_strerror( err ) ); 396 398 return err; 397 399 } … … 403 405 * https://bugs.launchpad.net/ubuntu/+source/transmission/+bug/318249 404 406 */ 405 if( alreadyExisted && ( desiredFileSize < (uint64_t)sb.st_size ) ) 406 ftruncate( file->fd, desiredFileSize ); 407 408 if( doWrite && !alreadyExisted && ( preallocationMode == TR_PREALLOCATE_SPARSE ) ) 409 preallocateFileSparse( file->fd, desiredFileSize ); 410 411 #ifdef HAVE_POSIX_FADVISE 412 /* this doubles the OS level readahead buffer, which in practice 413 * turns out to be a good thing, because many (most?) clients request 414 * chunks of blocks in order. 415 * It's okay for this to fail silently, so don't let it affect errno */ 416 { 417 const int err = errno; 418 posix_fadvise( file->fd, 0, 0, POSIX_FADV_SEQUENTIAL ); 419 errno = err; 420 } 421 #endif 422 423 #if defined( SYS_DARWIN ) 424 /** 425 * 1. Enable readahead for reasons described above w/POSIX_FADV_SEQUENTIAL. 426 * 427 * 2. Disable OS-level caching due to user reports of adverse effects of 428 * excessive inactive memory. However this is experimental because 429 * previous attempts at this have *also* had adverse effects (see r8198) 430 * 431 * It's okay for this to fail silently, so don't let it affect errno 432 */ 433 { 434 const int err = errno; 435 fcntl( file->fd, F_NOCACHE, 1 ); 436 fcntl( file->fd, F_RDAHEAD, 1 ); 437 errno = err; 438 } 439 #endif 407 if( alreadyExisted && ( file_size < (uint64_t)sb.st_size ) ) 408 ftruncate( o->fd, file_size ); 409 410 if( writable && !alreadyExisted && ( allocation == TR_PREALLOCATE_SPARSE ) ) 411 preallocateFileSparse( o->fd, file_size ); 412 413 /* Many (most?) clients request blocks in ascending order, 414 * so increase the readahead buffer. 415 * Also, disable OS-level caching because "inactive memory" angers users. */ 416 tr_set_file_for_single_pass( o->fd ); 440 417 441 418 return 0; 442 419 } 443 420 444 static inline tr_bool 445 fileIsOpen( const struct tr_openfile * o ) 446 { 447 return o->fd >= 0; 448 } 421 /*** 422 **** 423 ***/ 424 425 struct tr_fileset 426 { 427 struct tr_cached_file * begin; 428 struct tr_cached_file * end; 429 }; 449 430 450 431 static void 451 TrCloseFile( struct tr_openfile * o ) 452 { 453 assert( o != NULL ); 454 assert( fileIsOpen( o ) ); 455 456 tr_close_file( o->fd ); 457 o->fd = -1; 458 } 459 460 int 461 tr_fdFileGetCached( tr_session * session, 462 int torrentId, 463 tr_file_index_t fileNum, 464 tr_bool doWrite ) 465 { 466 struct tr_openfile * match = NULL; 467 struct tr_fdInfo * gFd; 468 469 assert( tr_isSession( session ) ); 470 assert( session->fdInfo != NULL ); 471 assert( torrentId > 0 ); 472 assert( tr_isBool( doWrite ) ); 473 474 gFd = session->fdInfo; 475 476 /* is it already open? */ 477 { 478 int i; 479 struct tr_openfile * o; 480 for( i=0; i<gFd->openFileLimit; ++i ) 481 { 482 o = &gFd->openFiles[i]; 483 484 if( torrentId != o->torrentId ) 485 continue; 486 if( fileNum != o->fileNum ) 487 continue; 488 if( !fileIsOpen( o ) ) 489 continue; 490 491 match = o; 492 break; 493 } 494 } 495 496 if( ( match != NULL ) && ( !doWrite || match->isWritable ) ) 497 { 498 match->date = tr_time( ); 499 return match->fd; 500 } 501 502 return -1; 432 fileset_construct( struct tr_fileset * set, int n ) 433 { 434 struct tr_cached_file * o; 435 const struct tr_cached_file TR_CACHED_FILE_INIT = { 0, -1, 0, 0, 0 }; 436 437 set->begin = tr_new( struct tr_cached_file, n ); 438 set->end = set->begin + n; 439 440 for( o=set->begin; o!=set->end; ++o ) 441 *o = TR_CACHED_FILE_INIT; 442 } 443 444 static void 445 fileset_close_all( struct tr_fileset * set ) 446 { 447 struct tr_cached_file * o; 448 449 if( set != NULL ) 450 for( o=set->begin; o!=set->end; ++o ) 451 if( cached_file_is_open( o ) ) 452 cached_file_close( o ); 453 } 454 455 static void 456 fileset_destruct( struct tr_fileset * set ) 457 { 458 fileset_close_all( set ); 459 tr_free( set->begin ); 460 set->begin = set->end = NULL; 461 } 462 463 static void 464 fileset_close_torrent( struct tr_fileset * set, int torrent_id ) 465 { 466 struct tr_cached_file * o; 467 468 if( set != NULL ) 469 for( o=set->begin; o!=set->end; ++o ) 470 if( ( o->torrent_id == torrent_id ) && cached_file_is_open( o ) ) 471 cached_file_close( o ); 472 } 473 474 static struct tr_cached_file * 475 fileset_lookup( struct tr_fileset * set, int torrent_id, tr_file_index_t i ) 476 { 477 struct tr_cached_file * o; 478 479 if( set != NULL ) 480 for( o=set->begin; o!=set->end; ++o ) 481 if( ( torrent_id == o->torrent_id ) && ( i == o->file_index ) && cached_file_is_open( o ) ) 482 return o; 483 484 return NULL; 485 } 486 487 static struct tr_cached_file * 488 fileset_get_empty_slot( struct tr_fileset * set ) 489 { 490 struct tr_cached_file * o; 491 struct tr_cached_file * cull; 492 493 /* try to find an unused slot */ 494 for( o=set->begin; o!=set->end; ++o ) 495 if( !cached_file_is_open( o ) ) 496 return o; 497 498 /* all slots are full... recycle the least recently used */ 499 for( cull=NULL, o=set->begin; o!=set->end; ++o ) 500 if( !cull || o->used_at < cull->used_at ) 501 cull = o; 502 cached_file_close( cull ); 503 return cull; 504 } 505 506 /*** 507 **** 508 ***/ 509 510 struct tr_fdInfo 511 { 512 int socket_count; 513 int socket_limit; 514 int public_socket_limit; 515 struct tr_fileset fileset; 516 }; 517 518 static struct tr_fileset* 519 get_fileset( tr_session * session ) 520 { 521 return session && session->fdInfo ? &session->fdInfo->fileset : NULL; 522 } 523 524 void 525 tr_fdFileClose( tr_session * s, const tr_torrent * tor, tr_file_index_t i ) 526 { 527 struct tr_cached_file * o; 528 529 if(( o = fileset_lookup( get_fileset( s ), tr_torrentId( tor ), i ))) 530 cached_file_close( o ); 531 } 532 533 int 534 tr_fdFileGetCached( tr_session * s, int torrent_id, tr_file_index_t i, tr_bool writable ) 535 { 536 struct tr_cached_file * o = fileset_lookup( get_fileset( s ), torrent_id, i ); 537 538 if( !o || ( writable && !o->is_writable ) ) 539 return -1; 540 541 o->used_at = tr_time( ); 542 return o->fd; 543 } 544 545 void 546 tr_fdTorrentClose( tr_session * session, int torrent_id ) 547 { 548 fileset_close_torrent( get_fileset( session ), torrent_id ); 503 549 } 504 550 … … 506 552 int 507 553 tr_fdFileCheckout( tr_session * session, 508 int torrent Id,509 tr_file_index_t fileNum,554 int torrent_id, 555 tr_file_index_t i, 510 556 const char * filename, 511 tr_bool doWrite, 512 tr_preallocation_mode preallocationMode, 513 uint64_t desiredFileSize ) 514 { 515 int i, winner = -1; 516 struct tr_fdInfo * gFd; 517 struct tr_openfile * o; 518 519 assert( tr_isSession( session ) ); 520 assert( session->fdInfo != NULL ); 521 assert( torrentId > 0 ); 522 assert( filename && *filename ); 523 assert( tr_isBool( doWrite ) ); 524 525 gFd = session->fdInfo; 526 527 dbgmsg( "looking for file '%s', writable %c", filename, doWrite ? 'y' : 'n' ); 528 529 /* is it already open? */ 530 for( i=0; i<gFd->openFileLimit; ++i ) 531 { 532 o = &gFd->openFiles[i]; 533 534 if( torrentId != o->torrentId ) 535 continue; 536 if( fileNum != o->fileNum ) 537 continue; 538 if( !fileIsOpen( o ) ) 539 continue; 540 541 if( doWrite && !o->isWritable ) 542 { 543 dbgmsg( "found it! it's open and available, but isn't writable. closing..." ); 544 TrCloseFile( o ); 545 break; 546 } 547 548 dbgmsg( "found it! it's ready for use!" ); 549 winner = i; 550 break; 551 } 552 553 dbgmsg( "it's not already open. looking for an open slot or an old file." ); 554 while( winner < 0 ) 555 { 556 time_t date = tr_time( ) + 1; 557 558 /* look for the file that's been open longest */ 559 for( i=0; i<gFd->openFileLimit; ++i ) 560 { 561 o = &gFd->openFiles[i]; 562 563 if( !fileIsOpen( o ) ) 564 { 565 winner = i; 566 dbgmsg( "found an empty slot in %d", winner ); 567 break; 568 } 569 570 if( date > o->date ) 571 { 572 date = o->date; 573 winner = i; 574 } 575 } 576 577 assert( winner >= 0 ); 578 579 if( fileIsOpen( &gFd->openFiles[winner] ) ) 580 { 581 dbgmsg( "closing file \"%s\"", gFd->openFiles[winner].filename ); 582 TrCloseFile( &gFd->openFiles[winner] ); 583 } 584 } 585 586 assert( winner >= 0 ); 587 o = &gFd->openFiles[winner]; 588 if( !fileIsOpen( o ) ) 589 { 590 const int err = TrOpenFile( session, winner, filename, doWrite, 591 preallocationMode, desiredFileSize ); 557 tr_bool writable, 558 tr_preallocation_mode preallocation_mode, 559 uint64_t file_size ) 560 { 561 struct tr_fileset * set = get_fileset( session ); 562 struct tr_cached_file * o = fileset_lookup( set, torrent_id, i ); 563 564 if( o && writable && !o->is_writable ) 565 cached_file_close( o ); /* close it so we can reopen in rw mode */ 566 else if( !o ) 567 o = fileset_get_empty_slot( set ); 568 569 if( !cached_file_is_open( o ) ) 570 { 571 const int err = cached_file_open( o, filename, writable, preallocation_mode, file_size ); 592 572 if( err ) { 593 573 errno = err; … … 595 575 } 596 576 597 dbgmsg( "opened '%s' in slot %d, doWrite %c", filename, winner, 598 doWrite ? 'y' : 'n' ); 599 tr_strlcpy( o->filename, filename, sizeof( o->filename ) ); 600 o->isWritable = doWrite; 601 } 602 603 dbgmsg( "checking out '%s' in slot %d", filename, winner ); 604 o->torrentId = torrentId; 605 o->fileNum = fileNum; 606 o->date = tr_time( ); 577 dbgmsg( "opened '%s' writable %c", filename, writable?'y':'n' ); 578 o->is_writable = writable; 579 } 580 581 dbgmsg( "checking out '%s'", filename ); 582 o->torrent_id = torrent_id; 583 o->file_index = i; 584 o->used_at = tr_time( ); 607 585 return o->fd; 608 586 } 609 587 610 void 611 tr_fdFileClose( tr_session * session, 612 const tr_torrent * tor, 613 tr_file_index_t fileNum ) 614 { 615 struct tr_openfile * o; 588 /*** 589 **** 590 **** Sockets 591 **** 592 ***/ 593 594 int 595 tr_fdSocketCreate( tr_session * session, int domain, int type ) 596 { 597 int s = -1; 616 598 struct tr_fdInfo * gFd; 617 const struct tr_openfile * end;618 const int torrentId = tr_torrentId( tor );619 599 620 600 assert( tr_isSession( session ) ); 621 601 assert( session->fdInfo != NULL ); 622 assert( tr_isTorrent( tor ) );623 assert( fileNum < tor->info.fileCount );624 602 625 603 gFd = session->fdInfo; 626 604 627 for( o=gFd->openFiles, end=o+gFd->openFileLimit; o!=end; ++o ) 628 { 629 if( torrentId != o->torrentId ) 630 continue; 631 if( fileNum != o->fileNum ) 632 continue; 633 if( !fileIsOpen( o ) ) 634 continue; 635 636 dbgmsg( "tr_fdFileClose closing \"%s\"", o->filename ); 637 TrCloseFile( o ); 638 } 639 } 640 641 void 642 tr_fdTorrentClose( tr_session * session, int torrentId ) 643 { 644 assert( tr_isSession( session ) ); 645 646 if( session->fdInfo != NULL ) 647 { 648 struct tr_openfile * o; 649 const struct tr_openfile * end; 650 struct tr_fdInfo * gFd = session->fdInfo; 651 652 for( o=gFd->openFiles, end=o+gFd->openFileLimit; o!=end; ++o ) 653 if( fileIsOpen( o ) && ( o->torrentId == torrentId ) ) 654 TrCloseFile( o ); 655 } 656 } 657 658 /*** 659 **** 660 **** Sockets 661 **** 662 ***/ 663 664 int 665 tr_fdSocketCreate( tr_session * session, int domain, int type ) 666 { 667 int s = -1; 668 struct tr_fdInfo * gFd; 669 670 assert( tr_isSession( session ) ); 671 assert( session->fdInfo != NULL ); 672 673 gFd = session->fdInfo; 674 675 if( gFd->socketCount < gFd->socketLimit ) 676 if( ( s = socket( domain, type, 0 ) ) < 0 ) 677 { 605 if( gFd->socket_count < gFd->socket_limit ) 606 if(( s = socket( domain, type, 0 )) < 0 ) 678 607 if( sockerrno != EAFNOSUPPORT ) 679 tr_err( _( "Couldn't create socket: %s" ), 680 tr_strerror( sockerrno ) ); 681 } 608 tr_err( _( "Couldn't create socket: %s" ), tr_strerror( sockerrno ) ); 682 609 683 610 if( s > -1 ) 684 ++gFd->socket Count;685 686 assert( gFd->socket Count >= 0 );611 ++gFd->socket_count; 612 613 assert( gFd->socket_count >= 0 ); 687 614 688 615 if( s >= 0 ) … … 705 632 706 633 int 707 tr_fdSocketAccept( tr_session * session, 708 int b, 709 tr_address * addr, 710 tr_port * port ) 711 { 712 int s; 634 tr_fdSocketAccept( tr_session * s, int sockfd, tr_address * addr, tr_port * port ) 635 { 636 int fd; 713 637 unsigned int len; 714 638 struct tr_fdInfo * gFd; 715 639 struct sockaddr_storage sock; 716 640 717 assert( tr_isSession( s ession) );718 assert( s ession->fdInfo != NULL );641 assert( tr_isSession( s ) ); 642 assert( s->fdInfo != NULL ); 719 643 assert( addr ); 720 644 assert( port ); 721 645 722 gFd = s ession->fdInfo;646 gFd = s->fdInfo; 723 647 724 648 len = sizeof( struct sockaddr_storage ); 725 s = accept( b, (struct sockaddr *) &sock, &len );726 727 if( ( s >= 0 ) && gFd->socketCount > gFd->socketLimit )728 { 729 tr_netCloseSocket( s);730 s= -1;731 } 732 733 if( s>= 0 )649 fd = accept( sockfd, (struct sockaddr *) &sock, &len ); 650 651 if( ( fd >= 0 ) && gFd->socket_count > gFd->socket_limit ) 652 { 653 tr_netCloseSocket( fd ); 654 fd = -1; 655 } 656 657 if( fd >= 0 ) 734 658 { 735 659 /* "The ss_family field of the sockaddr_storage structure will always … … 755 679 *port = si->sin6_port; 756 680 } 757 ++gFd->socket Count;758 } 759 760 return s;681 ++gFd->socket_count; 682 } 683 684 return fd; 761 685 } 762 686 … … 773 697 { 774 698 tr_netCloseSocket( fd ); 775 --gFd->socket Count;776 } 777 778 assert( gFd->socket Count >= 0 );699 --gFd->socket_count; 700 } 701 702 assert( gFd->socket_count >= 0 ); 779 703 } 780 704 } … … 798 722 tr_fdClose( tr_session * session ) 799 723 { 800 struct tr_fdInfo * gFd; 801 struct tr_openfile * o; 802 const struct tr_openfile * end; 803 804 assert( tr_isSession( session ) ); 805 assert( session->fdInfo != NULL ); 806 807 gFd = session->fdInfo; 808 809 for( o=gFd->openFiles, end=o+gFd->openFileLimit; o!=end; ++o ) 810 if( fileIsOpen( o ) ) 811 TrCloseFile( o ); 812 813 tr_free( gFd->openFiles ); 814 tr_free( gFd ); 724 struct tr_fdInfo * gFd = session->fdInfo; 725 726 if( gFd != NULL ) 727 { 728 fileset_destruct( &gFd->fileset ); 729 tr_free( gFd ); 730 } 731 815 732 session->fdInfo = NULL; 816 733 } … … 819 736 **** 820 737 ***/ 738 739 int 740 tr_fdGetFileLimit( const tr_session * session ) 741 { 742 const struct tr_fileset * set = session && session->fdInfo ? &session->fdInfo->fileset : NULL; 743 return set ? set->end - set->begin : 0; 744 } 821 745 822 746 void 823 747 tr_fdSetFileLimit( tr_session * session, int limit ) 824 748 { 825 struct tr_fdInfo * gFd;826 827 749 ensureSessionFdInfoExists( session ); 828 750 829 gFd = session->fdInfo; 830 831 if( gFd->openFileLimit != limit ) 832 { 833 int i; 834 struct tr_openfile * o; 835 const struct tr_openfile * end; 836 837 /* close any files we've got open */ 838 for( o=gFd->openFiles, end=o+gFd->openFileLimit; o!=end; ++o ) 839 if( fileIsOpen( o ) ) 840 TrCloseFile( o ); 841 842 /* rebuild the openFiles array */ 843 tr_free( gFd->openFiles ); 844 gFd->openFiles = tr_new0( struct tr_openfile, limit ); 845 gFd->openFileLimit = limit; 846 for( i=0; i<gFd->openFileLimit; ++i ) 847 gFd->openFiles[i].fd = -1; 848 } 849 } 850 851 int 852 tr_fdGetFileLimit( const tr_session * session ) 853 { 854 return session && session->fdInfo ? session->fdInfo->openFileLimit : -1; 751 if( limit != tr_fdGetFileLimit( session ) ) 752 { 753 struct tr_fileset * set = get_fileset( session ); 754 fileset_destruct( set ); 755 fileset_construct( set, limit ); 756 } 855 757 } 856 758 857 759 void 858 tr_fdSetPeerLimit( tr_session * session, int socket Limit )760 tr_fdSetPeerLimit( tr_session * session, int socket_limit ) 859 761 { 860 762 struct tr_fdInfo * gFd; … … 874 776 setrlimit( RLIMIT_NOFILE, &rlim ); 875 777 tr_dbg( "setrlimit( RLIMIT_NOFILE, %d )", (int)rlim.rlim_cur ); 876 gFd->socket Limit = MIN( socketLimit, (int)rlim.rlim_cur - NOFILE_BUFFER );778 gFd->socket_limit = MIN( socket_limit, (int)rlim.rlim_cur - NOFILE_BUFFER ); 877 779 } 878 780 #else 879 gFd->socket Limit = socketLimit;880 #endif 881 gFd->public SocketLimit = socketLimit;882 883 tr_dbg( "socket limit is %d", (int)gFd->socket Limit );781 gFd->socket_limit = socket_limit; 782 #endif 783 gFd->public_socket_limit = socket_limit; 784 785 tr_dbg( "socket limit is %d", (int)gFd->socket_limit ); 884 786 } 885 787 … … 887 789 tr_fdGetPeerLimit( const tr_session * session ) 888 790 { 889 return session && session->fdInfo ? session->fdInfo->public SocketLimit : -1;890 } 791 return session && session->fdInfo ? session->fdInfo->public_socket_limit : -1; 792 } -
trunk/libtransmission/fdlimit.h
r11599 r11602 99 99 100 100 int tr_fdSocketAccept( tr_session * session, 101 int b,101 int listening_sockfd, 102 102 tr_address * addr, 103 103 tr_port * port );
Note: See TracChangeset
for help on using the changeset viewer.