Changeset 3650 for trunk/libtransmission/fdlimit.c
- Timestamp:
- Oct 30, 2007, 6:35:06 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/fdlimit.c
r3171 r3650 32 32 #include <sys/stat.h> 33 33 #include <unistd.h> 34 #include <libgen.h> /* basename, dirname */ 34 35 #include <fcntl.h> 35 36 37 #include <sys/queue.h> /* libevent needs this */ 38 #include <sys/types.h> /* libevent needs this */ 39 #include <event.h> 40 #include <evhttp.h> 36 41 #include <evutil.h> 37 42 38 43 #include "transmission.h" 44 #include "trcompat.h" 39 45 #include "net.h" 40 46 #include "platform.h" 41 47 #include "utils.h" 42 48 43 #define TR_MAX_OPEN_FILES 16 /* That is, real files, not sockets */ 44 #define TR_RESERVED_FDS 16 /* Number of sockets reserved for 45 connections to trackers */ 46 47 /*********************************************************************** 48 * Structures 49 **********************************************************************/ 50 typedef struct tr_openFile_s 51 { 52 char folder[MAX_PATH_LENGTH]; 53 char name[MAX_PATH_LENGTH]; 54 int file; 55 int write; 56 57 #define STATUS_INVALID 1 58 #define STATUS_UNUSED 2 59 #define STATUS_USED 4 60 #define STATUS_CLOSING 8 61 int status; 62 63 uint64_t date; 64 } 65 tr_openFile_t; 66 67 typedef struct tr_fd_s 68 { 69 tr_lock * lock; 70 tr_cond * cond; 71 72 int reserved; 73 74 int normal; 75 int normalMax; 76 77 tr_openFile_t open[TR_MAX_OPEN_FILES]; 78 } 79 tr_fd_t; 80 81 static tr_fd_t * gFd = NULL; 82 83 /*********************************************************************** 84 * Local prototypes 85 **********************************************************************/ 86 static int TrOpenFile( int i, const char * folder, const char * name, int write ); 87 static void TrCloseFile( int i ); 88 89 90 /*********************************************************************** 91 * tr_fdInit 92 **********************************************************************/ 93 void tr_fdInit( void ) 94 { 95 int i, j, s[4096]; 96 97 if( gFd ) 98 { 99 tr_err( "tr_fdInit was called before!" ); 100 return; 101 } 102 103 gFd = calloc( 1, sizeof( tr_fd_t ) ); 104 105 /* Init lock and cond */ 106 gFd->lock = tr_lockNew( ); 107 gFd->cond = tr_condNew( ); 108 109 /* Detect the maximum number of open files or sockets */ 110 for( i = 0; i < 4096; i++ ) 111 { 112 if( ( s[i] = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) 113 { 114 break; 115 } 116 } 117 for( j = 0; j < i; j++ ) 118 { 119 #ifdef BEOS_NETSERVER 120 closesocket( s[j] ); 121 #else 122 EVUTIL_CLOSESOCKET( s[j] ); 123 #endif 124 } 125 126 tr_dbg( "%d usable file descriptors", i ); 127 128 gFd->reserved = 0; 129 gFd->normal = 0; 130 131 gFd->normalMax = i - TR_RESERVED_FDS - 10; 132 /* To be safe, in case the UI needs to write a preferences file 133 or something */ 134 135 for( i = 0; i < TR_MAX_OPEN_FILES; i++ ) 136 { 137 gFd->open[i].status = STATUS_INVALID; 138 } 139 } 140 141 /*********************************************************************** 142 * tr_fdFileOpen 143 **********************************************************************/ 144 int tr_fdFileOpen( const char * folder, const char * name, int write ) 145 { 146 int i, winner, ret; 147 uint64_t date; 148 149 tr_lockLock( gFd->lock ); 150 151 /* Is it already open? */ 152 for( i = 0; i < TR_MAX_OPEN_FILES; i++ ) 153 { 154 if( gFd->open[i].status & STATUS_INVALID || 155 strcmp( folder, gFd->open[i].folder ) || 156 strcmp( name, gFd->open[i].name ) ) 157 { 158 continue; 159 } 160 if( gFd->open[i].status & STATUS_CLOSING ) 161 { 162 /* File is being closed by another thread, wait until 163 * it's done before we reopen it */ 164 tr_condWait( gFd->cond, gFd->lock ); 165 i = -1; 166 continue; 167 } 168 if( gFd->open[i].write < write ) 169 { 170 /* File is open read-only and needs to be closed then 171 * re-opened read-write */ 172 TrCloseFile( i ); 173 continue; 174 } 175 winner = i; 176 goto done; 177 } 178 179 /* Can we open one more file? */ 180 for( i = 0; i < TR_MAX_OPEN_FILES; i++ ) 181 { 182 if( gFd->open[i].status & STATUS_INVALID ) 183 { 184 winner = i; 185 goto open; 186 } 187 } 188 189 /* All slots taken - close the oldest currently unused file */ 190 for( ;; ) 191 { 192 date = tr_date() + 1; 193 winner = -1; 194 195 for( i = 0; i < TR_MAX_OPEN_FILES; i++ ) 196 { 197 if( !( gFd->open[i].status & STATUS_UNUSED ) ) 198 { 199 continue; 200 } 201 if( gFd->open[i].date < date ) 202 { 203 winner = i; 204 date = gFd->open[i].date; 205 } 206 } 207 208 if( winner >= 0 ) 209 { 210 TrCloseFile( winner ); 211 goto open; 212 } 213 214 /* All used! Wait a bit and try again */ 215 tr_condWait( gFd->cond, gFd->lock ); 216 } 217 218 open: 219 if( ( ret = TrOpenFile( winner, folder, name, write ) ) ) 220 { 221 tr_lockUnlock( gFd->lock ); 222 return ret; 223 } 224 snprintf( gFd->open[winner].folder, MAX_PATH_LENGTH, "%s", folder ); 225 snprintf( gFd->open[winner].name, MAX_PATH_LENGTH, "%s", name ); 226 gFd->open[winner].write = write; 227 228 done: 229 gFd->open[winner].status = STATUS_USED; 230 gFd->open[winner].date = tr_date(); 231 tr_lockUnlock( gFd->lock ); 232 233 return gFd->open[winner].file; 234 } 235 236 /*********************************************************************** 237 * tr_fdFileRelease 238 **********************************************************************/ 239 void tr_fdFileRelease( int file ) 240 { 241 int i; 242 tr_lockLock( gFd->lock ); 243 244 for( i = 0; i < TR_MAX_OPEN_FILES; i++ ) 245 { 246 if( gFd->open[i].file == file ) 247 { 248 gFd->open[i].status = STATUS_UNUSED; 249 break; 250 } 251 } 252 253 tr_condSignal( gFd->cond ); 254 tr_lockUnlock( gFd->lock ); 255 } 256 257 /*********************************************************************** 258 * tr_fdFileClose 259 **********************************************************************/ 260 void tr_fdFileClose( const char * folder, const char * name ) 261 { 262 int i; 263 264 tr_lockLock( gFd->lock ); 265 266 for( i = 0; i < TR_MAX_OPEN_FILES; i++ ) 267 { 268 if( gFd->open[i].status & STATUS_INVALID ) 269 { 270 continue; 271 } 272 if( !strcmp( folder, gFd->open[i].folder ) && 273 !strcmp( name, gFd->open[i].name ) ) 274 { 275 TrCloseFile( i ); 276 } 277 } 278 279 tr_lockUnlock( gFd->lock ); 280 } 281 282 283 /*********************************************************************** 284 * Sockets 285 **********************************************************************/ 286 typedef struct 287 { 288 int socket; 289 int priority; 290 } 291 tr_socket_t; 292 293 /* Remember the priority of every socket we open, so that we can keep 294 * track of how many reserved file descriptors we are using */ 295 static tr_socket_t * gSockets = NULL; 296 static int gSocketsSize = 0; 297 static int gSocketsCount = 0; 298 static void SocketSetPriority( int s, int priority ) 299 { 300 if( gSocketsSize < 1 ) 301 { 302 gSocketsSize = 256; 303 gSockets = malloc( gSocketsSize * sizeof( tr_socket_t ) ); 304 } 305 if( gSocketsSize <= gSocketsCount ) 306 { 307 gSocketsSize *= 2; 308 gSockets = realloc( gSockets, gSocketsSize * sizeof( tr_socket_t ) ); 309 } 310 gSockets[gSocketsCount].socket = s; 311 gSockets[gSocketsCount].priority = priority; 312 gSocketsCount++; 313 } 314 static int SocketGetPriority( int s ) 315 { 316 int i, ret; 317 for( i = 0; i < gSocketsCount; i++ ) 318 if( gSockets[i].socket == s ) 319 break; 320 if( i >= gSocketsCount ) 321 { 322 tr_err( "could not find that socket (%d)!", s ); 323 return -1; 324 } 325 ret = gSockets[i].priority; 326 gSocketsCount--; 327 memmove( &gSockets[i], &gSockets[i+1], 328 ( gSocketsCount - i ) * sizeof( tr_socket_t ) ); 329 return ret; 330 } 331 332 /*********************************************************************** 333 * tr_fdSocketCreate 334 **********************************************************************/ 335 int tr_fdSocketCreate( int type, int priority ) 336 { 337 int s = -1; 338 339 tr_lockLock( gFd->lock ); 340 341 if( priority && gFd->reserved >= TR_RESERVED_FDS ) 342 priority = FALSE; 343 344 if( priority || ( gFd->normal < gFd->normalMax ) ) 345 if( ( s = socket( AF_INET, type, 0 ) ) < 0 ) 346 tr_err( "Couldn't create socket (%s)", strerror( sockerrno ) ); 347 348 if( s > -1 ) 349 { 350 SocketSetPriority( s, priority ); 351 if( priority ) 352 gFd->reserved++; 353 else 354 gFd->normal++; 355 } 356 tr_lockUnlock( gFd->lock ); 357 358 return s; 359 } 360 361 int 362 tr_fdSocketAccept( int b, struct in_addr * addr, tr_port_t * port ) 363 { 364 int s = -1; 365 unsigned len; 366 struct sockaddr_in sock; 367 368 assert( addr != NULL ); 369 assert( port != NULL ); 370 371 tr_lockLock( gFd->lock ); 372 if( gFd->normal < gFd->normalMax ) 373 { 374 len = sizeof( sock ); 375 s = accept( b, (struct sockaddr *) &sock, &len ); 376 } 377 if( s > -1 ) 378 { 379 SocketSetPriority( s, 0 ); 380 *addr = sock.sin_addr; 381 *port = sock.sin_port; 382 gFd->normal++; 383 } 384 tr_lockUnlock( gFd->lock ); 385 386 return s; 387 } 388 389 /*********************************************************************** 390 * tr_fdSocketClose 391 **********************************************************************/ 392 void tr_fdSocketClose( int s ) 393 { 394 if( s >= 0 ) 395 { 396 tr_lockLock( gFd->lock ); 397 #ifdef BEOS_NETSERVER 398 closesocket( s ); 399 #else 400 EVUTIL_CLOSESOCKET( s ); 401 #endif 402 if( SocketGetPriority( s ) ) 403 gFd->reserved--; 404 else 405 gFd->normal--; 406 tr_lockUnlock( gFd->lock ); 407 } 408 } 409 410 /*********************************************************************** 411 * tr_fdClose 412 **********************************************************************/ 413 void tr_fdClose( void ) 414 { 415 tr_lockFree( gFd->lock ); 416 tr_condFree( gFd->cond ); 417 free( gFd ); 418 } 419 420 421 /*********************************************************************** 422 * Local functions 423 **********************************************************************/ 424 425 /*********************************************************************** 426 * CheckFolder 427 *********************************************************************** 428 * 429 **********************************************************************/ 430 static int TrOpenFile( int i, const char * folder, const char * name, int write ) 431 { 432 tr_openFile_t * file = &gFd->open[i]; 49 /** 50 *** 51 **/ 52 53 static void 54 myDebug( const char * file, int line, const char * fmt, ... ) 55 { 56 FILE * fp = tr_getLog( ); 57 if( fp != NULL ) 58 { 59 va_list args; 60 char s[64]; 61 struct evbuffer * buf = evbuffer_new( ); 62 char * myfile = tr_strdup( file ); 63 64 evbuffer_add_printf( buf, "[%s] ", tr_getLogTimeStr( s, sizeof(s) ) ); 65 va_start( args, fmt ); 66 evbuffer_add_vprintf( buf, fmt, args ); 67 va_end( args ); 68 evbuffer_add_printf( buf, " (%s:%d)\n", basename(myfile), line ); 69 fwrite( EVBUFFER_DATA(buf), 1, EVBUFFER_LENGTH(buf), fp ); 70 71 tr_free( myfile ); 72 evbuffer_free( buf ); 73 } 74 } 75 76 #define dbgmsg(fmt...) myDebug(__FILE__, __LINE__, ##fmt ) 77 78 /** 79 *** 80 **/ 81 82 enum 83 { 84 TR_MAX_OPEN_FILES = 16, /* That is, real files, not sockets */ 85 86 TR_RESERVED_FDS = 16 /* sockets reserved for tracker connections */ 87 }; 88 89 struct tr_openfile 90 { 91 unsigned int isCheckedOut : 1; 92 unsigned int isWritable : 1; 93 char filename[MAX_PATH_LENGTH]; 94 int file; 95 uint64_t date; 96 }; 97 98 struct tr_fd_s 99 { 100 int reserved; 101 int normal; 102 int normalMax; 103 tr_lock * lock; 104 tr_cond * cond; 105 struct tr_openfile open[TR_MAX_OPEN_FILES]; 106 }; 107 108 static struct tr_fd_s * gFd = NULL; 109 110 /*** 111 **** 112 **** Local Files 113 **** 114 ***/ 115 116 static int 117 TrOpenFile( int i, const char * filename, int write ) 118 { 119 struct tr_openfile * file = &gFd->open[i]; 433 120 struct stat sb; 434 char path[MAX_PATH_LENGTH]; 435 int ret; 121 char * dir; 436 122 int flags; 437 123 438 tr_dbg( "Opening %s in %s (%d)", name, folder, write ); 124 tr_dbg( "Opening '%s' (%d)", filename, write ); 125 126 /* create subfolders, if any */ 127 dir = dirname( tr_strdup( filename ) ); 128 if( write && tr_mkdirp( dir, 0700 ) ) { 129 free( dir ); 130 return tr_ioErrorFromErrno( ); 131 } 439 132 440 133 /* Make sure the parent folder exists */ 441 if( stat( folder, &sb ) || !S_ISDIR( sb.st_mode ) )442 {134 if( stat( dir, &sb ) || !S_ISDIR( sb.st_mode ) ) { 135 free( dir ); 443 136 return TR_ERROR_IO_PARENT; 444 137 } 445 138 446 snprintf( path, sizeof(path), "%s" TR_PATH_DELIMITER_STR "%s",447 folder,448 name );449 450 /* Create subfolders, if any */451 if( write )452 {453 char * p = path + strlen( folder ) + 1;454 char * s;455 456 while( ( s = strchr( p, TR_PATH_DELIMITER ) ) )457 {458 *s = '\0';459 if( stat( path, &sb ) )460 {461 if( tr_mkdir( path, 0777 ) )462 {463 ret = tr_ioErrorFromErrno();464 tr_err( "Couldn't create folder '%s'", path );465 return ret;466 }467 }468 else469 {470 if( !S_ISDIR( sb.st_mode ) )471 {472 tr_err( "Is not a folder: '%s'", path );473 return TR_ERROR_IO_OTHER;474 }475 }476 *s = TR_PATH_DELIMITER;477 p = s + 1;478 }479 }480 481 /* Now try to really open the file */482 139 errno = 0; 483 140 flags = 0; … … 486 143 #endif 487 144 flags |= write ? (O_RDWR | O_CREAT) : O_RDONLY; 488 file->file = open( path, flags, 0666 ); 145 file->file = open( filename, flags, 0666 ); 146 free( dir ); 489 147 if( write && ( file->file < 0 ) ) 490 148 { 491 ret = tr_ioErrorFromErrno();149 const int ret = tr_ioErrorFromErrno(); 492 150 if( errno ) 493 tr_err( "Couldn't open %s in %s: %s", name, folder, strerror(errno) );151 tr_err( "Couldn't open '%s': %s", filename, strerror(errno) ); 494 152 else 495 tr_err( "Couldn't open %s in %s", name, folder);153 tr_err( "Couldn't open '%s'", filename ); 496 154 return ret; 497 155 } … … 500 158 } 501 159 502 /*********************************************************************** 503 * TrCloseFile 504 *********************************************************************** 505 * We first mark it as closing then release the lock while doing so, 506 * because close() may take same time and we don't want to block other 507 * threads. 508 **********************************************************************/ 509 static void TrCloseFile( int i ) 510 { 511 tr_openFile_t * file = &gFd->open[i]; 512 513 /* If it's already being closed by another thread, just wait till 514 * it is done */ 515 while( file->status & STATUS_CLOSING ) 516 { 160 static int 161 fileIsOpen( const struct tr_openfile * o ) 162 { 163 return o->file >= 0; 164 } 165 166 static void 167 TrCloseFile( int i ) 168 { 169 struct tr_openfile * file = &gFd->open[i]; 170 171 assert( i >= 0 ); 172 assert( i < TR_MAX_OPEN_FILES ); 173 assert( fileIsOpen( file ) ); 174 175 dbgmsg( "closing %s in slot %d writable %c", 176 file->filename, i, file->isWritable?'y':'n' ); 177 close( file->file ); 178 file->file = -1; 179 file->isCheckedOut = 0; 180 tr_condSignal( gFd->cond ); 181 } 182 183 static int 184 fileIsCheckedOut( const struct tr_openfile * o ) 185 { 186 return fileIsOpen(o) && o->isCheckedOut; 187 } 188 189 int 190 tr_fdFileOpen( const char * filename, int write ) 191 { 192 int i, winner; 193 struct tr_openfile * o; 194 195 dbgmsg( "looking for file '%s', writable %c", filename, write?'y':'n' ); 196 197 tr_lockLock( gFd->lock ); 198 199 /* Is it already open? */ 200 for( i=0; i<TR_MAX_OPEN_FILES; ++i ) 201 { 202 o = &gFd->open[i]; 203 204 if( !fileIsOpen( o ) ) 205 continue; 206 207 if( strcmp( filename, o->filename ) ) 208 continue; 209 210 if( fileIsCheckedOut( o ) ) { 211 dbgmsg( "found it! it's open, but checked out. waiting..." ); 212 tr_condWait( gFd->cond, gFd->lock ); 213 i = -1; 214 continue; 215 } 216 217 if( write && !o->isWritable ) { 218 dbgmsg( "found it! it's open and available, but isn't writable. closing..." ); 219 TrCloseFile( i ); 220 continue; 221 } 222 223 dbgmsg( "found it! it's ready for use!" ); 224 winner = i; 225 goto done; 226 } 227 228 229 dbgmsg( "it's not already open. looking for an open slot or an old file." ); 230 for( ;; ) 231 { 232 uint64_t date = tr_date() + 1; 233 winner = -1; 234 235 for( i=0; i<TR_MAX_OPEN_FILES; ++i ) 236 { 237 o = &gFd->open[i]; 238 239 if( !fileIsOpen( o ) ) { 240 winner = i; 241 dbgmsg( "found an empty slot in %d", winner ); 242 goto done; 243 } 244 245 if( o->date < date ) { 246 winner = i; 247 date = o->date; 248 } 249 } 250 251 if( winner >= 0 ) { 252 dbgmsg( "closing file '%s', slot #%d", gFd->open[winner].filename, winner ); 253 TrCloseFile( winner ); 254 goto done; 255 } 256 257 /* All used! Wait a bit and try again */ 258 dbgmsg( "everything's full! waiting for someone else to finish something" ); 517 259 tr_condWait( gFd->cond, gFd->lock ); 518 260 } 519 if( file->status & STATUS_INVALID ) 520 { 521 return; 522 } 523 524 /* Nobody is closing it already, so let's do it */ 525 if( file->status & STATUS_USED ) 526 { 527 tr_err( "TrCloseFile: closing a file that's being used!" ); 528 } 529 tr_dbg( "Closing %s in %s (%d)", file->name, file->folder, file->write ); 530 file->status = STATUS_CLOSING; 261 262 done: 263 264 o = &gFd->open[winner]; 265 if( !fileIsOpen( o ) ) 266 { 267 const int ret = TrOpenFile( winner, filename, write ); 268 if( ret ) { 269 tr_lockUnlock( gFd->lock ); 270 return ret; 271 } 272 273 dbgmsg( "opened '%s' in slot %d, write %c", filename, winner, write?'y':'n' ); 274 strlcpy( gFd->open[winner].filename, filename, MAX_PATH_LENGTH ); 275 gFd->open[winner].isWritable = write; 276 } 277 278 dbgmsg( "checking out '%s' in slot %d", filename, winner ); 279 gFd->open[winner].isCheckedOut = 1; 280 gFd->open[winner].date = tr_date(); 531 281 tr_lockUnlock( gFd->lock ); 532 close( file->file ); 282 return gFd->open[winner].file; 283 } 284 285 void 286 tr_fdFileRelease( int file ) 287 { 288 int i; 533 289 tr_lockLock( gFd->lock ); 534 file->status = STATUS_INVALID; 290 291 for( i=0; i<TR_MAX_OPEN_FILES; ++i ) { 292 struct tr_openfile * o = &gFd->open[i]; 293 if( o->file == file ) { 294 dbgmsg( "releasing file '%s' in slot #%d", o->filename, i ); 295 if( o->isWritable ) 296 fsync( o->file ); /* fflush */ 297 o->isCheckedOut = 0; 298 break; 299 } 300 } 301 535 302 tr_condSignal( gFd->cond ); 536 } 537 303 tr_lockUnlock( gFd->lock ); 304 } 305 306 /*** 307 **** 308 **** Sockets 309 **** 310 ***/ 311 312 struct tr_socket 313 { 314 int socket; 315 int priority; 316 }; 317 318 /* Remember the priority of every socket we open, so that we can keep 319 * track of how many reserved file descriptors we are using */ 320 static struct tr_socket * gSockets = NULL; 321 static int gSocketsSize = 0; 322 static int gSocketsCount = 0; 323 324 static void 325 SocketSetPriority( int s, int priority ) 326 { 327 if( gSocketsSize <= gSocketsCount ) { 328 gSocketsSize += 64; 329 gSockets = tr_renew( struct tr_socket, gSockets, gSocketsSize ); 330 } 331 332 gSockets[gSocketsCount].socket = s; 333 gSockets[gSocketsCount].priority = priority; 334 ++gSocketsCount; 335 } 336 337 static int 338 SocketGetPriority( int s ) 339 { 340 int i, ret; 341 342 for( i=0; i<gSocketsCount; ++i ) 343 if( gSockets[i].socket == s ) 344 break; 345 346 if( i >= gSocketsCount ) { 347 tr_err( "could not find that socket (%d)!", s ); 348 return -1; 349 } 350 351 ret = gSockets[i].priority; 352 gSocketsCount--; 353 memmove( &gSockets[i], &gSockets[i+1], 354 ( gSocketsCount - i ) * sizeof( struct tr_socket ) ); 355 return ret; 356 } 357 358 int 359 tr_fdSocketCreate( int type, int priority ) 360 { 361 int s = -1; 362 363 tr_lockLock( gFd->lock ); 364 365 if( priority && gFd->reserved >= TR_RESERVED_FDS ) 366 priority = FALSE; 367 368 if( priority || ( gFd->normal < gFd->normalMax ) ) 369 if( ( s = socket( AF_INET, type, 0 ) ) < 0 ) 370 tr_err( "Couldn't create socket (%s)", strerror( sockerrno ) ); 371 372 if( s > -1 ) 373 { 374 SocketSetPriority( s, priority ); 375 if( priority ) 376 gFd->reserved++; 377 else 378 gFd->normal++; 379 } 380 tr_lockUnlock( gFd->lock ); 381 382 return s; 383 } 384 385 int 386 tr_fdSocketAccept( int b, struct in_addr * addr, tr_port_t * port ) 387 { 388 int s = -1; 389 unsigned len; 390 struct sockaddr_in sock; 391 392 assert( addr != NULL ); 393 assert( port != NULL ); 394 395 tr_lockLock( gFd->lock ); 396 if( gFd->normal < gFd->normalMax ) 397 { 398 len = sizeof( sock ); 399 s = accept( b, (struct sockaddr *) &sock, &len ); 400 } 401 if( s > -1 ) 402 { 403 SocketSetPriority( s, 0 ); 404 *addr = sock.sin_addr; 405 *port = sock.sin_port; 406 gFd->normal++; 407 } 408 tr_lockUnlock( gFd->lock ); 409 410 return s; 411 } 412 413 static void 414 socketClose( int fd ) 415 { 416 #ifdef BEOS_NETSERVER 417 closesocket( fd ); 418 #else 419 EVUTIL_CLOSESOCKET( fd ); 420 #endif 421 } 422 423 void 424 tr_fdSocketClose( int s ) 425 { 426 if( s >= 0 ) 427 { 428 tr_lockLock( gFd->lock ); 429 socketClose( s ); 430 if( SocketGetPriority( s ) ) 431 gFd->reserved--; 432 else 433 gFd->normal--; 434 tr_lockUnlock( gFd->lock ); 435 } 436 } 437 438 /*** 439 **** 440 **** Startup / Shutdown 441 **** 442 ***/ 443 444 void 445 tr_fdInit( void ) 446 { 447 int i, j, s[4096]; 448 449 assert( gFd == NULL ); 450 451 gFd = tr_new0( struct tr_fd_s, 1 ); 452 gFd->lock = tr_lockNew( ); 453 gFd->cond = tr_condNew( ); 454 455 /* count the max number of sockets we can use */ 456 for( i=0; i<4096; ++i ) 457 if( ( s[i] = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) 458 break; 459 for( j=0; j<i; ++j ) 460 socketClose( s[j] ); 461 tr_dbg( "%d usable file descriptors", i ); 462 463 /* set some fds aside for the UI or daemon to use */ 464 gFd->normalMax = i - TR_RESERVED_FDS - 10; 465 466 for( i=0; i<TR_MAX_OPEN_FILES; ++i ) 467 gFd->open[i].file = -1; 468 469 } 470 471 void 472 tr_fdClose( void ) 473 { 474 int i = 0; 475 476 for( i=0; i<TR_MAX_OPEN_FILES; ++i ) 477 if( fileIsOpen( &gFd->open[i] ) ) 478 TrCloseFile( i ); 479 480 tr_lockFree( gFd->lock ); 481 tr_condFree( gFd->cond ); 482 483 tr_free( gSockets ); 484 tr_free( gFd ); 485 }
Note: See TracChangeset
for help on using the changeset viewer.