Ignore:
Timestamp:
Mar 12, 2008 8:52:16 PM (16 years ago)
Author:
bennylp
Message:

More ticket #485: implementation of TURN UDP client session

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/src/pjnath/turn_session.c

    r1854 r1862  
    1818 */ 
    1919#include <pjnath/turn_session.h> 
     20#include <pjnath/errno.h> 
    2021#include <pjlib-util/srv_resolver.h> 
    2122#include <pj/addr_resolv.h> 
    2223#include <pj/assert.h> 
    2324#include <pj/errno.h> 
     25#include <pj/hash.h> 
     26#include <pj/lock.h> 
    2427#include <pj/log.h> 
     28#include <pj/os.h> 
    2529#include <pj/pool.h> 
    2630#include <pj/sock.h> 
    2731 
    28  
    29 enum state_t 
    30 { 
    31     STATE_NULL, 
    32     STATE_RESOLVING, 
    33     STATE_RESOLVED, 
    34     STATE_ALLOCATING, 
    35     STATE_READY 
     32#define MAX_SRV_CNT         4 
     33#define REFRESH_SEC_BEFORE  60 
     34 
     35static const char *state_names[] =  
     36{ 
     37    "Null", 
     38    "Resolving", 
     39    "Resolved", 
     40    "Allocating", 
     41    "Ready", 
     42    "Deallocating", 
     43    "Deallocated", 
     44    "Destroying" 
    3645}; 
    3746 
     47enum timer_id_t 
     48{ 
     49    TIMER_NONE, 
     50    TIMER_KEEP_ALIVE, 
     51    TIMER_DESTROY 
     52}; 
     53 
     54 
    3855struct peer 
    3956{ 
    40     unsigned        ch_id; 
    41     pj_sockaddr     peer_addr; 
     57    pj_uint16_t     ch_id; 
     58    pj_bool_t       bound; 
     59    pj_sockaddr     addr; 
    4260    pj_time_val     expiry; 
    43     pj_uint8_t      tsx_id[12]; /* Pending ChannelBind request */ 
    4461}; 
    4562 
     
    4966    const char          *obj_name; 
    5067    pj_turn_session_cb   cb; 
    51  
    52     enum state_t         state; 
     68    void                *user_data; 
     69 
     70    pj_lock_t           *lock; 
     71    int                  busy; 
     72 
     73    pj_turn_state_t      state; 
     74    pj_bool_t            pending_destroy; 
     75    pj_bool_t            destroy_notified; 
    5376 
    5477    pj_stun_session     *stun; 
    5578 
     79    unsigned             lifetime; 
     80    int                  ka_interval; 
     81    pj_time_val          expiry; 
     82 
     83    pj_timer_heap_t     *timer_heap; 
     84    pj_timer_entry       timer; 
     85 
    5686    pj_dns_async_query  *dns_async; 
    57  
    58     unsigned             srv_addr_cnt; 
     87    pj_uint16_t          default_port; 
     88 
     89    pj_uint16_t          af; 
     90    pj_turn_tp_type      tp_type; 
     91    pj_uint16_t          srv_addr_cnt; 
    5992    pj_sockaddr         *srv_addr_list; 
    6093    pj_sockaddr         *srv_addr; 
     
    6396    pj_turn_alloc_param  alloc_param; 
    6497 
     98    pj_hash_table_t     *peer_table; 
     99 
    65100    /* tx_pkt must be 16bit aligned */ 
    66101    pj_uint8_t           tx_pkt[PJ_TURN_MAX_PKT_LEN]; 
     
    73108 * Prototypes. 
    74109 */ 
     110static void sess_shutdown(pj_turn_session *sess, 
     111                          pj_bool_t notify, 
     112                          pj_status_t status); 
     113static void do_destroy(pj_turn_session *sess); 
     114static void send_refresh(pj_turn_session *sess, int lifetime); 
    75115static pj_status_t stun_on_send_msg(pj_stun_session *sess, 
    76116                                    const void *pkt, 
     
    93133                                pj_status_t status, 
    94134                                const pj_dns_srv_record *rec); 
    95 static void dns_a_resolver_cb(void *user_data, 
    96                               pj_status_t status, 
    97                               pj_dns_parsed_packet *response); 
    98135static struct peer *lookup_peer_by_addr(pj_turn_session *sess, 
    99136                                        const pj_sockaddr_t *addr, 
    100137                                        unsigned addr_len, 
    101                                         pj_bool_t update); 
     138                                        pj_bool_t update, 
     139                                        pj_bool_t bind_channel); 
    102140static struct peer *lookup_peer_by_chnum(pj_turn_session *sess, 
    103                                          unsigned chnum); 
    104  
     141                                         pj_uint16_t chnum); 
     142static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e); 
     143 
     144 
     145/** 
     146 * Get TURN state name. 
     147 */ 
     148PJ_DEF(const char*) pj_turn_state_name(pj_turn_state_t state) 
     149{ 
     150    return state_names[state]; 
     151} 
    105152 
    106153/* 
     
    108155 */ 
    109156PJ_DEF(pj_status_t) pj_turn_session_create( pj_stun_config *cfg, 
     157                                            const char *name, 
     158                                            int af, 
     159                                            pj_turn_tp_type tp_type, 
    110160                                            const pj_turn_session_cb *cb, 
     161                                            void *user_data, 
     162                                            unsigned options, 
    111163                                            pj_turn_session **p_sess) 
    112164{ 
     
    114166    pj_turn_session *sess; 
    115167    pj_stun_session_cb stun_cb; 
     168    pj_lock_t *null_lock; 
    116169    pj_status_t status; 
    117170 
    118171    PJ_ASSERT_RETURN(cfg && cfg->pf && cb && p_sess, PJ_EINVAL); 
     172    PJ_ASSERT_RETURN(cb->on_send_pkt, PJ_EINVAL); 
     173 
     174    PJ_UNUSED_ARG(options); 
     175 
     176    if (name == NULL) 
     177        name = "turn%p"; 
    119178 
    120179    /* Allocate and create TURN session */ 
    121     pool = pj_pool_create(cfg->pf, "turn%p", 1000, 1000, NULL); 
     180    pool = pj_pool_create(cfg->pf, name, 1000, 1000, NULL); 
    122181    sess = PJ_POOL_ZALLOC_T(pool, pj_turn_session); 
    123182    sess->pool = pool; 
    124183    sess->obj_name = pool->obj_name; 
    125  
     184    sess->timer_heap = cfg->timer_heap; 
     185    sess->af = (pj_uint16_t)af; 
     186    sess->tp_type = tp_type; 
     187    sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC; 
     188    sess->user_data = user_data; 
     189 
     190    /* Copy callback */ 
    126191    pj_memcpy(&sess->cb, cb, sizeof(*cb)); 
     192 
     193    /* Peer hash table */ 
     194    sess->peer_table = pj_hash_create(pool, PJ_TURN_PEER_HTABLE_SIZE); 
     195 
     196    /* Session lock */ 
     197    status = pj_lock_create_recursive_mutex(pool, sess->obj_name,  
     198                                            &sess->lock); 
     199    if (status != PJ_SUCCESS) { 
     200        do_destroy(sess); 
     201        return status; 
     202    } 
     203 
     204    /* Timer */ 
     205    pj_timer_entry_init(&sess->timer, TIMER_NONE, sess, &on_timer_event); 
    127206 
    128207    /* Create STUN session */ 
     
    134213                                    &sess->stun); 
    135214    if (status != PJ_SUCCESS) { 
    136         pj_turn_session_destroy(sess); 
     215        do_destroy(sess); 
    137216        return status; 
    138217    } 
    139218 
    140     /* Done for now */ 
     219    /* Replace mutex in STUN session with a NULL mutex, since access to 
     220     * STUN session is serialized. 
     221     */ 
     222    status = pj_lock_create_null_mutex(pool, name, &null_lock); 
     223    if (status != PJ_SUCCESS) { 
     224        do_destroy(sess); 
     225        return status; 
     226    } 
     227    pj_stun_session_set_lock(sess->stun, null_lock, PJ_TRUE); 
     228 
     229    /* Done */ 
     230 
     231    PJ_LOG(4,(sess->obj_name, "TURN client session created")); 
     232 
    141233    *p_sess = sess; 
    142234    return PJ_SUCCESS; 
     
    144236 
    145237 
    146 /* 
    147  * Destroy TURN client session. 
     238/* Destroy */ 
     239static void do_destroy(pj_turn_session *sess) 
     240{ 
     241    /* Lock session */ 
     242    if (sess->lock) { 
     243        pj_lock_acquire(sess->lock); 
     244    } 
     245 
     246    /* Cancel pending timer, if any */ 
     247    if (sess->timer.id != TIMER_NONE) { 
     248        pj_timer_heap_cancel(sess->timer_heap, &sess->timer); 
     249        sess->timer.id = TIMER_NONE; 
     250    } 
     251 
     252    /* Destroy STUN session */ 
     253    if (sess->stun) { 
     254        pj_stun_session_destroy(sess->stun); 
     255        sess->stun = NULL; 
     256    } 
     257 
     258    /* Destroy lock */ 
     259    if (sess->lock) { 
     260        pj_lock_release(sess->lock); 
     261        pj_lock_destroy(sess->lock); 
     262        sess->lock = NULL; 
     263    } 
     264 
     265    /* Destroy pool */ 
     266    if (sess->pool) { 
     267        pj_pool_t *pool = sess->pool; 
     268 
     269        PJ_LOG(4,(sess->obj_name, "TURN client session destroyed")); 
     270 
     271        sess->pool = NULL; 
     272        pj_pool_release(pool); 
     273    } 
     274} 
     275 
     276 
     277/* Set session state */ 
     278static void set_state(pj_turn_session *sess, enum pj_turn_state_t state) 
     279{ 
     280    pj_turn_state_t old_state = sess->state; 
     281 
     282    PJ_LOG(4,(sess->obj_name, "State changed %s --> %s", 
     283              state_names[old_state], state_names[state])); 
     284    sess->state = state; 
     285 
     286    if (sess->cb.on_state) { 
     287        (*sess->cb.on_state)(sess, old_state, state); 
     288    } 
     289} 
     290 
     291/* 
     292 * Notify application and shutdown the TURN session. 
     293 */ 
     294static void sess_shutdown(pj_turn_session *sess, 
     295                          pj_bool_t notify, 
     296                          pj_status_t status) 
     297{ 
     298    pj_bool_t can_destroy = PJ_TRUE; 
     299 
     300    PJ_UNUSED_ARG(notify); 
     301 
     302    PJ_LOG(4,(sess->obj_name, "Request to shutdown in state %s, cause:%d", 
     303              state_names[sess->state], status)); 
     304 
     305    switch (sess->state) { 
     306    case PJ_TURN_STATE_NULL: 
     307        break; 
     308    case PJ_TURN_STATE_RESOLVING: 
     309        pj_assert(sess->dns_async != NULL); 
     310        pj_dns_resolver_cancel_query(sess->dns_async, PJ_FALSE); 
     311        sess->dns_async = NULL; 
     312        break; 
     313    case PJ_TURN_STATE_RESOLVED: 
     314        break; 
     315    case PJ_TURN_STATE_ALLOCATING: 
     316        /* We need to wait until allocation complete */ 
     317        sess->pending_destroy = PJ_TRUE; 
     318        can_destroy = PJ_FALSE; 
     319        break; 
     320    case PJ_TURN_STATE_READY: 
     321        /* Send REFRESH with LIFETIME=0 */ 
     322        can_destroy = PJ_FALSE; 
     323        sess->pending_destroy = PJ_TRUE; 
     324        break; 
     325    case PJ_TURN_STATE_DEALLOCATING: 
     326        can_destroy = PJ_FALSE; 
     327        /* This may recursively call this function again with 
     328         * state==PJ_TURN_STATE_DEALLOCATED. 
     329         */ 
     330        send_refresh(sess, 0); 
     331        break; 
     332    case PJ_TURN_STATE_DEALLOCATED: 
     333        break; 
     334    } 
     335 
     336    if (can_destroy) { 
     337        /* Schedule destroy */ 
     338        pj_time_val delay = {0, 0}; 
     339 
     340        if (sess->timer.id != TIMER_NONE) { 
     341            pj_timer_heap_cancel(sess->timer_heap, &sess->timer); 
     342            sess->timer.id = TIMER_NONE; 
     343        } 
     344 
     345        set_state(sess, PJ_TURN_STATE_DESTROYING); 
     346 
     347        sess->timer.id = TIMER_DESTROY; 
     348        pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay); 
     349    } 
     350} 
     351 
     352 
     353/* 
     354 * Public API to destroy TURN client session. 
    148355 */ 
    149356PJ_DEF(pj_status_t) pj_turn_session_destroy(pj_turn_session *sess) 
     
    151358    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    152359 
    153     /* TODO */ 
    154 } 
    155  
    156  
    157 /* 
    158  * Notify application and destroy the TURN session. 
    159  */ 
    160 static void destroy(pj_turn_session *sess, 
    161                     pj_bool_t notify, 
    162                     pj_status_t status) 
    163 { 
     360    pj_lock_acquire(sess->lock); 
     361 
     362    sess_shutdown(sess, PJ_FALSE, PJ_SUCCESS); 
     363 
     364    pj_lock_release(sess->lock); 
     365 
     366    return PJ_SUCCESS; 
     367} 
     368 
     369 
     370/* 
     371 * Re-assign user data. 
     372 */ 
     373PJ_DEF(pj_status_t) pj_turn_session_set_user_data( pj_turn_session *sess, 
     374                                                   void *user_data) 
     375{ 
     376    sess->user_data = user_data; 
     377    return PJ_SUCCESS; 
     378} 
     379 
     380 
     381/** 
     382 * Retrieve user data. 
     383 */ 
     384PJ_DEF(void*) pj_turn_session_get_user_data(pj_turn_session *sess) 
     385{ 
     386    return sess->user_data; 
    164387} 
    165388 
     
    170393PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess, 
    171394                                                const pj_str_t *domain, 
    172                                                 const pj_str_t *res_name, 
    173395                                                int default_port, 
    174396                                                pj_dns_resolver *resolver) 
     
    177399 
    178400    PJ_ASSERT_RETURN(sess && domain, PJ_EINVAL); 
    179  
    180     if (res_name) { 
    181         /* res_name is specified, resolve with DNS SRV resolution. 
    182          * Resolver must be specified in this case. 
     401    PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_NULL, PJ_EINVALIDOP); 
     402 
     403    pj_lock_acquire(sess->lock); 
     404 
     405    if (resolver) { 
     406        /* Resolve with DNS SRV resolution, and fallback to DNS A resolution 
     407         * if default_port is specified. 
    183408         */ 
    184         PJ_ASSERT_RETURN(resolver, PJ_EINVAL); 
    185      
    186         sess->state = STATE_RESOLVING; 
    187         status = pj_dns_srv_resolve(domain, res_name, default_port, sess->pool, 
    188                                     resolver, PJ_DNS_SRV_FALLBACK_A, sess,  
     409        unsigned opt = 0; 
     410        pj_str_t res_name; 
     411 
     412        switch (sess->tp_type) { 
     413        case PJ_TURN_TP_UDP: 
     414            res_name = pj_str("_turn._udp."); 
     415            break; 
     416        case PJ_TURN_TP_TCP: 
     417            res_name = pj_str("_turn._tcp."); 
     418            break; 
     419        case PJ_TURN_TP_TLS: 
     420            res_name = pj_str("_turns._tcp."); 
     421            break; 
     422        default: 
     423            status = PJNATH_ETURNINTP; 
     424            goto on_return; 
     425        } 
     426 
     427        /* Fallback to DNS A only if default port is specified */ 
     428        if (default_port>0 && default_port<65536) { 
     429            opt = PJ_DNS_SRV_FALLBACK_A; 
     430            sess->default_port = (pj_uint16_t)default_port; 
     431        } 
     432 
     433        set_state(sess, PJ_TURN_STATE_RESOLVING); 
     434        status = pj_dns_srv_resolve(domain, &res_name, default_port,  
     435                                    sess->pool, resolver, opt, sess,  
    189436                                    &dns_srv_resolver_cb, &sess->dns_async); 
    190437        if (status != PJ_SUCCESS) { 
    191             sess->state = STATE_NULL; 
    192             return status; 
    193         } 
    194  
    195     } else if (resolver) { 
    196         /* res_name is not specified, but resolver is specified. 
    197          * Resolve domain as a hostname with DNS A resolution. 
     438            set_state(sess, PJ_TURN_STATE_NULL); 
     439            goto on_return; 
     440        } 
     441 
     442    } else { 
     443        /* Resolver is not specified, resolve with standard gethostbyname(). 
     444         * The default_port MUST be specified in this case. 
    198445         */ 
    199         sess->state = STATE_RESOLVING; 
    200         status = pj_dns_resolver_start_query(resolver, domain, PJ_DNS_TYPE_A, 
    201                                              0, &dns_a_resolver_cb, 
    202                                              sess, &sess->dns_async); 
    203         if (status != PJ_SUCCESS) { 
    204             sess->state = STATE_NULL; 
    205             return status; 
    206         } 
    207  
    208     } else { 
    209         /* Both res_name and resolver is not specified. 
    210          * Resolve with standard gethostbyname() 
    211          */ 
    212         pj_addrinfo ai[3]; 
    213         unsigned i, cnt = PJ_ARRAY_SIZE(ai); 
    214  
    215         status = pj_getaddrinfo(pj_AF_INET(), domain, &cnt, ai); 
     446        pj_addrinfo *ai; 
     447        unsigned i, cnt; 
     448 
     449        /* Default port must be specified */ 
     450        PJ_ASSERT_RETURN(default_port>0 && default_port<65536, PJ_EINVAL); 
     451        sess->default_port = (pj_uint16_t)default_port; 
     452 
     453        cnt = MAX_SRV_CNT; 
     454        ai = (pj_addrinfo*) 
     455             pj_pool_calloc(sess->pool, cnt, sizeof(pj_addrinfo)); 
     456 
     457        status = pj_getaddrinfo(sess->af, domain, &cnt, ai); 
    216458        if (status != PJ_SUCCESS) 
    217             return status; 
    218  
    219         sess->srv_addr_cnt = cnt; 
     459            goto on_return; 
     460 
     461        sess->srv_addr_cnt = (pj_uint16_t)cnt; 
    220462        sess->srv_addr_list = (pj_sockaddr*) 
    221463                              pj_pool_calloc(sess->pool, cnt,  
    222464                                             sizeof(pj_sockaddr)); 
    223465        for (i=0; i<cnt; ++i) { 
    224             pj_memcpy(&sess->srv_addr_list[i], &ai[i].ai_addr,  
    225                       sizeof(pj_sockaddr)); 
     466            pj_sockaddr *addr = &sess->srv_addr_list[i]; 
     467            pj_memcpy(addr, &ai[i].ai_addr, sizeof(pj_sockaddr)); 
     468            addr->addr.sa_family = sess->af; 
     469            addr->ipv4.sin_port = pj_htons(sess->default_port); 
    226470        } 
    227471 
    228472        sess->srv_addr = &sess->srv_addr_list[0]; 
    229         sess->state = STATE_RESOLVED; 
    230     } 
    231  
    232     return PJ_SUCCESS; 
     473        set_state(sess, PJ_TURN_STATE_RESOLVED); 
     474    } 
     475 
     476on_return: 
     477    pj_lock_release(sess->lock); 
     478    return status; 
    233479} 
    234480 
     
    241487{ 
    242488    PJ_ASSERT_RETURN(sess && cred, PJ_EINVAL); 
     489 
     490    pj_lock_acquire(sess->lock); 
     491 
    243492    pj_stun_session_set_credential(sess->stun, cred); 
     493 
     494    pj_lock_release(sess->lock); 
     495 
    244496    return PJ_SUCCESS; 
    245497} 
     
    256508 
    257509    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    258     PJ_ASSERT_RETURN(sess->state <= STATE_RESOLVED, PJ_EINVALIDOP); 
    259  
    260     if (sess->state < STATE_RESOLVED) { 
    261         if (param) 
     510    PJ_ASSERT_RETURN(sess->state>PJ_TURN_STATE_NULL && sess->state<=PJ_TURN_STATE_RESOLVED,  
     511                     PJ_EINVALIDOP); 
     512 
     513    pj_lock_acquire(sess->lock); 
     514 
     515    if (sess->state < PJ_TURN_STATE_RESOLVED) { 
     516        if (param && param != &sess->alloc_param) 
    262517            pj_memcpy(&sess->alloc_param, param, sizeof(*param)); 
    263518        sess->pending_alloc = PJ_TRUE; 
     519 
     520        PJ_LOG(4,(sess->obj_name, "Pending ALLOCATE in state %s", 
     521                  state_names[sess->state])); 
     522 
     523        pj_lock_release(sess->lock); 
    264524        return PJ_SUCCESS; 
    265525 
     
    267527 
    268528    /* Ready to allocate */ 
    269     pj_assert(sess->state == STATE_RESOLVED); 
     529    pj_assert(sess->state == PJ_TURN_STATE_RESOLVED); 
    270530     
    271531    /* Create a bare request */ 
    272532    status = pj_stun_session_create_req(sess->stun, PJ_STUN_ALLOCATE_REQUEST, 
    273533                                        PJ_STUN_MAGIC, NULL, &tdata); 
    274     if (status != PJ_SUCCESS) 
     534    if (status != PJ_SUCCESS) { 
     535        pj_lock_release(sess->lock); 
    275536        return status; 
     537    } 
    276538 
    277539    /* MUST include REQUESTED-TRANSPORT attribute */ 
     
    294556    } 
    295557 
    296     /* Select server address */ 
     558    /* Server address must be set */ 
    297559    pj_assert(sess->srv_addr != NULL); 
    298560 
    299561    /* Send request */ 
    300     sess->state = STATE_ALLOCATING; 
     562    set_state(sess, PJ_TURN_STATE_ALLOCATING); 
    301563    status = pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 
    302564                                      pj_sockaddr_get_len(sess->srv_addr),  
    303565                                      tdata); 
    304566    if (status != PJ_SUCCESS) { 
    305         sess->state = STATE_RESOLVED; 
    306     } 
    307  
     567        /* Set state back to RESOLVED. We don't want to destroy session now, 
     568         * let the application do it if it wants to. 
     569         */ 
     570        set_state(sess, PJ_TURN_STATE_RESOLVED); 
     571    } 
     572 
     573    pj_lock_release(sess->lock); 
    308574    return status; 
     575} 
     576 
     577 
     578/* 
     579 * Send REFRESH 
     580 */ 
     581static void send_refresh(pj_turn_session *sess, int lifetime) 
     582{ 
     583    pj_stun_tx_data *tdata; 
     584    pj_status_t status; 
     585 
     586    PJ_ASSERT_ON_FAIL(sess->state==PJ_TURN_STATE_READY, return); 
     587 
     588    /* Create a bare REFRESH request */ 
     589    status = pj_stun_session_create_req(sess->stun, PJ_STUN_REFRESH_REQUEST, 
     590                                        PJ_STUN_MAGIC, NULL, &tdata); 
     591    if (status != PJ_SUCCESS) 
     592        goto on_error; 
     593 
     594    /* Add LIFETIME */ 
     595    if (lifetime >= 0) { 
     596        pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 
     597                                  PJ_STUN_ATTR_LIFETIME, lifetime); 
     598    } 
     599 
     600    /* Send request */ 
     601    if (lifetime == 0) { 
     602        set_state(sess, PJ_TURN_STATE_DEALLOCATING); 
     603    } 
     604 
     605    status = pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 
     606                                      pj_sockaddr_get_len(sess->srv_addr),  
     607                                      tdata); 
     608    if (status != PJ_SUCCESS) 
     609        goto on_error; 
     610 
     611    return; 
     612 
     613on_error: 
     614    if (lifetime == 0) { 
     615        set_state(sess, PJ_TURN_STATE_DEALLOCATED); 
     616        sess_shutdown(sess, PJ_FALSE, status); 
     617    } 
    309618} 
    310619 
     
    316625                                            const pj_uint8_t *pkt, 
    317626                                            unsigned pkt_len, 
    318                                             const pj_sockaddr_t *peer_addr, 
     627                                            const pj_sockaddr_t *addr, 
    319628                                            unsigned addr_len) 
    320629{ 
    321630    struct peer *peer; 
    322  
    323     PJ_ASSERT_RETURN(sess && pkt && pkt_len && peer_addr && addr_len,  
     631    pj_status_t status; 
     632 
     633    PJ_ASSERT_RETURN(sess && pkt && pkt_len && addr && addr_len,  
    324634                     PJ_EINVAL); 
    325635 
    326636    /* Return error if we're not ready */ 
    327     if (sess->state != STATE_READY) { 
     637    if (sess->state != PJ_TURN_STATE_READY) { 
    328638        return PJ_EIGNORED; 
    329639    } 
     640 
     641    /* Lock session now */ 
     642    pj_lock_acquire(sess->lock); 
    330643 
    331644    /* Lookup peer to see whether we've assigned a channel number 
    332645     * to this peer. 
    333646     */ 
    334     peer = lookup_peer_by_addr(sess, peer_addr, addr_len, PJ_TRUE); 
     647    peer = lookup_peer_by_addr(sess, addr, addr_len, PJ_TRUE, PJ_FALSE); 
    335648    pj_assert(peer != NULL); 
    336649 
    337     if (peer->ch_id != PJ_TURN_INVALID_CHANNEL) { 
     650    if (peer->ch_id != PJ_TURN_INVALID_CHANNEL && peer->bound) { 
    338651        /* Peer is assigned Channel number, we can use ChannelData */ 
    339652        pj_turn_channel_data *cd = (pj_turn_channel_data*)sess->tx_pkt; 
     
    341654        pj_assert(sizeof(*cd)==4); 
    342655 
    343         if (pkt_len > sizeof(sess->tx_pkt)-sizeof(*cd)) 
    344             return PJ_ETOOBIG; 
     656        if (pkt_len > sizeof(sess->tx_pkt)-sizeof(*cd)) { 
     657            status = PJ_ETOOBIG; 
     658            goto on_return; 
     659        } 
    345660 
    346661        cd->ch_number = pj_htons((pj_uint16_t)peer->ch_id); 
     
    350665        pj_assert(sess->srv_addr != NULL); 
    351666 
    352         return sess->cb.on_send_pkt(sess, sess->tx_pkt, pkt_len+sizeof(*cd), 
    353                                     sess->srv_addr, 
    354                                     pj_sockaddr_get_len(sess->srv_addr)); 
     667        status = sess->cb.on_send_pkt(sess, sess->tx_pkt, pkt_len+sizeof(*cd), 
     668                                      sess->srv_addr, 
     669                                      pj_sockaddr_get_len(sess->srv_addr)); 
    355670 
    356671    } else { 
     
    359674         */ 
    360675        pj_stun_tx_data *tdata; 
    361         pj_status_t status; 
    362676 
    363677        /* Create blank SEND-INDICATION */ 
     
    365679                                            PJ_STUN_SEND_INDICATION, &tdata); 
    366680        if (status != PJ_SUCCESS) 
    367             return status; 
     681            goto on_return; 
    368682 
    369683        /* Add PEER-ADDRESS */ 
    370684        pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 
    371685                                      PJ_STUN_ATTR_PEER_ADDR, PJ_TRUE, 
    372                                       peer_addr, addr_len); 
     686                                      addr, addr_len); 
    373687 
    374688        /* Add DATA attribute */ 
     
    377691 
    378692        /* Send the indication */ 
    379         return pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 
    380                                         pj_sockaddr_get_len(sess->srv_addr), 
    381                                         tdata); 
    382     } 
     693        status = pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 
     694                                          pj_sockaddr_get_len(sess->srv_addr), 
     695                                          tdata); 
     696    } 
     697 
     698on_return: 
     699    pj_lock_release(sess->lock); 
     700    return status; 
    383701} 
    384702 
     
    393711    struct peer *peer; 
    394712    pj_stun_tx_data *tdata; 
    395     unsigned ch_num; 
     713    pj_uint16_t ch_num; 
    396714    pj_status_t status; 
    397715 
    398     PJ_ASSERT_RETURN(sess && peer && addr_len, PJ_EINVAL); 
     716    PJ_ASSERT_RETURN(sess && peer_adr && addr_len, PJ_EINVAL); 
     717    PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_READY, PJ_EINVALIDOP); 
     718 
     719    pj_lock_acquire(sess->lock); 
    399720 
    400721    /* Create blank ChannelBind request */ 
     
    403724                                        PJ_STUN_MAGIC, NULL, &tdata); 
    404725    if (status != PJ_SUCCESS) 
    405         return status; 
     726        goto on_return; 
    406727 
    407728    /* Lookup peer */ 
    408     peer = lookup_peer_by_addr(sess, peer_adr, addr_len, PJ_TRUE); 
     729    peer = lookup_peer_by_addr(sess, peer_adr, addr_len, PJ_TRUE, PJ_FALSE); 
    409730    pj_assert(peer); 
    410731 
     732    /* Associate peer data structure with tdata for future reference 
     733     * when we receive the ChannelBind response. 
     734     */ 
     735    tdata->user_data = peer; 
     736 
    411737    if (peer->ch_id != PJ_TURN_INVALID_CHANNEL) { 
     738        /* Channel is already bound. This is a refresh request. */ 
    412739        ch_num = peer->ch_id; 
    413740    } else { 
    414         PJ_ASSERT_RETURN(sess->next_ch <= PJ_TURN_CHANNEL_MAX, PJ_ETOOMANY); 
    415         ch_num = sess->next_ch++; 
     741        PJ_ASSERT_ON_FAIL(sess->next_ch <= PJ_TURN_CHANNEL_MAX,  
     742                            {status=PJ_ETOOMANY; goto on_return;}); 
     743        peer->ch_id = ch_num = sess->next_ch++; 
    416744    } 
    417745 
     
    426754                                  peer_adr, addr_len); 
    427755 
    428     /* Save transaction ID to peer */ 
    429     pj_memcpy(peer->tsx_id, tdata->msg->hdr.tsx_id, sizeof(peer->tsx_id)); 
    430  
    431756    /* Send the request */ 
    432     return pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 
    433                                     pj_sockaddr_get_len(sess->srv_addr), 
    434                                     tdata); 
     757    status = pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 
     758                                      pj_sockaddr_get_len(sess->srv_addr), 
     759                                      tdata); 
     760 
     761on_return: 
     762    pj_lock_release(sess->lock); 
     763    return status; 
    435764} 
    436765 
     
    446775{ 
    447776    pj_bool_t is_stun; 
     777    pj_status_t status; 
    448778 
    449779    /* Packet could be ChannelData or STUN message (response or 
    450780     * indication). 
    451781     */ 
     782 
     783    /* Start locking the session */ 
     784    pj_lock_acquire(sess->lock); 
     785 
    452786    /* Quickly check if this is STUN message */ 
    453787    is_stun = ((pkt[0] & 0xC0) == 0); 
     
    460794        if (is_datagram) 
    461795            options |= PJ_STUN_IS_DATAGRAM; 
    462         return pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len, 
     796        status=pj_stun_session_on_rx_pkt(sess->stun, pkt, pkt_len, 
    463797                                         options, NULL, 
    464798                                         sess->srv_addr, 
    465799                                         pj_sockaddr_get_len(sess->srv_addr)); 
    466     } else { 
    467         /* This must be ChannelData */ 
     800 
     801    } else if (sess->cb.on_rx_data) { 
     802 
     803        /* This must be ChannelData. Only makes sense when on_rx_data() is 
     804         * implemented by application. 
     805         */ 
    468806        pj_turn_channel_data cd; 
    469807        struct peer *peer; 
    470808 
     809        PJ_ASSERT_RETURN(pkt_len >= 4, PJ_ETOOSMALL); 
     810 
    471811        /* Lookup peer */ 
    472812        pj_memcpy(&cd, pkt, sizeof(pj_turn_channel_data)); 
    473         peer = lookup_peer_by_chnum(sess, pj_ntohs(cd.ch_number)); 
    474         if (!peer) 
    475             return PJ_ENOTFOUND; 
     813        cd.ch_number = pj_ntohs(cd.ch_number); 
     814        cd.length = pj_ntohs(cd.length); 
     815        peer = lookup_peer_by_chnum(sess, cd.ch_number); 
     816        if (!peer || !peer->bound) { 
     817            status = PJ_ENOTFOUND; 
     818            goto on_return; 
     819        } 
     820 
     821        /* Check that size is correct, for UDP */ 
     822        if (pkt_len < cd.length+sizeof(cd)) { 
     823            status = PJ_ETOOSMALL; 
     824            goto on_return; 
     825        } 
    476826 
    477827        /* Notify application */ 
    478         if (sess->cb.on_rx_data) { 
    479             (*sess->cb.on_rx_data)(sess, pkt+sizeof(cd), pj_ntohs(cd.length), 
    480                                    &peer->peer_addr, 
    481                                    pj_sockaddr_get_len(&peer->peer_addr)); 
    482         } 
    483  
    484         return PJ_SUCCESS; 
    485     } 
     828        (*sess->cb.on_rx_data)(sess, pkt+sizeof(cd), cd.length, 
     829                               &peer->addr, 
     830                               pj_sockaddr_get_len(&peer->addr)); 
     831 
     832        status = PJ_SUCCESS; 
     833 
     834    } else { 
     835        /* This is ChannelData and application doesn't implement 
     836         * on_rx_data() callback. Just ignore the packet. 
     837         */ 
     838        status = PJ_SUCCESS; 
     839    } 
     840 
     841on_return: 
     842    pj_lock_release(sess->lock); 
     843    return status; 
    486844} 
    487845 
     
    503861} 
    504862 
     863 
     864/* 
     865 * Handle failed ALLOCATE or REFRESH request. This may switch to alternate 
     866 * server if we have one. 
     867 */ 
     868static void on_session_fail( pj_turn_session *sess,  
     869                             enum pj_stun_method_e method, 
     870                             pj_status_t status, 
     871                             const pj_str_t *reason) 
     872{ 
     873    do { 
     874        pj_str_t reason1; 
     875        char err_msg[PJ_ERR_MSG_SIZE]; 
     876 
     877        if (reason == NULL) { 
     878            pj_strerror(status, err_msg, sizeof(err_msg)); 
     879            reason1 = pj_str(err_msg); 
     880            reason = &reason1; 
     881        } 
     882 
     883        PJ_LOG(4,(sess->obj_name, "%s error: %.*s", 
     884                  pj_stun_get_method_name(method), 
     885                  (int)reason->slen, reason->ptr)); 
     886 
     887        /* If this is ALLOCATE response and we don't have more server  
     888         * addresses to try, notify application and destroy the TURN 
     889         * session. 
     890         */ 
     891        if (method==PJ_STUN_ALLOCATE_METHOD && 
     892            sess->srv_addr == &sess->srv_addr_list[sess->srv_addr_cnt-1])  
     893        { 
     894 
     895            set_state(sess, PJ_TURN_STATE_DEALLOCATED); 
     896            sess_shutdown(sess, PJ_TRUE, status); 
     897            return; 
     898        } 
     899 
     900        /* Otherwise if this is REFRESH response, notify application 
     901         * that session has been TERMINATED. 
     902         */ 
     903        if (method==PJ_STUN_REFRESH_METHOD) { 
     904            set_state(sess, PJ_TURN_STATE_DEALLOCATED); 
     905            sess_shutdown(sess, PJ_TRUE, status); 
     906            return; 
     907        } 
     908 
     909        /* Try next server */ 
     910        ++sess->srv_addr; 
     911        reason = NULL; 
     912 
     913        PJ_LOG(4,(sess->obj_name, "Trying next server")); 
     914 
     915        status = pj_turn_session_alloc(sess, NULL); 
     916 
     917    } while (status != PJ_SUCCESS); 
     918} 
     919 
     920 
     921/* 
     922 * Handle successful response to ALLOCATE or REFRESH request. 
     923 */ 
     924static void on_allocate_success(pj_turn_session *sess,  
     925                                enum pj_stun_method_e method, 
     926                                const pj_stun_msg *msg) 
     927{ 
     928    const pj_stun_lifetime_attr *lf_attr; 
     929    const pj_stun_relay_addr_attr *raddr_attr; 
     930    pj_str_t s; 
     931    pj_time_val timeout; 
     932 
     933    /* Must have LIFETIME attribute */ 
     934    lf_attr = (const pj_stun_lifetime_attr*) 
     935              pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_LIFETIME, 0); 
     936    if (lf_attr == NULL) { 
     937        on_session_fail(sess, method, PJNATH_EINSTUNMSG, 
     938                        pj_cstr(&s, "Error: Missing LIFETIME attribute")); 
     939        return; 
     940    } 
     941 
     942    /* If LIFETIME is zero, this is a deallocation */ 
     943    if (lf_attr->value == 0) { 
     944        pj_bool_t notify = sess->state < PJ_TURN_STATE_DEALLOCATING; 
     945        set_state(sess, PJ_TURN_STATE_DEALLOCATED); 
     946        sess_shutdown(sess, notify, PJ_SUCCESS); 
     947        return; 
     948    } 
     949 
     950    /* Update lifetime and keep-alive interval */ 
     951    sess->lifetime = lf_attr->value; 
     952    pj_gettimeofday(&sess->expiry); 
     953 
     954    if (sess->lifetime < PJ_TURN_KEEP_ALIVE_SEC) { 
     955        if (sess->lifetime <= 2) { 
     956            on_session_fail(sess, method, PJ_ETOOSMALL, 
     957                             pj_cstr(&s, "Error: LIFETIME too small")); 
     958            return; 
     959        } 
     960        sess->ka_interval = sess->lifetime - 2; 
     961        sess->expiry.sec += (sess->ka_interval-1); 
     962    } else { 
     963        int timeout; 
     964 
     965        sess->ka_interval = PJ_TURN_KEEP_ALIVE_SEC; 
     966 
     967        timeout = sess->lifetime - PJ_TURN_REFRESH_SEC_BEFORE; 
     968        if (timeout < sess->ka_interval) 
     969            timeout = sess->ka_interval - 1; 
     970 
     971        sess->expiry.sec += timeout; 
     972    } 
     973 
     974    /* Check that relayed transport address contains correct 
     975     * address family. 
     976     */ 
     977    raddr_attr = (const pj_stun_relay_addr_attr*) 
     978                 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_RELAY_ADDR, 0); 
     979    if (raddr_attr == NULL && method==PJ_STUN_ALLOCATE_METHOD) { 
     980        on_session_fail(sess, method, PJNATH_EINSTUNMSG, 
     981                        pj_cstr(&s, "Error: Received ALLOCATE without " 
     982                                    "RELAY-ADDRESS attribute")); 
     983        return; 
     984    } 
     985    if (raddr_attr && raddr_attr->sockaddr.addr.sa_family != sess->af) { 
     986        on_session_fail(sess, method, PJNATH_EINSTUNMSG, 
     987                        pj_cstr(&s, "Error: RELAY-ADDRESS with non IPv4" 
     988                                    " address family is not supported " 
     989                                    "for now")); 
     990        return; 
     991    } 
     992     
     993 
     994    /* Success */ 
     995 
     996    /* Cancel existing keep-alive timer, if any */ 
     997    pj_assert(sess->timer.id != TIMER_DESTROY); 
     998 
     999    if (sess->timer.id != TIMER_NONE) { 
     1000        pj_timer_heap_cancel(sess->timer_heap, &sess->timer); 
     1001        sess->timer.id = TIMER_NONE; 
     1002    } 
     1003 
     1004    /* Start keep-alive timer once allocation succeeds */ 
     1005    timeout.sec = sess->ka_interval; 
     1006    timeout.msec = 0; 
     1007 
     1008    sess->timer.id = TIMER_KEEP_ALIVE; 
     1009    pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &timeout); 
     1010 
     1011    set_state(sess, PJ_TURN_STATE_READY); 
     1012} 
    5051013 
    5061014/* 
     
    5151023{ 
    5161024    pj_turn_session *sess; 
    517     int method = PJ_STUN_GET_METHOD(response->hdr.type); 
     1025    int method = PJ_STUN_GET_METHOD(tdata->msg->hdr.type); 
     1026 
     1027    PJ_UNUSED_ARG(src_addr); 
     1028    PJ_UNUSED_ARG(src_addr_len); 
    5181029 
    5191030    sess = (pj_turn_session*)pj_stun_session_get_user_data(stun); 
     
    5211032    if (method == PJ_STUN_ALLOCATE_METHOD) { 
    5221033        /* Handle ALLOCATE response */ 
    523         if (PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) { 
     1034        if (status==PJ_SUCCESS &&  
     1035            PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))  
     1036        { 
     1037 
    5241038            /* Successful Allocate response */ 
     1039            on_allocate_success(sess, method, response); 
    5251040 
    5261041        } else { 
    527             /* Error Allocate response */ 
    528  
     1042            /* Failed Allocate request */ 
     1043            const pj_str_t *err_msg = NULL; 
     1044 
     1045            if (status == PJ_SUCCESS) { 
     1046                const pj_stun_errcode_attr *err_attr; 
     1047                err_attr = (const pj_stun_errcode_attr*) 
     1048                           pj_stun_msg_find_attr(response, 
     1049                                                 PJ_STUN_ATTR_ERROR_CODE, 0); 
     1050                if (err_attr) { 
     1051                    status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code); 
     1052                    err_msg = &err_attr->reason; 
     1053                } else { 
     1054                    status = PJNATH_EINSTUNMSG; 
     1055                } 
     1056            } 
     1057 
     1058            on_session_fail(sess, method, status, err_msg); 
     1059        } 
     1060 
     1061    } else if (method == PJ_STUN_REFRESH_METHOD) { 
     1062        /* Handle Refresh response */ 
     1063        if (status==PJ_SUCCESS &&  
     1064            PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))  
     1065        { 
     1066            /* Success, schedule next refresh. */ 
     1067            on_allocate_success(sess, method, response); 
     1068 
     1069        } else { 
     1070            /* Failed Refresh request */ 
     1071            const pj_str_t *err_msg = NULL; 
     1072 
     1073            if (status == PJ_SUCCESS) { 
     1074                const pj_stun_errcode_attr *err_attr; 
     1075                err_attr = (const pj_stun_errcode_attr*) 
     1076                           pj_stun_msg_find_attr(response, 
     1077                                                 PJ_STUN_ATTR_ERROR_CODE, 0); 
     1078                if (err_attr) { 
     1079                    status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code); 
     1080                    err_msg = &err_attr->reason; 
     1081                } else { 
     1082                    status = PJNATH_EINSTUNMSG; 
     1083                } 
     1084            } 
     1085 
     1086            /* Notify and destroy */ 
     1087            on_session_fail(sess, method, status, err_msg); 
    5291088        } 
    5301089 
    5311090    } else if (method == PJ_STUN_CHANNEL_BIND_METHOD) { 
    5321091        /* Handle ChannelBind response */ 
    533         if (PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type)) { 
     1092        if (status==PJ_SUCCESS &&  
     1093            PJ_STUN_IS_SUCCESS_RESPONSE(response->hdr.type))  
     1094        { 
    5341095            /* Successful ChannelBind response */ 
     1096            struct peer *peer = (struct peer*)tdata->user_data; 
     1097 
     1098            pj_assert(peer->ch_id != PJ_TURN_INVALID_CHANNEL); 
     1099            peer->bound = PJ_TRUE; 
     1100 
     1101            /* Update hash table */ 
     1102            lookup_peer_by_addr(sess, &peer->addr, 
     1103                                pj_sockaddr_get_len(&peer->addr), 
     1104                                PJ_TRUE, PJ_TRUE); 
    5351105 
    5361106        } else { 
    537             /* Error ChannelBind response */ 
    538  
     1107            /* Failed ChannelBind response */ 
     1108            pj_str_t err_msg = {"", 0}; 
     1109 
     1110            if (status == PJ_SUCCESS) { 
     1111                const pj_stun_errcode_attr *err_attr; 
     1112                err_attr = (const pj_stun_errcode_attr*) 
     1113                           pj_stun_msg_find_attr(response, 
     1114                                                 PJ_STUN_ATTR_ERROR_CODE, 0); 
     1115                if (err_attr) { 
     1116                    status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_code); 
     1117                    err_msg = err_attr->reason; 
     1118                } else { 
     1119                    status = PJNATH_EINSTUNMSG; 
     1120                } 
     1121            } 
     1122 
     1123            PJ_LOG(4,(sess->obj_name, "ChannelBind failed: %.*s", 
     1124                      (int)err_msg.slen, err_msg.ptr)); 
    5391125        } 
    5401126 
     
    5611147    pj_stun_data_attr *data_attr; 
    5621148 
     1149    PJ_UNUSED_ARG(src_addr); 
     1150    PJ_UNUSED_ARG(src_addr_len); 
     1151 
    5631152    sess = (pj_turn_session*)pj_stun_session_get_user_data(stun); 
    5641153 
     
    6041193{ 
    6051194    pj_turn_session *sess = (pj_turn_session*) user_data; 
     1195    unsigned i, cnt; 
     1196 
     1197    /* Clear async resolver */ 
     1198    sess->dns_async = NULL; 
    6061199 
    6071200    /* Check failure */ 
    6081201    if (status != PJ_SUCCESS) { 
    609         destroy(sess, PJ_TRUE, status); 
     1202        sess_shutdown(sess, PJ_TRUE, status); 
    6101203        return; 
    6111204    } 
    6121205 
    6131206    /* Copy results to server entries */ 
    614  
    615     /* Set state to STATE_RESOLVED */ 
     1207    for (i=0, cnt=0; i<rec->count && cnt<MAX_SRV_CNT; ++i) { 
     1208        unsigned j; 
     1209 
     1210        for (j=0; j<rec->entry[i].server.addr_count && cnt<MAX_SRV_CNT; ++j) { 
     1211            pj_sockaddr_in *addr = &sess->srv_addr[cnt].ipv4; 
     1212 
     1213            addr->sin_family = sess->af; 
     1214            addr->sin_port = pj_htons(rec->entry[i].port); 
     1215            addr->sin_addr.s_addr = rec->entry[i].server.addr[j].s_addr; 
     1216 
     1217            ++cnt; 
     1218        } 
     1219    } 
     1220    sess->srv_addr_cnt = (pj_uint16_t)cnt; 
     1221 
     1222    /* Set current server */ 
     1223    sess->srv_addr = &sess->srv_addr[0]; 
     1224 
     1225    /* Set state to PJ_TURN_STATE_RESOLVED */ 
     1226    set_state(sess, PJ_TURN_STATE_RESOLVED); 
    6161227 
    6171228    /* Run pending allocation */ 
    618 } 
    619  
    620  
    621 /* 
    622  * Notification on completion of DNS A resolution. 
    623  */ 
    624 static void dns_a_resolver_cb(void *user_data, 
    625                               pj_status_t status, 
    626                               pj_dns_parsed_packet *response) 
    627 { 
     1229    if (sess->pending_alloc) { 
     1230        pj_turn_session_alloc(sess, NULL); 
     1231    } 
    6281232} 
    6291233 
     
    6351239                                        const pj_sockaddr_t *addr, 
    6361240                                        unsigned addr_len, 
    637                                         pj_bool_t update) 
    638 { 
     1241                                        pj_bool_t update, 
     1242                                        pj_bool_t bind_channel) 
     1243{ 
     1244    unsigned hval = 0; 
     1245    struct peer *peer; 
     1246 
     1247    peer = (struct peer*) pj_hash_get(sess->peer_table, addr, addr_len, &hval); 
     1248    if (peer == NULL && update) { 
     1249        peer = PJ_POOL_ZALLOC_T(sess->pool, struct peer); 
     1250        peer->ch_id = PJ_TURN_INVALID_CHANNEL; 
     1251        pj_memcpy(&peer->addr, addr, addr_len); 
     1252 
     1253        /* Register by peer address */ 
     1254        pj_hash_set(sess->pool, sess->peer_table, &peer->addr, addr_len, 
     1255                    hval, peer); 
     1256    } 
     1257 
     1258    if (peer && update) { 
     1259        pj_gettimeofday(&peer->expiry); 
     1260        if (peer->bound) { 
     1261            peer->expiry.sec += PJ_TURN_CHANNEL_TIMEOUT - 10; 
     1262        } else { 
     1263            peer->expiry.sec += PJ_TURN_PERM_TIMEOUT - 10; 
     1264        } 
     1265 
     1266        if (bind_channel) { 
     1267            /* Register by channel number */ 
     1268            pj_assert(peer->ch_id != PJ_TURN_INVALID_CHANNEL && peer->bound); 
     1269            pj_assert(pj_hash_get(sess->peer_table, &peer->ch_id,  
     1270                                  sizeof(peer->ch_id), NULL)==0); 
     1271 
     1272            pj_hash_set(sess->pool, sess->peer_table, &peer->ch_id, 
     1273                        sizeof(peer->ch_id), 0, peer); 
     1274        } 
     1275    } 
     1276 
     1277    return peer; 
    6391278} 
    6401279 
     
    6441283 */ 
    6451284static struct peer *lookup_peer_by_chnum(pj_turn_session *sess, 
    646                                          unsigned chnum) 
    647 { 
    648 } 
    649  
    650  
     1285                                         pj_uint16_t chnum) 
     1286{ 
     1287    return (struct peer*) pj_hash_get(sess->peer_table, &chnum,  
     1288                                      sizeof(chnum), NULL); 
     1289} 
     1290 
     1291 
     1292/* 
     1293 * Timer event. 
     1294 */ 
     1295static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e) 
     1296{ 
     1297    pj_turn_session *sess = (pj_turn_session*)e->user_data; 
     1298    enum timer_id_t eid; 
     1299 
     1300    PJ_UNUSED_ARG(th); 
     1301 
     1302    pj_lock_acquire(sess->lock); 
     1303 
     1304    eid = e->id; 
     1305    e->id = TIMER_NONE; 
     1306     
     1307    if (eid == TIMER_KEEP_ALIVE) { 
     1308        pj_time_val now; 
     1309        pj_hash_iterator_t itbuf, *it; 
     1310        pj_bool_t resched = PJ_TRUE; 
     1311        pj_bool_t pkt_sent = PJ_FALSE; 
     1312 
     1313        pj_gettimeofday(&now); 
     1314 
     1315        /* Refresh allocation if it's time to do so */ 
     1316        if (PJ_TIME_VAL_LTE(sess->expiry, now)) { 
     1317            int lifetime = sess->alloc_param.lifetime; 
     1318 
     1319            if (lifetime == 0) 
     1320                lifetime = -1; 
     1321 
     1322            send_refresh(sess, lifetime); 
     1323            resched = PJ_FALSE; 
     1324            pkt_sent = PJ_TRUE; 
     1325        } 
     1326 
     1327        /* Scan hash table to refresh bound channels */ 
     1328        it = pj_hash_first(sess->peer_table, &itbuf); 
     1329        while (it) { 
     1330            struct peer *peer = (struct peer*)  
     1331                                pj_hash_this(sess->peer_table, it); 
     1332            if (peer->bound && PJ_TIME_VAL_LTE(peer->expiry, now)) { 
     1333 
     1334                /* Send ChannelBind to refresh channel binding and  
     1335                 * permission. 
     1336                 */ 
     1337                pj_turn_session_bind_channel(sess, &peer->addr, 
     1338                                             pj_sockaddr_get_len(&peer->addr)); 
     1339                pkt_sent = PJ_TRUE; 
     1340            } 
     1341 
     1342            it = pj_hash_next(sess->peer_table, it); 
     1343        } 
     1344 
     1345        /* If no packet is sent, send a blank Send indication to 
     1346         * refresh local NAT. 
     1347         */ 
     1348        if (!pkt_sent && sess->alloc_param.ka_interval > 0) { 
     1349            pj_stun_tx_data *tdata; 
     1350            pj_status_t rc; 
     1351 
     1352            /* Create blank SEND-INDICATION */ 
     1353            rc = pj_stun_session_create_ind(sess->stun,  
     1354                                            PJ_STUN_SEND_INDICATION, &tdata); 
     1355            if (rc == PJ_SUCCESS) { 
     1356                /* Add DATA attribute with zero length */ 
     1357                pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg, 
     1358                                            PJ_STUN_ATTR_DATA, NULL, 0); 
     1359 
     1360                /* Send the indication */ 
     1361                pj_stun_session_send_msg(sess->stun, PJ_FALSE, sess->srv_addr, 
     1362                                        pj_sockaddr_get_len(sess->srv_addr), 
     1363                                        tdata); 
     1364            } 
     1365        } 
     1366 
     1367        /* Reshcedule timer */ 
     1368        if (resched) { 
     1369            pj_time_val delay; 
     1370 
     1371            delay.sec = sess->ka_interval; 
     1372            delay.msec = 0; 
     1373 
     1374            pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay); 
     1375        } 
     1376 
     1377        pj_lock_release(sess->lock); 
     1378 
     1379    } else if (eid == TIMER_DESTROY) { 
     1380        /* Time to destroy */ 
     1381        pj_lock_release(sess->lock); 
     1382        do_destroy(sess); 
     1383    }     
     1384} 
     1385 
Note: See TracChangeset for help on using the changeset viewer.