Ignore:
Timestamp:
Mar 3, 2007 2:16:36 AM (17 years ago)
Author:
bennylp
Message:

Committed today's work on STUN

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib-util/src/pjlib-util/stun_session.c

    r1034 r1037  
    2828    void                *user_data; 
    2929 
    30     /* Long term credential */ 
    31     pj_str_t             l_realm; 
    32     pj_str_t             l_username; 
    33     pj_str_t             l_password; 
    34  
    35     /* Short term credential */ 
    36     pj_str_t             s_username; 
    37     pj_str_t             s_password; 
     30    pj_bool_t            use_fingerprint; 
     31    pj_stun_auth_cred   *cred; 
     32    pj_str_t             srv_name; 
    3833 
    3934    pj_stun_tx_data      pending_request_list; 
     
    214209} 
    215210 
     211static pj_str_t *get_passwd(pj_stun_session *sess) 
     212{ 
     213    if (sess->cred == NULL) 
     214        return NULL; 
     215    else if (sess->cred->type == PJ_STUN_AUTH_CRED_STATIC) 
     216        return &sess->cred->data.static_cred.data; 
     217    else 
     218        return NULL; 
     219} 
     220 
    216221static pj_status_t apply_msg_options(pj_stun_session *sess, 
    217222                                     pj_pool_t *pool, 
    218                                      unsigned options, 
    219                                      pj_stun_msg *msg, 
    220                                      pj_str_t **p_passwd) 
    221 { 
    222     pj_status_t status; 
     223                                     pj_stun_msg *msg) 
     224{ 
     225    pj_status_t status = 0; 
     226 
     227    /* The server SHOULD include a SERVER attribute in all responses */ 
     228    if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 
     229        PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))  
     230    { 
     231        pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SERVER, 
     232                                    &sess->srv_name); 
     233    } 
    223234 
    224235    /* From draft-ietf-behave-rfc3489bis-05.txt 
    225236     * Section 8.3.1.  Formulating the Request Message 
     237     * 
     238     * Note: only put MESSAGE-INTEGRITY in non error response. 
    226239     */ 
    227     if (options & PJ_STUN_USE_LONG_TERM_CRED) { 
    228         pj_stun_generic_string_attr *auname; 
    229         pj_stun_msg_integrity_attr *amsgi; 
    230         pj_stun_generic_string_attr *arealm; 
    231  
    232         *p_passwd = &sess->l_password; 
     240    if (sess->cred && sess->cred->type == PJ_STUN_AUTH_CRED_STATIC && 
     241        !PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))  
     242    { 
     243        const pj_str_t *username; 
    233244 
    234245        /* Create and add USERNAME attribute */ 
    235         status = pj_stun_generic_string_attr_create(pool,  
    236                                                     PJ_STUN_ATTR_USERNAME, 
    237                                                     &sess->l_username, 
    238                                                     &auname); 
     246        username = &sess->cred->data.static_cred.username; 
     247        status = pj_stun_msg_add_string_attr(pool, msg, 
     248                                             PJ_STUN_ATTR_USERNAME, 
     249                                             username); 
    239250        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    240251 
    241         status = pj_stun_msg_add_attr(msg, &auname->hdr); 
     252        /* Add REALM only when long term credential is used */ 
     253        if (sess->cred->data.static_cred.realm.slen) { 
     254            const pj_str_t *realm = &sess->cred->data.static_cred.realm; 
     255            status = pj_stun_msg_add_string_attr(pool, msg, 
     256                                                PJ_STUN_ATTR_REALM, 
     257                                                realm); 
     258        } 
     259 
     260        /* Add MESSAGE-INTEGRITY attribute */ 
     261        status = pj_stun_msg_add_msgint_attr(pool, msg); 
    242262        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    243263 
    244         /* Add REALM only when long term credential is used */ 
    245         status = pj_stun_generic_string_attr_create(pool,  
    246                                                     PJ_STUN_ATTR_REALM, 
    247                                                     &sess->l_realm, 
    248                                                     &arealm); 
    249         PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    250  
    251         status = pj_stun_msg_add_attr(msg, &arealm->hdr); 
    252         PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    253  
    254         /* Add MESSAGE-INTEGRITY attribute */ 
    255         status = pj_stun_msg_integrity_attr_create(pool, &amsgi); 
    256         PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    257  
    258         status = pj_stun_msg_add_attr(msg, &amsgi->hdr); 
    259         PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    260  
    261     } else if (options & PJ_STUN_USE_SHORT_TERM_CRED) { 
    262         pj_stun_generic_string_attr *auname; 
    263         pj_stun_msg_integrity_attr *amsgi; 
    264  
    265         *p_passwd = &sess->s_password; 
    266  
    267         /* Create and add USERNAME attribute */ 
    268         status = pj_stun_generic_string_attr_create(pool,  
    269                                                     PJ_STUN_ATTR_USERNAME, 
    270                                                     &sess->s_username, 
    271                                                     &auname); 
    272         PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    273  
    274         status = pj_stun_msg_add_attr(msg, &auname->hdr); 
    275         PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    276  
    277         /* Add MESSAGE-INTEGRITY attribute */ 
    278         status = pj_stun_msg_integrity_attr_create(pool, &amsgi); 
    279         PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    280  
    281         status = pj_stun_msg_add_attr(msg, &amsgi->hdr); 
    282         PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    283  
    284     } else { 
    285         *p_passwd = NULL; 
    286     } 
     264    }  
    287265 
    288266    /* Add FINGERPRINT attribute if necessary */ 
    289     if (options & PJ_STUN_USE_FINGERPRINT) { 
    290         pj_stun_fingerprint_attr *af; 
    291  
    292         status = pj_stun_generic_uint_attr_create(pool,  
    293                                                   PJ_STUN_ATTR_FINGERPRINT, 
    294                                                   0, &af); 
    295         PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    296  
    297         status = pj_stun_msg_add_attr(msg, &af->hdr); 
     267    if (sess->use_fingerprint) { 
     268        status = pj_stun_msg_add_uint_attr(pool, msg,  
     269                                          PJ_STUN_ATTR_FINGERPRINT, 0); 
    298270        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    299271    } 
     
    334306                                            const char *name, 
    335307                                            const pj_stun_session_cb *cb, 
     308                                            pj_bool_t fingerprint, 
    336309                                            pj_stun_session **p_sess) 
    337310{ 
     
    352325    sess->pool = pool; 
    353326    pj_memcpy(&sess->cb, cb, sizeof(*cb)); 
     327    sess->use_fingerprint = fingerprint; 
     328     
     329    sess->srv_name.ptr = pj_pool_alloc(pool, 32); 
     330    sess->srv_name.slen = pj_ansi_snprintf(sess->srv_name.ptr, 32, 
     331                                           "pj_stun-%s", PJ_VERSION); 
    354332 
    355333    pj_list_init(&sess->pending_request_list); 
     
    394372} 
    395373 
    396 PJ_DEF(pj_status_t)  
    397 pj_stun_session_set_long_term_credential(pj_stun_session *sess, 
    398                                          const pj_str_t *realm, 
    399                                          const pj_str_t *user, 
    400                                          const pj_str_t *passwd) 
    401 { 
    402     pj_str_t nil = { NULL, 0 }; 
    403  
    404     PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    405  
    406     pj_mutex_lock(sess->mutex); 
    407     pj_strdup_with_null(sess->pool, &sess->l_realm, realm ? realm : &nil); 
    408     pj_strdup_with_null(sess->pool, &sess->l_username, user ? user : &nil); 
    409     pj_strdup_with_null(sess->pool, &sess->l_password, passwd ? passwd : &nil); 
    410     pj_mutex_unlock(sess->mutex); 
    411  
    412     return PJ_SUCCESS; 
    413 } 
    414  
    415  
    416 PJ_DEF(pj_status_t)  
    417 pj_stun_session_set_short_term_credential(pj_stun_session *sess, 
    418                                           const pj_str_t *user, 
    419                                           const pj_str_t *passwd) 
    420 { 
    421     pj_str_t nil = { NULL, 0 }; 
    422  
    423     PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    424  
    425     pj_mutex_lock(sess->mutex); 
    426     pj_strdup_with_null(sess->pool, &sess->s_username, user ? user : &nil); 
    427     pj_strdup_with_null(sess->pool, &sess->s_password, passwd ? passwd : &nil); 
    428     pj_mutex_unlock(sess->mutex); 
    429  
    430     return PJ_SUCCESS; 
     374PJ_DEF(pj_status_t) pj_stun_session_set_server_name(pj_stun_session *sess, 
     375                                                    const pj_str_t *srv_name) 
     376{ 
     377    PJ_ASSERT_RETURN(sess && srv_name, PJ_EINVAL); 
     378    pj_strdup(sess->pool, &sess->srv_name, srv_name); 
     379    return PJ_SUCCESS; 
     380} 
     381 
     382PJ_DEF(void) pj_stun_session_set_credential(pj_stun_session *sess, 
     383                                            const pj_stun_auth_cred *cred) 
     384{ 
     385    PJ_ASSERT_ON_FAIL(sess, return); 
     386    if (cred) { 
     387        if (!sess->cred) 
     388            sess->cred = pj_pool_alloc(sess->pool, sizeof(pj_stun_auth_cred)); 
     389        pj_stun_auth_cred_dup(sess->pool, sess->cred, cred); 
     390    } else { 
     391        sess->cred = NULL; 
     392    } 
    431393} 
    432394 
     
    570532 
    571533PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, 
    572                                               unsigned options, 
     534                                              pj_bool_t cache_res, 
    573535                                              const pj_sockaddr_t *server, 
    574536                                              unsigned addr_len, 
    575537                                              pj_stun_tx_data *tdata) 
    576538{ 
    577     pj_str_t *password; 
    578539    pj_status_t status; 
    579540 
    580541    PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL); 
    581  
    582     tdata->options = options; 
    583542 
    584543    /* Allocate packet */ 
     
    590549 
    591550    /* Apply options */ 
    592     status = apply_msg_options(sess, tdata->pool, options,  
    593                                tdata->msg, &password); 
     551    status = apply_msg_options(sess, tdata->pool, tdata->msg); 
    594552    if (status != PJ_SUCCESS) { 
    595553        pj_stun_msg_destroy_tdata(sess, tdata); 
     
    601559    /* Encode message */ 
    602560    status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len, 
    603                                 0, password, &tdata->pkt_size); 
     561                                0, get_passwd(sess), &tdata->pkt_size); 
    604562    if (status != PJ_SUCCESS) { 
    605563        pj_stun_msg_destroy_tdata(sess, tdata); 
     
    641599 
    642600    } else { 
    643         if ((options & PJ_STUN_CACHE_RESPONSE) &&  
     601        if (cache_res &&  
    644602            (PJ_STUN_IS_RESPONSE(tdata->msg->hdr.type) || 
    645603             PJ_STUN_IS_ERROR_RESPONSE(tdata->msg->hdr.type)))  
     
    688646 
    689647 
     648/* Send response */ 
     649static pj_status_t send_response(pj_stun_session *sess,  
     650                                 pj_pool_t *pool, pj_stun_msg *response, 
     651                                 pj_bool_t retransmission, 
     652                                 const pj_sockaddr_t *addr, unsigned addr_len) 
     653{ 
     654    pj_uint8_t *out_pkt; 
     655    unsigned out_max_len, out_len; 
     656    pj_status_t status; 
     657 
     658    /* Alloc packet buffer */ 
     659    out_max_len = PJ_STUN_MAX_PKT_LEN; 
     660    out_pkt = pj_pool_alloc(pool, out_max_len); 
     661 
     662    /* Apply options */ 
     663    if (!retransmission) { 
     664        apply_msg_options(sess, pool, response); 
     665    } 
     666 
     667    /* Encode */ 
     668    status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0,  
     669                                get_passwd(sess), &out_len); 
     670    if (status != PJ_SUCCESS) { 
     671        LOG_ERR_(sess, "Error encoding message", status); 
     672        return status; 
     673    } 
     674 
     675    /* Print log */ 
     676    dump_tx_msg(sess, response, out_len, addr); 
     677 
     678    /* Send packet */ 
     679    status = sess->cb.on_send_msg(sess, out_pkt, out_len, addr, addr_len); 
     680 
     681    return status; 
     682} 
     683 
     684/* Authenticate incoming message */ 
     685static pj_status_t authenticate_msg(pj_stun_session *sess, 
     686                                    const pj_uint8_t *pkt, 
     687                                    unsigned pkt_len, 
     688                                    const pj_stun_msg *msg, 
     689                                    pj_pool_t *tmp_pool, 
     690                                    const pj_sockaddr_t *src_addr, 
     691                                    unsigned src_addr_len) 
     692{ 
     693    pj_stun_msg *response; 
     694    pj_status_t status; 
     695 
     696    if (PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type) || sess->cred == NULL) 
     697        return PJ_SUCCESS; 
     698 
     699    status = pj_stun_verify_credential(pkt, pkt_len, msg, sess->cred, 
     700                                       tmp_pool, &response); 
     701    if (status != PJ_SUCCESS && response != NULL) { 
     702        send_response(sess, tmp_pool, response, PJ_FALSE,  
     703                      src_addr, src_addr_len); 
     704    } 
     705 
     706    return status; 
     707} 
     708 
     709 
    690710/* Handle incoming response */ 
    691711static pj_status_t on_incoming_response(pj_stun_session *sess, 
     
    724744 
    725745 
    726 /* Send response */ 
    727 static pj_status_t send_response(pj_stun_session *sess, unsigned options, 
    728                                  pj_pool_t *pool, pj_stun_msg *response, 
    729                                  const pj_sockaddr_t *addr, unsigned addr_len) 
    730 { 
    731     pj_uint8_t *out_pkt; 
    732     unsigned out_max_len, out_len; 
    733     pj_str_t *passwd; 
    734     pj_status_t status; 
    735  
    736     /* Alloc packet buffer */ 
    737     out_max_len = PJ_STUN_MAX_PKT_LEN; 
    738     out_pkt = pj_pool_alloc(pool, out_max_len); 
    739  
    740     /* Apply options */ 
    741     apply_msg_options(sess, pool, options, response, &passwd); 
    742  
    743     /* Encode */ 
    744     status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0,  
    745                                 passwd, &out_len); 
    746     if (status != PJ_SUCCESS) { 
    747         LOG_ERR_(sess, "Error encoding message", status); 
    748         return status; 
    749     } 
    750  
    751     /* Print log */ 
    752     dump_tx_msg(sess, response, out_len, addr); 
    753  
    754     /* Send packet */ 
    755     status = sess->cb.on_send_msg(sess, out_pkt, out_len, addr, addr_len); 
    756  
    757     return status; 
    758 } 
    759  
    760 /* Handle incoming request */ 
    761 static pj_status_t on_incoming_request(pj_stun_session *sess, 
    762                                        pj_pool_t *tmp_pool, 
    763                                        const pj_uint8_t *in_pkt, 
    764                                        unsigned in_pkt_len, 
    765                                        const pj_stun_msg *msg, 
    766                                        const pj_sockaddr_t *src_addr, 
    767                                        unsigned src_addr_len) 
     746/* For requests, check if we cache the response */ 
     747static pj_status_t check_cached_response(pj_stun_session *sess, 
     748                                         pj_pool_t *tmp_pool, 
     749                                         const pj_stun_msg *msg, 
     750                                         const pj_sockaddr_t *src_addr, 
     751                                         unsigned src_addr_len) 
    768752{ 
    769753    pj_stun_tx_data *t; 
    770     pj_status_t status; 
    771754 
    772755    /* First lookup response in response cache */ 
     
    784767    if (t != &sess->cached_response_list) { 
    785768        /* Found response in the cache */ 
    786         unsigned options; 
    787769 
    788770        PJ_LOG(5,(SNAME(sess),  
    789771                 "Request retransmission, sending cached response")); 
    790772 
    791         options = t->options; 
    792         options &= ~PJ_STUN_CACHE_RESPONSE; 
    793         pj_stun_session_send_msg(sess, options, src_addr, src_addr_len, t); 
     773        send_response(sess, tmp_pool, t->msg, PJ_TRUE,  
     774                      src_addr, src_addr_len); 
    794775        return PJ_SUCCESS; 
    795776    } 
     777 
     778    return PJ_ENOTFOUND; 
     779} 
     780 
     781/* Handle incoming request */ 
     782static pj_status_t on_incoming_request(pj_stun_session *sess, 
     783                                       pj_pool_t *tmp_pool, 
     784                                       const pj_uint8_t *in_pkt, 
     785                                       unsigned in_pkt_len, 
     786                                       const pj_stun_msg *msg, 
     787                                       const pj_sockaddr_t *src_addr, 
     788                                       unsigned src_addr_len) 
     789{ 
     790    pj_status_t status; 
    796791 
    797792    /* Distribute to handler, or respond with Bad Request */ 
     
    800795                                           src_addr, src_addr_len); 
    801796    } else { 
    802         pj_stun_msg *response = NULL; 
     797        pj_stun_msg *response; 
    803798 
    804799        status = pj_stun_msg_create_response(tmp_pool, msg,  
     
    806801                                             &response); 
    807802        if (status == PJ_SUCCESS && response) { 
    808             status = send_response(sess, 0, tmp_pool, response,  
    809                                    src_addr, src_addr_len); 
     803            status = send_response(sess, tmp_pool, response,  
     804                                   PJ_FALSE, src_addr, src_addr_len); 
    810805        } 
    811806    } 
     
    862857        LOG_ERR_(sess, "STUN msg_decode() error", status); 
    863858        if (response) { 
    864             send_response(sess, 0, tmp_pool, response,  
    865                           src_addr, src_addr_len); 
     859            send_response(sess, tmp_pool, response,  
     860                          PJ_FALSE, src_addr, src_addr_len); 
    866861        } 
    867862        pj_pool_release(tmp_pool); 
     
    880875    pj_mutex_lock(sess->mutex); 
    881876 
     877    /* For requests, check if we have cached response */ 
     878    status = check_cached_response(sess, tmp_pool, msg,  
     879                                   src_addr, src_addr_len); 
     880    if (status == PJ_SUCCESS) { 
     881        goto on_return; 
     882    } 
     883 
     884    /* Authenticate the message */ 
     885    status = authenticate_msg(sess, packet, pkt_size, msg, tmp_pool,  
     886                              src_addr, src_addr_len); 
     887    if (status != PJ_SUCCESS) 
     888        goto on_return; 
     889 
     890    /* Handle message */ 
    882891    if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 
    883892        PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 
     
    900909    } 
    901910 
     911on_return: 
    902912    pj_mutex_unlock(sess->mutex); 
    903913 
Note: See TracChangeset for help on using the changeset viewer.