Changeset 2863


Ignore:
Timestamp:
Aug 12, 2009 10:56:06 AM (10 years ago)
Author:
bennylp
Message:

Ticket #935: new pj_sockaddr_parse2() API

Location:
pjproject/trunk/pjlib
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib/include/pj/sock.h

    r2743 r2863  
    980980 * @param af        Optionally specify the address family to be used. If the 
    981981 *                  address family is to be deducted from the input, specify 
    982  *                  pj_AF_UNSPEC() here. 
     982 *                  pj_AF_UNSPEC() here. Other supported values are 
     983 *                  #pj_AF_INET() and #pj_AF_INET6() 
    983984 * @param options   Additional options to assist the parsing, must be zero 
    984985 *                  for now. 
     
    987988 * 
    988989 * @return          PJ_SUCCESS if the parsing is successful. 
     990 * 
     991 * @see pj_sockaddr_parse2() 
    989992 */ 
    990993PJ_DECL(pj_status_t) pj_sockaddr_parse(int af, unsigned options, 
    991994                                       const pj_str_t *str, 
    992995                                       pj_sockaddr *addr); 
     996 
     997/** 
     998 * This function is similar to #pj_sockaddr_parse(), except that it will not 
     999 * convert the hostpart into IP address (thus possibly resolving the hostname 
     1000 * into a #pj_sockaddr.  
     1001 * 
     1002 * Unlike #pj_sockaddr_parse(), this function has a limitation that if port  
     1003 * number is specified in an IPv6 input string, the IP part of the IPv6 socket 
     1004 * address MUST be enclosed in square brackets, otherwise the port number will 
     1005 * be considered as part of the IPv6 IP address. 
     1006 * 
     1007 * @param af        Optionally specify the address family to be used. If the 
     1008 *                  address family is to be deducted from the input, specify 
     1009 *                  #pj_AF_UNSPEC() here. Other supported values are 
     1010 *                  #pj_AF_INET() and #pj_AF_INET6() 
     1011 * @param options   Additional options to assist the parsing, must be zero 
     1012 *                  for now. 
     1013 * @param str       The input string to be parsed. 
     1014 * @param hostpart  Optional pointer to store the host part of the socket  
     1015 *                  address, with any brackets removed. 
     1016 * @param port      Optional pointer to store the port number. If port number 
     1017 *                  is not found, this will be set to zero upon return. 
     1018 * @param raf       Optional pointer to store the detected address family of 
     1019 *                  the input address. 
     1020 * 
     1021 * @return          PJ_SUCCESS if the parsing is successful. 
     1022 * 
     1023 * @see pj_sockaddr_parse() 
     1024 */ 
     1025PJ_DECL(pj_status_t) pj_sockaddr_parse2(int af, unsigned options, 
     1026                                        const pj_str_t *str, 
     1027                                        pj_str_t *hostpart, 
     1028                                        pj_uint16_t *port, 
     1029                                        int *raf); 
    9931030 
    9941031/***************************************************************************** 
  • pjproject/trunk/pjlib/src/pj/sock_common.c

    r2743 r2863  
    459459 * Parse address 
    460460 */ 
    461 PJ_DEF(pj_status_t) pj_sockaddr_parse( int af, unsigned options, 
     461PJ_DEF(pj_status_t) pj_sockaddr_parse2(int af, unsigned options, 
    462462                                       const pj_str_t *str, 
    463                                        pj_sockaddr *addr) 
     463                                       pj_str_t *p_hostpart, 
     464                                       pj_uint16_t *p_port, 
     465                                       int *raf) 
    464466{ 
    465467    const char *end = str->ptr + str->slen; 
    466468    const char *last_colon_pos = NULL; 
    467  
    468     PJ_ASSERT_RETURN(addr, PJ_EINVAL); 
    469     PJ_ASSERT_RETURN(af==PJ_AF_UNSPEC || 
    470                      af==PJ_AF_INET || 
    471                      af==PJ_AF_INET6, PJ_EINVAL); 
    472     PJ_ASSERT_RETURN(options == 0, PJ_EINVAL); 
     469    unsigned colon_cnt = 0; 
     470    const char *p; 
     471 
     472    PJ_ASSERT_RETURN((af==PJ_AF_INET || af==PJ_AF_INET6 || af==PJ_AF_UNSPEC) && 
     473                     options==0 && 
     474                     str!=NULL, PJ_EINVAL); 
     475 
     476    /* Special handling for empty input */ 
     477    if (str->slen==0 || str->ptr==NULL) { 
     478        if (p_hostpart) 
     479            p_hostpart->slen = 0; 
     480        if (p_port) 
     481            *p_port = 0; 
     482        if (*raf) 
     483            *raf = PJ_AF_INET; 
     484        return PJ_SUCCESS; 
     485    } 
     486 
     487    /* Count the colon and get the last colon */ 
     488    for (p=str->ptr; p!=end; ++p) { 
     489        if (*p == ':') { 
     490            ++colon_cnt; 
     491            last_colon_pos = p; 
     492        } 
     493    } 
    473494 
    474495    /* Deduce address family if it's not given */ 
    475496    if (af == PJ_AF_UNSPEC) { 
    476         unsigned colon_cnt = 0; 
    477         const char *p; 
    478  
    479         /* Can't accept NULL or empty input if address family is unknown */ 
    480         PJ_ASSERT_RETURN(str && str->slen, PJ_EINVAL); 
    481  
    482         for (p=str->ptr; p!=end; ++p) { 
    483             if (*p == ':') { 
    484                 ++colon_cnt; 
    485                 last_colon_pos = p; 
    486             } 
    487         } 
    488  
    489497        if (colon_cnt > 1) 
    490498            af = PJ_AF_INET6; 
    491499        else 
    492500            af = PJ_AF_INET; 
    493     } else { 
    494         /* Input may be NULL or empty as long as address family is given */ 
    495         if (str == NULL || str->slen == 0) 
    496             return pj_sockaddr_init(af, addr, NULL, 0); 
    497     } 
     501    } else if (af == PJ_AF_INET && colon_cnt > 1) 
     502        return PJ_EINVAL; 
     503 
     504    if (raf) 
     505        *raf = af; 
    498506 
    499507    if (af == PJ_AF_INET) { 
     
    505513         *  - ":" 
    506514         */ 
    507         pj_str_t ip_part; 
     515        pj_str_t hostpart; 
    508516        unsigned long port; 
    509517 
    510         if (last_colon_pos == NULL) 
    511             last_colon_pos = pj_strchr(str, ':'); 
    512          
    513         ip_part.ptr = (char*)str->ptr; 
     518        hostpart.ptr = (char*)str->ptr; 
    514519 
    515520        if (last_colon_pos) { 
     
    517522            int i; 
    518523 
    519             ip_part.slen = last_colon_pos - str->ptr; 
     524            hostpart.slen = last_colon_pos - str->ptr; 
    520525 
    521526            port_part.ptr = (char*)last_colon_pos + 1; 
     
    531536                return PJ_EINVAL; 
    532537        } else { 
    533             ip_part.slen = str->slen; 
     538            hostpart.slen = str->slen; 
    534539            port = 0; 
    535540        } 
    536541 
    537         return pj_sockaddr_in_init(&addr->ipv4, &ip_part, (pj_uint16_t)port); 
    538     } 
    539 #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6 
    540     else if (af == PJ_AF_INET6) { 
    541         /* Parse as IPv4. Supported formats: 
     542        if (p_hostpart) 
     543            *p_hostpart = hostpart; 
     544        if (p_port) 
     545            *p_port = (pj_uint16_t)port; 
     546 
     547        return PJ_SUCCESS; 
     548 
     549    } else if (af == PJ_AF_INET6) { 
     550 
     551        /* Parse as IPv6. Supported formats: 
    542552         *  - "fe::01:80"  ==> note: port number is zero in this case, not 80! 
    543553         *  - "[fe::01]:80" 
     
    553563         *  - "::" 
    554564         */ 
    555         pj_str_t ip_part, port_part; 
     565        pj_str_t hostpart, port_part; 
    556566 
    557567        if (*str->ptr == '[') { 
    558             char *end_bracket = pj_strchr(str, ']'); 
     568            char *end_bracket; 
    559569            int i; 
    560570            unsigned long port; 
    561571 
     572            if (last_colon_pos == NULL) 
     573                return PJ_EINVAL; 
     574 
     575            end_bracket = pj_strchr(str, ']'); 
    562576            if (end_bracket == NULL) 
    563577                return PJ_EINVAL; 
    564578 
    565             ip_part.ptr = (char*)str->ptr + 1; 
    566             ip_part.slen = end_bracket - ip_part.ptr; 
    567  
    568             if (last_colon_pos == NULL) { 
    569                 const char *p; 
    570                 for (p=str->ptr; p!=end; ++p) { 
    571                     if (*p == ':') 
    572                         last_colon_pos = p; 
    573                 } 
    574             } 
    575  
    576             if (last_colon_pos == NULL) 
    577                 return PJ_EINVAL; 
     579            hostpart.ptr = (char*)str->ptr + 1; 
     580            hostpart.slen = end_bracket - hostpart.ptr; 
    578581 
    579582            if (last_colon_pos < end_bracket) { 
     
    594597                return PJ_EINVAL; 
    595598 
    596             return pj_sockaddr_init(PJ_AF_INET6, addr, &ip_part,  
    597                                     (pj_uint16_t)port); 
     599            if (p_hostpart) 
     600                *p_hostpart = hostpart; 
     601            if (p_port) 
     602                *p_port = (pj_uint16_t)port; 
     603 
     604            return PJ_SUCCESS; 
     605 
    598606        } else { 
    599             int i; 
    600             unsigned long port; 
    601  
    602             /* First lets try to parse everything as IPv6 address */ 
    603             if (pj_sockaddr_init(PJ_AF_INET6, addr, str, 0)==PJ_SUCCESS) 
    604                 return PJ_SUCCESS; 
    605  
    606             /* Parse as IPv6:port */ 
    607             if (last_colon_pos == NULL) { 
    608                 const char *p; 
    609                 for (p=str->ptr; p!=end; ++p) { 
    610                     if (*p == ':') 
    611                         last_colon_pos = p; 
    612                 } 
    613             } 
    614  
    615             if (last_colon_pos == NULL) 
    616                 return PJ_EINVAL; 
    617  
    618             ip_part.ptr = (char*)str->ptr; 
    619             ip_part.slen = last_colon_pos - str->ptr; 
    620  
    621             port_part.ptr = (char*)last_colon_pos + 1; 
    622             port_part.slen = end - port_part.ptr; 
    623  
    624             /* Make sure port number is valid */ 
    625             for (i=0; i<port_part.slen; ++i) { 
    626                 if (!pj_isdigit(port_part.ptr[i])) 
    627                     return PJ_EINVAL; 
    628             } 
    629             port = pj_strtoul(&port_part); 
    630             if (port > 65535) 
    631                 return PJ_EINVAL; 
    632  
    633             return pj_sockaddr_init(PJ_AF_INET6, addr, &ip_part,  
    634                                     (pj_uint16_t)port); 
     607            /* Treat everything as part of the IPv6 IP address */ 
     608            if (p_hostpart) 
     609                *p_hostpart = *str; 
     610            if (p_port) 
     611                *p_port = 0; 
     612 
     613            return PJ_SUCCESS; 
    635614        } 
     615 
     616    } else { 
     617        return PJ_EAFNOTSUP; 
     618    } 
     619 
     620} 
     621 
     622/* 
     623 * Parse address 
     624 */ 
     625PJ_DEF(pj_status_t) pj_sockaddr_parse( int af, unsigned options, 
     626                                       const pj_str_t *str, 
     627                                       pj_sockaddr *addr) 
     628{ 
     629    pj_str_t hostpart; 
     630    pj_uint16_t port; 
     631    pj_status_t status; 
     632 
     633    PJ_ASSERT_RETURN(addr, PJ_EINVAL); 
     634    PJ_ASSERT_RETURN(af==PJ_AF_UNSPEC || 
     635                     af==PJ_AF_INET || 
     636                     af==PJ_AF_INET6, PJ_EINVAL); 
     637    PJ_ASSERT_RETURN(options == 0, PJ_EINVAL); 
     638 
     639    status = pj_sockaddr_parse2(af, options, str, &hostpart, &port, &af); 
     640    if (status != PJ_SUCCESS) 
     641        return status; 
     642     
     643    status = pj_sockaddr_init(af, addr, &hostpart, port); 
     644#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6 
     645    if (status != PJ_SUCCESS && af == PJ_AF_INET6) { 
     646        /* Parsing does not yield valid address. Try to treat the last  
     647         * portion after the colon as port number. 
     648         */ 
     649        const char *last_colon_pos=NULL, *p; 
     650        const char *end = str->ptr + str->slen; 
     651        unsigned long long_port; 
     652        pj_str_t port_part; 
     653        int i; 
     654 
     655        /* Parse as IPv6:port */ 
     656        for (p=str->ptr; p!=end; ++p) { 
     657            if (*p == ':') 
     658                last_colon_pos = p; 
     659        } 
     660 
     661        if (last_colon_pos == NULL) 
     662            return status; 
     663 
     664        hostpart.ptr = (char*)str->ptr; 
     665        hostpart.slen = last_colon_pos - str->ptr; 
     666 
     667        port_part.ptr = (char*)last_colon_pos + 1; 
     668        port_part.slen = end - port_part.ptr; 
     669 
     670        /* Make sure port number is valid */ 
     671        for (i=0; i<port_part.slen; ++i) { 
     672            if (!pj_isdigit(port_part.ptr[i])) 
     673                return status; 
     674        } 
     675        long_port = pj_strtoul(&port_part); 
     676        if (long_port > 65535) 
     677            return status; 
     678 
     679        port = (pj_uint16_t)long_port; 
     680 
     681        status = pj_sockaddr_init(PJ_AF_INET6, addr, &hostpart, port); 
    636682    } 
    637683#endif 
    638     else { 
    639         return PJ_EIPV6NOTSUP; 
    640     } 
     684     
     685    return status; 
    641686} 
    642687 
  • pjproject/trunk/pjlib/src/pjlib-test/sock.c

    r2770 r2863  
    220220        { "10.0.0.1:123456", IPv4}, /* port too big     */ 
    221221        { "1.2.3.4.5:80", IPv4},    /* invalid IP */ 
     222        { "10:0:80", IPv4},         /* hostname has colon */ 
    222223 
    223224#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6 
Note: See TracChangeset for help on using the changeset viewer.