Ignore:
Timestamp:
Nov 26, 2007, 8:21:52 PM (14 years ago)
Author:
charles
Message:

move tr_getDefaultRoute() to natpmp.c because it's the only code that uses it

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/natpmp.c

    r3775 r3984  
    2929#include <time.h>
    3030
     31#include <unistd.h> /* close */
     32#include <fcntl.h> /* fcntl */
     33
    3134#ifdef __BEOS__
    3235    #include <netdb.h>
     
    3841#include "natpmp.h"
    3942#include "net.h"
    40 #include "platform.h" /* tr_getDefaultRoute() */
    4143#include "utils.h"
    4244
     
    6466#define PMP_FROMBUF16( buf )    ( htons( *( (uint16_t *) (buf) ) ) )
    6567#define PMP_FROMBUF32( buf )    ( htonl( *( (uint32_t *) (buf) ) ) )
     68
     69static int tr_getDefaultRoute( struct in_addr * addr );
    6670
    6771typedef struct tr_natpmp_uptime_s
     
    822826    return TR_NET_OK;
    823827}
     828
     829/***
     830****  tr_getDefaultRoute()
     831***/
     832
     833#ifdef BSD
     834
     835#include <sys/types.h>
     836#include <sys/socket.h>
     837#include <netinet/in.h>
     838#include <arpa/inet.h>
     839#include <netinet/in.h> /* struct in_addr */
     840#include <sys/sysctl.h>
     841#include <net/route.h>
     842
     843static uint8_t *
     844getroute( int * buflen );
     845static int
     846parseroutes( uint8_t * buf, int len, struct in_addr * addr );
     847
     848static int
     849tr_getDefaultRoute( struct in_addr * addr )
     850{
     851    uint8_t * buf;
     852    int len;
     853
     854    buf = getroute( &len );
     855    if( NULL == buf )
     856    {
     857        tr_err( "failed to get default route (BSD)" );
     858        return 1;
     859    }
     860
     861    len = parseroutes( buf, len, addr );
     862    free( buf );
     863
     864    return len;
     865}
     866
     867#ifndef SA_SIZE
     868#define ROUNDUP( a, size ) \
     869    ( ( (a) & ( (size) - 1 ) ) ? ( 1 + ( (a) | ( (size) - 1 ) ) ) : (a) )
     870#define SA_SIZE( sap ) \
     871    ( sap->sa_len ? ROUNDUP( (sap)->sa_len, sizeof( u_long ) ) : \
     872                    sizeof( u_long ) )
     873#endif /* !SA_SIZE */
     874#define NEXT_SA( sap ) \
     875    (struct sockaddr *) ( (caddr_t) (sap) + ( SA_SIZE( (sap) ) ) )
     876
     877static uint8_t *
     878getroute( int * buflen )
     879{
     880    int     mib[6];
     881    size_t  len;
     882    uint8_t * buf;
     883
     884    mib[0] = CTL_NET;
     885    mib[1] = PF_ROUTE;
     886    mib[2] = 0;
     887    mib[3] = AF_INET;
     888    mib[4] = NET_RT_FLAGS;
     889    mib[5] = RTF_GATEWAY;
     890
     891    if( sysctl( mib, 6, NULL, &len, NULL, 0 ) )
     892    {
     893        if( ENOENT != errno )
     894        {
     895            tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
     896                    strerror( sockerrno ) );
     897        }
     898        *buflen = 0;
     899        return NULL;
     900    }
     901
     902    buf = malloc( len );
     903    if( NULL == buf )
     904    {
     905        *buflen = 0;
     906        return NULL;
     907    }
     908
     909    if( sysctl( mib, 6, buf, &len, NULL, 0 ) )
     910    {
     911        tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
     912                strerror( sockerrno ) );
     913        free( buf );
     914        *buflen = 0;
     915        return NULL;
     916    }
     917
     918    *buflen = len;
     919
     920    return buf;
     921}
     922
     923static int
     924parseroutes( uint8_t * buf, int len, struct in_addr * addr )
     925{
     926    uint8_t            * end;
     927    struct rt_msghdr   * rtm;
     928    struct sockaddr    * sa;
     929    struct sockaddr_in * sin;
     930    int                  ii;
     931    struct in_addr       dest, gw;
     932
     933    end = buf + len;
     934    while( end > buf + sizeof( *rtm ) )
     935    {
     936        rtm = (struct rt_msghdr *) buf;
     937        buf += rtm->rtm_msglen;
     938        if( end >= buf )
     939        {
     940            dest.s_addr = INADDR_NONE;
     941            gw.s_addr   = INADDR_NONE;
     942            sa = (struct sockaddr *) ( rtm + 1 );
     943
     944            for( ii = 0; ii < RTAX_MAX && (uint8_t *) sa < buf; ii++ )
     945            {
     946                if( buf < (uint8_t *) NEXT_SA( sa ) )
     947                {
     948                    break;
     949                }
     950
     951                if( rtm->rtm_addrs & ( 1 << ii ) )
     952                {
     953                    if( AF_INET == sa->sa_family )
     954                    {
     955                        sin = (struct sockaddr_in *) sa;
     956                        switch( ii )
     957                        {
     958                            case RTAX_DST:
     959                                dest = sin->sin_addr;
     960                                break;
     961                            case RTAX_GATEWAY:
     962                                gw = sin->sin_addr;
     963                                break;
     964                        }
     965                    }
     966                    sa = NEXT_SA( sa );
     967                }
     968            }
     969
     970            if( INADDR_ANY == dest.s_addr && INADDR_NONE != gw.s_addr )
     971            {
     972                *addr = gw;
     973                return 0;
     974            }
     975        }
     976    }
     977
     978    return 1;
     979}
     980
     981#elif defined( linux ) || defined( __linux ) || defined( __linux__ )
     982
     983#include <linux/types.h>
     984#include <linux/netlink.h>
     985#include <linux/rtnetlink.h>
     986
     987#define SEQNUM 195909
     988
     989static int
     990getsock( void );
     991static uint8_t *
     992getroute( int fd, unsigned int * buflen );
     993static int
     994parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr );
     995
     996int
     997tr_getDefaultRoute( struct in_addr * addr )
     998{
     999    int fd, ret;
     1000    unsigned int len;
     1001    uint8_t * buf;
     1002
     1003    ret = 1;
     1004    fd = getsock();
     1005    if( 0 <= fd )
     1006    {
     1007        while( ret )
     1008        {
     1009            buf = getroute( fd, &len );
     1010            if( NULL == buf )
     1011            {
     1012                break;
     1013            }
     1014            ret = parseroutes( buf, len, addr );
     1015            free( buf );
     1016        }
     1017        close( fd );
     1018    }
     1019
     1020    if( ret )
     1021    {
     1022        tr_err( "failed to get default route (Linux)" );
     1023    }
     1024
     1025    return ret;
     1026}
     1027
     1028static int
     1029getsock( void )
     1030{
     1031    int fd, flags;
     1032    struct
     1033    {
     1034        struct nlmsghdr nlh;
     1035        struct rtgenmsg rtg;
     1036    } req;
     1037    struct sockaddr_nl snl;
     1038
     1039    fd = socket( PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE );
     1040    if( 0 > fd )
     1041    {
     1042        tr_err( "failed to create routing socket (%s)", strerror( sockerrno ) );
     1043        return -1;
     1044    }
     1045
     1046    flags = fcntl( fd, F_GETFL );
     1047    if( 0 > flags || 0 > fcntl( fd, F_SETFL, O_NONBLOCK | flags ) )
     1048    {
     1049        tr_err( "failed to set socket nonblocking (%s)", strerror( sockerrno ) );
     1050        close( fd );
     1051        return -1;
     1052    }
     1053
     1054    bzero( &snl, sizeof( snl ) );
     1055    snl.nl_family = AF_NETLINK;
     1056
     1057    bzero( &req, sizeof( req ) );
     1058    req.nlh.nlmsg_len = NLMSG_LENGTH( sizeof( req.rtg ) );
     1059    req.nlh.nlmsg_type = RTM_GETROUTE;
     1060    req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
     1061    req.nlh.nlmsg_seq = SEQNUM;
     1062    req.nlh.nlmsg_pid = 0;
     1063    req.rtg.rtgen_family = AF_INET;
     1064
     1065    if( 0 > sendto( fd, &req, sizeof( req ), 0,
     1066                    (struct sockaddr *) &snl, sizeof( snl ) ) )
     1067    {
     1068        tr_err( "failed to write to routing socket (%s)", strerror( sockerrno ) );
     1069        close( fd );
     1070        return -1;
     1071    }
     1072
     1073    return fd;
     1074}
     1075
     1076static uint8_t *
     1077getroute( int fd, unsigned int * buflen )
     1078{
     1079    void             * buf;
     1080    unsigned int       len;
     1081    ssize_t            res;
     1082    struct sockaddr_nl snl;
     1083    socklen_t          slen;
     1084
     1085    len = 8192;
     1086    buf = calloc( 1, len );
     1087    if( NULL == buf )
     1088    {
     1089        *buflen = 0;
     1090        return NULL;
     1091    }
     1092
     1093    for( ;; )
     1094    {
     1095        bzero( &snl, sizeof( snl ) );
     1096        slen = sizeof( snl );
     1097        res = recvfrom( fd, buf, len, 0, (struct sockaddr *) &snl, &slen );
     1098        if( 0 > res )
     1099        {
     1100            if( EAGAIN != sockerrno )
     1101            {
     1102                tr_err( "failed to read from routing socket (%s)",
     1103                        strerror( sockerrno ) );
     1104            }
     1105            free( buf );
     1106            *buflen = 0;
     1107            return NULL;
     1108        }
     1109        if( slen < sizeof( snl ) || AF_NETLINK != snl.nl_family )
     1110        {
     1111            tr_err( "bad address" );
     1112            free( buf );
     1113            *buflen = 0;
     1114            return NULL;
     1115        }
     1116
     1117        if( 0 == snl.nl_pid )
     1118        {
     1119            break;
     1120        }
     1121    }
     1122
     1123    *buflen = res;
     1124
     1125    return buf;
     1126}
     1127
     1128static int
     1129parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr )
     1130{
     1131    struct nlmsghdr * nlm;
     1132    struct nlmsgerr * nle;
     1133    struct rtmsg    * rtm;
     1134    struct rtattr   * rta;
     1135    int               rtalen;
     1136    struct in_addr    gw, dst;
     1137
     1138    nlm = ( struct nlmsghdr * ) buf;
     1139    while( NLMSG_OK( nlm, len ) )
     1140    {
     1141        gw.s_addr = INADDR_ANY;
     1142        dst.s_addr = INADDR_ANY;
     1143        if( NLMSG_ERROR == nlm->nlmsg_type )
     1144        {
     1145            nle = (struct nlmsgerr *) NLMSG_DATA( nlm );
     1146            if( NLMSG_LENGTH( NLMSG_ALIGN( sizeof( struct nlmsgerr ) ) ) >
     1147                nlm->nlmsg_len )
     1148            {
     1149                tr_err( "truncated netlink error" );
     1150            }
     1151            else
     1152            {
     1153                tr_err( "netlink error (%s)", strerror( nle->error ) );
     1154            }
     1155            return 1;
     1156        }
     1157        else if( RTM_NEWROUTE == nlm->nlmsg_type && SEQNUM == nlm->nlmsg_seq &&
     1158                 getpid() == (pid_t) nlm->nlmsg_pid &&
     1159                 NLMSG_LENGTH( sizeof( struct rtmsg ) ) <= nlm->nlmsg_len )
     1160        {
     1161            rtm = NLMSG_DATA( nlm );
     1162            rta = RTM_RTA( rtm );
     1163            rtalen = RTM_PAYLOAD( nlm );
     1164
     1165            while( RTA_OK( rta, rtalen ) )
     1166            {
     1167                if( sizeof( struct in_addr ) <= RTA_PAYLOAD( rta ) )
     1168                {
     1169                    switch( rta->rta_type )
     1170                    {
     1171                        case RTA_GATEWAY:
     1172                            memcpy( &gw, RTA_DATA( rta ), sizeof( gw ) );
     1173                            break;
     1174                        case RTA_DST:
     1175                            memcpy( &dst, RTA_DATA( rta ), sizeof( dst ) );
     1176                            break;
     1177                    }
     1178                }
     1179                rta = RTA_NEXT( rta, rtalen );
     1180            }
     1181        }
     1182
     1183        if( INADDR_NONE != gw.s_addr && INADDR_ANY != gw.s_addr &&
     1184            INADDR_ANY == dst.s_addr )
     1185        {
     1186            *addr = gw;
     1187            return 0;
     1188        }
     1189
     1190        nlm = NLMSG_NEXT( nlm, len );
     1191    }
     1192
     1193    return 1;
     1194}
     1195
     1196#else /* not BSD or Linux */
     1197
     1198int
     1199tr_getDefaultRoute( struct in_addr * addr UNUSED )
     1200{
     1201    tr_inf( "don't know how to get default route on this platform" );
     1202    return 1;
     1203}
     1204
     1205#endif
Note: See TracChangeset for help on using the changeset viewer.