Changeset 4001 for trunk/libtransmission/platform.c
- Timestamp:
- Nov 27, 2007, 3:39:59 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/platform.c
r3984 r4001 44 44 #include <sys/types.h> 45 45 #include <dirent.h> 46 #include <unistd.h> /* getuid getpid */ 46 #include <fcntl.h> 47 #include <unistd.h> /* getuid getpid close */ 47 48 48 49 #include "transmission.h" … … 625 626 return buf; 626 627 } 628 629 /*** 630 **** SOCKETS 631 ***/ 632 633 #ifdef BSD 634 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 int 646 parseroutes( uint8_t * buf, int len, struct in_addr * addr ); 647 648 int 649 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_SIZE 668 #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 int 724 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 195909 788 789 static int 790 getsock( void ); 791 static uint8_t * 792 getroute( int fd, unsigned int * buflen ); 793 static int 794 parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr ); 795 796 int 797 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 int 829 getsock( void ) 830 { 831 int fd, flags; 832 struct 833 { 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 int 929 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 else 952 { 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 int 999 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.