source: trunk/libtransmission/platform.c @ 4092

Last change on this file since 4092 was 4092, checked in by charles, 13 years ago

Use libnatpmp for port mapping. rewrite the upnp/natpmp manager.

NOTE: this will break the xpjets build until SoftwareElves? or a volunteer patches the xcode project file to make a libnatpmp library just like was done for libminiupnp.

  • Property svn:keywords set to Date Rev Author Id
File size: 9.9 KB
Line 
1/******************************************************************************
2 * $Id: platform.c 4092 2007-12-08 19:34:15Z charles $
3 *
4 * Copyright (c) 2005 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#ifdef __BEOS__
26  #include <signal.h> 
27  #include <fs_info.h>
28  #include <FindDirectory.h>
29  #include <kernel/OS.h>
30  #define BEOS_MAX_THREADS 256
31#elif defined(WIN32)
32  #include <windows.h>
33  #include <shlobj.h> /* for CSIDL_APPDATA, CSIDL_PROFILE */
34#else
35  #define _XOPEN_SOURCE 500 /* needed for recursive locks. */
36  #ifndef __USE_UNIX98
37  #define __USE_UNIX98 /* some older Linuxes need it spelt out for them */
38  #endif
39  #include <pthread.h>
40#endif
41
42#include <assert.h>
43#include <errno.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47
48#include <sys/types.h>
49#include <dirent.h>
50#include <fcntl.h>
51#include <unistd.h> /* getuid getpid close */
52
53#include "transmission.h"
54#include "list.h"
55#include "net.h"
56#include "platform.h"
57#include "utils.h"
58
59/***
60****  THREADS
61***/
62
63#ifdef __BEOS__
64typedef thread_id tr_thread_id;
65#elif defined(WIN32)
66typedef DWORD tr_thread_id;
67#else
68typedef pthread_t tr_thread_id;
69#endif
70
71static tr_thread_id
72tr_getCurrentThread( void )
73{
74#ifdef __BEOS__
75    return find_thread( NULL );
76#elif defined(WIN32)
77    return GetCurrentThreadId();
78#else
79    return pthread_self( );
80#endif
81}
82
83static int
84tr_areThreadsEqual( tr_thread_id a, tr_thread_id b )
85{
86#ifdef __BEOS__
87    return a == b;
88#elif defined(WIN32)
89    return a == b;
90#else
91    return pthread_equal( a, b );
92#endif
93}
94
95struct tr_thread
96{
97    void          (* func ) ( void * );
98    void           * arg;
99    const char     * name;
100
101#ifdef __BEOS__
102    thread_id        thread;
103#elif defined(WIN32)
104    HANDLE           thread;
105    unsigned int     thread_id;
106#else
107    pthread_t        thread;
108#endif
109
110};
111
112int
113tr_amInThread ( const tr_thread * t )
114{
115    return tr_areThreadsEqual( tr_getCurrentThread(), t->thread );
116}
117
118#ifdef WIN32
119#define ThreadFuncReturnType unsigned WINAPI
120#else
121#define ThreadFuncReturnType void
122#endif
123
124static ThreadFuncReturnType
125ThreadFunc( void * _t )
126{
127    tr_thread * t = _t;
128    const char * name = t->name;
129
130#ifdef __BEOS__
131    /* This is required because on BeOS, SIGINT is sent to each thread,
132       which kills them not nicely */
133    signal( SIGINT, SIG_IGN );
134#endif
135
136    tr_dbg( "Thread '%s' started", name );
137    t->func( t->arg );
138    tr_dbg( "Thread '%s' exited", name );
139
140#ifdef WIN32
141    _endthreadex( 0 );
142    return 0;
143#endif
144}
145
146tr_thread *
147tr_threadNew( void (*func)(void *),
148              void * arg,
149              const char * name )
150{
151    tr_thread * t = tr_new0( tr_thread, 1 );
152    t->func = func;
153    t->arg  = arg;
154    t->name = name;
155
156#ifdef __BEOS__
157    t->thread = spawn_thread( (void*)ThreadFunc, name, B_NORMAL_PRIORITY, t );
158    resume_thread( t->thread );
159#elif defined(WIN32)
160    t->thread = (HANDLE) _beginthreadex( NULL, 0, &ThreadFunc, t, 0, &t->thread_id );
161#else
162    pthread_create( &t->thread, NULL, (void * (*) (void *)) ThreadFunc, t );
163#endif
164
165    return t;
166}
167   
168void
169tr_threadJoin( tr_thread * t )
170{
171    if( t != NULL )
172    {
173#ifdef __BEOS__
174        long exit;
175        wait_for_thread( t->thread, &exit );
176#elif defined(WIN32)
177        WaitForSingleObject( t->thread, INFINITE );
178        CloseHandle( t->thread );
179#else
180        pthread_join( t->thread, NULL );
181#endif
182
183        tr_dbg( "Thread '%s' joined", t->name );
184        t->name = NULL;
185        t->func = NULL;
186        tr_free( t );
187    }
188}
189
190/***
191****  LOCKS
192***/
193
194struct tr_lock
195{
196    int depth;
197#ifdef __BEOS__
198    sem_id lock;
199    thread_id lockThread;
200#elif defined(WIN32)
201    CRITICAL_SECTION lock;
202    DWORD lockThread;
203#else
204    pthread_mutex_t lock;
205    pthread_t lockThread;
206#endif
207};
208
209tr_lock*
210tr_lockNew( void )
211{
212    tr_lock * l = tr_new0( tr_lock, 1 );
213
214#ifdef __BEOS__
215    l->lock = create_sem( 1, "" );
216#elif defined(WIN32)
217    InitializeCriticalSection( &l->lock ); /* critical sections support recursion */
218#else
219    pthread_mutexattr_t attr;
220    pthread_mutexattr_init( &attr );
221    pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
222    pthread_mutex_init( &l->lock, &attr );
223#endif
224
225    return l;
226}
227
228void
229tr_lockFree( tr_lock * l )
230{
231#ifdef __BEOS__
232    delete_sem( l->lock );
233#elif defined(WIN32)
234    DeleteCriticalSection( &l->lock );
235#else
236    pthread_mutex_destroy( &l->lock );
237#endif
238    tr_free( l );
239}
240
241void
242tr_lockLock( tr_lock * l )
243{
244#ifdef __BEOS__
245    acquire_sem( l->lock );
246#elif defined(WIN32)
247    EnterCriticalSection( &l->lock );
248#else
249    pthread_mutex_lock( &l->lock );
250#endif
251    assert( l->depth >= 0 );
252    if( l->depth )
253        assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ) );
254    l->lockThread = tr_getCurrentThread( );
255    ++l->depth;
256}
257
258int
259tr_lockHave( const tr_lock * l )
260{
261    return ( l->depth > 0 )
262        && ( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ) );
263}
264
265void
266tr_lockUnlock( tr_lock * l )
267{
268    assert( l->depth > 0 );
269    assert( tr_areThreadsEqual( l->lockThread, tr_getCurrentThread() ));
270
271    --l->depth;
272    assert( l->depth >= 0 );
273#ifdef __BEOS__
274    release_sem( l->lock );
275#elif defined(WIN32)
276    LeaveCriticalSection( &l->lock );
277#else
278    pthread_mutex_unlock( &l->lock );
279#endif
280}
281
282/***
283****  PATHS
284***/
285
286#if !defined(WIN32) && !defined(__BEOS__) && !defined(__AMIGAOS4__)
287#include <pwd.h>
288#endif
289
290const char *
291tr_getHomeDirectory( void )
292{
293    static char buf[MAX_PATH_LENGTH];
294    static int init = 0;
295    const char * envHome;
296
297    if( init )
298        return buf;
299
300    envHome = getenv( "HOME" );
301    if( envHome )
302        snprintf( buf, sizeof(buf), "%s", envHome );
303    else {
304#ifdef WIN32
305        SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, buf );
306#elif defined(__BEOS__) || defined(__AMIGAOS4__)
307        *buf = '\0';
308#else
309        struct passwd * pw = getpwuid( getuid() );
310        endpwent();
311        if( pw != NULL )
312            snprintf( buf, sizeof(buf), "%s", pw->pw_dir );
313#endif
314    }
315
316    init = 1;
317    return buf;
318}
319
320
321static void
322tr_migrateResume( const char *oldDirectory, const char *newDirectory )
323{
324    DIR * dirh = opendir( oldDirectory );
325
326    if( dirh != NULL )
327    {
328        struct dirent * dirp;
329
330        while( ( dirp = readdir( dirh ) ) )
331        {
332            if( !strncmp( "resume.", dirp->d_name, 7 ) )
333            {
334                char o[MAX_PATH_LENGTH];
335                char n[MAX_PATH_LENGTH];
336                tr_buildPath( o, sizeof(o), oldDirectory, dirp->d_name, NULL );
337                tr_buildPath( n, sizeof(n), newDirectory, dirp->d_name, NULL );
338                rename( o, n );
339            }
340        }
341
342        closedir( dirh );
343    }
344}
345
346const char *
347tr_getPrefsDirectory( void )
348{
349    static char   buf[MAX_PATH_LENGTH];
350    static int    init = 0;
351    static size_t buflen = sizeof(buf);
352    const char* h;
353
354    if( init )
355        return buf;
356
357    h = tr_getHomeDirectory();
358#ifdef __BEOS__
359    find_directory( B_USER_SETTINGS_DIRECTORY,
360                    dev_for_path("/boot"), true, buf, buflen );
361    strcat( buf, "/Transmission" );
362#elif defined( SYS_DARWIN )
363    tr_buildPath ( buf, buflen, h,
364                  "Library", "Application Support", "Transmission", NULL );
365#elif defined(__AMIGAOS4__)
366    snprintf( buf, buflen, "PROGDIR:.transmission" );
367#elif defined(WIN32)
368    {
369        char tmp[MAX_PATH_LENGTH];
370        SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, tmp );
371        tr_buildPath( buf, sizeof(buf), tmp, "Transmission", NULL );
372        buflen = strlen( buf );
373    }
374#else
375    tr_buildPath ( buf, buflen, h, ".transmission", NULL );
376#endif
377
378    tr_mkdirp( buf, 0700 );
379    init = 1;
380
381#ifdef SYS_DARWIN
382    char old[MAX_PATH_LENGTH];
383    tr_buildPath ( old, sizeof(old), h, ".transmission", NULL );
384    tr_migrateResume( old, buf );
385    rmdir( old );
386#endif
387
388    return buf;
389}
390
391const char *
392tr_getCacheDirectory( void )
393{
394    static char buf[MAX_PATH_LENGTH];
395    static int  init = 0;
396    static const size_t buflen = sizeof(buf);
397    const char * p;
398
399    if( init )
400        return buf;
401
402    p = tr_getPrefsDirectory();
403#if defined(__BEOS__) || defined(WIN32)
404    tr_buildPath( buf, buflen, p, "Cache", NULL );
405#elif defined( SYS_DARWIN )
406    tr_buildPath( buf, buflen, tr_getHomeDirectory(),
407                  "Library", "Caches", "Transmission", NULL );
408#else
409    tr_buildPath( buf, buflen, p, "cache", NULL );
410#endif
411
412    tr_mkdirp( buf, 0700 );
413    init = 1;
414
415    if( strcmp( p, buf ) )
416        tr_migrateResume( p, buf );
417
418    return buf;
419}
420
421const char *
422tr_getTorrentsDirectory( void )
423{
424    static char buf[MAX_PATH_LENGTH];
425    static int  init = 0;
426    static const size_t buflen = sizeof(buf);
427    const char * p;
428
429    if( init )
430        return buf;
431
432    p = tr_getPrefsDirectory ();
433
434#if defined(__BEOS__) || defined(WIN32)
435    tr_buildPath( buf, buflen, p, "Torrents", NULL );
436#elif defined( SYS_DARWIN )
437    tr_buildPath( buf, buflen, p, "Torrents", NULL );
438#else
439    tr_buildPath( buf, buflen, p, "torrents", NULL );
440#endif
441
442    tr_mkdirp( buf, 0700 );
443    init = 1;
444    return buf;
445}
Note: See TracBrowser for help on using the repository browser.