Changeset 3984 for trunk/libtransmission/platform.c
- Timestamp:
- Nov 26, 2007, 8:21:52 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/platform.c
r3838 r3984 44 44 #include <sys/types.h> 45 45 #include <dirent.h> 46 #include <fcntl.h> 47 #include <unistd.h> /* getuid getpid close */ 46 #include <unistd.h> /* getuid getpid */ 48 47 49 48 #include "transmission.h" … … 626 625 return buf; 627 626 } 628 629 /***630 **** SOCKETS631 ***/632 633 #ifdef BSD634 635 #include <sys/types.h>636 #include <sys/socket.h>637 #include <netinet/in.h>638 #include <arpa/inet.h>639 #include <netinet/in.h> /* struct in_addr */640 #include <sys/sysctl.h>641 #include <net/route.h>642 643 static uint8_t *644 getroute( int * buflen );645 static int646 parseroutes( uint8_t * buf, int len, struct in_addr * addr );647 648 int649 tr_getDefaultRoute( struct in_addr * addr )650 {651 uint8_t * buf;652 int len;653 654 buf = getroute( &len );655 if( NULL == buf )656 {657 tr_err( "failed to get default route (BSD)" );658 return 1;659 }660 661 len = parseroutes( buf, len, addr );662 free( buf );663 664 return len;665 }666 667 #ifndef SA_SIZE668 #define ROUNDUP( a, size ) \669 ( ( (a) & ( (size) - 1 ) ) ? ( 1 + ( (a) | ( (size) - 1 ) ) ) : (a) )670 #define SA_SIZE( sap ) \671 ( sap->sa_len ? ROUNDUP( (sap)->sa_len, sizeof( u_long ) ) : \672 sizeof( u_long ) )673 #endif /* !SA_SIZE */674 #define NEXT_SA( sap ) \675 (struct sockaddr *) ( (caddr_t) (sap) + ( SA_SIZE( (sap) ) ) )676 677 static uint8_t *678 getroute( int * buflen )679 {680 int mib[6];681 size_t len;682 uint8_t * buf;683 684 mib[0] = CTL_NET;685 mib[1] = PF_ROUTE;686 mib[2] = 0;687 mib[3] = AF_INET;688 mib[4] = NET_RT_FLAGS;689 mib[5] = RTF_GATEWAY;690 691 if( sysctl( mib, 6, NULL, &len, NULL, 0 ) )692 {693 if( ENOENT != errno )694 {695 tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",696 strerror( sockerrno ) );697 }698 *buflen = 0;699 return NULL;700 }701 702 buf = malloc( len );703 if( NULL == buf )704 {705 *buflen = 0;706 return NULL;707 }708 709 if( sysctl( mib, 6, buf, &len, NULL, 0 ) )710 {711 tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",712 strerror( sockerrno ) );713 free( buf );714 *buflen = 0;715 return NULL;716 }717 718 *buflen = len;719 720 return buf;721 }722 723 static int724 parseroutes( uint8_t * buf, int len, struct in_addr * addr )725 {726 uint8_t * end;727 struct rt_msghdr * rtm;728 struct sockaddr * sa;729 struct sockaddr_in * sin;730 int ii;731 struct in_addr dest, gw;732 733 end = buf + len;734 while( end > buf + sizeof( *rtm ) )735 {736 rtm = (struct rt_msghdr *) buf;737 buf += rtm->rtm_msglen;738 if( end >= buf )739 {740 dest.s_addr = INADDR_NONE;741 gw.s_addr = INADDR_NONE;742 sa = (struct sockaddr *) ( rtm + 1 );743 744 for( ii = 0; ii < RTAX_MAX && (uint8_t *) sa < buf; ii++ )745 {746 if( buf < (uint8_t *) NEXT_SA( sa ) )747 {748 break;749 }750 751 if( rtm->rtm_addrs & ( 1 << ii ) )752 {753 if( AF_INET == sa->sa_family )754 {755 sin = (struct sockaddr_in *) sa;756 switch( ii )757 {758 case RTAX_DST:759 dest = sin->sin_addr;760 break;761 case RTAX_GATEWAY:762 gw = sin->sin_addr;763 break;764 }765 }766 sa = NEXT_SA( sa );767 }768 }769 770 if( INADDR_ANY == dest.s_addr && INADDR_NONE != gw.s_addr )771 {772 *addr = gw;773 return 0;774 }775 }776 }777 778 return 1;779 }780 781 #elif defined( linux ) || defined( __linux ) || defined( __linux__ )782 783 #include <linux/types.h>784 #include <linux/netlink.h>785 #include <linux/rtnetlink.h>786 787 #define SEQNUM 195909788 789 static int790 getsock( void );791 static uint8_t *792 getroute( int fd, unsigned int * buflen );793 static int794 parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr );795 796 int797 tr_getDefaultRoute( struct in_addr * addr )798 {799 int fd, ret;800 unsigned int len;801 uint8_t * buf;802 803 ret = 1;804 fd = getsock();805 if( 0 <= fd )806 {807 while( ret )808 {809 buf = getroute( fd, &len );810 if( NULL == buf )811 {812 break;813 }814 ret = parseroutes( buf, len, addr );815 free( buf );816 }817 close( fd );818 }819 820 if( ret )821 {822 tr_err( "failed to get default route (Linux)" );823 }824 825 return ret;826 }827 828 static int829 getsock( void )830 {831 int fd, flags;832 struct833 {834 struct nlmsghdr nlh;835 struct rtgenmsg rtg;836 } req;837 struct sockaddr_nl snl;838 839 fd = socket( PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE );840 if( 0 > fd )841 {842 tr_err( "failed to create routing socket (%s)", strerror( sockerrno ) );843 return -1;844 }845 846 flags = fcntl( fd, F_GETFL );847 if( 0 > flags || 0 > fcntl( fd, F_SETFL, O_NONBLOCK | flags ) )848 {849 tr_err( "failed to set socket nonblocking (%s)", strerror( sockerrno ) );850 close( fd );851 return -1;852 }853 854 bzero( &snl, sizeof( snl ) );855 snl.nl_family = AF_NETLINK;856 857 bzero( &req, sizeof( req ) );858 req.nlh.nlmsg_len = NLMSG_LENGTH( sizeof( req.rtg ) );859 req.nlh.nlmsg_type = RTM_GETROUTE;860 req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;861 req.nlh.nlmsg_seq = SEQNUM;862 req.nlh.nlmsg_pid = 0;863 req.rtg.rtgen_family = AF_INET;864 865 if( 0 > sendto( fd, &req, sizeof( req ), 0,866 (struct sockaddr *) &snl, sizeof( snl ) ) )867 {868 tr_err( "failed to write to routing socket (%s)", strerror( sockerrno ) );869 close( fd );870 return -1;871 }872 873 return fd;874 }875 876 static uint8_t *877 getroute( int fd, unsigned int * buflen )878 {879 void * buf;880 unsigned int len;881 ssize_t res;882 struct sockaddr_nl snl;883 socklen_t slen;884 885 len = 8192;886 buf = calloc( 1, len );887 if( NULL == buf )888 {889 *buflen = 0;890 return NULL;891 }892 893 for( ;; )894 {895 bzero( &snl, sizeof( snl ) );896 slen = sizeof( snl );897 res = recvfrom( fd, buf, len, 0, (struct sockaddr *) &snl, &slen );898 if( 0 > res )899 {900 if( EAGAIN != sockerrno )901 {902 tr_err( "failed to read from routing socket (%s)",903 strerror( sockerrno ) );904 }905 free( buf );906 *buflen = 0;907 return NULL;908 }909 if( slen < sizeof( snl ) || AF_NETLINK != snl.nl_family )910 {911 tr_err( "bad address" );912 free( buf );913 *buflen = 0;914 return NULL;915 }916 917 if( 0 == snl.nl_pid )918 {919 break;920 }921 }922 923 *buflen = res;924 925 return buf;926 }927 928 static int929 parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr )930 {931 struct nlmsghdr * nlm;932 struct nlmsgerr * nle;933 struct rtmsg * rtm;934 struct rtattr * rta;935 int rtalen;936 struct in_addr gw, dst;937 938 nlm = ( struct nlmsghdr * ) buf;939 while( NLMSG_OK( nlm, len ) )940 {941 gw.s_addr = INADDR_ANY;942 dst.s_addr = INADDR_ANY;943 if( NLMSG_ERROR == nlm->nlmsg_type )944 {945 nle = (struct nlmsgerr *) NLMSG_DATA( nlm );946 if( NLMSG_LENGTH( NLMSG_ALIGN( sizeof( struct nlmsgerr ) ) ) >947 nlm->nlmsg_len )948 {949 tr_err( "truncated netlink error" );950 }951 else952 {953 tr_err( "netlink error (%s)", strerror( nle->error ) );954 }955 return 1;956 }957 else if( RTM_NEWROUTE == nlm->nlmsg_type && SEQNUM == nlm->nlmsg_seq &&958 getpid() == (pid_t) nlm->nlmsg_pid &&959 NLMSG_LENGTH( sizeof( struct rtmsg ) ) <= nlm->nlmsg_len )960 {961 rtm = NLMSG_DATA( nlm );962 rta = RTM_RTA( rtm );963 rtalen = RTM_PAYLOAD( nlm );964 965 while( RTA_OK( rta, rtalen ) )966 {967 if( sizeof( struct in_addr ) <= RTA_PAYLOAD( rta ) )968 {969 switch( rta->rta_type )970 {971 case RTA_GATEWAY:972 memcpy( &gw, RTA_DATA( rta ), sizeof( gw ) );973 break;974 case RTA_DST:975 memcpy( &dst, RTA_DATA( rta ), sizeof( dst ) );976 break;977 }978 }979 rta = RTA_NEXT( rta, rtalen );980 }981 }982 983 if( INADDR_NONE != gw.s_addr && INADDR_ANY != gw.s_addr &&984 INADDR_ANY == dst.s_addr )985 {986 *addr = gw;987 return 0;988 }989 990 nlm = NLMSG_NEXT( nlm, len );991 }992 993 return 1;994 }995 996 #else /* not BSD or Linux */997 998 int999 tr_getDefaultRoute( struct in_addr * addr UNUSED )1000 {1001 tr_inf( "don't know how to get default route on this platform" );1002 return 1;1003 }1004 1005 #endif
Note: See TracChangeset
for help on using the changeset viewer.