Ignore:
Timestamp:
Dec 1, 2007 8:52:57 AM (16 years ago)
Author:
bennylp
Message:

More ticket #415: more IPv6 and some reorganization of the source codes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib/src/pj/sock_common.c

    r1585 r1601  
    1818 */ 
    1919#include <pj/sock.h> 
     20#include <pj/assert.h> 
     21#include <pj/errno.h> 
     22#include <pj/ip_helper.h> 
     23#include <pj/os.h> 
     24#include <pj/addr_resolv.h> 
     25#include <pj/string.h> 
     26#include <pj/compat/socket.h> 
     27 
     28 
     29/* 
     30 * Convert address string with numbers and dots to binary IP address. 
     31 */  
     32PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp) 
     33{ 
     34    pj_in_addr addr; 
     35 
     36    pj_inet_aton(cp, &addr); 
     37    return addr; 
     38} 
     39 
     40/* 
     41 * Convert address string with numbers and dots to binary IP address. 
     42 */  
     43PJ_DEF(pj_in_addr) pj_inet_addr2(const char *cp) 
     44{ 
     45    pj_str_t str = pj_str((char*)cp); 
     46    return pj_inet_addr(&str); 
     47} 
     48 
     49/* 
     50 * Set the IP address of an IP socket address from string address,  
     51 * with resolving the host if necessary. The string address may be in a 
     52 * standard numbers and dots notation or may be a hostname. If hostname 
     53 * is specified, then the function will resolve the host into the IP 
     54 * address. 
     55 */ 
     56PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr, 
     57                                                 const pj_str_t *str_addr) 
     58{ 
     59    PJ_CHECK_STACK(); 
     60 
     61    PJ_ASSERT_RETURN(!str_addr || str_addr->slen < PJ_MAX_HOSTNAME,  
     62                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); 
     63 
     64    PJ_SOCKADDR_RESET_LEN(addr); 
     65    addr->sin_family = AF_INET; 
     66    pj_bzero(addr->sin_zero, sizeof(addr->sin_zero)); 
     67 
     68    if (str_addr && str_addr->slen) { 
     69        addr->sin_addr = pj_inet_addr(str_addr); 
     70        if (addr->sin_addr.s_addr == PJ_INADDR_NONE) { 
     71            pj_hostent he; 
     72            pj_status_t rc; 
     73 
     74            rc = pj_gethostbyname(str_addr, &he); 
     75            if (rc == 0) { 
     76                addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr; 
     77            } else { 
     78                addr->sin_addr.s_addr = PJ_INADDR_NONE; 
     79                return rc; 
     80            } 
     81        } 
     82 
     83    } else { 
     84        addr->sin_addr.s_addr = 0; 
     85    } 
     86 
     87    return PJ_SUCCESS; 
     88} 
     89 
     90/* Set address from a name */ 
     91PJ_DEF(pj_status_t) pj_sockaddr_set_str_addr(int af, 
     92                                             pj_sockaddr *addr, 
     93                                             const pj_str_t *str_addr) 
     94{ 
     95    pj_status_t status; 
     96 
     97    if (af == PJ_AF_INET) { 
     98        return pj_sockaddr_in_set_str_addr(&addr->ipv4, str_addr); 
     99    } 
     100 
     101    PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP); 
     102 
     103    /* IPv6 specific */ 
     104 
     105    addr->ipv6.sin6_family = PJ_AF_INET6; 
     106    PJ_SOCKADDR_RESET_LEN(addr); 
     107 
     108    if (str_addr && str_addr->slen) { 
     109        status = pj_inet_pton(PJ_AF_INET6, str_addr, &addr->ipv6.sin6_addr); 
     110        if (status != PJ_SUCCESS) { 
     111            pj_addrinfo ai; 
     112            unsigned count = 1; 
     113 
     114            status = pj_getaddrinfo(PJ_AF_INET6, str_addr, &count, &ai); 
     115            if (status==PJ_SUCCESS) { 
     116                pj_memcpy(&addr->ipv6.sin6_addr, &ai.ai_addr.ipv6.sin6_addr, 
     117                          sizeof(pj_sockaddr_in6)); 
     118            } 
     119        } 
     120    } else { 
     121        status = PJ_SUCCESS; 
     122    } 
     123 
     124    return status; 
     125} 
     126 
     127/* 
     128 * Set the IP address and port of an IP socket address. 
     129 * The string address may be in a standard numbers and dots notation or  
     130 * may be a hostname. If hostname is specified, then the function will  
     131 * resolve the host into the IP address. 
     132 */ 
     133PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr, 
     134                                         const pj_str_t *str_addr, 
     135                                         pj_uint16_t port) 
     136{ 
     137    PJ_ASSERT_RETURN(addr, (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL)); 
     138 
     139    PJ_SOCKADDR_RESET_LEN(addr); 
     140    addr->sin_family = PJ_AF_INET; 
     141    pj_bzero(addr->sin_zero, sizeof(addr->sin_zero)); 
     142    pj_sockaddr_in_set_port(addr, port); 
     143    return pj_sockaddr_in_set_str_addr(addr, str_addr); 
     144} 
     145 
     146/* 
     147 * Initialize IP socket address based on the address and port info. 
     148 */ 
     149PJ_DEF(pj_status_t) pj_sockaddr_init(int af,  
     150                                     pj_sockaddr *addr, 
     151                                     const pj_str_t *cp, 
     152                                     pj_uint16_t port) 
     153{ 
     154    pj_status_t status; 
     155 
     156    if (af == PJ_AF_INET) { 
     157        return pj_sockaddr_in_init(&addr->ipv4, cp, port); 
     158    } 
     159 
     160    /* IPv6 specific */ 
     161    PJ_ASSERT_RETURN(af==PJ_AF_INET6, PJ_EAFNOTSUP); 
     162 
     163    pj_bzero(addr, sizeof(pj_sockaddr_in6)); 
     164    addr->addr.sa_family = PJ_AF_INET6; 
     165     
     166    status = pj_sockaddr_set_str_addr(af, addr, cp); 
     167    if (status != PJ_SUCCESS) 
     168        return status; 
     169 
     170    addr->ipv6.sin6_port = pj_htons(port); 
     171    return PJ_SUCCESS; 
     172} 
     173 
     174/* 
     175 * Get first IP address associated with the hostname. 
     176 */ 
     177PJ_DEF(pj_in_addr) pj_gethostaddr(void) 
     178{ 
     179    pj_sockaddr_in addr; 
     180    const pj_str_t *hostname = pj_gethostname(); 
     181 
     182    pj_sockaddr_in_set_str_addr(&addr, hostname); 
     183    return addr.sin_addr; 
     184} 
     185 
     186/* 
     187 * Get port number of a pj_sockaddr_in 
     188 */ 
     189PJ_DEF(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr) 
     190{ 
     191    return pj_ntohs(addr->sin_port); 
     192} 
     193 
     194/* 
     195 * Get the address part 
     196 */ 
     197PJ_DEF(void*) pj_sockaddr_get_addr(const pj_sockaddr_t *addr) 
     198{ 
     199    const pj_sockaddr *a = (const pj_sockaddr*)addr; 
     200 
     201    PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || 
     202                     a->addr.sa_family == PJ_AF_INET6, NULL); 
     203 
     204    if (a->addr.sa_family == PJ_AF_INET6) 
     205        return (void*) &a->ipv6.sin6_addr; 
     206    else 
     207        return (void*) &a->ipv4.sin_addr; 
     208} 
     209 
     210/* 
     211 * Check if sockaddr contains a non-zero address 
     212 */ 
     213PJ_DEF(pj_bool_t) pj_sockaddr_has_addr(const pj_sockaddr_t *addr) 
     214{ 
     215    const pj_sockaddr *a = (const pj_sockaddr*)addr; 
     216 
     217    PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || 
     218                     a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP); 
     219 
     220    if (a->addr.sa_family == PJ_AF_INET6) { 
     221        pj_uint8_t zero[24]; 
     222        pj_bzero(zero, sizeof(zero)); 
     223        return pj_memcmp(a->ipv6.sin6_addr.s6_addr, zero,  
     224                         sizeof(pj_in6_addr)) != 0; 
     225    } else 
     226        return a->ipv4.sin_addr.s_addr != PJ_INADDR_ANY; 
     227} 
     228 
     229/* 
     230 * Get port number 
     231 */ 
     232PJ_DEF(pj_uint16_t) pj_sockaddr_get_port(const pj_sockaddr_t *addr) 
     233{ 
     234    const pj_sockaddr *a = (const pj_sockaddr*) addr; 
     235 
     236    PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || 
     237                     a->addr.sa_family == PJ_AF_INET6, (pj_uint16_t)0xFFFF); 
     238 
     239    return pj_ntohs((pj_uint16_t)(a->addr.sa_family == PJ_AF_INET6 ? 
     240                                    a->ipv6.sin6_port : a->ipv4.sin_port)); 
     241} 
     242 
     243/* 
     244 * Get the length of the address part. 
     245 */ 
     246PJ_DEF(unsigned) pj_sockaddr_get_addr_len(const pj_sockaddr_t *addr) 
     247{ 
     248    const pj_sockaddr *a = (const pj_sockaddr*) addr; 
     249    PJ_ASSERT_RETURN(a->addr.sa_family == PJ_AF_INET || 
     250                     a->addr.sa_family == PJ_AF_INET6, PJ_EAFNOTSUP); 
     251    return a->addr.sa_family == PJ_AF_INET6 ? 
     252            sizeof(pj_in6_addr) : sizeof(pj_in_addr); 
     253} 
     254 
     255/* 
     256 * Set port number of pj_sockaddr_in 
     257 */ 
     258PJ_DEF(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr,  
     259                                     pj_uint16_t hostport) 
     260{ 
     261    addr->sin_port = pj_htons(hostport); 
     262} 
     263 
     264/* 
     265 * Set port number of pj_sockaddr 
     266 */ 
     267PJ_DEF(pj_status_t) pj_sockaddr_set_port(pj_sockaddr *addr,  
     268                                         pj_uint16_t hostport) 
     269{ 
     270    int af = addr->addr.sa_family; 
     271 
     272    PJ_ASSERT_ON_FAIL(af == PJ_AF_INET || af == PJ_AF_INET6,  
     273                      PJ_EINVAL); 
     274 
     275    if (af == PJ_AF_INET6) 
     276        addr->ipv6.sin6_port = pj_htons(hostport); 
     277    else 
     278        addr->ipv4.sin_port = pj_htons(hostport); 
     279 
     280    return PJ_SUCCESS; 
     281} 
     282 
     283/* 
     284 * Get IPv4 address 
     285 */ 
     286PJ_DEF(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr) 
     287{ 
     288    pj_in_addr in_addr; 
     289    in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr); 
     290    return in_addr; 
     291} 
     292 
     293/* 
     294 * Set IPv4 address 
     295 */ 
     296PJ_DEF(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr, 
     297                                     pj_uint32_t hostaddr) 
     298{ 
     299    addr->sin_addr.s_addr = pj_htonl(hostaddr); 
     300} 
     301 
     302/* Resolve the IP address of local machine */ 
     303PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr) 
     304{ 
     305    unsigned count; 
     306    pj_addrinfo ai; 
     307    pj_status_t status; 
     308 
     309 
     310#ifdef _MSC_VER 
     311    /* Get rid of "uninitialized he variable" with MS compilers */ 
     312    pj_bzero(&ai, sizeof(ai)); 
     313#endif 
     314 
     315    addr->addr.sa_family = (pj_uint16_t)af; 
     316    PJ_SOCKADDR_RESET_LEN(addr); 
     317 
     318    /* Try with resolving local hostname first */ 
     319    count = 1; 
     320    status = pj_getaddrinfo(af, pj_gethostname(), &count, &ai); 
     321    if (status == PJ_SUCCESS) { 
     322        pj_memcpy(pj_sockaddr_get_addr(addr), 
     323                  pj_sockaddr_get_addr(&ai.ai_addr), 
     324                  pj_sockaddr_get_addr_len(&ai.ai_addr)); 
     325    } 
     326 
     327 
     328    /* If we end up with 127.x.x.x, resolve the IP by getting the default 
     329     * interface to connect to some public host. 
     330     */ 
     331    if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(addr) || 
     332        (af==PJ_AF_INET && (pj_ntohl(addr->ipv4.sin_addr.s_addr) >> 24)==127)) 
     333    { 
     334        status = pj_getdefaultipinterface(af, addr); 
     335    } 
     336 
     337    /* If failed, get the first available interface */ 
     338    if (status != PJ_SUCCESS) { 
     339        pj_sockaddr itf[1]; 
     340        unsigned count = PJ_ARRAY_SIZE(itf); 
     341 
     342        status = pj_enum_ip_interface(af, &count, itf); 
     343        if (status == PJ_SUCCESS) { 
     344            itf[0].addr.sa_family = (pj_uint16_t)af; 
     345            pj_memcpy(pj_sockaddr_get_addr(addr), 
     346                      pj_sockaddr_get_addr(&itf[0]), 
     347                      pj_sockaddr_get_addr_len(&itf[0])); 
     348        } 
     349    } 
     350 
     351    /* If else fails, returns loopback interface as the last resort */ 
     352    if (status != PJ_SUCCESS) { 
     353        if (af==PJ_AF_INET) { 
     354            addr->ipv4.sin_addr.s_addr = pj_htonl (0x7f000001); 
     355        } else { 
     356            pj_in6_addr *s6_addr; 
     357 
     358            s6_addr = (pj_in6_addr*) pj_sockaddr_get_addr(addr); 
     359            pj_bzero(s6_addr, sizeof(pj_in6_addr)); 
     360            s6_addr->s6_addr[15] = 1; 
     361        } 
     362        status = PJ_SUCCESS; 
     363    } 
     364 
     365    return status; 
     366} 
     367 
     368/* Get the default IP interface */ 
     369PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr) 
     370{ 
     371    pj_sock_t fd; 
     372    pj_str_t cp; 
     373    pj_sockaddr a; 
     374    int len; 
     375    pj_uint8_t zero[64]; 
     376    pj_status_t status; 
     377 
     378    addr->addr.sa_family = (pj_uint16_t)af; 
     379 
     380    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd); 
     381    if (status != PJ_SUCCESS) { 
     382        return status; 
     383    } 
     384 
     385    if (af == PJ_AF_INET) { 
     386        cp = pj_str("1.1.1.1"); 
     387    } else { 
     388        cp = pj_str("1::1"); 
     389    } 
     390    status = pj_sockaddr_init(af, &a, &cp, 53); 
     391    if (status != PJ_SUCCESS) { 
     392        pj_sock_close(fd); 
     393        return status; 
     394    } 
     395 
     396    status = pj_sock_connect(fd, &a, sizeof(a)); 
     397    if (status != PJ_SUCCESS) { 
     398        pj_sock_close(fd); 
     399        return status; 
     400    } 
     401 
     402    len = sizeof(a); 
     403    status = pj_sock_getsockname(fd, &a, &len); 
     404    if (status != PJ_SUCCESS) { 
     405        pj_sock_close(fd); 
     406        return status; 
     407    } 
     408 
     409    pj_sock_close(fd); 
     410 
     411    /* Check that the address returned is not zero */ 
     412    pj_bzero(zero, sizeof(zero)); 
     413    if (pj_memcmp(pj_sockaddr_get_addr(&a), zero, 
     414                  pj_sockaddr_get_addr_len(&a))==0) 
     415    { 
     416        return PJ_ENOTFOUND; 
     417    } 
     418 
     419    pj_memcpy(pj_sockaddr_get_addr(addr), 
     420              pj_sockaddr_get_addr(&a), 
     421              pj_sockaddr_get_addr_len(&a)); 
     422 
     423    /* Success */ 
     424    return PJ_SUCCESS; 
     425} 
     426 
     427 
     428/* Only need to implement these in DLL build */ 
     429#if defined(PJ_DLL) 
    20430 
    21431PJ_DEF(pj_uint16_t) pj_AF_UNSPEC(void) 
     
    149559} 
    150560 
     561#endif  /* PJ_DLL */ 
     562 
Note: See TracChangeset for help on using the changeset viewer.