Ignore:
Timestamp:
Feb 23, 2007 1:07:54 AM (17 years ago)
Author:
bennylp
Message:

Ticket #121 and #122: Initial implementation of generic STUN transaction, with Binding request as an example

File:
1 edited

Legend:

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

    r993 r996  
    2727    void                *user_data; 
    2828 
    29     pj_str_t             realm; 
    30     pj_str_t             username; 
    31     pj_str_t             password; 
    32  
    33     pj_bool_t            fingerprint_enabled; 
     29    /* Long term credential */ 
     30    pj_str_t             l_realm; 
     31    pj_str_t             l_username; 
     32    pj_str_t             l_password; 
     33 
     34    /* Short term credential */ 
     35    pj_str_t             s_username; 
     36    pj_str_t             s_password; 
    3437 
    3538    pj_stun_tx_data      pending_request_list; 
     
    6568 
    6669static void tsx_on_complete(pj_stun_client_tsx *tsx, 
    67                                pj_status_t status,  
    68                                const pj_stun_msg *response); 
     70                            pj_status_t status,  
     71                            const pj_stun_msg *response); 
    6972static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx, 
    7073                                   const void *stun_pkt, 
     
    165168static pj_status_t session_apply_req(pj_stun_session *sess, 
    166169                                     pj_pool_t *pool, 
     170                                     unsigned options, 
    167171                                     pj_stun_msg *msg) 
    168172{ 
     
    172176     * Section 8.3.1.  Formulating the Request Message 
    173177     */ 
    174     if (sess->realm.slen || sess->username.slen) { 
     178    if (options & PJ_STUN_USE_LONG_TERM_CRED) { 
    175179        pj_stun_generic_string_attr *auname; 
    176180        pj_stun_msg_integrity_attr *amsgi; 
     181        pj_stun_generic_string_attr *arealm; 
    177182 
    178183        /* Create and add USERNAME attribute */ 
    179184        status = pj_stun_generic_string_attr_create(sess->pool,  
    180185                                                    PJ_STUN_ATTR_USERNAME, 
    181                                                     &sess->username, 
     186                                                    &sess->l_username, 
    182187                                                    &auname); 
    183188        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     
    186191        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    187192 
    188         if (sess->realm.slen) { 
    189             /* Add REALM only when long term credential is used */ 
    190             pj_stun_generic_string_attr *arealm; 
    191             status = pj_stun_generic_string_attr_create(sess->pool,  
    192                                                         PJ_STUN_ATTR_REALM, 
    193                                                         &sess->realm, 
    194                                                         &arealm); 
    195             PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    196  
    197             status = pj_stun_msg_add_attr(msg, &arealm->hdr); 
    198             PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    199         } 
     193        /* Add REALM only when long term credential is used */ 
     194        status = pj_stun_generic_string_attr_create(sess->pool,  
     195                                                    PJ_STUN_ATTR_REALM, 
     196                                                    &sess->l_realm, 
     197                                                    &arealm); 
     198        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     199 
     200        status = pj_stun_msg_add_attr(msg, &arealm->hdr); 
     201        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    200202 
    201203        /* Add MESSAGE-INTEGRITY attribute */ 
     
    206208        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    207209 
    208         PJ_TODO(COMPUTE_MESSAGE_INTEGRITY); 
    209  
     210        PJ_TODO(COMPUTE_MESSAGE_INTEGRITY1); 
     211 
     212    } else if (options & PJ_STUN_USE_SHORT_TERM_CRED) { 
     213        pj_stun_generic_string_attr *auname; 
     214        pj_stun_msg_integrity_attr *amsgi; 
     215 
     216        /* Create and add USERNAME attribute */ 
     217        status = pj_stun_generic_string_attr_create(sess->pool,  
     218                                                    PJ_STUN_ATTR_USERNAME, 
     219                                                    &sess->s_username, 
     220                                                    &auname); 
     221        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     222 
     223        status = pj_stun_msg_add_attr(msg, &auname->hdr); 
     224        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     225 
     226        /* Add MESSAGE-INTEGRITY attribute */ 
     227        status = pj_stun_msg_integrity_attr_create(sess->pool, &amsgi); 
     228        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     229 
     230        status = pj_stun_msg_add_attr(msg, &amsgi->hdr); 
     231        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     232 
     233        PJ_TODO(COMPUTE_MESSAGE_INTEGRITY2); 
    210234    } 
    211235 
    212236    /* Add FINGERPRINT attribute if necessary */ 
    213     if (sess->fingerprint_enabled) { 
     237    if (options & PJ_STUN_USE_FINGERPRINT) { 
    214238        pj_stun_fingerprint_attr *af; 
    215239 
     
    227251 
    228252 
    229  
    230  
    231  
     253static void tsx_on_complete(pj_stun_client_tsx *tsx, 
     254                            pj_status_t status,  
     255                            const pj_stun_msg *response) 
     256{ 
     257    pj_stun_tx_data *tdata; 
     258 
     259    tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx); 
     260 
     261    switch (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)) { 
     262    case PJ_STUN_BINDING_METHOD: 
     263        tdata->sess->cb.on_bind_response(tdata->sess, status, tdata, response); 
     264        break; 
     265    case PJ_STUN_ALLOCATE_METHOD: 
     266        tdata->sess->cb.on_allocate_response(tdata->sess, status, 
     267                                             tdata, response); 
     268        break; 
     269    case PJ_STUN_SET_ACTIVE_DESTINATION_METHOD: 
     270        tdata->sess->cb.on_set_active_destination_response(tdata->sess, status, 
     271                                                           tdata, response); 
     272        break; 
     273    case PJ_STUN_CONNECT_METHOD: 
     274        tdata->sess->cb.on_connect_response(tdata->sess, status, tdata, 
     275                                            response); 
     276        break; 
     277    default: 
     278        pj_assert(!"Unknown method"); 
     279        break; 
     280    } 
     281} 
     282 
     283static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx, 
     284                                   const void *stun_pkt, 
     285                                   pj_size_t pkt_size) 
     286{ 
     287    pj_stun_tx_data *tdata; 
     288 
     289    tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx); 
     290 
     291    return tdata->sess->cb.on_send_msg(tdata, stun_pkt, pkt_size, 
     292                                       tdata->addr_len, tdata->dst_addr); 
     293} 
     294 
     295/* **************************************************************************/ 
    232296 
    233297PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt, 
     
    261325{ 
    262326    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
     327 
    263328    pj_pool_release(sess->pool); 
    264329 
     
    281346} 
    282347 
    283 PJ_DEF(pj_status_t) pj_stun_session_set_credential( pj_stun_session *sess, 
    284                                                     const pj_str_t *realm, 
    285                                                     const pj_str_t *user, 
    286                                                     const pj_str_t *passwd) 
    287 { 
    288     pj_str_t empty = { NULL, 0 }; 
     348PJ_DEF(pj_status_t)  
     349pj_stun_session_set_long_term_credential(pj_stun_session *sess, 
     350                                         const pj_str_t *realm, 
     351                                         const pj_str_t *user, 
     352                                         const pj_str_t *passwd) 
     353{ 
     354    pj_str_t nil = { NULL, 0 }; 
    289355 
    290356    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    291     pj_strdup_with_null(sess->pool, &sess->realm, realm ? realm : &empty); 
    292     pj_strdup_with_null(sess->pool, &sess->username, user ? user : &empty); 
    293     pj_strdup_with_null(sess->pool, &sess->password, passwd ? passwd : &empty); 
    294  
    295     return PJ_SUCCESS; 
    296 } 
    297  
    298 PJ_DEF(pj_status_t) pj_stun_session_enable_fingerprint(pj_stun_session *sess, 
    299                                                        pj_bool_t enabled) 
    300 { 
     357    pj_strdup_with_null(sess->pool, &sess->l_realm, realm ? realm : &nil); 
     358    pj_strdup_with_null(sess->pool, &sess->l_username, user ? user : &nil); 
     359    pj_strdup_with_null(sess->pool, &sess->l_password, passwd ? passwd : &nil); 
     360 
     361    return PJ_SUCCESS; 
     362} 
     363 
     364 
     365PJ_DEF(pj_status_t)  
     366pj_stun_session_set_short_term_credential(pj_stun_session *sess, 
     367                                          const pj_str_t *user, 
     368                                          const pj_str_t *passwd) 
     369{ 
     370    pj_str_t nil = { NULL, 0 }; 
     371 
    301372    PJ_ASSERT_RETURN(sess, PJ_EINVAL); 
    302     sess->fingerprint_enabled = enabled; 
     373    pj_strdup_with_null(sess->pool, &sess->s_username, user ? user : &nil); 
     374    pj_strdup_with_null(sess->pool, &sess->s_password, passwd ? passwd : &nil); 
     375 
    303376    return PJ_SUCCESS; 
    304377} 
     
    308381                                                    pj_stun_tx_data **p_tdata) 
    309382{ 
    310     pj_pool_t *pool; 
    311383    pj_stun_tx_data *tdata; 
    312384    pj_status_t status; 
     
    318390        return status; 
    319391 
    320     status = session_apply_req(sess, pool, tdata->msg); 
    321     if (status != PJ_SUCCESS) { 
    322         destroy_tdata(tdata); 
    323         return status; 
    324     } 
    325  
    326392    *p_tdata = tdata; 
    327393    return PJ_SUCCESS; 
     
    368434 
    369435PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess, 
     436                                              unsigned options, 
    370437                                              unsigned addr_len, 
    371438                                              const pj_sockaddr_t *server, 
     
    376443    PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL); 
    377444 
     445    /* Allocate packet */ 
     446    tdata->max_len = PJ_STUN_MAX_PKT_LEN; 
     447    tdata->pkt = pj_pool_alloc(tdata->pool, tdata->max_len); 
     448 
    378449    if (PJ_LOG_MAX_LEVEL >= 5) { 
    379         char buf[512]; 
    380         unsigned buflen = sizeof(buf); 
     450        char *buf = (char*) tdata->pkt; 
    381451        const char *dst_name; 
    382452        int dst_port; 
     
    398468        PJ_LOG(5,(SNAME(sess),  
    399469                  "Sending STUN message to %s:%d:\n" 
    400                   "%s\n", 
     470                  "--- begin STUN message ---\n" 
     471                  "%s" 
     472                  "--- end of STUN message ---\n", 
    401473                  dst_name, dst_port, 
    402                   pj_stun_msg_dump(tdata->msg, buf, &buflen))); 
    403     } 
    404  
     474                  pj_stun_msg_dump(tdata->msg, buf, tdata->max_len, NULL))); 
     475    } 
     476 
     477    /* Apply options */ 
     478    status = session_apply_req(sess, tdata->pool, options, tdata->msg); 
     479    if (status != PJ_SUCCESS) { 
     480        LOG_ERR_(sess, "Error applying options", status); 
     481        destroy_tdata(tdata); 
     482        return status; 
     483    } 
     484 
     485    /* Encode message */ 
     486    status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len, 
     487                                0, &tdata->pkt_size); 
     488    if (status != PJ_SUCCESS) { 
     489        LOG_ERR_(sess, "STUN encode() error", status); 
     490        destroy_tdata(tdata); 
     491        return status; 
     492    } 
    405493 
    406494    /* If this is a STUN request message, then send the request with 
     
    410498 
    411499        /* Create STUN client transaction */ 
    412         status = pj_stun_client_tsx_create(sess->endpt, &tsx_cb,  
    413                                            &tdata->client_tsx); 
     500        status = pj_stun_client_tsx_create(sess->endpt, tdata->pool,  
     501                                           &tsx_cb, &tdata->client_tsx); 
    414502        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    415503        pj_stun_client_tsx_set_data(tdata->client_tsx, (void*)tdata); 
     504 
     505        /* Save the remote address */ 
     506        tdata->addr_len = addr_len; 
     507        tdata->dst_addr = server; 
    416508 
    417509        /* Send the request! */ 
    418510        status = pj_stun_client_tsx_send_msg(tdata->client_tsx, PJ_TRUE, 
    419                                              tdata->msg); 
     511                                             tdata->pkt, tdata->pkt_size); 
    420512        if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
    421513            LOG_ERR_(sess, "Error sending STUN request", status); 
     514            destroy_tdata(tdata); 
    422515            return status; 
    423516        } 
     
    428521    } else { 
    429522        /* Otherwise for non-request message, send directly to transport. */ 
    430         status = sess->cb.on_send_msg(tdata, addr_len, server); 
     523        status = sess->cb.on_send_msg(tdata, tdata->pkt, tdata->pkt_size, 
     524                                      addr_len, server); 
     525 
     526        if (status != PJ_SUCCESS && status != PJ_EPENDING) { 
     527            LOG_ERR_(sess, "Error sending STUN request", status); 
     528            destroy_tdata(tdata); 
     529            return status; 
     530        } 
    431531    } 
    432532 
     
    442542{ 
    443543    pj_stun_msg *msg; 
     544    pj_pool_t *tmp_pool; 
     545    char *dump; 
    444546    pj_status_t status; 
    445547 
    446548    PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL); 
    447549 
     550    tmp_pool = pj_pool_create(sess->endpt->pf, "tmpstun", 1024, 1024, NULL); 
     551    if (!tmp_pool) 
     552        return PJ_ENOMEM; 
     553 
    448554    /* Try to parse the message */ 
    449     status = pj_stun_msg_decode(tsx->pool, (const pj_uint8_t*)packet, 
     555    status = pj_stun_msg_decode(tmp_pool, (const pj_uint8_t*)packet, 
    450556                                pkt_size, 0, &msg, parsed_len, 
    451557                                NULL, NULL, NULL); 
    452558    if (status != PJ_SUCCESS) { 
    453559        LOG_ERR_(sess, "STUN msg_decode() error", status); 
     560        pj_pool_release(tmp_pool); 
    454561        return status; 
    455562    } 
     563 
     564    dump = pj_pool_alloc(tmp_pool, PJ_STUN_MAX_PKT_LEN); 
     565 
     566    PJ_LOG(4,(SNAME(sess),  
     567              "RX STUN message:\n" 
     568              "--- begin STUN message ---" 
     569              "%s" 
     570              "--- end of STUN message ---\n", 
     571              pj_stun_msg_dump(msg, dump, PJ_STUN_MAX_PKT_LEN, NULL))); 
     572 
    456573 
    457574    if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 
     
    464581        if (tdata == NULL) { 
    465582            LOG_ERR_(sess, "STUN error finding transaction", PJ_ENOTFOUND); 
     583            pj_pool_release(tmp_pool); 
    466584            return PJ_ENOTFOUND; 
    467585        } 
     
    472590         */ 
    473591        status = pj_stun_client_tsx_on_rx_msg(tdata->client_tsx, msg); 
    474         if (status != PJ_SUCCESS) 
     592        if (status != PJ_SUCCESS) { 
     593            pj_pool_release(tmp_pool); 
    475594            return status; 
     595        } 
    476596 
    477597        /* If transaction has completed, destroy the transmit data. 
     
    483603        } 
    484604 
     605        pj_pool_release(tmp_pool); 
    485606        return PJ_SUCCESS; 
    486607 
    487608    } else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) { 
    488609 
     610        PJ_TODO(HANDLE_INCOMING_STUN_REQUEST); 
    489611 
    490612    } else if (PJ_STUN_IS_INDICATION(msg->hdr.type)) { 
    491613 
     614        PJ_TODO(HANDLE_INCOMING_STUN_INDICATION); 
    492615 
    493616    } else { 
    494617        pj_assert(!"Unexpected!"); 
    495         return PJ_EBUG; 
    496     } 
    497  
    498 } 
    499  
     618    } 
     619 
     620    pj_pool_release(tmp_pool); 
     621    return PJ_ENOTSUP; 
     622} 
     623 
Note: See TracChangeset for help on using the changeset viewer.