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

Ticket #935: new pj_sockaddr_parse2() API

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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 
Note: See TracChangeset for help on using the changeset viewer.