source: trunk/libtransmission/platform.c @ 2552

Last change on this file since 2552 was 2552, checked in by charles, 14 years ago

better encapsulation of platform-specific constructs: tr_thread_t, tr_cond_t, tr_lock_t

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