Ignore:
Timestamp:
Sep 25, 2006, 6:37:45 PM (15 years ago)
Author:
joshe
Message:

Merge nat-traversal branch to trunk.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/platform.c

    r679 r920  
    197197}
    198198
     199#if defined( BSD )
     200
     201#include <sys/sysctl.h>
     202#include <net/route.h>
     203
     204static uint8_t *
     205getroute( int * buflen );
     206static int
     207parseroutes( uint8_t * buf, int len, struct in_addr * addr );
     208
     209int
     210tr_getDefaultRoute( struct in_addr * addr )
     211{
     212    uint8_t * buf;
     213    int len;
     214
     215    buf = getroute( &len );
     216    if( NULL == buf )
     217    {
     218        tr_err( "failed to get default route (BSD)" );
     219        return 1;
     220    }
     221
     222    len = parseroutes( buf, len, addr );
     223    free( buf );
     224
     225    return len;
     226}
     227
     228#ifndef SA_SIZE
     229#define ROUNDUP( a, size ) \
     230    ( ( (a) & ( (size) - 1 ) ) ? ( 1 + ( (a) | ( (size) - 1 ) ) ) : (a) )
     231#define SA_SIZE( sap ) \
     232    ( sap->sa_len ? ROUNDUP( (sap)->sa_len, sizeof( u_long ) ) : \
     233                    sizeof( u_long ) )
     234#endif /* !SA_SIZE */
     235#define NEXT_SA( sap ) \
     236    (struct sockaddr *) ( (caddr_t) (sap) + ( SA_SIZE( (sap) ) ) )
     237
     238static uint8_t *
     239getroute( int * buflen )
     240{
     241    int     mib[6];
     242    size_t  len;
     243    uint8_t * buf;
     244
     245    mib[0] = CTL_NET;
     246    mib[1] = PF_ROUTE;
     247    mib[2] = 0;
     248    mib[3] = AF_INET;
     249    mib[4] = NET_RT_FLAGS;
     250    mib[5] = RTF_GATEWAY;
     251
     252    if( sysctl( mib, 6, NULL, &len, NULL, 0 ) )
     253    {
     254        if( ENOENT != errno )
     255        {
     256            tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
     257                    strerror( errno ) );
     258        }
     259        *buflen = 0;
     260        return NULL;
     261    }
     262
     263    buf = malloc( len );
     264    if( NULL == buf )
     265    {
     266        *buflen = 0;
     267        return NULL;
     268    }
     269
     270    if( sysctl( mib, 6, buf, &len, NULL, 0 ) )
     271    {
     272        tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
     273                strerror( errno ) );
     274        free( buf );
     275        *buflen = 0;
     276        return NULL;
     277    }
     278
     279    *buflen = len;
     280
     281    return buf;
     282}
     283
     284static int
     285parseroutes( uint8_t * buf, int len, struct in_addr * addr )
     286{
     287    uint8_t            * end;
     288    struct rt_msghdr   * rtm;
     289    struct sockaddr    * sa;
     290    struct sockaddr_in * sin;
     291    int                  ii;
     292    struct in_addr       dest, gw;
     293
     294    end = buf + len;
     295    while( end > buf + sizeof( *rtm ) )
     296    {
     297        rtm = (struct rt_msghdr *) buf;
     298        buf += rtm->rtm_msglen;
     299        if( end >= buf )
     300        {
     301            dest.s_addr = INADDR_NONE;
     302            gw.s_addr   = INADDR_NONE;
     303            sa = (struct sockaddr *) ( rtm + 1 );
     304
     305            for( ii = 0; ii < RTAX_MAX && (uint8_t *) sa < buf; ii++ )
     306            {
     307                if( buf < (uint8_t *) NEXT_SA( sa ) )
     308                {
     309                    break;
     310                }
     311
     312                if( rtm->rtm_addrs & ( 1 << ii ) )
     313                {
     314                    if( AF_INET == sa->sa_family )
     315                    {
     316                        sin = (struct sockaddr_in *) sa;
     317                        switch( ii )
     318                        {
     319                            case RTAX_DST:
     320                                dest = sin->sin_addr;
     321                                break;
     322                            case RTAX_GATEWAY:
     323                                gw = sin->sin_addr;
     324                                break;
     325                        }
     326                    }
     327                    sa = NEXT_SA( sa );
     328                }
     329            }
     330
     331            if( INADDR_ANY == dest.s_addr && INADDR_NONE != gw.s_addr )
     332            {
     333                *addr = gw;
     334                return 0;
     335            }
     336        }
     337    }
     338
     339    return 1;
     340}
     341
     342#elif defined( linux ) || defined( __linux ) || defined( __linux__ )
     343
     344#include <linux/types.h>
     345#include <linux/netlink.h>
     346#include <linux/rtnetlink.h>
     347
     348#define SEQNUM 195909
     349
     350static int
     351getsock( void );
     352static uint8_t *
     353getroute( int fd, unsigned int * buflen );
     354static int
     355parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr );
     356
     357int
     358tr_getDefaultRoute( struct in_addr * addr )
     359{
     360    int fd, ret;
     361    unsigned int len;
     362    uint8_t * buf;
     363
     364    ret = 1;
     365    fd = getsock();
     366    if( 0 <= fd )
     367    {
     368        while( ret )
     369        {
     370            buf = getroute( fd, &len );
     371            if( NULL == buf )
     372            {
     373                break;
     374            }
     375            ret = parseroutes( buf, len, addr );
     376            free( buf );
     377        }
     378        close( fd );
     379    }
     380
     381    if( ret )
     382    {
     383        tr_err( "failed to get default route (Linux)" );
     384    }
     385
     386    return ret;
     387}
     388
     389static int
     390getsock( void )
     391{
     392    int fd, flags;
     393    struct
     394    {
     395        struct nlmsghdr nlh;
     396        struct rtgenmsg rtg;
     397    } req;
     398    struct sockaddr_nl snl;
     399
     400    fd = socket( PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE );
     401    if( 0 > fd )
     402    {
     403        tr_err( "failed to create routing socket (%s)", strerror( errno ) );
     404        return -1;
     405    }
     406
     407    flags = fcntl( fd, F_GETFL );
     408    if( 0 > flags || 0 > fcntl( fd, F_SETFL, O_NONBLOCK | flags ) )
     409    {
     410        tr_err( "failed to set socket nonblocking (%s)", strerror( errno ) );
     411        close( fd );
     412        return -1;
     413    }
     414
     415    bzero( &snl, sizeof( snl ) );
     416    snl.nl_family = AF_NETLINK;
     417
     418    bzero( &req, sizeof( req ) );
     419    req.nlh.nlmsg_len = NLMSG_LENGTH( sizeof( req.rtg ) );
     420    req.nlh.nlmsg_type = RTM_GETROUTE;
     421    req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
     422    req.nlh.nlmsg_seq = SEQNUM;
     423    req.nlh.nlmsg_pid = 0;
     424    req.rtg.rtgen_family = AF_INET;
     425
     426    if( 0 > sendto( fd, &req, sizeof( req ), 0,
     427                    (struct sockaddr *) &snl, sizeof( snl ) ) )
     428    {
     429        tr_err( "failed to write to routing socket (%s)", strerror( errno ) );
     430        close( fd );
     431        return -1;
     432    }
     433
     434    return fd;
     435}
     436
     437static uint8_t *
     438getroute( int fd, unsigned int * buflen )
     439{
     440    void             * buf;
     441    unsigned int       len;
     442    ssize_t            res;
     443    struct sockaddr_nl snl;
     444    socklen_t          slen;
     445
     446    len = 8192;
     447    buf = calloc( 1, len );
     448    if( NULL == buf )
     449    {
     450        *buflen = 0;
     451        return NULL;
     452    }
     453
     454    for( ;; )
     455    {
     456        bzero( &snl, sizeof( snl ) );
     457        slen = sizeof( snl );
     458        res = recvfrom( fd, buf, len, 0, (struct sockaddr *) &snl, &slen );
     459        if( 0 > res )
     460        {
     461            if( EAGAIN != errno )
     462            {
     463                tr_err( "failed to read from routing socket (%s)",
     464                        strerror( errno ) );
     465            }
     466            free( buf );
     467            *buflen = 0;
     468            return NULL;
     469        }
     470        if( slen < sizeof( snl ) || AF_NETLINK != snl.nl_family )
     471        {
     472            tr_err( "bad address" );
     473            free( buf );
     474            *buflen = 0;
     475            return NULL;
     476        }
     477
     478        if( 0 == snl.nl_pid )
     479        {
     480            break;
     481        }
     482    }
     483
     484    *buflen = res;
     485
     486    return buf;
     487}
     488
     489static int
     490parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr )
     491{
     492    struct nlmsghdr * nlm;
     493    struct nlmsgerr * nle;
     494    struct rtmsg    * rtm;
     495    struct rtattr   * rta;
     496    int               rtalen;
     497    struct in_addr    gw, dst;
     498
     499    nlm = ( struct nlmsghdr * ) buf;
     500    while( NLMSG_OK( nlm, len ) )
     501    {
     502        gw.s_addr = INADDR_ANY;
     503        dst.s_addr = INADDR_ANY;
     504        if( NLMSG_ERROR == nlm->nlmsg_type )
     505        {
     506            nle = (struct nlmsgerr *) NLMSG_DATA( nlm );
     507            if( NLMSG_LENGTH( NLMSG_ALIGN( sizeof( struct nlmsgerr ) ) ) >
     508                nlm->nlmsg_len )
     509            {
     510                tr_err( "truncated netlink error" );
     511            }
     512            else
     513            {
     514                tr_err( "netlink error (%s)", strerror( nle->error ) );
     515            }
     516            return 1;
     517        }
     518        else if( RTM_NEWROUTE == nlm->nlmsg_type && SEQNUM == nlm->nlmsg_seq &&
     519                 getpid() == (pid_t) nlm->nlmsg_pid &&
     520                 NLMSG_LENGTH( sizeof( struct rtmsg ) ) <= nlm->nlmsg_len )
     521        {
     522            rtm = NLMSG_DATA( nlm );
     523            rta = RTM_RTA( rtm );
     524            rtalen = RTM_PAYLOAD( nlm );
     525
     526            while( RTA_OK( rta, rtalen ) )
     527            {
     528                if( sizeof( struct in_addr ) <= RTA_PAYLOAD( rta ) )
     529                {
     530                    switch( rta->rta_type )
     531                    {
     532                        case RTA_GATEWAY:
     533                            memcpy( &gw, RTA_DATA( rta ), sizeof( gw ) );
     534                            break;
     535                        case RTA_DST:
     536                            memcpy( &dst, RTA_DATA( rta ), sizeof( dst ) );
     537                            break;
     538                    }
     539                }
     540                rta = RTA_NEXT( rta, rtalen );
     541            }
     542        }
     543
     544        if( INADDR_NONE != gw.s_addr && INADDR_ANY != gw.s_addr &&
     545            INADDR_ANY == dst.s_addr )
     546        {
     547            *addr = gw;
     548            return 0;
     549        }
     550
     551        nlm = NLMSG_NEXT( nlm, len );
     552    }
     553
     554    return 1;
     555}
     556
     557#else /* not BSD or Linux */
     558
     559int
     560tr_getDefaultRoute( struct in_addr * addr UNUSED )
     561{
     562    tr_inf( "don't know how to get default route on this platform" );
     563    return 1;
     564}
     565
     566#endif
Note: See TracChangeset for help on using the changeset viewer.