source: trunk/libtransmission/platform.c @ 2576

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

get the socket/net code working on win32 too

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