Changeset 1382 for pjproject/trunk


Ignore:
Timestamp:
Jun 22, 2007 11:32:49 AM (17 years ago)
Author:
bennylp
Message:

Committed ticket #337: Ability to restart PJSIP UDP transport

Location:
pjproject/trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/build/samples.dsp

    r1127 r1382  
    103103# Begin Source File 
    104104 
     105SOURCE=..\src\samples\invtester.c 
     106# End Source File 
     107# Begin Source File 
     108 
    105109SOURCE=..\src\samples\level.c 
    106110# End Source File 
     
    168172 
    169173SOURCE=..\src\samples\tonegen.c 
     174# End Source File 
     175# Begin Source File 
     176 
     177SOURCE=..\src\samples\transportpausetest.c 
    170178# End Source File 
    171179# End Group 
  • pjproject/trunk/pjsip/include/pjsip/sip_errno.h

    r974 r1382  
    223223 */ 
    224224#define PJSIP_ETPNOTSUITABLE    (PJSIP_ERRNO_START_PJSIP + 64)  /* 171064 */ 
    225  
     225/** 
     226 * @hideinitializer 
     227 * Transport not available. This error occurs for example when the SIP stack  
     228 * is trying to use a SIP transport while the transport is being paused by  
     229 * application. 
     230 */ 
     231#define PJSIP_ETPNOTAVAIL       (PJSIP_ERRNO_START_PJSIP + 65)  /* 171065 */ 
    226232 
    227233/************************************************************ 
  • pjproject/trunk/pjsip/include/pjsip/sip_transport_udp.h

    r974 r1382  
    3737 * the transport to the framework. 
    3838 */ 
     39 
     40/** 
     41 * Flag that can be specified when calling #pjsip_udp_transport_pause() or 
     42 * #pjsip_udp_transport_restart(). 
     43 */ 
     44enum 
     45{ 
     46    /** 
     47     * This flag tells the transport to keep the existing/internal socket 
     48     * handle. 
     49     */ 
     50    PJSIP_UDP_TRANSPORT_KEEP_SOCKET     = 1, 
     51 
     52    /** 
     53     * This flag tells the transport to destroy the existing/internal socket 
     54     * handle. Naturally this flag and PJSIP_UDP_TRANSPORT_KEEP_SOCKET are  
     55     * mutually exclusive. 
     56     */ 
     57    PJSIP_UDP_TRANSPORT_DESTROY_SOCKET  = 2 
     58}; 
     59 
    3960 
    4061/** 
     
    82103 
    83104 
     105/** 
     106 * Retrieve the internal socket handle used by the UDP transport. Note 
     107 * that this socket normally is registered to ioqueue, so if application 
     108 * wants to make use of this socket, it should temporarily pause the 
     109 * transport. 
     110 * 
     111 * @param transport     The UDP transport. 
     112 * 
     113 * @return              The socket handle, or PJ_INVALID_SOCKET if no socket 
     114 *                      is currently being used (for example, when transport 
     115 *                      is being paused). 
     116 */ 
     117PJ_DECL(pj_sock_t) pjsip_udp_transport_get_socket(pjsip_transport *transport); 
     118 
     119 
     120/** 
     121 * Temporarily pause or shutdown the transport. When transport is being 
     122 * paused, it cannot be used by the SIP stack to send or receive SIP 
     123 * messages. 
     124 * 
     125 * Two types of operations are supported by this function: 
     126 *  - to temporarily make this transport unavailable for SIP uses, but 
     127 *    otherwise keep the socket handle intact. Application then can 
     128 *    retrieve the socket handle with #pjsip_udp_transport_get_socket() 
     129 *    and use it to send/receive application data (for example, STUN 
     130 *    messages). In this case, application should specify 
     131 *    PJSIP_UDP_TRANSPORT_KEEP_SOCKET when calling this function, and 
     132 *    also to specify this flag when calling #pjsip_udp_transport_restart() 
     133 *    later. 
     134 *  - to temporarily shutdown the transport, including closing down 
     135 *    the internal socket handle. This is useful for example to 
     136 *    temporarily suspend the application for an indefinite period. In 
     137 *    this case, application should specify PJSIP_UDP_TRANSPORT_DESTROY_SOCKET 
     138 *    flag when calling this function, and specify a new socket when 
     139 *    calling #pjsip_udp_transport_restart(). 
     140 * 
     141 * @param transport     The UDP transport. 
     142 * @param option        Pause option. 
     143 * 
     144 * @return              PJ_SUCCESS if transport is paused successfully, 
     145 *                      or the appropriate error code. 
     146 */ 
     147PJ_DECL(pj_status_t) pjsip_udp_transport_pause(pjsip_transport *transport, 
     148                                               unsigned option); 
     149 
     150/** 
     151 * Restart the transport. Several operations are supported by this function: 
     152 *  - if transport was made temporarily unavailable to SIP stack with 
     153 *    pjsip_udp_transport_pause() and PJSIP_UDP_TRANSPORT_KEEP_SOCKET, 
     154 *    application can make the transport available to the SIP stack 
     155 *    again, by specifying PJSIP_UDP_TRANSPORT_KEEP_SOCKET flag here. 
     156 *  - if application wants to replace the internal socket with a new 
     157 *    socket, it must specify PJSIP_UDP_TRANSPORT_DESTROY_SOCKET when 
     158 *    calling this function, so that the internal socket will be destroyed 
     159 *    if it hasn't been closed. In this case, application has two choices 
     160 *    on how to create the new socket: 1) to let the transport create 
     161 *    the new socket, in this case the \a sock option should be set 
     162 *    to \a PJ_INVALID_SOCKET and optionally the \a local parameter can be 
     163 *    filled with the desired address and port where the new socket  
     164 *    should be bound to, or 2) to specify its own socket to be used 
     165 *    by this transport, by specifying a valid socket in \a sock argument 
     166 *    and set the \a local argument to NULL. In both cases, application 
     167 *    may specify the published address of the socket in \a a_name 
     168 *    argument. 
     169 * 
     170 * @param transport     The UDP transport. 
     171 * @param option        Restart option. 
     172 * @param sock          Optional socket to be used by the transport. 
     173 * @param local         The address where the socket should be bound to. 
     174 *                      If this argument is NULL, socket will be bound 
     175 *                      to any available port. 
     176 * @param a_name        Optionally specify the published address for 
     177 *                      this transport. If the socket is not replaced 
     178 *                      (PJSIP_UDP_TRANSPORT_KEEP_SOCKET flag is 
     179 *                      specified), then if this argument is NULL, the 
     180 *                      previous value will be used. If the socket is 
     181 *                      replaced and this argument is NULL, the bound 
     182 *                      address will be used as the published address  
     183 *                      of the transport. 
     184 * 
     185 * @return              PJ_SUCCESS if transport can be restarted, or 
     186 *                      the appropriate error code. 
     187 */ 
     188PJ_DECL(pj_status_t) pjsip_udp_transport_restart(pjsip_transport *transport, 
     189                                                 unsigned option, 
     190                                                 pj_sock_t sock, 
     191                                                 const pj_sockaddr_in *local, 
     192                                                 const pjsip_host_port *a_name); 
     193 
     194 
    84195PJ_END_DECL 
    85196 
  • pjproject/trunk/pjsip/src/pjsip/sip_errno.c

    r974 r1382  
    6969    PJ_BUILD_ERR( PJSIP_EBUFDESTROYED,  "Buffer destroyed"), 
    7070    PJ_BUILD_ERR( PJSIP_ETPNOTSUITABLE, "Unsuitable transport selected"), 
     71    PJ_BUILD_ERR( PJSIP_ETPNOTAVAIL,    "Transport not available for use"), 
    7172 
    7273    /* Transaction errors */ 
  • pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c

    r1269 r1382  
    6868    pjsip_rx_data     **rdata; 
    6969    int                 is_closing; 
     70    pj_bool_t           is_paused; 
    7071}; 
    7172 
     
    122123        return; 
    123124    } 
     125 
     126    /* Don't do anything if transport is being paused. */ 
     127    if (tp->is_paused) 
     128        return; 
    124129 
    125130    /* 
     
    205210            op_key = &rdata->tp_info.op_key.op_key; 
    206211        } 
     212 
     213        /* Only read next packet if transport is not being paused. This 
     214         * check handles the case where transport is paused while endpoint 
     215         * is still processing a SIP message. 
     216         */ 
     217        if (tp->is_paused) 
     218            return; 
    207219 
    208220        /* Read next packet. */ 
     
    296308    PJ_ASSERT_RETURN(tdata->op_key.tdata == NULL, PJSIP_EPENDINGTX); 
    297309     
     310    /* Return error if transport is paused */ 
     311    if (tp->is_paused) 
     312        return PJSIP_ETPNOTAVAIL; 
     313 
    298314    /* Init op key. */ 
    299315    tdata->op_key.tdata = tdata; 
     
    396412 
    397413 
    398 /* 
    399  * pjsip_udp_transport_attach() 
    400  * 
    401  * Attach UDP socket and start transport. 
    402  */ 
    403 PJ_DEF(pj_status_t) pjsip_udp_transport_attach( pjsip_endpoint *endpt, 
    404                                                 pj_sock_t sock, 
    405                                                 const pjsip_host_port *a_name, 
    406                                                 unsigned async_cnt, 
    407                                                 pjsip_transport **p_transport) 
    408 { 
    409     enum { M = 80 }; 
    410     pj_pool_t *pool; 
    411     struct udp_transport *tp; 
    412     pj_ioqueue_t *ioqueue; 
    413     pj_ioqueue_callback ioqueue_cb; 
     414/* Create socket */ 
     415static pj_status_t create_socket(const pj_sockaddr_in *local_a, 
     416                                 pj_sock_t *p_sock) 
     417{ 
     418    pj_sock_t sock; 
     419    pj_sockaddr_in tmp_addr; 
     420    pj_status_t status; 
     421 
     422    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); 
     423    if (status != PJ_SUCCESS) 
     424        return status; 
     425 
     426    if (local_a == NULL) { 
     427        pj_sockaddr_in_init(&tmp_addr, NULL, 0); 
     428        local_a = &tmp_addr; 
     429    } 
     430 
     431    status = pj_sock_bind(sock, local_a, sizeof(*local_a)); 
     432    if (status != PJ_SUCCESS) { 
     433        pj_sock_close(sock); 
     434        return status; 
     435    } 
     436 
     437    *p_sock = sock; 
     438    return PJ_SUCCESS; 
     439} 
     440 
     441 
     442/* Generate transport's published address */ 
     443static pj_status_t get_published_name(pj_sock_t sock, 
     444                                      char hostbuf[], 
     445                                      pjsip_host_port *bound_name) 
     446{ 
     447    pj_sockaddr_in tmp_addr; 
     448    int addr_len; 
     449    pj_status_t status; 
     450 
     451    addr_len = sizeof(tmp_addr); 
     452    status = pj_sock_getsockname(sock, &tmp_addr, &addr_len); 
     453    if (status != PJ_SUCCESS) 
     454        return status; 
     455 
     456    bound_name->host.ptr = hostbuf; 
     457    bound_name->port = pj_ntohs(tmp_addr.sin_port); 
     458 
     459    /* If bound address specifies "0.0.0.0", get the IP address 
     460     * of local hostname. 
     461     */ 
     462    if (tmp_addr.sin_addr.s_addr == PJ_INADDR_ANY) { 
     463        pj_in_addr hostip; 
     464 
     465        status = pj_gethostip(&hostip); 
     466        if (status != PJ_SUCCESS) 
     467            return status; 
     468 
     469        pj_strcpy2(&bound_name->host, pj_inet_ntoa(hostip)); 
     470    } else { 
     471        /* Otherwise use bound address. */ 
     472        pj_strcpy2(&bound_name->host, pj_inet_ntoa(tmp_addr.sin_addr)); 
     473    } 
     474 
     475    return PJ_SUCCESS; 
     476} 
     477 
     478/* Set the published address of the transport */ 
     479static void udp_set_pub_name(struct udp_transport *tp, 
     480                             const pjsip_host_port *a_name) 
     481{ 
     482    enum { INFO_LEN = 80 }; 
     483 
     484    pj_assert(a_name->host.slen != 0); 
     485    pj_strdup_with_null(tp->base.pool, &tp->base.local_name.host,  
     486                        &a_name->host); 
     487    tp->base.local_name.port = a_name->port; 
     488 
     489    /* Update transport info. */ 
     490    if (tp->base.info == NULL) { 
     491        tp->base.info = (char*) pj_pool_alloc(tp->base.pool, INFO_LEN); 
     492    } 
     493    pj_ansi_snprintf(  
     494        tp->base.info, INFO_LEN, "udp %s:%d [published as %s:%d]", 
     495        pj_inet_ntoa(((pj_sockaddr_in*)&tp->base.local_addr)->sin_addr), 
     496        pj_ntohs(((pj_sockaddr_in*)&tp->base.local_addr)->sin_port), 
     497        tp->base.local_name.host.ptr, 
     498        tp->base.local_name.port); 
     499} 
     500 
     501/* Set the socket handle of the transport */ 
     502static void udp_set_socket(struct udp_transport *tp, 
     503                           pj_sock_t sock, 
     504                           const pjsip_host_port *a_name) 
     505{ 
    414506    long sobuf_size; 
    415     unsigned i; 
    416507    pj_status_t status; 
    417  
    418     PJ_ASSERT_RETURN(endpt && sock!=PJ_INVALID_SOCKET && a_name && async_cnt>0, 
    419                      PJ_EINVAL); 
    420  
    421508 
    422509    /* Adjust socket rcvbuf size */ 
     
    442529    } 
    443530 
    444     /* Create pool. */ 
    445     pool = pjsip_endpt_create_pool(endpt, "udp%p", PJSIP_POOL_LEN_TRANSPORT,  
    446                                    PJSIP_POOL_INC_TRANSPORT); 
    447     if (!pool) 
    448         return PJ_ENOMEM; 
    449  
    450     /* Create the UDP transport object. */ 
    451     tp = PJ_POOL_ZALLOC_T(pool, struct udp_transport); 
    452  
    453     /* Save pool. */ 
    454     tp->base.pool = pool; 
    455  
    456     /* Object name. */ 
    457     pj_ansi_snprintf(tp->base.obj_name, sizeof(tp->base.obj_name),  
    458                      "udp%p", tp); 
    459  
    460     /* Init reference counter. */ 
    461     status = pj_atomic_create(pool, 0, &tp->base.ref_cnt); 
    462     if (status != PJ_SUCCESS) 
    463         goto on_error; 
    464  
    465     /* Init lock. */ 
    466     status = pj_lock_create_recursive_mutex(pool, "udp%p", &tp->base.lock); 
    467     if (status != PJ_SUCCESS) 
    468         goto on_error; 
    469  
    470     /* Set type. */ 
    471     tp->base.key.type = PJSIP_TRANSPORT_UDP; 
    472  
    473     /* Remote address is left zero (except the family) */ 
    474     tp->base.key.rem_addr.addr.sa_family = PJ_AF_INET; 
    475  
    476     /* Type name. */ 
    477     tp->base.type_name = "UDP"; 
    478  
    479     /* Transport flag */ 
    480     tp->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP); 
    481  
    482  
    483     /* Length of addressess. */ 
    484     tp->base.addr_len = sizeof(pj_sockaddr_in); 
    485  
    486     /* Init local address. */ 
    487     status = pj_sock_getsockname(sock, &tp->base.local_addr,  
    488                                  &tp->base.addr_len); 
    489     if (status != PJ_SUCCESS) 
    490         goto on_error; 
     531    /* Set the socket. */ 
     532    tp->sock = sock; 
    491533 
    492534    /* Init address name (published address) */ 
    493     pj_strdup_with_null(pool, &tp->base.local_name.host, &a_name->host); 
    494     tp->base.local_name.port = a_name->port; 
    495  
    496     /* Init remote name. */ 
    497     tp->base.remote_name.host = pj_str("0.0.0.0"); 
    498     tp->base.remote_name.port = 0; 
    499  
    500     /* Transport info. */ 
    501     tp->base.info = (char*) pj_pool_alloc(pool, M); 
    502     pj_ansi_snprintf(  
    503         tp->base.info, M, "udp %s:%d [published as %s:%d]", 
    504         pj_inet_ntoa(((pj_sockaddr_in*)&tp->base.local_addr)->sin_addr), 
    505         pj_ntohs(((pj_sockaddr_in*)&tp->base.local_addr)->sin_port), 
    506         tp->base.local_name.host.ptr, 
    507         tp->base.local_name.port); 
    508  
    509     /* Set endpoint. */ 
    510     tp->base.endpt = endpt; 
    511  
    512     /* Transport manager and timer will be initialized by tpmgr */ 
    513  
    514     /* Attach socket. */ 
    515     tp->sock = sock; 
     535    udp_set_pub_name(tp, a_name); 
     536} 
     537 
     538/* Register socket to ioqueue */ 
     539static pj_status_t register_to_ioqueue(struct udp_transport *tp) 
     540{ 
     541    pj_ioqueue_t *ioqueue; 
     542    pj_ioqueue_callback ioqueue_cb; 
    516543 
    517544    /* Register to ioqueue. */ 
    518     ioqueue = pjsip_endpt_get_ioqueue(endpt); 
     545    ioqueue = pjsip_endpt_get_ioqueue(tp->base.endpt); 
    519546    pj_memset(&ioqueue_cb, 0, sizeof(ioqueue_cb)); 
    520547    ioqueue_cb.on_read_complete = &udp_on_read_complete; 
    521548    ioqueue_cb.on_write_complete = &udp_on_write_complete; 
    522     status = pj_ioqueue_register_sock(pool, ioqueue, tp->sock, tp,  
    523                                       &ioqueue_cb, &tp->key); 
    524     if (status != PJ_SUCCESS) 
    525         goto on_error; 
    526  
    527     /* Set functions. */ 
    528     tp->base.send_msg = &udp_send_msg; 
    529     tp->base.do_shutdown = &udp_shutdown; 
    530     tp->base.destroy = &udp_destroy; 
    531  
    532     /* This is a permanent transport, so we initialize the ref count 
    533      * to one so that transport manager don't destroy this transport 
    534      * when there's no user! 
    535      */ 
    536     pj_atomic_inc(tp->base.ref_cnt); 
    537  
    538     /* Register to transport manager. */ 
    539     tp->base.tpmgr = pjsip_endpt_get_tpmgr(endpt); 
    540     status = pjsip_transport_register( tp->base.tpmgr, (pjsip_transport*)tp); 
    541     if (status != PJ_SUCCESS) 
    542         goto on_error; 
    543  
    544  
    545     /* Create rdata and put it in the array. */ 
    546     tp->rdata_cnt = 0; 
    547     tp->rdata = (pjsip_rx_data**) 
    548                 pj_pool_calloc(tp->base.pool, async_cnt,  
    549                                sizeof(pjsip_rx_data*)); 
    550     for (i=0; i<async_cnt; ++i) { 
    551         pj_pool_t *rdata_pool = pjsip_endpt_create_pool(endpt, "rtd%p",  
    552                                                         PJSIP_POOL_RDATA_LEN, 
    553                                                         PJSIP_POOL_RDATA_INC); 
    554         if (!rdata_pool) { 
    555             pj_atomic_set(tp->base.ref_cnt, 0); 
    556             pjsip_transport_destroy(&tp->base); 
    557             return PJ_ENOMEM; 
    558         } 
    559  
    560         init_rdata(tp, i, rdata_pool, NULL); 
    561         tp->rdata_cnt++; 
    562     } 
     549 
     550    return pj_ioqueue_register_sock(tp->base.pool, ioqueue, tp->sock, tp, 
     551                                    &ioqueue_cb, &tp->key); 
     552} 
     553 
     554/* Start ioqueue asynchronous reading to all rdata */ 
     555static pj_status_t start_async_read(struct udp_transport *tp) 
     556{ 
     557    pj_ioqueue_t *ioqueue; 
     558    int i; 
     559    pj_status_t status; 
     560 
     561    ioqueue = pjsip_endpt_get_ioqueue(tp->base.endpt); 
    563562 
    564563    /* Start reading the ioqueue. */ 
    565     for (i=0; i<async_cnt; ++i) { 
     564    for (i=0; i<tp->rdata_cnt; ++i) { 
    566565        pj_ssize_t size; 
    567566 
     
    580579        } else if (status != PJ_EPENDING) { 
    581580            /* Error! */ 
     581            return status; 
     582        } 
     583    } 
     584 
     585    return PJ_SUCCESS; 
     586} 
     587 
     588 
     589/* 
     590 * pjsip_udp_transport_attach() 
     591 * 
     592 * Attach UDP socket and start transport. 
     593 */ 
     594PJ_DEF(pj_status_t) pjsip_udp_transport_attach( pjsip_endpoint *endpt, 
     595                                                pj_sock_t sock, 
     596                                                const pjsip_host_port *a_name, 
     597                                                unsigned async_cnt, 
     598                                                pjsip_transport **p_transport) 
     599{ 
     600    pj_pool_t *pool; 
     601    struct udp_transport *tp; 
     602    unsigned i; 
     603    pj_status_t status; 
     604 
     605    PJ_ASSERT_RETURN(endpt && sock!=PJ_INVALID_SOCKET && a_name && async_cnt>0, 
     606                     PJ_EINVAL); 
     607 
     608    /* Create pool. */ 
     609    pool = pjsip_endpt_create_pool(endpt, "udp%p", PJSIP_POOL_LEN_TRANSPORT,  
     610                                   PJSIP_POOL_INC_TRANSPORT); 
     611    if (!pool) 
     612        return PJ_ENOMEM; 
     613 
     614    /* Create the UDP transport object. */ 
     615    tp = PJ_POOL_ZALLOC_T(pool, struct udp_transport); 
     616 
     617    /* Save pool. */ 
     618    tp->base.pool = pool; 
     619 
     620    /* Object name. */ 
     621    pj_ansi_snprintf(tp->base.obj_name, sizeof(tp->base.obj_name),  
     622                     "udp%p", tp); 
     623 
     624    /* Init reference counter. */ 
     625    status = pj_atomic_create(pool, 0, &tp->base.ref_cnt); 
     626    if (status != PJ_SUCCESS) 
     627        goto on_error; 
     628 
     629    /* Init lock. */ 
     630    status = pj_lock_create_recursive_mutex(pool, "udp%p", &tp->base.lock); 
     631    if (status != PJ_SUCCESS) 
     632        goto on_error; 
     633 
     634    /* Set type. */ 
     635    tp->base.key.type = PJSIP_TRANSPORT_UDP; 
     636 
     637    /* Remote address is left zero (except the family) */ 
     638    tp->base.key.rem_addr.addr.sa_family = PJ_AF_INET; 
     639 
     640    /* Type name. */ 
     641    tp->base.type_name = "UDP"; 
     642 
     643    /* Transport flag */ 
     644    tp->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP); 
     645 
     646 
     647    /* Length of addressess. */ 
     648    tp->base.addr_len = sizeof(pj_sockaddr_in); 
     649 
     650    /* Init local address. */ 
     651    status = pj_sock_getsockname(sock, &tp->base.local_addr,  
     652                                 &tp->base.addr_len); 
     653    if (status != PJ_SUCCESS) 
     654        goto on_error; 
     655 
     656    /* Init remote name. */ 
     657    tp->base.remote_name.host = pj_str("0.0.0.0"); 
     658    tp->base.remote_name.port = 0; 
     659 
     660    /* Set endpoint. */ 
     661    tp->base.endpt = endpt; 
     662 
     663    /* Transport manager and timer will be initialized by tpmgr */ 
     664 
     665    /* Attach socket and assign name. */ 
     666    udp_set_socket(tp, sock, a_name); 
     667 
     668    /* Register to ioqueue */ 
     669    status = register_to_ioqueue(tp); 
     670    if (status != PJ_SUCCESS) 
     671        goto on_error; 
     672 
     673    /* Set functions. */ 
     674    tp->base.send_msg = &udp_send_msg; 
     675    tp->base.do_shutdown = &udp_shutdown; 
     676    tp->base.destroy = &udp_destroy; 
     677 
     678    /* This is a permanent transport, so we initialize the ref count 
     679     * to one so that transport manager don't destroy this transport 
     680     * when there's no user! 
     681     */ 
     682    pj_atomic_inc(tp->base.ref_cnt); 
     683 
     684    /* Register to transport manager. */ 
     685    tp->base.tpmgr = pjsip_endpt_get_tpmgr(endpt); 
     686    status = pjsip_transport_register( tp->base.tpmgr, (pjsip_transport*)tp); 
     687    if (status != PJ_SUCCESS) 
     688        goto on_error; 
     689 
     690 
     691    /* Create rdata and put it in the array. */ 
     692    tp->rdata_cnt = 0; 
     693    tp->rdata = (pjsip_rx_data**) 
     694                pj_pool_calloc(tp->base.pool, async_cnt,  
     695                               sizeof(pjsip_rx_data*)); 
     696    for (i=0; i<async_cnt; ++i) { 
     697        pj_pool_t *rdata_pool = pjsip_endpt_create_pool(endpt, "rtd%p",  
     698                                                        PJSIP_POOL_RDATA_LEN, 
     699                                                        PJSIP_POOL_RDATA_INC); 
     700        if (!rdata_pool) { 
     701            pj_atomic_set(tp->base.ref_cnt, 0); 
    582702            pjsip_transport_destroy(&tp->base); 
    583             return status; 
    584         } 
     703            return PJ_ENOMEM; 
     704        } 
     705 
     706        init_rdata(tp, i, rdata_pool, NULL); 
     707        tp->rdata_cnt++; 
     708    } 
     709 
     710    /* Start reading the ioqueue. */ 
     711    status = start_async_read(tp); 
     712    if (status != PJ_SUCCESS) { 
     713        pjsip_transport_destroy(&tp->base); 
     714        return status; 
    585715    } 
    586716 
     
    616746    pj_status_t status; 
    617747    char addr_buf[16]; 
    618     pj_sockaddr_in tmp_addr; 
    619748    pjsip_host_port bound_name; 
    620749 
    621750    PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL); 
    622751 
    623     status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock); 
     752    status = create_socket(local_a, &sock); 
    624753    if (status != PJ_SUCCESS) 
    625754        return status; 
    626  
    627     if (local_a == NULL) { 
    628         pj_sockaddr_in_init(&tmp_addr, NULL, 0); 
    629         local_a = &tmp_addr; 
    630     } 
    631  
    632     status = pj_sock_bind(sock, local_a, sizeof(*local_a)); 
    633     if (status != PJ_SUCCESS) { 
    634         pj_sock_close(sock); 
    635         return status; 
    636     } 
    637755 
    638756    if (a_name == NULL) { 
     
    640758         * Build a name based on bound address. 
    641759         */ 
    642         int addr_len; 
    643  
    644         addr_len = sizeof(tmp_addr); 
    645         status = pj_sock_getsockname(sock, &tmp_addr, &addr_len); 
     760        status = get_published_name(sock, addr_buf, &bound_name); 
    646761        if (status != PJ_SUCCESS) { 
    647762            pj_sock_close(sock); 
     
    650765 
    651766        a_name = &bound_name; 
    652         bound_name.host.ptr = addr_buf; 
    653         bound_name.port = pj_ntohs(tmp_addr.sin_port); 
    654  
    655         /* If bound address specifies "0.0.0.0", get the IP address 
    656          * of local hostname. 
    657          */ 
    658         if (tmp_addr.sin_addr.s_addr == PJ_INADDR_ANY) { 
    659             pj_in_addr hostip; 
    660  
    661             status = pj_gethostip(&hostip); 
     767    } 
     768 
     769    return pjsip_udp_transport_attach( endpt, sock, a_name, async_cnt,  
     770                                       p_transport ); 
     771} 
     772 
     773 
     774/* 
     775 * Retrieve the internal socket handle used by the UDP transport. 
     776 */ 
     777PJ_DEF(pj_sock_t) pjsip_udp_transport_get_socket(pjsip_transport *transport) 
     778{ 
     779    struct udp_transport *tp; 
     780 
     781    PJ_ASSERT_RETURN(transport != NULL, PJ_INVALID_SOCKET); 
     782 
     783    tp = (struct udp_transport*) transport; 
     784 
     785    return tp->sock; 
     786} 
     787 
     788 
     789/* 
     790 * Temporarily pause or shutdown the transport.  
     791 */ 
     792PJ_DEF(pj_status_t) pjsip_udp_transport_pause(pjsip_transport *transport, 
     793                                              unsigned option) 
     794{ 
     795    struct udp_transport *tp; 
     796    unsigned i; 
     797 
     798    PJ_ASSERT_RETURN(transport != NULL, PJ_EINVAL); 
     799 
     800    /* Flag must be specified */ 
     801    PJ_ASSERT_RETURN((option & 0x03) != 0, PJ_EINVAL); 
     802 
     803    tp = (struct udp_transport*) transport; 
     804 
     805    /* Transport must not have been paused */ 
     806    PJ_ASSERT_RETURN(tp->is_paused==0, PJ_EINVALIDOP); 
     807 
     808    /* Set transport to paused first, so that when the read callback is  
     809     * called by pj_ioqueue_post_completion() it will not try to 
     810     * re-register the rdata. 
     811     */ 
     812    tp->is_paused = PJ_TRUE; 
     813 
     814    /* Cancel the ioqueue operation. */ 
     815    for (i=0; i<(unsigned)tp->rdata_cnt; ++i) { 
     816        pj_ioqueue_post_completion(tp->key,  
     817                                   &tp->rdata[i]->tp_info.op_key.op_key, -1); 
     818    } 
     819 
     820    /* Destroy the socket? */ 
     821    if (option & PJSIP_UDP_TRANSPORT_DESTROY_SOCKET) { 
     822        if (tp->key) { 
     823            /* This implicitly closes the socket */ 
     824            pj_ioqueue_unregister(tp->key); 
     825            tp->key = NULL; 
     826        } else { 
     827            /* Close socket. */ 
     828            if (tp->sock && tp->sock != PJ_INVALID_SOCKET) { 
     829                pj_sock_close(tp->sock); 
     830                tp->sock = PJ_INVALID_SOCKET; 
     831            } 
     832        } 
     833        tp->sock = PJ_INVALID_SOCKET; 
     834    } 
     835 
     836    PJ_LOG(4,(tp->base.obj_name, "SIP UDP transport paused")); 
     837 
     838    return PJ_SUCCESS; 
     839} 
     840 
     841 
     842/* 
     843 * Restart transport. 
     844 * 
     845 * If option is KEEP_SOCKET, just re-activate ioqueue operation. 
     846 * 
     847 * If option is DESTROY_SOCKET: 
     848 *  - if socket is specified, replace. 
     849 *  - if socket is not specified, create and replace. 
     850 */ 
     851PJ_DEF(pj_status_t) pjsip_udp_transport_restart(pjsip_transport *transport, 
     852                                                unsigned option, 
     853                                                pj_sock_t sock, 
     854                                                const pj_sockaddr_in *local, 
     855                                                const pjsip_host_port *a_name) 
     856{ 
     857    struct udp_transport *tp; 
     858    pj_status_t status; 
     859 
     860    PJ_ASSERT_RETURN(transport != NULL, PJ_EINVAL); 
     861    /* Flag must be specified */ 
     862    PJ_ASSERT_RETURN((option & 0x03) != 0, PJ_EINVAL); 
     863 
     864    tp = (struct udp_transport*) transport; 
     865 
     866    if (option & PJSIP_UDP_TRANSPORT_DESTROY_SOCKET) { 
     867        char addr_buf[16]; 
     868        pjsip_host_port bound_name; 
     869 
     870        /* Request to recreate transport */ 
     871 
     872        /* Destroy existing socket, if any. */ 
     873        if (tp->key) { 
     874            /* This implicitly closes the socket */ 
     875            pj_ioqueue_unregister(tp->key); 
     876            tp->key = NULL; 
     877        } else { 
     878            /* Close socket. */ 
     879            if (tp->sock && tp->sock != PJ_INVALID_SOCKET) { 
     880                pj_sock_close(tp->sock); 
     881                tp->sock = PJ_INVALID_SOCKET; 
     882            } 
     883        } 
     884        tp->sock = PJ_INVALID_SOCKET; 
     885 
     886        /* Create the socket if it's not specified */ 
     887        if (sock == PJ_INVALID_SOCKET) { 
     888            status = create_socket(local, &sock); 
    662889            if (status != PJ_SUCCESS) 
    663890                return status; 
    664  
    665             pj_strcpy2(&bound_name.host, pj_inet_ntoa(hostip)); 
    666         } else { 
    667             /* Otherwise use bound address. */ 
    668             pj_strcpy2(&bound_name.host, pj_inet_ntoa(tmp_addr.sin_addr)); 
    669         } 
    670          
    671     } 
    672  
    673     return pjsip_udp_transport_attach( endpt, sock, a_name, async_cnt,  
    674                                        p_transport ); 
    675 } 
    676  
    677  
     891        } 
     892 
     893        /* If transport published name is not specified, calculate it 
     894         * from the bound address. 
     895         */ 
     896        if (a_name == NULL) { 
     897            status = get_published_name(sock, addr_buf, &bound_name); 
     898            if (status != PJ_SUCCESS) { 
     899                pj_sock_close(sock); 
     900                return status; 
     901            } 
     902 
     903            a_name = &bound_name; 
     904        } 
     905 
     906        /* Assign the socket and published address to transport. */ 
     907        udp_set_socket(tp, sock, a_name); 
     908 
     909    } else { 
     910 
     911        /* For KEEP_SOCKET, transport must have been paused before */ 
     912        PJ_ASSERT_RETURN(tp->is_paused, PJ_EINVALIDOP); 
     913 
     914        /* If address name is specified, update it */ 
     915        if (a_name != NULL) 
     916            udp_set_pub_name(tp, a_name); 
     917    } 
     918 
     919    /* Re-register new or existing socket to ioqueue. */ 
     920    status = register_to_ioqueue(tp); 
     921    if (status != PJ_SUCCESS) { 
     922        return status; 
     923    } 
     924 
     925    /* Restart async read operation. */ 
     926    status = start_async_read(tp); 
     927    if (status != PJ_SUCCESS) 
     928        return status; 
     929 
     930    /* Everything has been set up */ 
     931    tp->is_paused = PJ_FALSE; 
     932 
     933    PJ_LOG(4,(tp->base.obj_name,  
     934              "SIP UDP transport restarted, published address is %.*s:%d", 
     935              (int)tp->base.local_name.host.slen, 
     936              tp->base.local_name.host.ptr, 
     937              tp->base.local_name.port)); 
     938 
     939    return PJ_SUCCESS; 
     940} 
     941 
Note: See TracChangeset for help on using the changeset viewer.