Changeset 3650


Ignore:
Timestamp:
Oct 30, 2007, 6:35:06 PM (13 years ago)
Author:
charles
Message:

part 1 of the data corruption fix: plug the leaky abstraction in fdlimit

Location:
trunk/libtransmission
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/basename.c

    r2683 r3650  
    2626
    2727char *
    28 basename(const char *path)
     28basename( char * path )
    2929{
    3030        static char bname[MAXPATHLEN];
  • trunk/libtransmission/dirname.c

    r2683 r3650  
    2626
    2727char *
    28 dirname(const char *path)
     28dirname( char *path )
    2929{
    3030        static char dname[MAXPATHLEN];
  • trunk/libtransmission/fdlimit.c

    r3171 r3650  
    3232#include <sys/stat.h>
    3333#include <unistd.h>
     34#include <libgen.h> /* basename, dirname */
    3435#include <fcntl.h>
    3536
     37#include <sys/queue.h> /* libevent needs this */
     38#include <sys/types.h> /* libevent needs this */
     39#include <event.h>
     40#include <evhttp.h>
    3641#include <evutil.h>
    3742
    3843#include "transmission.h"
     44#include "trcompat.h"
    3945#include "net.h"
    4046#include "platform.h"
    4147#include "utils.h"
    4248
    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
     53static void
     54myDebug( 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
     82enum
     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
     89struct 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
     98struct 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
     108static struct tr_fd_s * gFd = NULL;
     109
     110/***
     111****
     112****  Local Files
     113****
     114***/
     115
     116static int
     117TrOpenFile( int i, const char * filename, int write )
     118{
     119    struct tr_openfile * file = &gFd->open[i];
    433120    struct stat sb;
    434     char path[MAX_PATH_LENGTH];
    435     int ret;
     121    char * dir;
    436122    int flags;
    437123
    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    }
    439132
    440133    /* 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 );
    443136        return TR_ERROR_IO_PARENT;
    444137    }
    445138
    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             else
    469             {
    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 */
    482139    errno = 0;
    483140    flags = 0;
     
    486143#endif
    487144    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 );
    489147    if( write && ( file->file < 0 ) )
    490148    {
    491         ret = tr_ioErrorFromErrno();
     149        const int ret = tr_ioErrorFromErrno();
    492150        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) );
    494152        else
    495             tr_err( "Couldn't open %s in %s", name, folder );
     153            tr_err( "Couldn't open '%s'", filename );
    496154        return ret;
    497155    }
     
    500158}
    501159
    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     {
     160static int
     161fileIsOpen( const struct tr_openfile * o )
     162{
     163    return o->file >= 0;
     164}
     165
     166static void
     167TrCloseFile( 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
     183static int
     184fileIsCheckedOut( const struct tr_openfile * o )
     185{
     186    return fileIsOpen(o) && o->isCheckedOut;
     187}
     188
     189int
     190tr_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" );
    517259        tr_condWait( gFd->cond, gFd->lock );
    518260    }
    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
     262done:
     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();
    531281    tr_lockUnlock( gFd->lock );
    532     close( file->file );
     282    return gFd->open[winner].file;
     283}
     284
     285void
     286tr_fdFileRelease( int file )
     287{
     288    int i;
    533289    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   
    535302    tr_condSignal( gFd->cond );
    536 }
    537 
     303    tr_lockUnlock( gFd->lock );
     304}
     305
     306/***
     307****
     308****  Sockets
     309****
     310***/
     311
     312struct 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 */
     320static struct tr_socket * gSockets = NULL;
     321static int gSocketsSize = 0;
     322static int gSocketsCount = 0;
     323
     324static void
     325SocketSetPriority( 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
     337static int
     338SocketGetPriority( 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
     358int
     359tr_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
     385int
     386tr_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
     413static void
     414socketClose( int fd )
     415{
     416#ifdef BEOS_NETSERVER
     417    closesocket( fd );
     418#else
     419    EVUTIL_CLOSESOCKET( fd );
     420#endif
     421}
     422
     423void
     424tr_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
     444void
     445tr_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
     471void
     472tr_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}
  • trunk/libtransmission/fdlimit.h

    r2573 r3650  
    3232void tr_fdInit( void );
    3333
     34void tr_fdClose( void );
     35
    3436/***********************************************************************
    3537 * tr_fdFileOpen
     
    4244 * one of the TR_ERROR_IO_*.
    4345 **********************************************************************/
    44 int tr_fdFileOpen( const char * folder, const char * name, int write );
     46int tr_fdFileOpen( const char * filename, int write );
    4547
    4648/***********************************************************************
     
    5153 **********************************************************************/
    5254void tr_fdFileRelease( int file );
    53 
    54 /***********************************************************************
    55  * tr_fdFileClose
    56  ***********************************************************************
    57  * If the file 'name' in directory 'folder' was open, closes it,
    58  * flushing data on disk.
    59  **********************************************************************/
    60 void tr_fdFileClose( const char * folder, const char * name );
    6155
    6256/***********************************************************************
  • trunk/libtransmission/inout.c

    r3606 r3650  
    7373    else if ((ioMode==TR_IO_READ) && stat( path, &sb ) ) /* fast check to make sure file exists */
    7474        ret = tr_ioErrorFromErrno ();
    75     else if ((fd = tr_fdFileOpen ( tor->destination, file->name, ioMode==TR_IO_WRITE )) < 0)
     75    else if ((fd = tr_fdFileOpen ( path, ioMode==TR_IO_WRITE )) < 0)
    7676        ret = fd;
    7777    else if( lseek( fd, (off_t)fileOffset, SEEK_SET ) == ((off_t)-1) )
     
    118118static int
    119119ensureMinimumFileSize ( const tr_torrent  * tor,
    120                         int                   fileIndex,
    121                         uint64_t              minSize ) /* in bytes */
     120                        int                 fileIndex,
     121                        uint64_t            minSize ) /* in bytes */
    122122{
    123123    int fd;
     
    125125    struct stat sb;
    126126    const tr_file * file = &tor->info.files[fileIndex];
     127    char path[MAX_PATH_LENGTH];
    127128
    128129    assert ( 0<=fileIndex && fileIndex<tor->info.fileCount );
    129130    assert ( minSize <= file->length );
    130131
    131     fd = tr_fdFileOpen( tor->destination, file->name, TRUE );
     132    tr_buildPath ( path, sizeof(path), tor->destination, file->name, NULL );
     133
     134    fd = tr_fdFileOpen( path, TRUE );
    132135    if( fd < 0 ) /* bad fd */
    133136        ret = fd;
     
    245248**/
    246249
    247 void
    248 tr_ioClose( const tr_torrent * tor )
    249 {
    250     int i;
    251     const tr_info * info = &tor->info;
    252 
    253     for( i=0; i<info->fileCount; ++i )
    254         tr_fdFileClose( tor->destination, info->files[i].name );
    255 }
    256 
    257250int
    258251tr_ioHash( tr_torrent * tor, int pieceIndex )
  • trunk/libtransmission/inout.h

    r3284 r3650  
    4444int tr_ioHash ( tr_torrent*, int piece );
    4545
    46 /* close all the files associated with this torrent*/
    47 void tr_ioClose( const tr_torrent * );
    48 
    4946/**
    5047***
  • trunk/libtransmission/torrent.c

    r3619 r3650  
    10611061    tr_peerMgrStopTorrent( tor->handle->peerMgr, tor->info.hash );
    10621062    tr_trackerStop( tor->tracker );
    1063     tr_ioClose( tor );
    10641063}
    10651064
     
    11411140            tr_trackerCompleted( tor->tracker ); /* tell the tracker */
    11421141        }
    1143         tr_ioClose( tor );
    11441142        saveFastResumeNow( tor );
    11451143    }
  • trunk/libtransmission/trcompat.h

    r2551 r3650  
    4747#endif
    4848#ifndef HAVE_DIRNAME
    49     char* dirname(const char *path);
     49    char* dirname( char *path);
    5050#endif
    5151#ifndef HAVE_BASENAME
    52     char* basename(const char *path);
     52    char* basename( char *path );
    5353#endif
    5454
  • trunk/libtransmission/utils.c

    r3473 r3650  
    425425
    426426int
    427 tr_mkdirp( char * path, int permissions )
    428 {
    429     char      * p, * pp;
     427tr_mkdirp( const char * path_in, int permissions )
     428{
     429    char * path = tr_strdup( path_in );
     430    char * p, * pp;
    430431    struct stat sb;
    431432    int done;
    432433
     434    /* walk past the root */
    433435    p = path;
    434     while( '/' == *p )
    435       p++;
     436    while( *p == TR_PATH_DELIMITER )
     437        ++p;
     438
    436439    pp = p;
    437440    done = 0;
    438     while( ( p = strchr( pp, '/' ) ) || ( p = strchr( pp, '\0' ) ) )
    439     {
    440         if( '\0' == *p)
    441         {
     441    while( ( p = strchr( pp, TR_PATH_DELIMITER ) ) || ( p = strchr( pp, '\0' ) ) )
     442    {
     443        if( !*p )
    442444            done = 1;
    443         }
    444445        else
    445         {
    446446            *p = '\0';
    447         }
     447
    448448        if( stat( path, &sb ) )
    449449        {
     
    453453                tr_err( "Could not create directory %s (%s)", path,
    454454                        strerror( errno ) );
    455                 *p = '/';
     455                tr_free( path );
    456456                return 1;
    457457            }
     
    461461            /* Node exists but isn't a folder */
    462462            tr_err( "Remove %s, it's in the way.", path );
    463             *p = '/';
     463            tr_free( path );
    464464            return 1;
    465465        }
     466
    466467        if( done )
    467         {
    468468            break;
    469         }
    470         *p = '/';
     469
     470        *p = TR_PATH_DELIMITER;
    471471        p++;
    472472        pp = p;
    473473    }
    474474
     475    tr_free( path );
    475476    return 0;
    476477}
  • trunk/libtransmission/utils.h

    r3473 r3650  
    5151 * Note that the string passed in must be writable!
    5252 **********************************************************************/
    53 int tr_mkdirp( char * path, int permissions );
     53int tr_mkdirp( const char * path, int permissions );
    5454
    5555int tr_mkdir( const char * path, int permissions );
Note: See TracChangeset for help on using the changeset viewer.