source: trunk/libtransmission/platform.c @ 3105

Last change on this file since 3105 was 3105, checked in by livings124, 13 years ago

merge encryption branch to trunk (xcode project is still out of date)

  • Property svn:keywords set to Date Rev Author Id
File size: 21.0 KB
Line 
1/******************************************************************************
2 * $Id: platform.c 3105 2007-09-20 16:32:01Z livings124 $
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#include <assert.h>
26#include <errno.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#ifdef __BEOS__
32  #include <signal.h> 
33  #include <fs_info.h>
34  #include <FindDirectory.h>
35  #include <kernel/OS.h>
36  #define BEOS_MAX_THREADS 256
37#elif defined(WIN32)
38  #include <windows.h>
39  #include <shlobj.h> /* for CSIDL_APPDATA, CSIDL_PROFILE */
40#else
41  #include <pthread.h>
42#endif
43
44#include <sys/types.h>
45#include <dirent.h>
46#include <fcntl.h>
47#include <unistd.h> /* getuid getpid close */
48
49#include "transmission.h"
50#include "list.h"
51#include "net.h"
52#include "platform.h"
53#include "utils.h"
54
55/***
56****  THREADS
57***/
58
59struct tr_thread
60{
61    void          (* func ) ( void * );
62    void           * arg;
63    const char     * name;
64
65#ifdef __BEOS__
66    thread_id        thread;
67#elif defined(WIN32)
68    HANDLE           thread;
69    unsigned int     thread_id;
70#else
71    pthread_t        thread;
72#endif
73
74};
75
76#ifdef WIN32
77#define ThreadFuncReturnType unsigned WINAPI
78#else
79#define ThreadFuncReturnType void
80#endif
81
82static ThreadFuncReturnType
83ThreadFunc( void * _t )
84{
85    tr_thread * t = _t;
86    const char * name = t->name;
87
88#ifdef __BEOS__
89    /* This is required because on BeOS, SIGINT is sent to each thread,
90       which kills them not nicely */
91    signal( SIGINT, SIG_IGN );
92#endif
93
94    tr_dbg( "Thread '%s' started", name );
95    t->func( t->arg );
96    tr_dbg( "Thread '%s' exited", name );
97
98#ifdef WIN32
99    _endthreadex( 0 );
100    return 0;
101#endif
102}
103
104tr_thread *
105tr_threadNew( void (*func)(void *),
106              void * arg,
107              const char * name )
108{
109    tr_thread * t = tr_new0( tr_thread, 1 );
110    t->func = func;
111    t->arg  = arg;
112    t->name = name;
113
114#ifdef __BEOS__
115    t->thread = spawn_thread( (void*)ThreadFunc, name, B_NORMAL_PRIORITY, t );
116    resume_thread( t->thread );
117#elif defined(WIN32)
118    t->thread = (HANDLE) _beginthreadex( NULL, 0, &ThreadFunc, t, 0, &t->thread_id );
119#else
120    pthread_create( &t->thread, NULL, (void * (*) (void *)) ThreadFunc, t );
121#endif
122
123    return t;
124}
125
126int
127tr_amInThread ( const tr_thread * t )
128{
129#ifdef __BEOS__
130    return find_thread(NULL) == t->thread;
131#elif defined(WIN32)
132    return GetCurrentThreadId() == t->thread_id;
133#else
134    return pthread_equal( t->thread, pthread_self( ) );
135#endif
136}
137   
138void
139tr_threadJoin( tr_thread * t )
140{
141    if( t != NULL )
142    {
143#ifdef __BEOS__
144        long exit;
145        wait_for_thread( t->thread, &exit );
146#elif defined(WIN32)
147        WaitForSingleObject( t->thread, INFINITE );
148        CloseHandle( t->thread );
149#else
150        pthread_join( t->thread, NULL );
151#endif
152
153        tr_dbg( "Thread '%s' joined", t->name );
154        t->name = NULL;
155        t->func = NULL;
156        tr_free( t );
157    }
158}
159
160/***
161****  LOCKS
162***/
163
164struct tr_lock
165{
166#ifdef __BEOS__
167    sem_id lock;
168#elif defined(WIN32)
169    CRITICAL_SECTION lock;
170#else
171    pthread_mutex_t lock;
172#endif
173};
174
175tr_lock*
176tr_lockNew( void )
177{
178    tr_lock * l = tr_new0( tr_lock, 1 );
179
180#ifdef __BEOS__
181    l->lock = create_sem( 1, "" );
182#elif defined(WIN32)
183    InitializeCriticalSection( &l->lock );
184#else
185    pthread_mutex_init( &l->lock, NULL );
186#endif
187
188    return l;
189}
190
191void
192tr_lockFree( tr_lock * l )
193{
194#ifdef __BEOS__
195    delete_sem( l->lock );
196#elif defined(WIN32)
197    DeleteCriticalSection( &l->lock );
198#else
199    pthread_mutex_destroy( &l->lock );
200#endif
201    tr_free( l );
202}
203
204int
205tr_lockTryLock( tr_lock * l ) /* success on zero! */
206{
207#ifdef __BEOS__
208    return acquire_sem_etc( l->lock, 1, B_RELATIVE_TIMEOUT, 0 );
209#elif defined(WIN32)
210    return !TryEnterCriticalSection( &l->lock );
211#else
212    return pthread_mutex_trylock( &l->lock );
213#endif
214}
215
216void
217tr_lockLock( tr_lock * l )
218{
219#ifdef __BEOS__
220    acquire_sem( l->lock );
221#elif defined(WIN32)
222    EnterCriticalSection( &l->lock );
223#else
224    pthread_mutex_lock( &l->lock );
225#endif
226}
227
228void
229tr_lockUnlock( tr_lock * l )
230{
231#ifdef __BEOS__
232    release_sem( l->lock );
233#elif defined(WIN32)
234    LeaveCriticalSection( &l->lock );
235#else
236    pthread_mutex_unlock( &l->lock );
237#endif
238}
239
240/***
241****  COND
242***/
243
244struct tr_cond
245{
246#ifdef __BEOS__
247    sem_id sem;
248    thread_id threads[BEOS_MAX_THREADS];
249    int start, end;
250#elif defined(WIN32)
251    tr_list * events;
252    tr_lock * lock;
253#else
254    pthread_cond_t cond;
255#endif
256};
257
258#ifdef WIN32
259static DWORD getContEventTLS( void )
260{
261    static int inited = FALSE;
262    static DWORD event_tls;
263    if( !inited ) {
264        inited = TRUE;
265        event_tls = TlsAlloc();
266    }
267    return event_tls;
268}
269#endif
270
271tr_cond*
272tr_condNew( void )
273{
274    tr_cond * c = tr_new0( tr_cond, 1 );
275#ifdef __BEOS__
276    c->sem = create_sem( 1, "" );
277    c->start = 0;
278    c->end = 0;
279#elif defined(WIN32)
280    c->events = NULL;
281    c->lock = tr_lockNew( );
282#else
283    pthread_cond_init( &c->cond, NULL );
284#endif
285    return c;
286}
287
288void
289tr_condWait( tr_cond * c, tr_lock * l )
290{
291#ifdef __BEOS__
292
293    /* Keep track of that thread */
294    acquire_sem( c->sem );
295    c->threads[c->end] = find_thread( NULL );
296    c->end = ( c->end + 1 ) % BEOS_MAX_THREADS;
297    assert( c->end != c->start ); /* We hit BEOS_MAX_THREADS, arggh */
298    release_sem( c->sem );
299
300    release_sem( l->lock );
301    suspend_thread( find_thread( NULL ) ); /* Wait for signal */
302    acquire_sem( l->lock );
303
304#elif defined(WIN32)
305
306    /* get this thread's cond event */
307    DWORD key = getContEventTLS ( );
308    HANDLE hEvent = TlsGetValue( key );
309    if( !hEvent ) {
310        hEvent = CreateEvent( 0, FALSE, FALSE, 0 );
311        TlsSetValue( key, hEvent );
312    }
313
314    /* add it to the list of events waiting to be signaled */
315    tr_lockLock( c->lock );
316    tr_list_append( &c->events, hEvent );
317    tr_lockUnlock( c->lock );
318
319    /* now wait for it to be signaled */
320    tr_lockUnlock( l );
321    WaitForSingleObject( hEvent, INFINITE );
322    tr_lockLock( l );
323
324    /* remove it from the list of events waiting to be signaled */
325    tr_lockLock( c->lock );
326    tr_list_remove_data( &c->events, hEvent );
327    tr_lockUnlock( c->lock );
328
329#else
330
331    pthread_cond_wait( &c->cond, &l->lock );
332
333#endif
334}
335
336#ifdef __BEOS__
337static int condTrySignal( tr_cond * c )
338{
339    if( c->start == c->end )
340        return 1;
341
342    for( ;; )
343    {
344        thread_info info;
345        get_thread_info( c->threads[c->start], &info );
346        if( info.state == B_THREAD_SUSPENDED )
347        {
348            resume_thread( c->threads[c->start] );
349            c->start = ( c->start + 1 ) % BEOS_MAX_THREADS;
350            break;
351        }
352        /* The thread is not suspended yet, which can happen since
353         * tr_condWait does not atomically suspends after releasing
354         * the semaphore. Wait a bit and try again. */
355        snooze( 5000 );
356    }
357    return 0;
358}
359#endif
360void
361tr_condSignal( tr_cond * c )
362{
363#ifdef __BEOS__
364
365    acquire_sem( c->sem );
366    condTrySignal( c );
367    release_sem( c->sem );
368
369#elif defined(WIN32)
370
371    tr_lockLock( c->lock );
372    if( c->events != NULL )
373        SetEvent( (HANDLE)c->events->data );
374    tr_lockUnlock( c->lock );
375
376#else
377
378    pthread_cond_signal( &c->cond );
379
380#endif
381}
382
383void
384tr_condBroadcast( tr_cond * c )
385{
386#ifdef __BEOS__
387
388    acquire_sem( c->sem );
389    while( !condTrySignal( c ) );
390    release_sem( c->sem );
391
392#elif defined(WIN32)
393
394    tr_list * l;
395    tr_lockLock( c->lock );
396    for( l=c->events; l!=NULL; l=l->next )
397        SetEvent( (HANDLE)l->data );
398    tr_lockUnlock( c->lock );
399
400#else
401
402    pthread_cond_broadcast( &c->cond );
403
404#endif
405}
406
407void
408tr_condFree( tr_cond * c )
409{
410#ifdef __BEOS__
411    delete_sem( c->sem );
412#elif defined(WIN32)
413    tr_list_free( &c->events );
414    tr_lockFree( c->lock );
415#else
416    pthread_cond_destroy( &c->cond );
417#endif
418    tr_free( c );
419}
420
421
422/***
423****  PATHS
424***/
425
426#if !defined(WIN32) && !defined(__BEOS__) && !defined(__AMIGAOS4__)
427#include <pwd.h>
428#endif
429
430const char *
431tr_getHomeDirectory( void )
432{
433    static char buf[MAX_PATH_LENGTH];
434    static int init = 0;
435    const char * envHome;
436
437    if( init )
438        return buf;
439
440    envHome = getenv( "HOME" );
441    if( envHome )
442        snprintf( buf, sizeof(buf), "%s", envHome );
443    else {
444#ifdef WIN32
445        SHGetFolderPath( NULL, CSIDL_PROFILE, NULL, 0, buf );
446#elif defined(__BEOS__) || defined(__AMIGAOS4__)
447        *buf = '\0';
448#else
449        struct passwd * pw = getpwuid( getuid() );
450        endpwent();
451        if( pw != NULL )
452            snprintf( buf, sizeof(buf), "%s", pw->pw_dir );
453#endif
454    }
455
456    init = 1;
457    return buf;
458}
459
460
461static void
462tr_migrateResume( const char *oldDirectory, const char *newDirectory )
463{
464    DIR * dirh = opendir( oldDirectory );
465
466    if( dirh != NULL )
467    {
468        struct dirent * dirp;
469
470        while( ( dirp = readdir( dirh ) ) )
471        {
472            if( !strncmp( "resume.", dirp->d_name, 7 ) )
473            {
474                char o[MAX_PATH_LENGTH];
475                char n[MAX_PATH_LENGTH];
476                tr_buildPath( o, sizeof(o), oldDirectory, dirp->d_name, NULL );
477                tr_buildPath( n, sizeof(n), newDirectory, dirp->d_name, NULL );
478                rename( o, n );
479            }
480        }
481
482        closedir( dirh );
483    }
484}
485
486const char *
487tr_getPrefsDirectory( void )
488{
489    static char   buf[MAX_PATH_LENGTH];
490    static int    init = 0;
491    static size_t buflen = sizeof(buf);
492    const char* h;
493
494    if( init )
495        return buf;
496
497    h = tr_getHomeDirectory();
498#ifdef __BEOS__
499    find_directory( B_USER_SETTINGS_DIRECTORY,
500                    dev_for_path("/boot"), true, buf, buflen );
501    strcat( buf, "/Transmission" );
502#elif defined( SYS_DARWIN )
503    tr_buildPath ( buf, buflen, h,
504                  "Library", "Application Support", "Transmission", NULL );
505#elif defined(__AMIGAOS4__)
506    snprintf( buf, buflen, "PROGDIR:.transmission" );
507#elif defined(WIN32)
508    {
509        char tmp[MAX_PATH_LENGTH];
510        SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, 0, tmp );
511        tr_buildPath( buf, sizeof(buf), tmp, "Transmission", NULL );
512        buflen = strlen( buf );
513    }
514#else
515    tr_buildPath ( buf, buflen, h, ".transmission", NULL );
516#endif
517
518    tr_mkdirp( buf, 0700 );
519    init = 1;
520
521#ifdef SYS_DARWIN
522    char old[MAX_PATH_LENGTH];
523    tr_buildPath ( old, sizeof(old), h, ".transmission", NULL );
524    tr_migrateResume( old, buf );
525    rmdir( old );
526#endif
527
528    return buf;
529}
530
531const char *
532tr_getCacheDirectory( void )
533{
534    static char buf[MAX_PATH_LENGTH];
535    static int  init = 0;
536    static const size_t buflen = sizeof(buf);
537    const char * p;
538
539    if( init )
540        return buf;
541
542    p = tr_getPrefsDirectory();
543#if defined(__BEOS__) || defined(WIN32)
544    tr_buildPath( buf, buflen, p, "Cache", NULL );
545#elif defined( SYS_DARWIN )
546    tr_buildPath( buf, buflen, tr_getHomeDirectory(),
547                  "Library", "Caches", "Transmission", NULL );
548#else
549    tr_buildPath( buf, buflen, p, "cache", NULL );
550#endif
551
552    tr_mkdirp( buf, 0700 );
553    init = 1;
554
555    if( strcmp( p, buf ) )
556        tr_migrateResume( p, buf );
557
558    return buf;
559}
560
561const char *
562tr_getTorrentsDirectory( void )
563{
564    static char buf[MAX_PATH_LENGTH];
565    static int  init = 0;
566    static const size_t buflen = sizeof(buf);
567    const char * p;
568
569    if( init )
570        return buf;
571
572    p = tr_getPrefsDirectory ();
573
574#if defined(__BEOS__) || defined(WIN32)
575    tr_buildPath( buf, buflen, p, "Torrents", NULL );
576#elif defined( SYS_DARWIN )
577    tr_buildPath( buf, buflen, p, "Torrents", NULL );
578#else
579    tr_buildPath( buf, buflen, p, "torrents", NULL );
580#endif
581
582    tr_mkdirp( buf, 0700 );
583    init = 1;
584    return buf;
585}
586
587/***
588****  SOCKETS
589***/
590
591#ifdef BSD
592
593#include <sys/types.h>
594#include <sys/socket.h>
595#include <netinet/in.h>
596#include <arpa/inet.h>
597#include <sys/sysctl.h>
598#include <net/route.h>
599
600static uint8_t *
601getroute( int * buflen );
602static int
603parseroutes( uint8_t * buf, int len, struct in_addr * addr );
604
605int
606tr_getDefaultRoute( struct in_addr * addr )
607{
608    uint8_t * buf;
609    int len;
610
611    buf = getroute( &len );
612    if( NULL == buf )
613    {
614        tr_err( "failed to get default route (BSD)" );
615        return 1;
616    }
617
618    len = parseroutes( buf, len, addr );
619    free( buf );
620
621    return len;
622}
623
624#ifndef SA_SIZE
625#define ROUNDUP( a, size ) \
626    ( ( (a) & ( (size) - 1 ) ) ? ( 1 + ( (a) | ( (size) - 1 ) ) ) : (a) )
627#define SA_SIZE( sap ) \
628    ( sap->sa_len ? ROUNDUP( (sap)->sa_len, sizeof( u_long ) ) : \
629                    sizeof( u_long ) )
630#endif /* !SA_SIZE */
631#define NEXT_SA( sap ) \
632    (struct sockaddr *) ( (caddr_t) (sap) + ( SA_SIZE( (sap) ) ) )
633
634static uint8_t *
635getroute( int * buflen )
636{
637    int     mib[6];
638    size_t  len;
639    uint8_t * buf;
640
641    mib[0] = CTL_NET;
642    mib[1] = PF_ROUTE;
643    mib[2] = 0;
644    mib[3] = AF_INET;
645    mib[4] = NET_RT_FLAGS;
646    mib[5] = RTF_GATEWAY;
647
648    if( sysctl( mib, 6, NULL, &len, NULL, 0 ) )
649    {
650        if( ENOENT != errno )
651        {
652            tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
653                    strerror( sockerrno ) );
654        }
655        *buflen = 0;
656        return NULL;
657    }
658
659    buf = malloc( len );
660    if( NULL == buf )
661    {
662        *buflen = 0;
663        return NULL;
664    }
665
666    if( sysctl( mib, 6, buf, &len, NULL, 0 ) )
667    {
668        tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
669                strerror( sockerrno ) );
670        free( buf );
671        *buflen = 0;
672        return NULL;
673    }
674
675    *buflen = len;
676
677    return buf;
678}
679
680static int
681parseroutes( uint8_t * buf, int len, struct in_addr * addr )
682{
683    uint8_t            * end;
684    struct rt_msghdr   * rtm;
685    struct sockaddr    * sa;
686    struct sockaddr_in * sin;
687    int                  ii;
688    struct in_addr       dest, gw;
689
690    end = buf + len;
691    while( end > buf + sizeof( *rtm ) )
692    {
693        rtm = (struct rt_msghdr *) buf;
694        buf += rtm->rtm_msglen;
695        if( end >= buf )
696        {
697            dest.s_addr = INADDR_NONE;
698            gw.s_addr   = INADDR_NONE;
699            sa = (struct sockaddr *) ( rtm + 1 );
700
701            for( ii = 0; ii < RTAX_MAX && (uint8_t *) sa < buf; ii++ )
702            {
703                if( buf < (uint8_t *) NEXT_SA( sa ) )
704                {
705                    break;
706                }
707
708                if( rtm->rtm_addrs & ( 1 << ii ) )
709                {
710                    if( AF_INET == sa->sa_family )
711                    {
712                        sin = (struct sockaddr_in *) sa;
713                        switch( ii )
714                        {
715                            case RTAX_DST:
716                                dest = sin->sin_addr;
717                                break;
718                            case RTAX_GATEWAY:
719                                gw = sin->sin_addr;
720                                break;
721                        }
722                    }
723                    sa = NEXT_SA( sa );
724                }
725            }
726
727            if( INADDR_ANY == dest.s_addr && INADDR_NONE != gw.s_addr )
728            {
729                *addr = gw;
730                return 0;
731            }
732        }
733    }
734
735    return 1;
736}
737
738#elif defined( linux ) || defined( __linux ) || defined( __linux__ )
739
740#include <linux/types.h>
741#include <linux/netlink.h>
742#include <linux/rtnetlink.h>
743
744#define SEQNUM 195909
745
746static int
747getsock( void );
748static uint8_t *
749getroute( int fd, unsigned int * buflen );
750static int
751parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr );
752
753int
754tr_getDefaultRoute( struct in_addr * addr )
755{
756    int fd, ret;
757    unsigned int len;
758    uint8_t * buf;
759
760    ret = 1;
761    fd = getsock();
762    if( 0 <= fd )
763    {
764        while( ret )
765        {
766            buf = getroute( fd, &len );
767            if( NULL == buf )
768            {
769                break;
770            }
771            ret = parseroutes( buf, len, addr );
772            free( buf );
773        }
774        close( fd );
775    }
776
777    if( ret )
778    {
779        tr_err( "failed to get default route (Linux)" );
780    }
781
782    return ret;
783}
784
785static int
786getsock( void )
787{
788    int fd, flags;
789    struct
790    {
791        struct nlmsghdr nlh;
792        struct rtgenmsg rtg;
793    } req;
794    struct sockaddr_nl snl;
795
796    fd = socket( PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE );
797    if( 0 > fd )
798    {
799        tr_err( "failed to create routing socket (%s)", strerror( sockerrno ) );
800        return -1;
801    }
802
803    flags = fcntl( fd, F_GETFL );
804    if( 0 > flags || 0 > fcntl( fd, F_SETFL, O_NONBLOCK | flags ) )
805    {
806        tr_err( "failed to set socket nonblocking (%s)", strerror( sockerrno ) );
807        close( fd );
808        return -1;
809    }
810
811    bzero( &snl, sizeof( snl ) );
812    snl.nl_family = AF_NETLINK;
813
814    bzero( &req, sizeof( req ) );
815    req.nlh.nlmsg_len = NLMSG_LENGTH( sizeof( req.rtg ) );
816    req.nlh.nlmsg_type = RTM_GETROUTE;
817    req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
818    req.nlh.nlmsg_seq = SEQNUM;
819    req.nlh.nlmsg_pid = 0;
820    req.rtg.rtgen_family = AF_INET;
821
822    if( 0 > sendto( fd, &req, sizeof( req ), 0,
823                    (struct sockaddr *) &snl, sizeof( snl ) ) )
824    {
825        tr_err( "failed to write to routing socket (%s)", strerror( sockerrno ) );
826        close( fd );
827        return -1;
828    }
829
830    return fd;
831}
832
833static uint8_t *
834getroute( int fd, unsigned int * buflen )
835{
836    void             * buf;
837    unsigned int       len;
838    ssize_t            res;
839    struct sockaddr_nl snl;
840    socklen_t          slen;
841
842    len = 8192;
843    buf = calloc( 1, len );
844    if( NULL == buf )
845    {
846        *buflen = 0;
847        return NULL;
848    }
849
850    for( ;; )
851    {
852        bzero( &snl, sizeof( snl ) );
853        slen = sizeof( snl );
854        res = recvfrom( fd, buf, len, 0, (struct sockaddr *) &snl, &slen );
855        if( 0 > res )
856        {
857            if( EAGAIN != sockerrno )
858            {
859                tr_err( "failed to read from routing socket (%s)",
860                        strerror( sockerrno ) );
861            }
862            free( buf );
863            *buflen = 0;
864            return NULL;
865        }
866        if( slen < sizeof( snl ) || AF_NETLINK != snl.nl_family )
867        {
868            tr_err( "bad address" );
869            free( buf );
870            *buflen = 0;
871            return NULL;
872        }
873
874        if( 0 == snl.nl_pid )
875        {
876            break;
877        }
878    }
879
880    *buflen = res;
881
882    return buf;
883}
884
885static int
886parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr )
887{
888    struct nlmsghdr * nlm;
889    struct nlmsgerr * nle;
890    struct rtmsg    * rtm;
891    struct rtattr   * rta;
892    int               rtalen;
893    struct in_addr    gw, dst;
894
895    nlm = ( struct nlmsghdr * ) buf;
896    while( NLMSG_OK( nlm, len ) )
897    {
898        gw.s_addr = INADDR_ANY;
899        dst.s_addr = INADDR_ANY;
900        if( NLMSG_ERROR == nlm->nlmsg_type )
901        {
902            nle = (struct nlmsgerr *) NLMSG_DATA( nlm );
903            if( NLMSG_LENGTH( NLMSG_ALIGN( sizeof( struct nlmsgerr ) ) ) >
904                nlm->nlmsg_len )
905            {
906                tr_err( "truncated netlink error" );
907            }
908            else
909            {
910                tr_err( "netlink error (%s)", strerror( nle->error ) );
911            }
912            return 1;
913        }
914        else if( RTM_NEWROUTE == nlm->nlmsg_type && SEQNUM == nlm->nlmsg_seq &&
915                 getpid() == (pid_t) nlm->nlmsg_pid &&
916                 NLMSG_LENGTH( sizeof( struct rtmsg ) ) <= nlm->nlmsg_len )
917        {
918            rtm = NLMSG_DATA( nlm );
919            rta = RTM_RTA( rtm );
920            rtalen = RTM_PAYLOAD( nlm );
921
922            while( RTA_OK( rta, rtalen ) )
923            {
924                if( sizeof( struct in_addr ) <= RTA_PAYLOAD( rta ) )
925                {
926                    switch( rta->rta_type )
927                    {
928                        case RTA_GATEWAY:
929                            memcpy( &gw, RTA_DATA( rta ), sizeof( gw ) );
930                            break;
931                        case RTA_DST:
932                            memcpy( &dst, RTA_DATA( rta ), sizeof( dst ) );
933                            break;
934                    }
935                }
936                rta = RTA_NEXT( rta, rtalen );
937            }
938        }
939
940        if( INADDR_NONE != gw.s_addr && INADDR_ANY != gw.s_addr &&
941            INADDR_ANY == dst.s_addr )
942        {
943            *addr = gw;
944            return 0;
945        }
946
947        nlm = NLMSG_NEXT( nlm, len );
948    }
949
950    return 1;
951}
952
953#else /* not BSD or Linux */
954
955int
956tr_getDefaultRoute( struct in_addr * addr UNUSED )
957{
958    tr_inf( "don't know how to get default route on this platform" );
959    return 1;
960}
961
962#endif
Note: See TracBrowser for help on using the repository browser.