Ignore:
Timestamp:
Mar 9, 2008 12:55:00 PM (16 years ago)
Author:
bennylp
Message:

More work for ticket #485: updated pjnath with TURN-07 and added authentication in the server

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/src/pjturn-srv/server.c

    r1850 r1852  
    1818 */ 
    1919#include "turn.h" 
     20#include "auth.h" 
    2021 
    2122#define MAX_CLIENTS             32 
    2223#define MAX_PEERS_PER_CLIENT    8 
    23 #define MAX_HANDLES             (MAX_CLIENTS*MAX_PEERS_PER_CLIENT+MAX_LISTENERS) 
     24//#define MAX_HANDLES           (MAX_CLIENTS*MAX_PEERS_PER_CLIENT+MAX_LISTENERS) 
     25#define MAX_HANDLES             PJ_IOQUEUE_MAX_HANDLES 
    2426#define MAX_TIMER               (MAX_HANDLES * 2) 
    2527#define MIN_PORT                49152 
     
    2729#define MAX_LISTENERS           16 
    2830#define MAX_THREADS             2 
    29  
    30 #define MAX_CLIENT_BANDWIDTH    128  /* In Kbps */ 
    31 #define DEFA_CLIENT_BANDWIDTH   64 
    32  
    33 #define MIN_LIFETIME            32 
    34 #define MAX_LIFETIME            600 
    35 #define DEF_LIFETIME            300 
    36  
     31#define MAX_NET_EVENTS          10 
    3732 
    3833/* Prototypes */ 
     34static int server_thread_proc(void *arg); 
    3935static pj_status_t on_tx_stun_msg( pj_stun_session *sess, 
    4036                                   const void *pkt, 
     
    4945                                      unsigned src_addr_len); 
    5046 
    51 /* 
    52  * Get transport type name. 
    53  */ 
    54 PJ_DEF(const char*) pjturn_tp_type_name(int tp_type) 
     47struct saved_cred 
     48{ 
     49    pj_str_t realm; 
     50    pj_str_t username; 
     51    pj_str_t nonce; 
     52    int      data_type; 
     53    pj_str_t data; 
     54}; 
     55 
     56 
     57/* 
     58 * Get transport type name, normally for logging purpose only. 
     59 */ 
     60PJ_DEF(const char*) pj_turn_tp_type_name(int tp_type) 
    5561{ 
    5662    /* Must be 3 characters long! */ 
    57     if (tp_type == PJTURN_TP_UDP) 
     63    if (tp_type == PJ_TURN_TP_UDP) { 
    5864        return "UDP"; 
    59     else if (tp_type == PJTURN_TP_TCP) 
     65    } else if (tp_type == PJ_TURN_TP_TCP) { 
    6066        return "TCP"; 
    61     else 
     67    } else { 
     68        pj_assert(!"Unsupported transport"); 
    6269        return "???"; 
     70    } 
    6371} 
    6472 
     
    6674 * Create server. 
    6775 */ 
    68 PJ_DEF(pj_status_t) pjturn_srv_create( pj_pool_factory *pf, 
    69                                        pjturn_srv **p_srv) 
     76PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf,  
     77                                       pj_turn_srv **p_srv) 
    7078{ 
    7179    pj_pool_t *pool; 
    72     pjturn_srv *srv; 
     80    pj_turn_srv *srv; 
     81    unsigned i; 
    7382    pj_status_t status; 
    7483 
     
    7786    /* Create server and init core settings */ 
    7887    pool = pj_pool_create(pf, "srv%p", 1000, 1000, NULL); 
    79     srv = PJ_POOL_ZALLOC_T(pool, pjturn_srv); 
    80     srv->core.obj_name = pool->obj_name; 
     88    srv = PJ_POOL_ZALLOC_T(pool, pj_turn_srv); 
     89    srv->obj_name = pool->obj_name; 
    8190    srv->core.pf = pf; 
    8291    srv->core.pool = pool; 
     92    srv->core.tls_key = srv->core.tls_data = -1; 
    8393     
     94    /* Create ioqueue */ 
    8495    status = pj_ioqueue_create(pool, MAX_HANDLES, &srv->core.ioqueue); 
    8596    if (status != PJ_SUCCESS) 
    8697        goto on_error; 
    8798 
     99    /* Server mutex */ 
     100    status = pj_lock_create_recursive_mutex(pool, srv->obj_name,  
     101                                            &srv->core.lock); 
     102    if (status != PJ_SUCCESS) 
     103        goto on_error; 
     104 
     105    /* Allocate TLS */ 
     106    status = pj_thread_local_alloc(&srv->core.tls_key); 
     107    if (status != PJ_SUCCESS) 
     108        goto on_error; 
     109 
     110    status = pj_thread_local_alloc(&srv->core.tls_data); 
     111    if (status != PJ_SUCCESS) 
     112        goto on_error; 
     113     
     114    /* Create timer heap */ 
    88115    status = pj_timer_heap_create(pool, MAX_TIMER, &srv->core.timer_heap); 
    89116    if (status != PJ_SUCCESS) 
    90117        goto on_error; 
    91118 
    92     srv->core.listener = pj_pool_calloc(pool, MAX_LISTENERS,  
     119    /* Configure lock for the timer heap */ 
     120    pj_timer_heap_set_lock(srv->core.timer_heap, srv->core.lock, PJ_FALSE); 
     121 
     122    /* Array of listeners */ 
     123    srv->core.listener = (pj_turn_listener**) 
     124                         pj_pool_calloc(pool, MAX_LISTENERS,  
    93125                                        sizeof(srv->core.listener[0])); 
    94     srv->core.stun_sess = pj_pool_calloc(pool, MAX_LISTENERS, 
     126 
     127    /* Array of STUN sessions, one for each listener */ 
     128    srv->core.stun_sess = (pj_stun_session**) 
     129                          pj_pool_calloc(pool, MAX_LISTENERS, 
    95130                                         (sizeof(srv->core.stun_sess[0]))); 
    96  
    97     srv->core.thread_cnt = MAX_THREADS; 
    98     srv->core.thread = pj_pool_calloc(pool, srv->core.thread_cnt,  
    99                                       sizeof(pj_thread_t*)); 
    100  
    101     status = pj_lock_create_recursive_mutex(pool, "srv%p", &srv->core.lock); 
    102     if (status != PJ_SUCCESS) 
    103         goto on_error; 
    104131 
    105132    /* Create hash tables */ 
     
    117144                        srv->core.timer_heap); 
    118145 
     146    /* Init STUN credential */ 
     147    srv->core.cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; 
     148    srv->core.cred.data.dyn_cred.user_data = srv; 
     149    srv->core.cred.data.dyn_cred.get_auth = &pj_turn_get_auth; 
     150    srv->core.cred.data.dyn_cred.get_cred = &pj_turn_srv_get_cred; 
     151    srv->core.cred.data.dyn_cred.get_password = &pj_turn_get_password; 
     152    srv->core.cred.data.dyn_cred.verify_nonce = &pj_turn_verify_nonce; 
     153 
     154    /* Array of worker threads */ 
     155    srv->core.thread_cnt = MAX_THREADS; 
     156    srv->core.thread = (pj_thread_t**) 
     157                       pj_pool_calloc(pool, srv->core.thread_cnt,  
     158                                      sizeof(pj_thread_t*)); 
     159 
     160    /* Start the worker threads */ 
     161    for (i=0; i<srv->core.thread_cnt; ++i) { 
     162        status = pj_thread_create(pool, srv->obj_name, &server_thread_proc,  
     163                                  srv, 0, 0, &srv->core.thread[i]); 
     164        if (status != PJ_SUCCESS) 
     165            goto on_error; 
     166    } 
     167 
     168    /* We're done. Application should add listeners now */ 
     169    PJ_LOG(4,(srv->obj_name, "TURN server v%s is running",  
     170              pj_get_version())); 
     171 
    119172    *p_srv = srv; 
    120173    return PJ_SUCCESS; 
    121174 
    122175on_error: 
    123     pjturn_srv_destroy(srv); 
     176    pj_turn_srv_destroy(srv); 
    124177    return status; 
    125178} 
    126179 
    127 /**  
    128  * Create server. 
    129  */ 
    130 PJ_DEF(pj_status_t) pjturn_srv_destroy(pjturn_srv *srv) 
    131 { 
     180 
     181/*  
     182 * Handle timer and network events  
     183 */ 
     184static void srv_handle_events(pj_turn_srv *srv, const pj_time_val *max_timeout) 
     185{ 
     186    /* timeout is 'out' var. This just to make compiler happy. */ 
     187    pj_time_val timeout = { 0, 0}; 
     188    unsigned net_event_count = 0; 
     189    int c; 
     190 
     191    /* Poll the timer. The timer heap has its own mutex for better  
     192     * granularity, so we don't need to lock the server.  
     193     */ 
     194    timeout.sec = timeout.msec = 0; 
     195    c = pj_timer_heap_poll( srv->core.timer_heap, &timeout ); 
     196 
     197    /* timer_heap_poll should never ever returns negative value, or otherwise 
     198     * ioqueue_poll() will block forever! 
     199     */ 
     200    pj_assert(timeout.sec >= 0 && timeout.msec >= 0); 
     201    if (timeout.msec >= 1000) timeout.msec = 999; 
     202 
     203    /* If caller specifies maximum time to wait, then compare the value with 
     204     * the timeout to wait from timer, and use the minimum value. 
     205     */ 
     206    if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) { 
     207        timeout = *max_timeout; 
     208    } 
     209 
     210    /* Poll ioqueue.  
     211     * Repeat polling the ioqueue while we have immediate events, because 
     212     * timer heap may process more than one events, so if we only process 
     213     * one network events at a time (such as when IOCP backend is used), 
     214     * the ioqueue may have trouble keeping up with the request rate. 
     215     * 
     216     * For example, for each send() request, one network event will be 
     217     *   reported by ioqueue for the send() completion. If we don't poll 
     218     *   the ioqueue often enough, the send() completion will not be 
     219     *   reported in timely manner. 
     220     */ 
     221    do { 
     222        c = pj_ioqueue_poll( srv->core.ioqueue, &timeout); 
     223        if (c < 0) { 
     224            pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout)); 
     225            return; 
     226        } else if (c == 0) { 
     227            break; 
     228        } else { 
     229            net_event_count += c; 
     230            timeout.sec = timeout.msec = 0; 
     231        } 
     232    } while (c > 0 && net_event_count < MAX_NET_EVENTS); 
     233 
     234} 
     235 
     236/* 
     237 * Server worker thread proc. 
     238 */ 
     239static int server_thread_proc(void *arg) 
     240{ 
     241    pj_turn_srv *srv = (pj_turn_srv*)arg; 
     242 
     243    while (!srv->core.quit) { 
     244        pj_time_val timeout_max = {0, 500}; 
     245        srv_handle_events(srv, &timeout_max); 
     246    } 
     247 
     248    return 0; 
     249} 
     250 
     251/* 
     252 * Destroy the server. 
     253 */ 
     254PJ_DEF(pj_status_t) pj_turn_srv_destroy(pj_turn_srv *srv) 
     255{ 
     256    pj_hash_iterator_t itbuf, *it; 
     257    unsigned i; 
     258 
     259    /* Stop all worker threads */ 
     260    srv->core.quit = PJ_TRUE; 
     261    for (i=0; i<srv->core.thread_cnt; ++i) { 
     262        if (srv->core.thread[i]) { 
     263            pj_thread_join(srv->core.thread[i]); 
     264            pj_thread_destroy(srv->core.thread[i]); 
     265            srv->core.thread[i] = NULL; 
     266        } 
     267    } 
     268 
     269    /* Destroy all listeners and STUN sessions associated with them. */ 
     270    for (i=0; i<srv->core.lis_cnt; ++i) { 
     271        if (srv->core.listener[i]) { 
     272            pj_turn_listener_destroy(srv->core.listener[i]); 
     273            srv->core.listener[i] = NULL; 
     274        } 
     275        if (srv->core.stun_sess[i]) { 
     276            pj_stun_session_destroy(srv->core.stun_sess[i]); 
     277            srv->core.stun_sess[i] = NULL; 
     278        } 
     279    } 
     280 
     281    /* Destroy all allocations */ 
     282    if (srv->tables.alloc) { 
     283        it = pj_hash_first(srv->tables.alloc, &itbuf); 
     284        while (it != NULL) { 
     285            pj_turn_allocation *alloc = (pj_turn_allocation*) 
     286                                        pj_hash_this(srv->tables.alloc, it); 
     287            pj_turn_allocation_destroy(alloc); 
     288            it = pj_hash_next(srv->tables.alloc, it); 
     289        } 
     290    } 
     291     
     292 
     293    /* Destroy hash tables (well, sort of) */ 
     294    if (srv->tables.alloc) { 
     295        srv->tables.alloc = NULL; 
     296        srv->tables.res = NULL; 
     297    } 
     298     
     299    /* Destroy timer heap */ 
     300    if (srv->core.timer_heap) { 
     301        pj_timer_heap_destroy(srv->core.timer_heap); 
     302        srv->core.timer_heap = NULL; 
     303    } 
     304 
     305    /* Destroy ioqueue */ 
     306    if (srv->core.ioqueue) { 
     307        pj_ioqueue_destroy(srv->core.ioqueue); 
     308        srv->core.ioqueue = NULL; 
     309    } 
     310 
     311    /* Destroy thread local IDs */ 
     312    if (srv->core.tls_key != -1) { 
     313        pj_thread_local_free(srv->core.tls_key); 
     314        srv->core.tls_key = -1; 
     315    } 
     316    if (srv->core.tls_data != -1) { 
     317        pj_thread_local_free(srv->core.tls_data); 
     318        srv->core.tls_data = -1; 
     319    } 
     320 
     321    /* Destroy server lock */ 
     322    if (srv->core.lock) { 
     323        pj_lock_destroy(srv->core.lock); 
     324        srv->core.lock = NULL; 
     325    } 
     326 
     327    /* Release pool */ 
     328    if (srv->core.pool) { 
     329        pj_pool_t *pool = srv->core.pool; 
     330        srv->core.pool = NULL; 
     331        pj_pool_release(pool); 
     332    } 
     333 
     334    /* Done */ 
    132335    return PJ_SUCCESS; 
    133336} 
    134337 
    135 /**  
     338 
     339/* 
    136340 * Add listener. 
    137341 */ 
    138 PJ_DEF(pj_status_t) pjturn_srv_add_listener(pjturn_srv *srv, 
    139                                             pjturn_listener *lis) 
     342PJ_DEF(pj_status_t) pj_turn_srv_add_listener(pj_turn_srv *srv, 
     343                                             pj_turn_listener *lis) 
    140344{ 
    141345    pj_stun_session_cb sess_cb; 
     
    157361    sess_cb.on_send_msg = &on_tx_stun_msg; 
    158362 
    159     status = pj_stun_session_create(&srv->core.stun_cfg, "lis%p", &sess_cb, 
    160                                     PJ_FALSE, &sess); 
     363    status = pj_stun_session_create(&srv->core.stun_cfg, lis->obj_name,  
     364                                    &sess_cb, PJ_FALSE, &sess); 
    161365    if (status != PJ_SUCCESS) { 
    162366        srv->core.listener[index] = NULL; 
     
    165369 
    166370    pj_stun_session_set_user_data(sess, lis); 
     371    pj_stun_session_set_credential(sess, &srv->core.cred); 
    167372 
    168373    srv->core.stun_sess[index] = sess; 
     
    170375    srv->core.lis_cnt++; 
    171376 
     377    PJ_LOG(4,(srv->obj_name, "Listener %s/%s added at index %d", 
     378              lis->obj_name, lis->info, lis->id)); 
     379 
    172380    return PJ_SUCCESS; 
    173381} 
    174382 
    175 /** 
    176  * Register an allocation. 
    177  */ 
    178 PJ_DEF(pj_status_t) pjturn_srv_register_allocation(pjturn_srv *srv, 
    179                                                    pjturn_allocation *alloc) 
     383 
     384/* 
     385 * Send packet with this listener. 
     386 */ 
     387PJ_DEF(pj_status_t) pj_turn_listener_sendto(pj_turn_listener *listener, 
     388                                            const void *packet, 
     389                                            pj_size_t size, 
     390                                            unsigned flag, 
     391                                            const pj_sockaddr_t *addr, 
     392                                            int addr_len) 
     393{ 
     394    pj_assert(listener->id != PJ_TURN_INVALID_LIS_ID); 
     395    return listener->sendto(listener, packet, size, flag, addr, addr_len); 
     396} 
     397 
     398 
     399/* 
     400 * Destroy listener. 
     401 */ 
     402PJ_DEF(pj_status_t) pj_turn_listener_destroy(pj_turn_listener *listener) 
     403{ 
     404    pj_turn_srv *srv = listener->server; 
     405    unsigned i; 
     406 
     407    /* Remove from our listener list */ 
     408    pj_lock_acquire(srv->core.lock); 
     409    for (i=0; i<srv->core.lis_cnt; ++i) { 
     410        if (srv->core.listener[i] == listener) { 
     411            srv->core.listener[i] = NULL; 
     412            srv->core.lis_cnt--; 
     413            listener->id = PJ_TURN_INVALID_LIS_ID; 
     414            if (srv->core.stun_sess[i]) { 
     415                pj_stun_session_destroy(srv->core.stun_sess[i]); 
     416                srv->core.stun_sess[i] = NULL; 
     417            } 
     418            break; 
     419        } 
     420    } 
     421    pj_lock_release(srv->core.lock); 
     422 
     423    /* Destroy */ 
     424    return listener->destroy(listener); 
     425} 
     426 
     427 
     428/* 
     429 * Register an allocation to the hash tables. 
     430 */ 
     431PJ_DEF(pj_status_t) pj_turn_srv_register_allocation(pj_turn_srv *srv, 
     432                                                    pj_turn_allocation *alloc) 
    180433{ 
    181434    /* Add to hash tables */ 
     
    191444} 
    192445 
    193 /** 
    194  * Unregister an allocation. 
    195  */ 
    196 PJ_DEF(pj_status_t) pjturn_srv_unregister_allocation(pjturn_srv *srv, 
    197                                                      pjturn_allocation *alloc) 
     446 
     447/* 
     448 * Unregister an allocation from the hash tables. 
     449 */ 
     450PJ_DEF(pj_status_t) pj_turn_srv_unregister_allocation(pj_turn_srv *srv, 
     451                                                     pj_turn_allocation *alloc) 
    198452{ 
    199453    /* Unregister from hash tables */ 
     
    209463 
    210464 
    211 /* Callback from our own STUN session to send packet */ 
     465/* Callback from our own STUN session whenever it needs to send  
     466 * outgoing STUN packet. 
     467 */ 
    212468static pj_status_t on_tx_stun_msg( pj_stun_session *sess, 
    213469                                   const void *pkt, 
     
    216472                                   unsigned addr_len) 
    217473{ 
    218     pjturn_listener *listener; 
     474    pj_turn_listener *listener; 
    219475     
    220     listener = (pjturn_listener*) pj_stun_session_get_user_data(sess); 
     476    listener = (pj_turn_listener*) pj_stun_session_get_user_data(sess); 
    221477 
    222478    PJ_ASSERT_RETURN(listener!=NULL, PJ_EINVALIDOP); 
    223479 
    224     return pjturn_listener_sendto(listener, pkt, pkt_size, 0,  
    225                                   dst_addr, addr_len); 
    226 } 
    227  
    228 /* Create and send error response */ 
    229 static pj_status_t respond_error(pj_stun_session *sess, const pj_stun_msg *req, 
    230                                  pj_bool_t cache, int code, const char *errmsg, 
    231                                  const pj_sockaddr_t *dst_addr,  
    232                                  unsigned addr_len) 
     480    return pj_turn_listener_sendto(listener, pkt, pkt_size, 0,  
     481                                   dst_addr, addr_len); 
     482} 
     483 
     484 
     485/* Respond to STUN request */ 
     486static pj_status_t stun_respond(pj_turn_srv *srv, 
     487                                pj_stun_session *sess,  
     488                                const pj_stun_msg *req, 
     489                                unsigned code,  
     490                                const char *errmsg, 
     491                                pj_bool_t cache,  
     492                                const pj_sockaddr_t *dst_addr,  
     493                                unsigned addr_len) 
    233494{ 
    234495    pj_status_t status; 
     
    236497    pj_stun_tx_data *tdata; 
    237498 
    238     status = pj_stun_session_create_res(sess, req,  
    239                                         code, (errmsg?pj_cstr(&reason,errmsg):NULL),  
     499    /* Create response */ 
     500    status = pj_stun_session_create_res(sess, req, code,  
     501                                        (errmsg?pj_cstr(&reason,errmsg):NULL), 
    240502                                        &tdata); 
    241503    if (status != PJ_SUCCESS) 
    242504        return status; 
    243505 
    244     status = pj_stun_session_send_msg(sess, cache, dst_addr,  addr_len, tdata); 
    245     return status; 
    246  
    247 } 
    248  
    249 /* Parse ALLOCATE request */ 
    250 static pj_status_t parse_allocate_req(pjturn_allocation_req *cfg, 
    251                                       pjturn_listener *listener, 
    252                                       pj_stun_session *sess, 
    253                                       const pj_stun_msg *req, 
    254                                       const pj_sockaddr_t *src_addr, 
    255                                       unsigned src_addr_len) 
    256 { 
    257     pj_stun_bandwidth_attr *attr_bw; 
    258     pj_stun_req_transport_attr *attr_req_tp; 
    259     pj_stun_req_ip_attr *attr_req_ip; 
    260     pj_stun_req_port_props_attr *attr_rpp; 
    261     pj_stun_lifetime_attr *attr_lifetime; 
    262  
    263     pj_bzero(cfg, sizeof(*cfg)); 
    264  
    265     /* Get BANDWIDTH attribute, if any. */ 
    266     attr_bw = (pj_stun_uint_attr*) 
    267               pj_stun_msg_find_attr(req, PJ_STUN_ATTR_BANDWIDTH, 0); 
    268     if (attr_bw) { 
    269         cfg->bandwidth = attr_bw->value; 
    270     } else { 
    271         cfg->bandwidth = DEFA_CLIENT_BANDWIDTH; 
    272     } 
    273  
    274     /* Check if we can satisfy the bandwidth */ 
    275     if (cfg->bandwidth > MAX_CLIENT_BANDWIDTH) { 
    276         respond_error(sess, req, PJ_FALSE,  
    277                       PJ_STUN_SC_ALLOCATION_QUOTA_REACHED,  
    278                       "Invalid bandwidth", src_addr, src_addr_len); 
    279         return -1; 
    280     } 
    281  
    282     /* Get REQUESTED-TRANSPORT attribute, is any */ 
    283     attr_req_tp = (pj_stun_uint_attr*) 
    284                   pj_stun_msg_find_attr(req, PJ_STUN_ATTR_REQ_TRANSPORT, 0); 
    285     if (attr_req_tp) { 
    286         cfg->tp_type = PJ_STUN_GET_RT_PROTO(attr_req_tp->value); 
    287     } else { 
    288         cfg->tp_type = listener->tp_type; 
    289     } 
    290  
    291     /* Can only support UDP for now */ 
    292     if (cfg->tp_type != PJTURN_TP_UDP) { 
    293         respond_error(sess, req, PJ_FALSE,  
    294                       PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO,  
    295                       NULL, src_addr, src_addr_len); 
    296         return -1; 
    297     } 
    298  
    299     /* Get REQUESTED-IP attribute, if any */ 
    300     attr_req_ip = (pj_stun_sockaddr_attr*) 
    301                   pj_stun_msg_find_attr(req, PJ_STUN_ATTR_REQ_IP, 0); 
    302     if (attr_req_ip) { 
    303         pj_sockaddr_print(&attr_req_ip->sockaddr, cfg->addr,  
    304                           sizeof(cfg->addr), 0); 
    305     } 
    306  
    307     /* Get REQUESTED-PORT-PROPS attribute, if any */ 
    308     attr_rpp = (pj_stun_uint_attr*) 
    309                pj_stun_msg_find_attr(req, PJ_STUN_ATTR_REQ_PORT_PROPS, 0); 
    310     if (attr_rpp) { 
    311         cfg->rpp_bits = PJ_STUN_GET_RPP_BITS(attr_rpp->value); 
    312         cfg->rpp_port = PJ_STUN_GET_RPP_PORT(attr_rpp->value); 
    313     } else { 
    314         cfg->rpp_bits = 0; 
    315         cfg->rpp_port = 0; 
    316     } 
    317  
    318     /* Get LIFETIME attribute */ 
    319     attr_lifetime = (pj_stun_uint_attr*) 
    320                     pj_stun_msg_find_attr(req, PJ_STUN_ATTR_LIFETIME, 0); 
    321     if (attr_lifetime) { 
    322         cfg->lifetime = attr_lifetime->value; 
    323         if (cfg->lifetime < MIN_LIFETIME || cfg->lifetime > MAX_LIFETIME) { 
    324             respond_error(sess, req, PJ_FALSE,  
    325                           PJ_STUN_SC_BAD_REQUEST,  
    326                           "Invalid LIFETIME value", src_addr,  
    327                           src_addr_len); 
    328             return -1; 
    329         } 
    330     } else { 
    331         cfg->lifetime = DEF_LIFETIME; 
    332     } 
     506    /* Store the credential for future lookup. */ 
     507    if (pj_stun_auth_valid_for_msg(tdata->msg)) { 
     508        pj_turn_srv_put_cred(srv, req, tdata); 
     509    } 
     510 
     511    /* Send the response */ 
     512    return pj_stun_session_send_msg(sess, cache, dst_addr,  addr_len, tdata); 
     513} 
     514 
     515 
     516/* 
     517 * Store the credential to put placed for the specified message for 
     518 * future retrieval. 
     519 */ 
     520PJ_DEF(pj_status_t) pj_turn_srv_put_cred(pj_turn_srv *srv, 
     521                                         const pj_stun_msg *req, 
     522                                         pj_stun_tx_data *response) 
     523{ 
     524    pj_stun_username_attr *user; 
     525    pj_stun_realm_attr *realm; 
     526    pj_stun_nonce_attr *nonce; 
     527    struct saved_cred *saved_cred; 
     528    pj_status_t status; 
     529 
     530    realm = (pj_stun_realm_attr*) 
     531            pj_stun_msg_find_attr(req, PJ_STUN_ATTR_REALM, 0); 
     532    PJ_ASSERT_RETURN(realm != NULL, PJ_EBUG); 
     533 
     534    user = (pj_stun_username_attr*) 
     535           pj_stun_msg_find_attr(req, PJ_STUN_ATTR_USERNAME, 0); 
     536    PJ_ASSERT_RETURN(user != NULL, PJ_EBUG); 
     537 
     538    nonce = (pj_stun_nonce_attr*) 
     539            pj_stun_msg_find_attr(req, PJ_STUN_ATTR_NONCE, 0); 
     540    PJ_ASSERT_RETURN(nonce != NULL, PJ_EBUG); 
     541 
     542    saved_cred = PJ_POOL_ALLOC_T(response->pool, struct saved_cred); 
     543 
     544    /* Lookup the password */ 
     545    status = pj_turn_get_password(response->msg, NULL, &realm->value,  
     546                                  &user->value, response->pool,  
     547                                  &saved_cred->data_type,  
     548                                  &saved_cred->data); 
     549    if (status != PJ_SUCCESS) 
     550        return status; 
     551 
     552    /* Store credential */ 
     553    pj_strdup(response->pool, &saved_cred->username, &user->value); 
     554    pj_strdup(response->pool, &saved_cred->realm, &realm->value); 
     555    pj_strdup(response->pool, &saved_cred->nonce, &nonce->value); 
     556 
     557    pj_thread_local_set(srv->core.tls_key, response->msg); 
     558    pj_thread_local_set(srv->core.tls_data, saved_cred); 
    333559 
    334560    return PJ_SUCCESS; 
    335561} 
    336562 
    337 /* Callback from our own STUN session when incoming request arrives */ 
     563 
     564/** 
     565 * Retrieve previously stored credential for the specified message. 
     566 */ 
     567PJ_DEF(pj_status_t) pj_turn_srv_get_cred(const pj_stun_msg *msg, 
     568                                         void *user_data, 
     569                                         pj_pool_t *pool, 
     570                                         pj_str_t *realm, 
     571                                         pj_str_t *username, 
     572                                         pj_str_t *nonce, 
     573                                         int *data_type, 
     574                                         pj_str_t *data) 
     575{ 
     576    pj_turn_srv *srv; 
     577    const pj_stun_msg *saved_msg; 
     578    struct saved_cred *saved_cred; 
     579 
     580    PJ_UNUSED_ARG(pool); 
     581 
     582    srv = (pj_turn_srv*)user_data; 
     583 
     584    /* Lookup stored message and make sure it's for the same message */ 
     585    saved_msg = (const pj_stun_msg*) 
     586                pj_thread_local_get(srv->core.tls_key); 
     587    PJ_ASSERT_RETURN(saved_msg==msg, PJ_ENOTFOUND); 
     588 
     589    /* Lookup saved credential */ 
     590    saved_cred = (struct saved_cred*)  
     591                 pj_thread_local_get(srv->core.tls_data); 
     592    PJ_ASSERT_RETURN(saved_cred != NULL, PJ_ENOTFOUND); 
     593 
     594 
     595    *realm = saved_cred->realm; 
     596    *username = saved_cred->username; 
     597    *nonce = saved_cred->nonce; 
     598    *data_type = saved_cred->data_type; 
     599    *data = saved_cred->data; 
     600 
     601 
     602    /* Don't clear saved_cred as this may be called more than once */ 
     603 
     604    return PJ_SUCCESS; 
     605} 
     606 
     607 
     608/* Callback from our own STUN session when incoming request arrives. 
     609 * This function is triggered by pj_stun_session_on_rx_pkt() call in 
     610  * pj_turn_srv_on_rx_pkt() function below. 
     611 */ 
    338612static pj_status_t on_rx_stun_request(pj_stun_session *sess, 
    339613                                      const pj_uint8_t *pkt, 
     
    343617                                      unsigned src_addr_len) 
    344618{ 
    345     pjturn_listener *listener; 
    346     pjturn_srv *srv; 
    347     pjturn_allocation_req req; 
    348     pjturn_allocation *alloc; 
    349     pj_stun_tx_data *tdata; 
     619    pj_turn_listener *listener; 
     620    pj_turn_srv *srv; 
     621    pj_turn_allocation *alloc; 
    350622    pj_status_t status; 
    351623 
    352     listener = (pjturn_listener*) pj_stun_session_get_user_data(sess); 
     624    PJ_UNUSED_ARG(pkt); 
     625    PJ_UNUSED_ARG(pkt_len); 
     626 
     627    listener = (pj_turn_listener*) pj_stun_session_get_user_data(sess); 
    353628    srv = listener->server; 
    354629 
    355     /* Handle strayed REFRESH request */ 
    356     if (msg->hdr.type == PJ_STUN_REFRESH_REQUEST) { 
    357         return respond_error(sess, msg, PJ_FALSE,  
    358                              PJ_STUN_SC_ALLOCATION_MISMATCH, 
    359                              NULL, src_addr, src_addr_len); 
    360     } 
    361  
    362     /* Respond any other requests with Bad Request response */ 
     630    /* Respond any requests other than ALLOCATE with 437 response */ 
    363631    if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) { 
    364         return respond_error(sess, msg, PJ_FALSE, PJ_STUN_SC_BAD_REQUEST, 
    365                              NULL, src_addr, src_addr_len); 
    366     } 
    367  
    368     /* We have ALLOCATE request here, and it's authenticated. Parse the 
    369      * request. 
    370      */ 
    371     status = parse_allocate_req(&req, listener, sess, msg, src_addr,  
    372                                 src_addr_len); 
    373     if (status != PJ_SUCCESS) 
    374         return status; 
     632        stun_respond(srv, sess, msg, PJ_STUN_SC_ALLOCATION_MISMATCH, 
     633                     NULL, PJ_FALSE, src_addr, src_addr_len); 
     634        return PJ_SUCCESS; 
     635    } 
    375636 
    376637    /* Create new allocation. The relay resource will be allocated 
    377638     * in this function. 
    378639     */ 
    379     status = pjturn_allocation_create(listener, src_addr, src_addr_len, 
    380                                       msg, &req, &alloc); 
     640    status = pj_turn_allocation_create(listener, src_addr, src_addr_len, 
     641                                       msg, sess, &alloc); 
    381642    if (status != PJ_SUCCESS) { 
    382         char errmsg[PJ_ERR_MSG_SIZE]; 
    383  
    384         pj_strerror(status, errmsg, sizeof(errmsg)); 
    385         return respond_error(sess, msg, PJ_FALSE, PJ_STUN_SC_SERVER_ERROR, 
    386                              errmsg, src_addr, src_addr_len); 
    387     } 
    388  
    389     /* Respond the original ALLOCATE request */ 
    390     status = pj_stun_session_create_res(srv->core.stun_sess[listener->id], 
    391                                         msg, 0, NULL, &tdata); 
    392     if (status != PJ_SUCCESS) { 
    393         char errmsg[PJ_ERR_MSG_SIZE]; 
    394  
    395         pjturn_allocation_destroy(alloc); 
    396  
    397         pj_strerror(status, errmsg, sizeof(errmsg)); 
    398         return respond_error(sess, msg, PJ_FALSE, PJ_STUN_SC_SERVER_ERROR, 
    399                              errmsg, src_addr, src_addr_len); 
    400     } 
    401  
    402     /* Add RELAYED-ADDRESS attribute */ 
    403     pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 
    404                                   PJ_STUN_ATTR_RELAY_ADDR, PJ_TRUE, 
    405                                   &alloc->relay.hkey.addr, 
    406                                   pj_sockaddr_get_len(&alloc->relay.hkey.addr)); 
    407  
    408     /* Add LIFETIME. */ 
    409     pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 
    410                               PJ_STUN_ATTR_LIFETIME,  
    411                               (unsigned)alloc->relay.lifetime); 
    412  
    413     /* Add BANDWIDTH */ 
    414     pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, 
    415                               PJ_STUN_ATTR_BANDWIDTH, 
    416                               alloc->bandwidth); 
    417  
    418     /* Add RESERVATION-TOKEN */ 
    419     PJ_TODO(ADD_RESERVATION_TOKEN); 
    420  
    421     /* Add XOR-MAPPED-ADDRESS */ 
    422     pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 
    423                                   PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE, 
    424                                   &alloc->hkey.clt_addr, 
    425                                   pj_sockaddr_get_len(&alloc->hkey.clt_addr)); 
    426      
    427     /* Send the response */ 
    428     pj_stun_session_send_msg(srv->core.stun_sess[listener->id], PJ_TRUE, 
    429                              src_addr, src_addr_len, tdata); 
     643        /* STUN response has been sent, no need to reply here */ 
     644        return PJ_SUCCESS; 
     645    } 
    430646 
    431647    /* Done. */ 
     
    434650 
    435651 
    436 /* Handle packet from new client address. */ 
    437 static void handle_new_client( pjturn_srv *srv,  
    438                                pjturn_pkt *pkt) 
    439 { 
    440     unsigned options, lis_id; 
    441     pj_status_t status; 
    442  
    443     /* Check that this is a STUN message */ 
    444     options = PJ_STUN_CHECK_PACKET; 
    445     if (pkt->listener->tp_type == PJTURN_TP_UDP) 
    446         options |= PJ_STUN_IS_DATAGRAM; 
    447  
    448     status = pj_stun_msg_check(pkt->pkt, pkt->len, options); 
    449     if (status != PJ_SUCCESS) { 
    450         char errmsg[PJ_ERR_MSG_SIZE]; 
    451         char ip[PJ_INET6_ADDRSTRLEN+10]; 
    452  
    453         pj_strerror(status, errmsg, sizeof(errmsg)); 
    454         PJ_LOG(5,(srv->core.obj_name,  
    455                   "Non STUN packet from %s is dropped: %s", 
    456                   pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3), 
    457                   errmsg)); 
    458         return; 
    459     } 
    460  
    461     lis_id = pkt->listener->id; 
    462  
    463     /* Hand over processing to STUN session */ 
    464     options &= ~PJ_STUN_CHECK_PACKET; 
    465     status = pj_stun_session_on_rx_pkt(srv->core.stun_sess[lis_id], pkt->pkt,  
    466                                        pkt->len, options, NULL, 
    467                                        &pkt->src.clt_addr,  
    468                                        pkt->src_addr_len); 
    469     if (status != PJ_SUCCESS) { 
    470         char errmsg[PJ_ERR_MSG_SIZE]; 
    471         char ip[PJ_INET6_ADDRSTRLEN+10]; 
    472  
    473         pj_strerror(status, errmsg, sizeof(errmsg)); 
    474         PJ_LOG(5,(srv->core.obj_name,  
    475                   "Error processing STUN packet from %s: %s", 
    476                   pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3), 
    477                   errmsg)); 
    478         return; 
    479     } 
    480 } 
    481  
    482  
    483 /* 
    484  * This callback is called by UDP listener on incoming packet. 
    485  */ 
    486 PJ_DEF(void) pjturn_srv_on_rx_pkt( pjturn_srv *srv,  
    487                                    pjturn_pkt *pkt) 
    488 { 
    489     pjturn_allocation *alloc; 
     652/* 
     653 * This callback is called by UDP listener on incoming packet. This is 
     654 * the first entry for incoming packet (from client) to the server. From 
     655 * here, the packet may be handed over to an allocation if an allocation 
     656 * is found for the client address, or handed over to owned STUN session 
     657 * if an allocation is not found. 
     658 */ 
     659PJ_DEF(void) pj_turn_srv_on_rx_pkt(pj_turn_srv *srv,  
     660                                   pj_turn_pkt *pkt) 
     661{ 
     662    pj_turn_allocation *alloc; 
    490663 
    491664    /* Get TURN allocation from the source address */ 
     
    498671     */ 
    499672    if (alloc) { 
    500         pjturn_allocation_on_rx_client_pkt(alloc, pkt); 
     673        pj_turn_allocation_on_rx_client_pkt(alloc, pkt); 
    501674    } else { 
    502675        /* Otherwise this is a new client */ 
    503         handle_new_client(srv, pkt); 
    504     } 
    505 } 
    506  
    507  
     676        unsigned options, lis_id; 
     677        pj_status_t status; 
     678 
     679        /* Check that this is a STUN message */ 
     680        options = PJ_STUN_CHECK_PACKET; 
     681        if (pkt->listener->tp_type == PJ_TURN_TP_UDP) 
     682            options |= PJ_STUN_IS_DATAGRAM; 
     683 
     684        status = pj_stun_msg_check(pkt->pkt, pkt->len, options); 
     685        if (status != PJ_SUCCESS) { 
     686            char errmsg[PJ_ERR_MSG_SIZE]; 
     687            char ip[PJ_INET6_ADDRSTRLEN+10]; 
     688 
     689            pj_strerror(status, errmsg, sizeof(errmsg)); 
     690            PJ_LOG(5,(srv->obj_name,  
     691                      "Non STUN packet from %s is dropped: %s", 
     692                      pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3), 
     693                      errmsg)); 
     694            return; 
     695        } 
     696 
     697        lis_id = pkt->listener->id; 
     698 
     699        /* Hand over processing to STUN session. This will trigger 
     700         * on_rx_stun_request() callback to be called if the STUN 
     701         * message is a request. 
     702         */ 
     703        options &= ~PJ_STUN_CHECK_PACKET; 
     704        status = pj_stun_session_on_rx_pkt(srv->core.stun_sess[lis_id],  
     705                                           pkt->pkt, pkt->len, options, NULL, 
     706                                           &pkt->src.clt_addr,  
     707                                           pkt->src_addr_len); 
     708        if (status != PJ_SUCCESS) { 
     709            char errmsg[PJ_ERR_MSG_SIZE]; 
     710            char ip[PJ_INET6_ADDRSTRLEN+10]; 
     711 
     712            pj_strerror(status, errmsg, sizeof(errmsg)); 
     713            PJ_LOG(5,(srv->obj_name,  
     714                      "Error processing STUN packet from %s: %s", 
     715                      pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3), 
     716                      errmsg)); 
     717            return; 
     718        } 
     719    } 
     720} 
     721 
     722 
Note: See TracChangeset for help on using the changeset viewer.