Ignore:
Timestamp:
Sep 15, 2017 5:32:08 AM (7 years ago)
Author:
riza
Message:

Re #2041: Implement API to handle IP address change.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c

    r5534 r5649  
    6262    pj_qos_params            qos_params; 
    6363    pj_sockopt_params        sockopt_params; 
     64    pj_bool_t                reuse_addr;         
     65    unsigned                 async_cnt;     
    6466 
    6567    /* Group lock to be used by TCP listener and ioqueue key */ 
     
    242244 */ 
    243245 
     246static void update_bound_addr(struct tcp_listener *listener, 
     247                              const pj_sockaddr *local) 
     248{ 
     249    pj_sockaddr *listener_addr = &listener->factory.local_addr; 
     250    int af = pjsip_transport_type_get_af(listener->factory.type); 
     251 
     252    /* Bind address may be different than factory.local_addr because 
     253     * factory.local_addr will be resolved. 
     254     */ 
     255    if (local) { 
     256        pj_sockaddr_cp(&listener->bound_addr, local); 
     257    } 
     258    else { 
     259        pj_sockaddr_init(af, &listener->bound_addr, NULL, 0); 
     260    } 
     261    pj_sockaddr_cp(listener_addr, &listener->bound_addr); 
     262} 
     263 
     264static pj_status_t update_factory_addr(struct tcp_listener *listener,                                   
     265                                       const pjsip_host_port *addr_name) 
     266{ 
     267    pj_status_t status = PJ_SUCCESS;     
     268    pj_sockaddr *listener_addr = &listener->factory.local_addr;     
     269 
     270    /* If published host/IP is specified, then use that address as the 
     271     * listener advertised address. 
     272     */ 
     273    if (addr_name && addr_name->host.slen) { 
     274        pj_sockaddr tmp; 
     275        int af = pjsip_transport_type_get_af(listener->factory.type); 
     276 
     277        /* Verify that address given in a_name (if any) is valid */ 
     278        status = pj_sockaddr_init(af, &tmp, &addr_name->host, 
     279                                  (pj_uint16_t)addr_name->port); 
     280        if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) || 
     281            (af == pj_AF_INET() && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE)) 
     282        { 
     283            /* Invalid address */ 
     284            return PJ_EINVAL; 
     285        } 
     286 
     287        /* Copy the address */ 
     288        listener->factory.addr_name = *addr_name; 
     289        pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, 
     290                  &addr_name->host); 
     291        listener->factory.addr_name.port = addr_name->port; 
     292 
     293    } else { 
     294        /* No published address is given, use the bound address */ 
     295 
     296        /* If the address returns 0.0.0.0, use the default 
     297         * interface address as the transport's address. 
     298         */ 
     299        if (!pj_sockaddr_has_addr(listener_addr)) { 
     300            pj_sockaddr hostip; 
     301 
     302            status = pj_gethostip(listener->bound_addr.addr.sa_family, 
     303                                  &hostip); 
     304            if (status != PJ_SUCCESS) 
     305                return status; 
     306 
     307            pj_sockaddr_copy_addr(listener_addr, &hostip); 
     308        } 
     309 
     310        /* Save the address name */ 
     311        sockaddr_to_host_port(listener->factory.pool, 
     312                              &listener->factory.addr_name, 
     313                              listener_addr); 
     314    } 
     315 
     316    /* If port is zero, get the bound port */ 
     317    if (listener->factory.addr_name.port == 0) { 
     318        listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr); 
     319    } 
     320 
     321    pj_ansi_snprintf(listener->factory.obj_name, 
     322                     sizeof(listener->factory.obj_name), 
     323                     "tcptp:%d", listener->factory.addr_name.port); 
     324    return status; 
     325} 
     326 
     327static void update_transport_info(struct tcp_listener *listener) 
     328{     
     329    enum { INFO_LEN = 100 }; 
     330    char local_addr[PJ_INET6_ADDRSTRLEN + 10]; 
     331    pj_sockaddr *listener_addr = &listener->factory.local_addr; 
     332 
     333    /* Set transport info. */ 
     334    if (listener->factory.info == NULL) { 
     335        listener->factory.info = (char*)pj_pool_alloc(listener->factory.pool, 
     336                                                      INFO_LEN); 
     337    } 
     338    pj_sockaddr_print(listener_addr, local_addr, sizeof(local_addr), 3); 
     339    pj_ansi_snprintf( 
     340            listener->factory.info, INFO_LEN, "tcp %s [published as %.*s:%d]", 
     341            local_addr, 
     342            (int)listener->factory.addr_name.host.slen, 
     343            listener->factory.addr_name.host.ptr, 
     344            listener->factory.addr_name.port); 
     345 
     346    if (listener->asock) { 
     347        PJ_LOG(4, (listener->factory.obj_name, 
     348               "SIP TCP listener ready for incoming connections at %.*s:%d", 
     349               (int)listener->factory.addr_name.host.slen, 
     350               listener->factory.addr_name.host.ptr, 
     351               listener->factory.addr_name.port)); 
     352    } else { 
     353        PJ_LOG(4, (listener->factory.obj_name, "SIP TCP is ready " 
     354               "(client only)")); 
     355    } 
     356} 
     357 
    244358/* 
    245359 * This is the public API to create, initialize, register, and start the 
     
    251365                                        pjsip_tpfactory **p_factory 
    252366                                        ) 
    253 { 
    254     enum { INFO_LEN = 100 }; 
    255     char local_addr[PJ_INET6_ADDRSTRLEN+10]; 
    256     pj_pool_t *pool; 
    257     pj_sock_t sock = PJ_INVALID_SOCKET; 
    258     struct tcp_listener *listener; 
    259     pj_activesock_cfg asock_cfg; 
    260     pj_activesock_cb listener_cb; 
    261     pj_sockaddr *listener_addr; 
    262     int addr_len; 
    263     pj_bool_t has_listener = PJ_FALSE; 
     367{         
     368    pj_pool_t *pool;     
     369    struct tcp_listener *listener;         
    264370    pj_status_t status; 
    265371 
    266372    /* Sanity check */ 
    267373    PJ_ASSERT_RETURN(endpt && cfg->async_cnt, PJ_EINVAL); 
    268  
    269     /* Verify that address given in a_name (if any) is valid */ 
    270     if (cfg->addr_name.host.slen) { 
    271         pj_sockaddr tmp; 
    272  
    273         status = pj_sockaddr_init(cfg->af, &tmp, &cfg->addr_name.host,  
    274                                   (pj_uint16_t)cfg->addr_name.port); 
    275         if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) || 
    276             (cfg->af==pj_AF_INET() &&  
    277              tmp.ipv4.sin_addr.s_addr==PJ_INADDR_NONE))  
    278         { 
    279             /* Invalid address */ 
    280             return PJ_EINVAL; 
    281         } 
    282     } 
    283374 
    284375    pool = pjsip_endpt_create_pool(endpt, "tcptp", POOL_LIS_INIT,  
     
    292383                                                     PJSIP_TRANSPORT_TCP6; 
    293384    listener->factory.type_name = (char*) 
    294                 pjsip_transport_get_type_name(listener->factory.type); 
     385                         pjsip_transport_get_type_name(listener->factory.type); 
    295386    listener->factory.flag =  
    296         pjsip_transport_get_flag_from_type(listener->factory.type); 
     387                    pjsip_transport_get_flag_from_type(listener->factory.type); 
    297388    listener->qos_type = cfg->qos_type; 
     389    listener->reuse_addr = cfg->reuse_addr; 
     390    listener->async_cnt = cfg->async_cnt; 
    298391    pj_memcpy(&listener->qos_params, &cfg->qos_params, 
    299392              sizeof(cfg->qos_params)); 
     
    308401                                            &listener->factory.lock); 
    309402    if (status != PJ_SUCCESS) 
    310         goto on_error; 
    311  
    312 #if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \ 
    313       PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0) 
    314  
    315     /* Create socket */ 
    316     status = pj_sock_socket(cfg->af, pj_SOCK_STREAM(), 0, &sock); 
    317     if (status != PJ_SUCCESS) 
    318         goto on_error; 
    319  
    320     /* Apply QoS, if specified */ 
    321     status = pj_sock_apply_qos2(sock, cfg->qos_type, &cfg->qos_params,  
    322                                 2, listener->factory.obj_name,  
    323                                 "SIP TCP listener socket"); 
    324  
    325     /* Apply SO_REUSEADDR */ 
    326     if (cfg->reuse_addr) { 
    327         int enabled = 1; 
    328         status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(), 
    329                                     &enabled, sizeof(enabled)); 
    330         if (status != PJ_SUCCESS) { 
    331             PJ_PERROR(4,(listener->factory.obj_name, status, 
    332                          "Warning: error applying SO_REUSEADDR")); 
    333         } 
    334     } 
    335  
    336     /* Apply socket options, if specified */ 
    337     if (cfg->sockopt_params.cnt) 
    338         status = pj_sock_setsockopt_params(sock, &cfg->sockopt_params); 
    339  
    340 #else 
    341     PJ_UNUSED_ARG(addr_len); 
    342 #endif 
    343  
    344     /* Bind address may be different than factory.local_addr because 
    345      * factory.local_addr will be resolved below. 
    346      */ 
    347     pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr); 
    348  
    349     /* Bind socket */ 
    350     listener_addr = &listener->factory.local_addr; 
    351     pj_sockaddr_cp(listener_addr, &cfg->bind_addr); 
    352  
    353 #if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \ 
    354       PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0) 
    355  
    356     status = pj_sock_bind(sock, listener_addr,  
    357                           pj_sockaddr_get_len(listener_addr)); 
    358     if (status != PJ_SUCCESS) 
    359         goto on_error; 
    360  
    361     /* Retrieve the bound address */ 
    362     addr_len = pj_sockaddr_get_len(listener_addr); 
    363     status = pj_sock_getsockname(sock, listener_addr, &addr_len); 
    364     if (status != PJ_SUCCESS) 
    365         goto on_error; 
    366  
    367 #endif 
    368  
    369     /* If published host/IP is specified, then use that address as the 
    370      * listener advertised address. 
    371      */ 
    372     if (cfg->addr_name.host.slen) { 
    373         /* Copy the address */ 
    374         listener->factory.addr_name = cfg->addr_name; 
    375         pj_strdup(listener->factory.pool, &listener->factory.addr_name.host,  
    376                   &cfg->addr_name.host); 
    377         listener->factory.addr_name.port = cfg->addr_name.port; 
    378  
    379     } else { 
    380         /* No published address is given, use the bound address */ 
    381  
    382         /* If the address returns 0.0.0.0, use the default 
    383          * interface address as the transport's address. 
    384          */ 
    385         if (!pj_sockaddr_has_addr(listener_addr)) { 
    386             pj_sockaddr hostip; 
    387  
    388             status = pj_gethostip(listener->bound_addr.addr.sa_family, 
    389                                   &hostip); 
    390             if (status != PJ_SUCCESS) 
    391                 goto on_error; 
    392  
    393             pj_sockaddr_copy_addr(listener_addr, &hostip); 
    394         } 
    395  
    396         /* Save the address name */ 
    397         sockaddr_to_host_port(listener->factory.pool,  
    398                               &listener->factory.addr_name,  
    399                               listener_addr); 
    400     } 
    401  
    402     /* If port is zero, get the bound port */ 
    403     if (listener->factory.addr_name.port == 0) { 
    404         listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr); 
    405     } 
    406  
    407     pj_ansi_snprintf(listener->factory.obj_name,  
    408                      sizeof(listener->factory.obj_name), 
    409                      "tcptp:%d",  listener->factory.addr_name.port); 
    410  
    411  
    412 #if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \ 
    413       PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0) 
    414  
    415     /* Start listening to the address */ 
    416     status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG); 
    417     if (status != PJ_SUCCESS) 
    418         goto on_error; 
    419  
    420  
    421     /* Create active socket */ 
    422     pj_activesock_cfg_default(&asock_cfg); 
    423     if (cfg->async_cnt > MAX_ASYNC_CNT)  
    424         asock_cfg.async_cnt = MAX_ASYNC_CNT; 
    425     else 
    426         asock_cfg.async_cnt = cfg->async_cnt; 
    427  
    428 #endif 
     403        goto on_error;     
    429404 
    430405    /* Create group lock */ 
    431406    status = pj_grp_lock_create(pool, NULL, &listener->grp_lock); 
    432407    if (status != PJ_SUCCESS) 
    433         return status; 
     408        goto on_error; 
    434409 
    435410    pj_grp_lock_add_ref(listener->grp_lock); 
    436411    pj_grp_lock_add_handler(listener->grp_lock, pool, listener, 
    437412                            &lis_on_destroy); 
    438  
    439     asock_cfg.grp_lock = listener->grp_lock; 
    440  
    441     pj_bzero(&listener_cb, sizeof(listener_cb)); 
    442     listener_cb.on_accept_complete = &on_accept_complete; 
    443  
    444 #if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \ 
    445       PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0) 
    446  
    447     status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), &asock_cfg, 
    448                                   pjsip_endpt_get_ioqueue(endpt),  
    449                                   &listener_cb, listener, 
    450                                   &listener->asock); 
    451  
    452 #endif 
    453413 
    454414    /* Register to transport manager */ 
     
    456416    listener->tpmgr = pjsip_endpt_get_tpmgr(endpt); 
    457417    listener->factory.create_transport = lis_create_transport; 
    458     listener->factory.destroy = lis_destroy; 
     418    listener->factory.destroy = lis_destroy;     
     419 
     420#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \ 
     421              PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0) 
     422    /* Start listener. */ 
     423    status = pjsip_tcp_transport_lis_start(&listener->factory, &cfg->bind_addr,  
     424                                           &cfg->addr_name); 
     425    if (status != PJ_SUCCESS) 
     426        goto on_error; 
     427 
     428#else 
     429    update_bound_addr(listener, &cfg->bind_addr); 
     430    status = update_factory_addr(listener, &cfg->addr_name); 
     431    if (status != PJ_SUCCESS) 
     432        goto on_error; 
     433 
     434    /* Set transport info. */ 
     435    update_transport_info(listener); 
     436#endif 
     437 
    459438    listener->is_registered = PJ_TRUE; 
    460439    status = pjsip_tpmgr_register_tpfactory(listener->tpmgr, 
     
    465444    } 
    466445 
    467 #if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \ 
    468       PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0) 
    469  
    470     /* Start pending accept() operations */ 
    471     status = pj_activesock_start_accept(listener->asock, pool); 
    472     if (status != PJ_SUCCESS) 
    473         goto on_error; 
    474          
    475     has_listener = PJ_TRUE; 
    476  
    477 #endif 
    478  
    479     /* Set transport info. */ 
    480     if (listener->factory.info == NULL) { 
    481         listener->factory.info = (char*) pj_pool_alloc(listener->factory.pool, 
    482                                                        INFO_LEN); 
    483     } 
    484     pj_sockaddr_print(listener_addr, local_addr, sizeof(local_addr), 3); 
    485     pj_ansi_snprintf(  
    486         listener->factory.info, INFO_LEN, "tcp %s [published as %.*s:%d]", 
    487         local_addr, 
    488         (int)listener->factory.addr_name.host.slen, 
    489         listener->factory.addr_name.host.ptr, 
    490         listener->factory.addr_name.port); 
    491  
    492     if (has_listener) { 
    493         PJ_LOG(4,(listener->factory.obj_name,  
    494                  "SIP TCP listener ready for incoming connections at %.*s:%d", 
    495                  (int)listener->factory.addr_name.host.slen, 
    496                  listener->factory.addr_name.host.ptr, 
    497                  listener->factory.addr_name.port)); 
    498     } else { 
    499         PJ_LOG(4,(listener->factory.obj_name, "SIP TCP is ready " 
    500                   "(client only)"));     
    501     } 
    502  
    503446    /* Return the pointer to user */ 
    504447    if (p_factory) *p_factory = &listener->factory; 
     
    507450 
    508451on_error: 
    509     if (listener->asock==NULL && sock!=PJ_INVALID_SOCKET) 
    510         pj_sock_close(sock); 
    511452    lis_destroy(&listener->factory); 
    512453    return status; 
     
    572513} 
    573514 
    574  
    575 /* This callback is called by transport manager to destroy listener */ 
    576 static pj_status_t lis_destroy(pjsip_tpfactory *factory) 
    577 { 
    578     struct tcp_listener *listener = (struct tcp_listener *)factory; 
    579  
     515/* This will close the listener. */ 
     516static void lis_close(struct tcp_listener *listener) 
     517{ 
    580518    if (listener->is_registered) { 
    581519        pjsip_tpmgr_unregister_tpfactory(listener->tpmgr, &listener->factory); 
     
    587525        listener->asock = NULL; 
    588526    } 
     527} 
     528 
     529/* This callback is called by transport manager to destroy listener */ 
     530static pj_status_t lis_destroy(pjsip_tpfactory *factory) 
     531{ 
     532    struct tcp_listener *listener = (struct tcp_listener *)factory; 
     533 
     534    lis_close(listener); 
    589535 
    590536    if (listener->grp_lock) { 
     
    16381584 
    16391585 
     1586PJ_DEF(pj_status_t) pjsip_tcp_transport_lis_start(pjsip_tpfactory *factory, 
     1587                                                 const pj_sockaddr *local, 
     1588                                                 const pjsip_host_port *a_name) 
     1589{ 
     1590    pj_activesock_cfg asock_cfg; 
     1591    pj_activesock_cb listener_cb; 
     1592    pj_sock_t sock = PJ_INVALID_SOCKET; 
     1593    int addr_len, af;     
     1594    struct tcp_listener *listener = (struct tcp_listener *)factory; 
     1595    pj_sockaddr *listener_addr = &factory->local_addr; 
     1596    pj_status_t status = PJ_SUCCESS; 
     1597 
     1598    /* Nothing to be done, if listener already started. */ 
     1599    if (listener->asock) 
     1600        return PJ_SUCCESS; 
     1601     
     1602    update_bound_addr(listener, local); 
     1603       
     1604    addr_len = pj_sockaddr_get_len(listener_addr); 
     1605    af = pjsip_transport_type_get_af(listener->factory.type); 
     1606 
     1607    /* Create socket */ 
     1608    status = pj_sock_socket(af, pj_SOCK_STREAM(), 0, &sock); 
     1609    if (status != PJ_SUCCESS) 
     1610        goto on_error; 
     1611 
     1612    /* Apply QoS, if specified */ 
     1613    status = pj_sock_apply_qos2(sock, listener->qos_type, 
     1614                                &listener->qos_params, 2, 
     1615                                listener->factory.obj_name, 
     1616                                "SIP TCP listener socket"); 
     1617 
     1618    /* Apply SO_REUSEADDR */ 
     1619    if (listener->reuse_addr) { 
     1620        int enabled = 1; 
     1621        status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(), 
     1622                                    &enabled, sizeof(enabled)); 
     1623        if (status != PJ_SUCCESS) { 
     1624            PJ_LOG(1, ("TRACE", "fail set reuseaddr")); 
     1625            PJ_PERROR(4, (listener->factory.obj_name, status, 
     1626                "Warning: error applying SO_REUSEADDR")); 
     1627        } 
     1628    } 
     1629 
     1630    /* Apply socket options, if specified */ 
     1631    if (listener->sockopt_params.cnt) 
     1632        status = pj_sock_setsockopt_params(sock, &listener->sockopt_params); 
     1633 
     1634    status = pj_sock_bind(sock, listener_addr, addr_len); 
     1635    if (status != PJ_SUCCESS) 
     1636        goto on_error; 
     1637 
     1638    /* Retrieve the bound address */ 
     1639    status = pj_sock_getsockname(sock, &listener->factory.local_addr,  
     1640                                 &addr_len); 
     1641    if (status != PJ_SUCCESS) 
     1642        goto on_error; 
     1643 
     1644    status = update_factory_addr(listener, a_name); 
     1645    if (status != PJ_SUCCESS) 
     1646        goto on_error; 
     1647 
     1648    /* Start listening to the address */ 
     1649    status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG); 
     1650    if (status != PJ_SUCCESS) 
     1651        goto on_error; 
     1652 
     1653 
     1654    /* Create active socket */ 
     1655    pj_activesock_cfg_default(&asock_cfg); 
     1656    if (listener->async_cnt > MAX_ASYNC_CNT) 
     1657        asock_cfg.async_cnt = MAX_ASYNC_CNT; 
     1658    else 
     1659        asock_cfg.async_cnt = listener->async_cnt; 
     1660 
     1661    asock_cfg.grp_lock = listener->grp_lock; 
     1662    pj_bzero(&listener_cb, sizeof(listener_cb)); 
     1663    listener_cb.on_accept_complete = &on_accept_complete; 
     1664 
     1665    status = pj_activesock_create(listener->factory.pool, sock, 
     1666                                  pj_SOCK_STREAM(), &asock_cfg, 
     1667                                  pjsip_endpt_get_ioqueue(listener->endpt), 
     1668                                  &listener_cb, listener, 
     1669                                  &listener->asock); 
     1670 
     1671    /* Start pending accept() operations */ 
     1672    status = pj_activesock_start_accept(listener->asock, 
     1673                                        listener->factory.pool); 
     1674 
     1675    update_transport_info(listener); 
     1676 
     1677    return status; 
     1678 
     1679on_error: 
     1680    if (listener->asock == NULL && sock != PJ_INVALID_SOCKET) 
     1681        pj_sock_close(sock); 
     1682 
     1683    return status; 
     1684} 
     1685 
     1686 
     1687PJ_DEF(pj_status_t) pjsip_tcp_transport_restart(pjsip_tpfactory *factory, 
     1688                                                const pj_sockaddr *local, 
     1689                                                const pjsip_host_port *a_name) 
     1690{ 
     1691    pj_status_t status = PJ_SUCCESS; 
     1692    struct tcp_listener *listener = (struct tcp_listener *)factory; 
     1693 
     1694    lis_close(listener); 
     1695 
     1696    status = pjsip_tcp_transport_lis_start(factory, local, a_name); 
     1697    if (status != PJ_SUCCESS) {  
     1698        tcp_perror(listener->factory.obj_name, 
     1699                   "Unable to start listener after closing it", status); 
     1700 
     1701        return status; 
     1702    } 
     1703     
     1704    status = pjsip_tpmgr_register_tpfactory(listener->tpmgr, 
     1705                                            &listener->factory); 
     1706    if (status != PJ_SUCCESS) { 
     1707        tcp_perror(listener->factory.obj_name, 
     1708                   "Unable to register the transport listener", status); 
     1709    } else { 
     1710        listener->is_registered = PJ_TRUE;       
     1711    }     
     1712 
     1713    return status; 
     1714} 
     1715 
    16401716#endif  /* PJ_HAS_TCP */ 
    16411717 
Note: See TracChangeset for help on using the changeset viewer.