Changeset 1089


Ignore:
Timestamp:
Mar 20, 2007 10:36:54 PM (17 years ago)
Author:
bennylp
Message:

Today's work

Location:
pjproject/trunk/pjnath
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjnath/include/pjnath/errno.h

    r1080 r1089  
    4646#define PJNATH_ESTUNFINGERPRINT     -1 
    4747#define PJNATH_ESTUNNOTRESPOND      -1 
     48#define PJNATH_ESTUNNOXORMAP        -1 
    4849 
    4950/** 
  • pjproject/trunk/pjnath/include/pjnath/ice.h

    r1085 r1089  
    2828#include <pjlib-util/resolver.h> 
    2929#include <pj/sock.h> 
     30#include <pj/timer.h> 
     31 
    3032 
    3133PJ_BEGIN_DECL 
     
    6870#define PJ_ICE_MAX_COMP     8 
    6971#define PJ_ICE_MAX_CHECKS   32 
     72#define PJ_ICE_TA_VAL       20 
    7073 
    7174/** 
     
    7477typedef struct pj_ice_comp 
    7578{ 
    76     unsigned        comp_id; 
    77     pj_sock_t       sock; 
     79    unsigned         comp_id; 
     80    pj_sock_t        sock; 
     81    pj_stun_session *stun_sess; 
     82    pj_sockaddr      local_addr; 
    7883} pj_ice_comp; 
    7984 
     
    105110typedef struct pj_ice_check 
    106111{ 
    107     unsigned            cand_id; 
    108     pj_uint32_t         comp_id; 
    109     pj_str_t            foundation; 
    110  
    111     pj_uint64_t         check_prio; 
    112     pj_ice_check_state  check_state; 
    113  
    114     pj_ice_cand_type    rem_type; 
    115     pj_str_t            rem_foundation; 
    116     pj_uint32_t         rem_prio; 
    117     pj_sockaddr         rem_addr; 
    118     pj_sockaddr         rem_base_addr; 
     112    pj_ice_cand         *lcand; 
     113    pj_ice_cand         *rcand; 
     114 
     115    pj_uint64_t          prio; 
     116    pj_ice_check_state   state; 
     117    pj_bool_t            nominated; 
     118    pj_status_t          err_code; 
    119119} pj_ice_check; 
    120120 
     
    132132    unsigned                 count; 
    133133    pj_ice_check             checks[PJ_ICE_MAX_CHECKS]; 
     134    pj_timer_entry           timer; 
    134135} pj_ice_checklist; 
    135136 
     
    176177    pj_ice_role          role; 
    177178    pj_ice_state         state; 
    178  
    179179    pj_ice_cb            cb; 
     180 
     181    pj_stun_config       stun_cfg; 
    180182 
    181183    /* STUN credentials */ 
     
    206208    pj_bool_t            relay_enabled; 
    207209    pj_sockaddr          stun_srv; 
    208  
    209     /* STUN sessions */ 
    210     pj_stun_session     *tx_sess; 
    211     pj_stun_session     *rx_sess; 
    212210}; 
    213211 
    214212 
    215 PJ_DECL(pj_status_t) pj_ice_create(pj_stun_config *cfg, 
     213PJ_DECL(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg, 
    216214                                   const char *name, 
    217215                                   pj_ice_role role, 
     
    257255PJ_DECL(unsigned) pj_ice_get_cand_cnt(pj_ice *ice); 
    258256PJ_DECL(pj_status_t) pj_ice_enum_cands(pj_ice *ice, 
    259                                        unsigned sort_by, 
    260257                                       unsigned *p_count, 
    261258                                       unsigned cand_ids[]); 
    262 PJ_DECL(unsigned) pj_ice_get_default_cand(pj_ice *ice, 
    263                                           int *cand_id); 
     259PJ_DECL(pj_status_t) pj_ice_get_default_cand(pj_ice *ice, 
     260                                             unsigned comp_id, 
     261                                             int *cand_id); 
    264262PJ_DECL(pj_status_t) pj_ice_get_cand(pj_ice *ice, 
    265263                                     unsigned cand_id, 
     
    267265 
    268266PJ_DECL(pj_status_t) pj_ice_create_check_list(pj_ice *ice, 
    269                                               pj_bool_t is_remote_offer, 
    270267                                              unsigned rem_cand_cnt, 
    271268                                              const pj_ice_cand rem_cand[]); 
  • pjproject/trunk/pjnath/include/pjnath/stun_auth.h

    r1080 r1089  
    156156 
    157157            /** 
     158             * Get the credential to be put in outgoing message. 
     159             * 
     160             * @param msg       The outgoing message where the credential is 
     161             *                  to be applied. 
     162             * @param user_data The user data as specified in the credential. 
     163             * @param pool      Pool where the callback can allocate memory 
     164             *                  to fill in the credential. 
     165             * @param realm     On return, the callback may specify the realm 
     166             *                  if long term credential is desired, otherwise 
     167             *                  this string must be set to empty. 
     168             * @param username  On return, the callback must fill in with the 
     169             *                  username. 
     170             * @param nonce     On return, the callback may optionally fill in 
     171             *                  this argument with NONCE value if desired, 
     172             *                  otherwise this argument must be set to empty. 
     173             * @param data_type On return, the callback must set this argument 
     174             *                  with the type of password in the data argument. 
     175             * @param data      On return, the callback must set this with 
     176             *                  the password, encoded according to data_type 
     177             *                  argument. 
     178             * 
     179             * @return          The callback must return PJ_SUCCESS, otherwise 
     180             *                  the message transmission will be cancelled. 
     181             */ 
     182            pj_status_t (*get_cred)(const pj_stun_msg *msg, 
     183                                    void *user_data, 
     184                                    pj_pool_t *pool, 
     185                                    pj_str_t *realm, 
     186                                    pj_str_t *username, 
     187                                    pj_str_t *nonce, 
     188                                    int *data_type, 
     189                                    pj_str_t *data); 
     190 
     191            /** 
    158192             * Get the password for the specified username. This function  
    159193             * is also used to check whether the username is valid. 
    160194             * 
     195             * @param msg       The STUN message where the password will be 
     196             *                  applied to. 
    161197             * @param user_data The user data as specified in the credential. 
    162198             * @param realm     The realm as specified in the message. 
     
    176212             *                  username is not valid. 
    177213             */ 
    178             pj_status_t (*get_password)(void *user_data,  
     214            pj_status_t (*get_password)(const pj_stun_msg *msg, 
     215                                        void *user_data,  
    179216                                        const pj_str_t *realm, 
    180217                                        const pj_str_t *username, 
     
    188225             * PJ_FALSE, 438 (Stale Nonce) response will be created. 
    189226             * 
     227             * @param msg       The STUN message where the nonce was received. 
    190228             * @param user_data The user data as specified in the credential. 
    191229             * @param realm     The realm as specified in the message. 
     
    196234             *                  NONCE can be accepted. 
    197235             */ 
    198             pj_bool_t   (*verify_nonce)(void *user_data, 
     236            pj_bool_t   (*verify_nonce)(const pj_stun_msg *msg, 
     237                                        void *user_data, 
    199238                                        const pj_str_t *realm, 
    200239                                        const pj_str_t *username, 
  • pjproject/trunk/pjnath/src/pjnath/ice.c

    r1085 r1089  
    2020#include <pjnath/errno.h> 
    2121#include <pj/addr_resolv.h> 
     22#include <pj/array.h> 
    2223#include <pj/assert.h> 
    2324#include <pj/log.h> 
     
    2728 
    2829 
     30/* String names for candidate types */ 
     31static const char *cand_type_names[] = 
     32{ 
     33    "Host", 
     34    "Server Reflexive", 
     35    "Peer Reflexive", 
     36    "Relayed" 
     37 
     38}; 
     39 
     40/* String names for pj_ice_check_state */ 
    2941static const char *check_state_name[] =  
    3042{ 
     
    3648}; 
    3749 
     50static const char *clist_state_name[] = 
     51{ 
     52    "Idle", 
     53    "Running", 
     54    "Completed" 
     55}; 
     56 
     57const pj_str_t host_foundation = {"host", 4}; 
     58const pj_str_t mapped_foundation = {"srfx", 4}; 
     59const pj_str_t relayed_foundation = {"rlyd", 4}; 
     60const pj_str_t peer_mapped_foundation = {"peer", 4}; 
     61 
     62#define CHECK_NAME_LEN  128 
     63#define LOG(expr)       PJ_LOG(4,expr) 
     64 
    3865static void destroy_ice(pj_ice *ice, 
    3966                        pj_status_t reason); 
    4067static void ice_set_state(pj_ice *ice, 
    4168                          pj_ice_state new_state); 
    42  
     69static pj_status_t start_periodic_check(pj_timer_heap_t *th,  
     70                                        pj_timer_entry *te); 
    4371static pj_status_t on_stun_send_msg(pj_stun_session *sess, 
    4472                                    const void *pkt, 
     
    5280                                      const pj_sockaddr_t *src_addr, 
    5381                                      unsigned src_addr_len); 
    54 static void on_stun_request_complete(pj_stun_session *sess, 
     82static void on_stun_request_complete(pj_stun_session *stun_sess, 
    5583                                     pj_status_t status, 
    5684                                     pj_stun_tx_data *tdata, 
     
    6795                                      pj_str_t *realm, 
    6896                                      pj_str_t *nonce); 
    69 static pj_status_t stun_auth_get_password(void *user_data,  
     97static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg, 
     98                                      void *user_data, 
     99                                      pj_pool_t *pool, 
     100                                      pj_str_t *realm, 
     101                                      pj_str_t *username, 
     102                                      pj_str_t *nonce, 
     103                                      int *data_type, 
     104                                      pj_str_t *data); 
     105static pj_status_t stun_auth_get_password(const pj_stun_msg *msg, 
     106                                          void *user_data,  
    70107                                          const pj_str_t *realm, 
    71108                                          const pj_str_t *username, 
     
    73110                                          int *data_type, 
    74111                                          pj_str_t *data); 
    75 static pj_bool_t stun_auth_verify_nonce(void *user_data, 
     112static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg, 
     113                                        void *user_data, 
    76114                                        const pj_str_t *realm, 
    77115                                        const pj_str_t *username, 
     
    79117 
    80118 
    81 PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *cfg, 
     119PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg, 
    82120                                  const char *name, 
    83121                                  pj_ice_role role, 
     
    89127    pj_pool_t *pool; 
    90128    pj_ice *ice; 
    91     pj_stun_session_cb sess_cb; 
    92     pj_stun_auth_cred auth_cred; 
    93129    pj_status_t status; 
    94130 
    95     PJ_ASSERT_RETURN(cfg && cb && p_ice, PJ_EINVAL); 
     131    PJ_ASSERT_RETURN(stun_cfg && cb && p_ice, PJ_EINVAL); 
    96132    PJ_ASSERT_RETURN(sock_type==PJ_SOCK_DGRAM || sock_type==PJ_SOCK_STREAM, 
    97133                     PJ_EINVAL); 
     
    100136        name = "ice%p"; 
    101137 
    102     pool = pj_pool_create(cfg->pf, name, 4000, 4000, NULL); 
     138    pool = pj_pool_create(stun_cfg->pf, name, 4000, 4000, NULL); 
    103139    ice = PJ_POOL_ZALLOC_T(pool, pj_ice); 
    104140    ice->pool = pool; 
     
    118154 
    119155    pj_memcpy(&ice->cb, cb, sizeof(*cb)); 
    120  
    121     /* Init STUN callbacks */ 
    122     pj_bzero(&sess_cb, sizeof(sess_cb)); 
    123     sess_cb.on_request_complete = &on_stun_request_complete; 
    124     sess_cb.on_rx_indication = &on_stun_rx_indication; 
    125     sess_cb.on_rx_request = &on_stun_rx_request; 
    126     sess_cb.on_send_msg = &on_stun_send_msg; 
    127  
    128     /* Init STUN authentication credential */ 
    129     pj_bzero(&auth_cred, sizeof(auth_cred)); 
    130     auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; 
    131     auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth; 
    132     auth_cred.data.dyn_cred.get_password = &stun_auth_get_password; 
    133     auth_cred.data.dyn_cred.verify_nonce = &stun_auth_verify_nonce; 
    134  
    135     /* Create STUN session for outgoing requests */ 
    136     status = pj_stun_session_create(cfg, ice->obj_name, &sess_cb, PJ_FALSE, 
    137                                     &ice->tx_sess); 
    138     if (status != PJ_SUCCESS) { 
    139         destroy_ice(ice, status); 
    140         return status; 
    141     } 
    142  
    143     pj_stun_session_set_user_data(ice->tx_sess, ice); 
    144     auth_cred.data.dyn_cred.user_data = ice->tx_sess; 
    145     pj_stun_session_set_credential(ice->tx_sess, &auth_cred); 
    146  
    147     /* Create STUN session for incoming requests */ 
    148     status = pj_stun_session_create(cfg, ice->obj_name, &sess_cb, PJ_FALSE, 
    149                                     &ice->rx_sess); 
    150     if (status != PJ_SUCCESS) { 
    151         destroy_ice(ice, status); 
    152         return status; 
    153     } 
    154  
    155     pj_stun_session_set_user_data(ice->rx_sess, ice); 
    156     auth_cred.data.dyn_cred.user_data = ice->rx_sess; 
    157     pj_stun_session_set_credential(ice->rx_sess, &auth_cred); 
     156    pj_memcpy(&ice->stun_cfg, stun_cfg, sizeof(*stun_cfg)); 
     157 
    158158 
    159159    /* Done */ 
    160160    *p_ice = ice; 
    161161 
    162     PJ_LOG(4,(ice->obj_name, "ICE session created")); 
     162    LOG((ice->obj_name, "ICE session created")); 
    163163 
    164164    return PJ_SUCCESS; 
     
    170170{ 
    171171    if (reason == PJ_SUCCESS) { 
    172         PJ_LOG(4,(ice->obj_name, "Destroying ICE session")); 
     172        LOG((ice->obj_name, "Destroying ICE session")); 
    173173    } 
    174174 
     
    318318 
    319319 
     320 
    320321PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice, 
    321322                                    unsigned comp_id, 
     
    345346} 
    346347 
     348typedef struct stun_data 
     349{ 
     350    pj_ice      *ice; 
     351    unsigned     comp_id; 
     352    pj_ice_comp *comp; 
     353} stun_data; 
     354 
    347355 
    348356PJ_DEF(pj_status_t) pj_ice_add_sock_comp( pj_ice *ice, 
     
    350358                                          pj_sock_t sock) 
    351359{ 
     360    pj_stun_session_cb sess_cb; 
     361    pj_ice_comp *comp; 
     362    pj_stun_auth_cred auth_cred; 
     363    stun_data *sd; 
     364    int addr_len; 
     365    pj_status_t status; 
     366 
    352367    PJ_ASSERT_RETURN(ice && sock != PJ_INVALID_SOCKET, PJ_EINVAL); 
    353368    PJ_ASSERT_RETURN(ice->comp_cnt < PJ_ARRAY_SIZE(ice->comp), PJ_ETOOMANY); 
    354369 
    355370    pj_mutex_lock(ice->mutex); 
    356     ice->comp[ice->comp_cnt].comp_id = comp_id; 
    357     ice->comp[ice->comp_cnt].sock = sock; 
    358     ++ice->comp_cnt; 
     371 
     372    comp = &ice->comp[ice->comp_cnt]; 
     373    comp->comp_id = comp_id; 
     374    comp->sock = sock; 
     375 
     376    addr_len = sizeof(comp->local_addr); 
     377    status = pj_sock_getsockname(sock, &comp->local_addr, &addr_len); 
     378    if (status != PJ_SUCCESS) { 
     379        pj_mutex_unlock(ice->mutex); 
     380        return status; 
     381    } 
     382 
     383 
     384    /* Init STUN callbacks */ 
     385    pj_bzero(&sess_cb, sizeof(sess_cb)); 
     386    sess_cb.on_request_complete = &on_stun_request_complete; 
     387    sess_cb.on_rx_indication = &on_stun_rx_indication; 
     388    sess_cb.on_rx_request = &on_stun_rx_request; 
     389    sess_cb.on_send_msg = &on_stun_send_msg; 
     390 
     391    /* Create STUN session for this component */ 
     392    status = pj_stun_session_create(&ice->stun_cfg, ice->obj_name,  
     393                                    &sess_cb, PJ_FALSE, 
     394                                    &comp->stun_sess); 
     395    if (status != PJ_SUCCESS) { 
     396        pj_mutex_unlock(ice->mutex); 
     397        return status; 
     398    } 
     399 
     400    /* Associate data with this STUN session */ 
     401    sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data); 
     402    sd->ice = ice; 
     403    sd->comp_id = comp_id; 
     404    sd->comp = comp; 
     405    pj_stun_session_set_user_data(comp->stun_sess, sd); 
     406 
     407    /* Init STUN authentication credential */ 
     408    pj_bzero(&auth_cred, sizeof(auth_cred)); 
     409    auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC; 
     410    auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth; 
     411    auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred; 
     412    auth_cred.data.dyn_cred.get_password = &stun_auth_get_password; 
     413    auth_cred.data.dyn_cred.verify_nonce = &stun_auth_verify_nonce; 
     414    auth_cred.data.dyn_cred.user_data = comp->stun_sess; 
     415    pj_stun_session_set_credential(comp->stun_sess, &auth_cred); 
     416 
     417    /* Done */ 
     418    ice->comp_cnt++; 
    359419    pj_mutex_unlock(ice->mutex); 
    360420 
     
    378438 
    379439 
    380 static pj_status_t stun_auth_get_password(void *user_data,  
     440/* Get credential to be sent with outgoing message */ 
     441static pj_status_t stun_auth_get_cred(const pj_stun_msg *msg, 
     442                                      void *user_data, 
     443                                      pj_pool_t *pool, 
     444                                      pj_str_t *realm, 
     445                                      pj_str_t *username, 
     446                                      pj_str_t *nonce, 
     447                                      int *data_type, 
     448                                      pj_str_t *data) 
     449{ 
     450    pj_stun_session *sess = (pj_stun_session *)user_data; 
     451    stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess); 
     452    pj_ice *ice = sd->ice; 
     453 
     454    PJ_UNUSED_ARG(pool); 
     455    realm->slen = nonce->slen = 0; 
     456 
     457    if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 
     458        PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 
     459    { 
     460        /* Outgoing responses need to have the same credential as 
     461         * incoming requests. 
     462         */ 
     463        *username = ice->rx_uname; 
     464        *data_type = 0; 
     465        *data = ice->rx_pass; 
     466    } 
     467    else { 
     468        *username = ice->tx_uname; 
     469        *data_type = 0; 
     470        *data = ice->tx_pass; 
     471    } 
     472 
     473    return PJ_SUCCESS; 
     474} 
     475 
     476/* Get password to be used to authenticate incoming message */ 
     477static pj_status_t stun_auth_get_password(const pj_stun_msg *msg, 
     478                                          void *user_data,  
    381479                                          const pj_str_t *realm, 
    382480                                          const pj_str_t *username, 
     
    386484{ 
    387485    pj_stun_session *sess = (pj_stun_session *)user_data; 
    388     pj_ice *ice = (pj_ice*) pj_stun_session_get_user_data(sess); 
     486    stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess); 
     487    pj_ice *ice = sd->ice; 
    389488 
    390489    PJ_UNUSED_ARG(realm); 
    391490    PJ_UNUSED_ARG(pool); 
    392491 
    393     if (sess == ice->tx_sess) { 
     492    if (PJ_STUN_IS_RESPONSE(msg->hdr.type) || 
     493        PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 
     494    { 
     495        /* Incoming response is authenticated with TX credential */ 
    394496        /* Verify username */ 
    395497        if (pj_strcmp(username, &ice->tx_uname) != 0) 
     
    397499        *data_type = 0; 
    398500        *data = ice->tx_pass; 
     501 
    399502    } else { 
     503        /* Incoming request is authenticated with RX credential */ 
    400504        /* The agent MUST accept a credential if the username consists 
    401505         * of two values separated by a colon, where the first value is 
     
    408512        *data_type = 0; 
    409513        *data = ice->rx_pass; 
    410     } 
    411  
    412     return PJ_SUCCESS; 
    413 } 
    414  
    415  
    416 static pj_bool_t stun_auth_verify_nonce(void *user_data, 
     514 
     515    } 
     516 
     517    return PJ_SUCCESS; 
     518} 
     519 
     520 
     521static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg, 
     522                                        void *user_data, 
    417523                                        const pj_str_t *realm, 
    418524                                        const pj_str_t *username, 
     
    420526{ 
    421527    /* We don't use NONCE */ 
     528    PJ_UNUSED_ARG(msg); 
    422529    PJ_UNUSED_ARG(user_data); 
    423530    PJ_UNUSED_ARG(realm); 
     
    484591 
    485592        status = pj_ice_add_cand(ice, i, PJ_ICE_CAND_TYPE_HOST, 65535, 
    486                                  NULL, &addr, &addr, NULL, 
     593                                 &host_foundation, &addr, &addr, NULL, 
    487594                                 sizeof(pj_sockaddr_in), NULL); 
    488595        if (status != PJ_SUCCESS) 
     
    493600} 
    494601 
    495 static pj_status_t gather_mapped_cands(pj_ice *ice) 
    496 { 
    497     PJ_UNUSED_ARG(ice); 
    498     return PJ_ENOTSUP; 
    499 } 
    500  
    501 static pj_status_t gather_relayed_cands(pj_ice *ice) 
    502 { 
    503     PJ_UNUSED_ARG(ice); 
    504     return PJ_ENOTSUP; 
    505 } 
     602/* Eliminate redundant candidates. */ 
     603static void eliminate_redundant_cand(unsigned *cnt, 
     604                                     pj_ice_cand cand[]) 
     605{ 
     606 
     607    /* A candidate is redundant if its transport address equals another  
     608     * candidate, and its base equals the base of that other candidate. 
     609     * Note that two candidates can have the same transport address yet 
     610     * have different bases, and these would not be considered redundant. 
     611     */ 
     612    PJ_TODO(ELIMINATE_REDUNDANT_CANDIDATES); 
     613    PJ_UNUSED_ARG(cnt); 
     614    PJ_UNUSED_ARG(cand); 
     615} 
     616 
    506617 
    507618PJ_DEF(pj_status_t) pj_ice_start_gather(pj_ice *ice, 
     
    516627    if (status != PJ_SUCCESS) 
    517628        return status; 
     629 
     630    /* Eliminate redundant host candidates. */ 
     631    eliminate_redundant_cand(&ice->lcand_cnt, ice->lcand); 
    518632 
    519633    PJ_TODO(GATHER_MAPPED_AND_RELAYED_CANDIDATES); 
     
    556670    pj_ice_cand *lcand; 
    557671    pj_status_t status = PJ_SUCCESS; 
     672    char tmp[128]; 
     673 
     674    PJ_ASSERT_RETURN(ice && comp_id && type && local_pref && 
     675                     foundation && addr && base_addr && addr_len, 
     676                     PJ_EINVAL); 
    558677 
    559678    pj_mutex_lock(ice->mutex); 
     
    579698        *p_cand_id = ice->lcand_cnt; 
    580699 
     700    pj_ansi_strcpy(tmp, pj_inet_ntoa(lcand->addr.ipv4.sin_addr)); 
     701    LOG((ice->obj_name,  
     702         "Candidate %d added: comp_id=%d, type=%s, foundation=%.*s, " 
     703         "addr=%s:%d, base=%s:%d, prio=0x%x (%u)", 
     704         ice->lcand_cnt,  
     705         lcand->comp_id,  
     706         cand_type_names[lcand->type], 
     707         (int)lcand->foundation.slen, 
     708         lcand->foundation.ptr, 
     709         tmp,  
     710         (int)pj_ntohs(lcand->addr.ipv4.sin_port), 
     711         pj_inet_ntoa(lcand->base_addr.ipv4.sin_addr), 
     712         (int)pj_htons(lcand->base_addr.ipv4.sin_port), 
     713         lcand->prio, lcand->prio)); 
     714 
    581715    ++ice->lcand_cnt; 
    582716 
     
    594728 
    595729PJ_DEF(pj_status_t) pj_ice_enum_cands(pj_ice *ice, 
    596                                       unsigned sort_by, 
    597730                                      unsigned *p_count, 
    598731                                      unsigned cand_ids[]) 
     
    600733    unsigned i, count; 
    601734 
    602     PJ_UNUSED_ARG(sort_by); 
     735    PJ_ASSERT_RETURN(ice && p_count && *p_count && cand_ids, PJ_EINVAL); 
    603736 
    604737    pj_mutex_lock(ice->mutex); 
     
    615748 
    616749 
     750PJ_DEF(pj_status_t) pj_ice_get_default_cand(pj_ice *ice, 
     751                                            unsigned comp_id, 
     752                                            int *cand_id) 
     753{ 
     754    PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL); 
     755 
     756    pj_mutex_lock(ice->mutex); 
     757 
     758    /* First find in valid list if we have nominated pair */ 
     759 
     760    /* If there's no nominated pair, find relayed candidate */ 
     761 
     762    /* If there's no relayed candidate, find server reflexive candidate */ 
     763 
     764    /* Otherwise return host candidate */ 
     765 
     766    pj_assert(!"Not implemented yet"); 
     767    PJ_TODO(IMPLEMENT_GET_DEFAULT_CAND); 
     768 
     769    pj_mutex_unlock(ice->mutex); 
     770 
     771    return PJ_SUCCESS; 
     772} 
     773 
     774 
    617775PJ_DEF(pj_status_t) pj_ice_get_cand(pj_ice *ice, 
    618776                                    unsigned cand_id, 
     
    635793#endif 
    636794 
    637 static pj_uint64_t CALC_CHECK_PRIO(pj_uint32_t O, pj_uint32_t A) 
    638 { 
     795static pj_uint64_t CALC_CHECK_PRIO(const pj_ice *ice,  
     796                                   const pj_ice_cand *lcand, 
     797                                   const pj_ice_cand *rcand) 
     798{ 
     799    pj_uint32_t O, A; 
     800 
     801    if (ice->role == PJ_ICE_ROLE_CONTROLLING) { 
     802        O = lcand->prio;  
     803        A = rcand->prio; 
     804    } else { 
     805        O = rcand->prio; 
     806        A = lcand->prio; 
     807    } 
     808 
    639809    return ((pj_uint64_t)1 << 32) * MIN(O, A) + 
    640810           (pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0); 
     
    645815                              const pj_ice_check *check) 
    646816{ 
    647     char local_addr[128]; 
     817    const pj_ice_cand *lcand = check->lcand; 
     818    const pj_ice_cand *rcand = check->rcand; 
     819    char laddr[CHECK_NAME_LEN]; 
    648820    int len; 
    649821 
    650     pj_ansi_strcpy(local_addr,  
    651                    pj_inet_ntoa(ice->lcand[check->cand_id].addr.ipv4.sin_addr)); 
    652  
    653     len = pj_ansi_snprintf(buffer, bufsize, 
    654               "%s:%d-->%s:%d", 
    655               local_addr, 
    656               (int)pj_ntohs(ice->lcand[check->cand_id].addr.ipv4.sin_port), 
    657               pj_inet_ntoa(check->rem_addr.ipv4.sin_addr), 
    658               (int)pj_ntohs(check->rem_addr.ipv4.sin_port)); 
     822    pj_ansi_strcpy(laddr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr)); 
     823 
     824    if (lcand->addr.addr.sa_family == PJ_AF_INET) { 
     825        len = pj_ansi_snprintf(buffer, bufsize, 
     826                               "%s:%d-->%s:%d", 
     827                               laddr, (int)pj_ntohs(lcand->addr.ipv4.sin_port), 
     828                               pj_inet_ntoa(rcand->addr.ipv4.sin_addr), 
     829                               (int)pj_ntohs(rcand->addr.ipv4.sin_port)); 
     830    } else { 
     831        len = pj_ansi_snprintf(buffer, bufsize, "IPv6->IPv6"); 
     832    } 
     833 
     834 
    659835    if (len < 0) 
    660836        len = 0; 
     
    671847{ 
    672848    unsigned i; 
    673     char buffer[128]; 
    674  
    675     PJ_LOG(4,(ice->obj_name, "%s", title)); 
     849    char buffer[CHECK_NAME_LEN]; 
     850 
     851    LOG((ice->obj_name, "%s", title)); 
    676852    for (i=0; i<clist->count; ++i) { 
    677853        const pj_ice_check *c = &clist->checks[i]; 
    678         PJ_LOG(4,(ice->obj_name, " %d: %s (prio=%u, state=%s)", 
    679                   i, dump_check(buffer, sizeof(buffer), ice, c), 
    680                   c->check_prio, check_state_name[c->check_state])); 
     854        LOG((ice->obj_name, " %d: %s (prio=%u, state=%s)", 
     855             i, dump_check(buffer, sizeof(buffer), ice, c), 
     856             c->prio, check_state_name[c->state])); 
    681857    } 
    682858} 
     
    685861#endif 
    686862 
     863static void check_set_state(pj_ice *ice, pj_ice_check *check, 
     864                            pj_ice_check_state st,  
     865                            pj_status_t err_code) 
     866{ 
     867    char buf[CHECK_NAME_LEN]; 
     868    LOG((ice->obj_name, "Check %s: state changed from %s to %s", 
     869         dump_check(buf, sizeof(buf), ice, check), 
     870         check_state_name[check->state], 
     871         check_state_name[st])); 
     872    check->state = st; 
     873    check->err_code = err_code; 
     874} 
     875 
     876static void clist_set_state(pj_ice *ice, pj_ice_checklist *clist, 
     877                            pj_ice_checklist_state st) 
     878{ 
     879    LOG((ice->obj_name, "Checklist: state changed from %s to %s", 
     880         clist_state_name[clist->state], 
     881         clist_state_name[st])); 
     882    clist->state = st; 
     883} 
     884 
    687885static void sort_checklist(pj_ice_checklist *clist) 
    688886{ 
     
    692890        unsigned j, highest = i; 
    693891        for (j=i+1; j<clist->count; ++j) { 
    694             if (clist->checks[j].check_prio >  
    695                 clist->checks[highest].check_prio)  
    696             { 
     892            if (clist->checks[j].prio > clist->checks[highest].prio) { 
    697893                highest = j; 
    698894            } 
     
    710906} 
    711907 
     908 
     909enum  
     910{  
     911    SOCKADDR_EQUAL = 0,  
     912    SOCKADDR_NOT_EQUAL = 1  
     913}; 
     914 
     915/* Utility: compare sockaddr. 
     916 * Returns 0 if equal. 
     917 */ 
     918static int sockaddr_cmp(const pj_sockaddr *a1, const pj_sockaddr *a2) 
     919{ 
     920    if (a1->addr.sa_family != a2->addr.sa_family) 
     921        return SOCKADDR_NOT_EQUAL; 
     922 
     923    if (a1->addr.sa_family == PJ_AF_INET) { 
     924        return !(a1->ipv4.sin_addr.s_addr == a2->ipv4.sin_addr.s_addr && 
     925                 a1->ipv4.sin_port == a2->ipv4.sin_port); 
     926    } else if (a1->addr.sa_family == PJ_AF_INET6) { 
     927        return pj_memcmp(&a1->ipv6, &a2->ipv6, sizeof(a1->ipv6)); 
     928    } else { 
     929        pj_assert(!"Invalid address family!"); 
     930        return SOCKADDR_NOT_EQUAL; 
     931    } 
     932} 
     933 
     934 
     935/* Prune checklist, this must have been done after the checklist 
     936 * is sorted. 
     937 */ 
     938static void prune_checklist(pj_ice *ice, pj_ice_checklist *clist) 
     939{ 
     940    unsigned i; 
     941 
     942    /* Since an agent cannot send requests directly from a reflexive 
     943     * candidate, but only from its base, the agent next goes through the 
     944     * sorted list of candidate pairs.  For each pair where the local 
     945     * candidate is server reflexive, the server reflexive candidate MUST be 
     946     * replaced by its base.  Once this has been done, the agent MUST prune 
     947     * the list.  This is done by removing a pair if its local and remote 
     948     * candidates are identical to the local and remote candidates of a pair 
     949     * higher up on the priority list.  The result is a sequence of ordered 
     950     * candidate pairs, called the check list for that media stream.     
     951     */ 
     952    for (i=0; i<clist->count; ++i) { 
     953        pj_ice_cand *licand = clist->checks[i].lcand; 
     954        pj_ice_cand *ricand = clist->checks[i].rcand; 
     955        const pj_sockaddr *liaddr; 
     956        unsigned j; 
     957 
     958        if (licand->type == PJ_ICE_CAND_TYPE_MAPPED) 
     959            liaddr = &licand->base_addr; 
     960        else 
     961            liaddr = &licand->addr; 
     962 
     963        for (j=i+1; j<clist->count;) { 
     964            pj_ice_cand *ljcand = clist->checks[j].lcand; 
     965            pj_ice_cand *rjcand = clist->checks[j].rcand; 
     966            const pj_sockaddr *ljaddr; 
     967 
     968            if (ljcand->type == PJ_ICE_CAND_TYPE_MAPPED) 
     969                ljaddr = &licand->base_addr; 
     970            else 
     971                ljaddr = &licand->addr; 
     972 
     973            if (sockaddr_cmp(liaddr, ljaddr) == SOCKADDR_EQUAL && 
     974                sockaddr_cmp(&ricand->addr, &rjcand->addr) == SOCKADDR_EQUAL) 
     975            { 
     976                /* Found duplicate, remove it */ 
     977                char buf[CHECK_NAME_LEN]; 
     978 
     979                LOG((ice->obj_name, "Check %s pruned", 
     980                    dump_check(buf, sizeof(buf), ice, &clist->checks[j]))); 
     981 
     982                pj_array_erase(clist->checks, sizeof(clist->checks[0]), 
     983                               clist->count, j); 
     984                --clist->count; 
     985 
     986            } else { 
     987                ++j; 
     988            } 
     989        } 
     990    } 
     991} 
     992 
     993typedef struct timer_data 
     994{ 
     995    pj_ice              *ice; 
     996    pj_ice_checklist    *clist; 
     997} timer_data; 
     998 
    712999PJ_DEF(pj_status_t) pj_ice_create_check_list(pj_ice *ice, 
    713                                              pj_bool_t is_remote_offer, 
    714                                              unsigned rem_cand_cnt, 
    715                                              const pj_ice_cand rem_cand[]) 
     1000                                             unsigned rcand_cnt, 
     1001                                             const pj_ice_cand rcand[]) 
    7161002{ 
    7171003    pj_ice_checklist *clist; 
     1004    timer_data *td; 
    7181005    unsigned i, j; 
    7191006 
    720     PJ_ASSERT_RETURN(ice && rem_cand_cnt && rem_cand, PJ_EINVAL); 
    721     PJ_ASSERT_RETURN(rem_cand_cnt < PJ_ICE_MAX_CAND, PJ_ETOOMANY); 
     1007    PJ_ASSERT_RETURN(ice && rcand_cnt && rcand, PJ_EINVAL); 
     1008    PJ_ASSERT_RETURN(rcand_cnt + ice->rcand_cnt <= PJ_ICE_MAX_CAND,  
     1009                     PJ_ETOOMANY); 
    7221010 
    7231011    pj_mutex_lock(ice->mutex); 
     
    7251013    /* Save remote candidates */ 
    7261014    ice->rcand_cnt = 0; 
    727     for (i=0; i<rem_cand_cnt; ++i) { 
     1015    for (i=0; i<rcand_cnt; ++i) { 
    7281016        pj_ice_cand *cn = &ice->rcand[ice->rcand_cnt++]; 
    729         pj_memcpy(cn, &rem_cand[i], sizeof(pj_ice_cand)); 
    730         pj_strdup(ice->pool, &cn->foundation, &rem_cand[i].foundation); 
     1017        pj_memcpy(cn, &rcand[i], sizeof(pj_ice_cand)); 
     1018        pj_strdup(ice->pool, &cn->foundation, &rcand[i].foundation); 
    7311019    } 
    7321020 
     
    7341022    clist = &ice->cklist; 
    7351023    for (i=0; i<ice->lcand_cnt; ++i) { 
    736         for (j=0; j<rem_cand_cnt; ++j) { 
    737  
    738             pj_ice_check *c = &clist->checks[clist->count++]; 
     1024        for (j=0; j<ice->rcand_cnt; ++j) { 
     1025 
     1026            pj_ice_cand *lcand = &ice->lcand[i]; 
     1027            pj_ice_cand *rcand = &ice->rcand[j]; 
     1028            pj_ice_check *chk = &clist->checks[clist->count]; 
     1029 
     1030            if (clist->count > PJ_ICE_MAX_CHECKS) { 
     1031                pj_mutex_unlock(ice->mutex); 
     1032                return PJ_ETOOMANY; 
     1033            } else { 
     1034                clist->count++; 
     1035            } 
    7391036 
    7401037            /* A local candidate is paired with a remote candidate if 
     
    7421039             * and have the same IP address version.  
    7431040             */ 
    744             if (ice->lcand[i].comp_id != rem_cand[j].comp_id || 
    745                 pj_strcmp(&ice->lcand[i].foundation,&rem_cand[j].foundation)==0) 
     1041            if (lcand->comp_id != rcand->comp_id || 
     1042                lcand->addr.addr.sa_family != rcand->addr.addr.sa_family) 
    7461043            { 
    7471044                continue; 
    7481045            } 
    7491046 
    750             c->cand_id = i; 
    751             c->comp_id = ice->lcand[i].comp_id; 
    752             c->foundation = ice->lcand[i].foundation; 
    753  
    754             if (is_remote_offer) { 
    755                 c->check_prio = CALC_CHECK_PRIO(rem_cand[j].prio, 
    756                                                 ice->lcand[i].prio); 
    757             } else { 
    758                 c->check_prio = CALC_CHECK_PRIO(ice->lcand[i].prio,  
    759                                                 rem_cand[j].prio); 
    760             } 
    761  
    762             c->rem_type = rem_cand[j].type; 
    763             pj_strdup(ice->pool, &c->rem_foundation, &rem_cand[j].foundation); 
    764             c->rem_prio = rem_cand[j].prio; 
    765             pj_memcpy(&c->rem_addr, &rem_cand[j].addr,  
    766                       sizeof(rem_cand[j].addr)); 
    767             pj_memcpy(&c->rem_base_addr, &rem_cand[j].base_addr,  
    768                       sizeof(rem_cand[j].addr)); 
     1047 
     1048            chk->lcand = lcand; 
     1049            chk->rcand = rcand; 
     1050            chk->state = PJ_ICE_CHECK_STATE_FROZEN; 
     1051 
     1052            chk->prio = CALC_CHECK_PRIO(ice, lcand, rcand); 
    7691053        } 
    7701054    } 
     
    7741058 
    7751059    /* Prune the checklist */ 
    776     for (i=0; i<clist->count; ++i) { 
    777         PJ_TODO(PRUNE_CHECKLIST); 
    778     } 
     1060    prune_checklist(ice, clist); 
     1061 
     1062    /* Init timer entry in the checklist. Initially the timer ID is FALSE 
     1063     * because timer is not running. 
     1064     */ 
     1065    clist->timer.id = PJ_FALSE; 
     1066    td = PJ_POOL_ZALLOC_T(ice->pool, timer_data); 
     1067    td->ice = ice; 
     1068    td->clist = clist; 
     1069    clist->timer.user_data = (void*)td; 
     1070    clist->timer.cb = &start_periodic_check; 
     1071 
    7791072 
    7801073    /* Log checklist */ 
     
    7991092{ 
    8001093    pj_stun_tx_data *tdata; 
     1094    pj_ice_comp *comp; 
    8011095    struct req_data *rd; 
    8021096    pj_ice_check *check; 
     1097    const pj_ice_cand *lcand; 
     1098    const pj_ice_cand *rcand; 
    8031099    pj_uint32_t prio; 
    8041100    char buffer[128]; 
     
    8061102 
    8071103    check = &clist->checks[check_id]; 
    808  
    809     PJ_LOG(5,(ice->obj_name,  
    810               "Sending connectivity check for check %d: %s",  
    811               check_id, dump_check(buffer, sizeof(buffer), ice, check))); 
     1104    lcand = check->lcand; 
     1105    rcand = check->rcand; 
     1106    comp = &ice->comp[lcand->comp_id]; 
     1107 
     1108    LOG((ice->obj_name,  
     1109         "Sending connectivity check for check %d: %s",  
     1110         check_id, dump_check(buffer, sizeof(buffer), ice, check))); 
    8121111 
    8131112    /* Create request */ 
    814     status = pj_stun_session_create_req(ice->tx_sess,  
     1113    status = pj_stun_session_create_req(comp->stun_sess,  
    8151114                                        PJ_STUN_BINDING_REQUEST, &tdata); 
    8161115    if (status != PJ_SUCCESS) 
     
    8271126 
    8281127    /* Add PRIORITY */ 
    829     prio = CALC_CAND_PRIO(check->rem_type, 65535, check->comp_id); 
     1128    prio = CALC_CAND_PRIO(PJ_ICE_CAND_TYPE_PEER_MAPPED, 65535,  
     1129                          lcand->comp_id); 
    8301130    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_PRIORITY, 
    8311131                              prio); 
     
    8371137    } 
    8381138 
     1139    /* Note that USERNAME and MESSAGE-INTEGRITY will be added by the  
     1140     * STUN session. 
     1141     */ 
     1142 
    8391143    /* Initiate STUN transaction to send the request */ 
    840     status = pj_stun_session_send_msg(ice->tx_sess, PJ_FALSE,  
    841                                       &check->rem_addr,  
     1144    status = pj_stun_session_send_msg(comp->stun_sess, PJ_FALSE,  
     1145                                      &rcand->addr,  
    8421146                                      sizeof(pj_sockaddr_in), tdata); 
    8431147    if (status != PJ_SUCCESS) 
    8441148        return status; 
    8451149 
    846     check->check_state = PJ_ICE_CHECK_STATE_IN_PROGRESS; 
    847     return PJ_SUCCESS; 
    848 } 
    849  
    850 /* Start periodic check for the specified checklist */ 
    851 static pj_status_t start_periodic_check(pj_ice *ice, pj_ice_checklist *clist) 
    852 { 
     1150    check_set_state(ice, check, PJ_ICE_CHECK_STATE_IN_PROGRESS, PJ_SUCCESS); 
     1151    return PJ_SUCCESS; 
     1152} 
     1153 
     1154 
     1155/* Start periodic check for the specified checklist. 
     1156 * This callback is called by timer on every Ta (20msec by default) 
     1157 */ 
     1158static pj_status_t start_periodic_check(pj_timer_heap_t *th,  
     1159                                        pj_timer_entry *te) 
     1160{ 
     1161    timer_data *td; 
     1162    pj_ice *ice; 
     1163    pj_ice_checklist *clist; 
    8531164    unsigned i, start_count=0; 
    8541165    pj_status_t status; 
    8551166 
    856     /* Checklist state must be idle or completed */ 
    857     pj_assert(clist->state == PJ_ICE_CHECKLIST_ST_IDLE || 
    858               clist->state == PJ_ICE_CHECKLIST_ST_COMPLETED); 
     1167    td = (struct timer_data*) te->user_data; 
     1168    ice = td->ice; 
     1169    clist = td->clist; 
     1170 
     1171    pj_mutex_lock(ice->mutex); 
     1172 
     1173    /* Set timer ID to FALSE first */ 
     1174    te->id = PJ_FALSE; 
    8591175 
    8601176    /* Set checklist state to Running */ 
    861     clist->state = PJ_ICE_CHECKLIST_ST_RUNNING; 
    862  
    863     PJ_LOG(4,(ice->obj_name, "Starting checklist periodic check")); 
    864  
    865     /* Send STUN Binding request for checks in Waiting list */ 
     1177    clist_set_state(ice, clist, PJ_ICE_CHECKLIST_ST_RUNNING); 
     1178 
     1179    LOG((ice->obj_name, "Starting checklist periodic check")); 
     1180 
     1181    /* Send STUN Binding request for check with highest priority on 
     1182     * Waiting state. 
     1183     */ 
    8661184    for (i=0; i<clist->count; ++i) { 
    8671185        pj_ice_check *check = &clist->checks[i]; 
    8681186 
    869         if (check->check_state == PJ_ICE_CHECK_STATE_WAITING) { 
     1187        if (check->state == PJ_ICE_CHECK_STATE_WAITING) { 
    8701188            status = perform_check(ice, clist, i); 
    871             if (status != PJ_SUCCESS) 
     1189            if (status != PJ_SUCCESS) { 
     1190                pj_mutex_unlock(ice->mutex); 
    8721191                return status; 
     1192            } 
    8731193 
    8741194            ++start_count; 
     1195            break; 
    8751196        } 
    8761197    } 
     
    8831204            pj_ice_check *check = &clist->checks[i]; 
    8841205 
    885             if (check->check_state == PJ_ICE_CHECK_STATE_FROZEN) { 
     1206            if (check->state == PJ_ICE_CHECK_STATE_FROZEN) { 
    8861207                status = perform_check(ice, clist, i); 
    887                 if (status != PJ_SUCCESS) 
     1208                if (status != PJ_SUCCESS) { 
     1209                    pj_mutex_unlock(ice->mutex); 
    8881210                    return status; 
     1211                } 
    8891212 
    8901213                ++start_count; 
     
    8981221     */ 
    8991222    if (start_count==0) { 
    900         clist->state = PJ_ICE_CHECKLIST_ST_COMPLETED; 
    901         PJ_LOG(4,(ice->obj_name, "Checklist completed")); 
    902     } 
    903  
     1223        clist_set_state(ice, clist, PJ_ICE_CHECKLIST_ST_COMPLETED); 
     1224 
     1225    } else { 
     1226        /* Schedule for next timer */ 
     1227        pj_time_val timeout = {0, PJ_ICE_TA_VAL}; 
     1228 
     1229        te->id = PJ_TRUE; 
     1230        pj_time_val_normalize(&timeout); 
     1231        pj_timer_heap_schedule(th, te, &timeout); 
     1232    } 
     1233 
     1234    pj_mutex_unlock(ice->mutex); 
    9041235    return PJ_SUCCESS; 
    9051236} 
     
    9101241{ 
    9111242    pj_ice_checklist *clist; 
     1243    const pj_ice_cand *cand0; 
    9121244    unsigned i; 
    9131245 
    9141246    PJ_ASSERT_RETURN(ice, PJ_EINVAL); 
     1247 
     1248    LOG((ice->obj_name, "Starting ICE check..")); 
    9151249 
    9161250    clist = &ice->cklist; 
     
    9201254 
    9211255    /* Pickup the first pair and set the state to Waiting */ 
    922     clist->checks[0].check_state = PJ_ICE_CHECK_STATE_WAITING; 
     1256    clist->checks[0].state = PJ_ICE_CHECK_STATE_WAITING; 
     1257    cand0 = clist->checks[0].lcand; 
    9231258 
    9241259    /* Find all of the other pairs in that check list with the same 
     
    9271262     */ 
    9281263    for (i=1; i<clist->count; ++i) { 
    929         pj_ice_check *cki = &clist->checks[i]; 
    930  
    931         if (cki->comp_id != clist->checks[0].comp_id) 
    932             continue; 
    933  
    934         if (pj_strcmp(&cki->foundation, &clist->checks[0].foundation)==0) 
    935             continue; 
    936  
    937         clist->checks[i].check_state = PJ_ICE_CHECK_STATE_WAITING; 
     1264        const pj_ice_cand *cand1; 
     1265 
     1266        cand1 = clist->checks[i].lcand; 
     1267 
     1268        if (cand0->comp_id == cand1->comp_id && 
     1269            pj_strcmp(&cand0->foundation, &cand1->foundation)!=0) 
     1270        { 
     1271            clist->checks[i].state = PJ_ICE_CHECK_STATE_WAITING; 
     1272        } 
    9381273    } 
    9391274 
    9401275    /* Start periodic check */ 
    941     return start_periodic_check(ice, clist); 
     1276    return start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer); 
    9421277} 
    9431278 
     
    9561291 
    9571292 
    958 static pj_status_t on_stun_rx_request(pj_stun_session *sess, 
    959                                       const pj_uint8_t *pkt, 
    960                                       unsigned pkt_len, 
    961                                       const pj_stun_msg *msg, 
    962                                       const pj_sockaddr_t *src_addr, 
    963                                       unsigned src_addr_len) 
    964 { 
    965     pj_stun_tx_data *tdata; 
    966     pj_status_t status; 
    967  
    968     /* 7.2.1.2.  Learning Peer Reflexive Candidates */ 
    969     PJ_TODO(LEARN_PEER_REFLEXIVE_CANDIDATES); 
    970  
    971     /* Reject any requests except Binding request */ 
    972     if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) { 
    973         status = pj_stun_session_create_response(sess, msg,  
    974                                                  PJ_STUN_SC_BAD_REQUEST, 
    975                                                  NULL, &tdata); 
    976         if (status != PJ_SUCCESS) 
    977             return status; 
    978  
    979         status = pj_stun_session_send_msg(sess, PJ_TRUE,  
    980                                           src_addr, src_addr_len, tdata); 
    981         return status; 
    982     } 
    983  
    984     status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); 
    985     if (status != PJ_SUCCESS) 
    986         return status; 
    987  
    988     status = pj_stun_msg_add_sockaddr_attr(tdata->pool, msg,  
    989                                            PJ_STUN_ATTR_XOR_MAPPED_ADDR, 
    990                                            PJ_TRUE, src_addr, src_addr_len); 
    991  
    992     status = pj_stun_session_send_msg(sess, PJ_TRUE,  
    993                                       src_addr, src_addr_len, tdata); 
    994  
    995     /* 7.2.1.3.  Triggered Checks: 
    996      * Next, the agent constructs a pair whose local candidate is equal to 
    997      * the transport address on which the STUN request was received, and a 
    998      * remote candidate equal to the source transport address where the 
    999      * request came from (which may be peer-reflexive remote candidate that 
    1000      * was just learned).  
    1001      */ 
    1002      
    1003     return status; 
    1004 } 
    1005  
    10061293/* This callback is called when outgoing STUN request completed */ 
    1007 static void on_stun_request_complete(pj_stun_session *sess, 
     1294static void on_stun_request_complete(pj_stun_session *stun_sess, 
    10081295                                     pj_status_t status, 
    10091296                                     pj_stun_tx_data *tdata, 
     
    10131300    pj_ice *ice; 
    10141301    pj_ice_check *check, *valid_check; 
     1302    const pj_ice_cand *lcand; 
     1303    const pj_ice_cand *rcand; 
    10151304    pj_ice_checklist *clist; 
    1016     char buffer[128]; 
     1305    pj_stun_xor_mapped_addr_attr *xaddr; 
     1306    char buffer[CHECK_NAME_LEN]; 
     1307    unsigned i; 
     1308 
     1309    PJ_UNUSED_ARG(stun_sess); 
    10171310 
    10181311    ice = rd->ice; 
     
    10201313    clist = rd->clist; 
    10211314 
    1022     PJ_LOG(5,(ice->obj_name,  
    1023               "Connectivity check %s for check %d: %s", 
    1024               (status==PJ_SUCCESS ? "SUCCESS" : "FAILED"), rd->ckid,  
    1025               dump_check(buffer, sizeof(buffer), ice, check))); 
     1315    pj_mutex_lock(ice->mutex); 
     1316 
     1317    lcand = check->lcand; 
     1318    rcand = check->rcand; 
     1319 
     1320    LOG((ice->obj_name,  
     1321         "Connectivity check %s for check %s", 
     1322         (status==PJ_SUCCESS ? "SUCCESS" : "FAILED"),  
     1323         dump_check(buffer, sizeof(buffer), ice, check))); 
    10261324 
    10271325    if (status != PJ_SUCCESS) { 
    1028         check->check_state = PJ_ICE_CHECK_STATE_FAILED; 
     1326        check_set_state(ice, check, PJ_ICE_CHECK_STATE_FAILED, status); 
     1327        pj_mutex_unlock(ice->mutex); 
    10291328        return; 
    10301329    } 
     
    10361335     * Request was sent from. 
    10371336     */ 
    1038     PJ_TODO(CHECK_ICE_RESPONSE_SOURCE_ADDRESS); 
    1039  
    1040     /* Get the STUN MAPPED-ADDRESS attribute. If the 
    1041      * transport address does not match any of the local candidates that the 
    1042      * agent knows about, the mapped address represents a new candidate - a 
    1043      * peer reflexive candidate  
    1044      */ 
    1045     PJ_TODO(CHECK_ICE_RESPONSE_SOURCE_ADDRESS2); 
     1337    PJ_TODO(ICE_CHECK_RESPONSE_SOURCE_ADDRESS); 
     1338 
     1339    /* Get the STUN MAPPED-ADDRESS attribute. */ 
     1340    xaddr = (pj_stun_xor_mapped_addr_attr*) 
     1341            pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR,0); 
     1342    if (!xaddr) { 
     1343        check_set_state(ice, check, PJ_ICE_CHECK_STATE_FAILED,  
     1344                        PJNATH_ESTUNNOXORMAP); 
     1345        pj_mutex_unlock(ice->mutex); 
     1346        return; 
     1347    } 
     1348 
     1349    /* If the transport address returned in XOR-MAPPED-ADDRESS does not match 
     1350     * any of the local candidates that the agent knows about, the mapped  
     1351     * address represents a new candidate - a peer reflexive candidate. 
     1352     */ 
     1353    for (i=0; i<ice->lcand_cnt; ++i) { 
     1354        if (sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) { 
     1355            /* Match */ 
     1356            break; 
     1357        } 
     1358    } 
     1359 
     1360    if (i == ice->lcand_cnt) { 
     1361        unsigned cand_id; 
     1362 
     1363        /* Add new peer reflexive candidate */ 
     1364        status = pj_ice_add_cand(ice, lcand->comp_id,  
     1365                                 PJ_ICE_CAND_TYPE_PEER_MAPPED, 
     1366                                 65535, &peer_mapped_foundation, 
     1367                                 &xaddr->sockaddr, &lcand->base_addr, NULL, 
     1368                                 sizeof(pj_sockaddr_in), &cand_id); 
     1369        if (status != PJ_SUCCESS) { 
     1370            check_set_state(ice, check, PJ_ICE_CHECK_STATE_FAILED, status); 
     1371            pj_mutex_unlock(ice->mutex); 
     1372            return; 
     1373        } 
     1374 
     1375        /* Update local candidate */ 
     1376        lcand = &ice->lcand[cand_id]; 
     1377    } 
    10461378 
    10471379    /* Sets the state of the pair that generated the check to succeeded. */ 
    1048     check->check_state = PJ_ICE_CHECK_STATE_SUCCEEDED; 
     1380    check_set_state(ice, check, PJ_ICE_CHECK_STATE_SUCCEEDED, PJ_SUCCESS); 
     1381 
    10491382 
    10501383    /* This is a valid pair, so add this to the valid list */ 
    10511384    valid_check = &ice->valid_list.checks[ice->valid_list.count++]; 
    1052     pj_memcpy(valid_check, check, sizeof(*check)); 
     1385    valid_check->lcand = lcand; 
     1386    valid_check->rcand = rcand; 
     1387    valid_check->prio = CALC_CHECK_PRIO(ice, lcand, rcand); 
     1388    valid_check->state = PJ_ICE_CHECK_STATE_SUCCEEDED; 
     1389    valid_check->nominated = (pj_stun_msg_find_attr(tdata->msg,  
     1390                                                    PJ_STUN_ATTR_USE_CANDIDATE, 
     1391                                                    0) != NULL); 
     1392    valid_check->err_code = PJ_SUCCESS; 
    10531393 
    10541394    /* Sort valid_list */ 
    10551395    sort_checklist(&ice->valid_list); 
    1056  
    10571396 
    10581397    /* If the pair had a component ID of 1, the agent MUST change the 
     
    10601399     * same foundation, but different component IDs, to Waiting. 
    10611400     */ 
    1062     if (check->comp_id == 1) { 
     1401    if (lcand->comp_id == 1) { 
    10631402        unsigned i; 
     1403        pj_bool_t unfrozen = PJ_FALSE; 
     1404 
    10641405        for (i=0; i<clist->count; ++i)  { 
    10651406            pj_ice_check *c = &clist->checks[i]; 
    10661407 
    1067             if (c->check_state == PJ_ICE_CHECK_STATE_FROZEN && 
    1068                 c->comp_id != check->comp_id && 
    1069                 pj_strcmp(&c->foundation, &check->foundation)==0) 
     1408            if (c->state == PJ_ICE_CHECK_STATE_FROZEN && 
     1409                c->lcand->comp_id != lcand->comp_id && 
     1410                pj_strcmp(&c->lcand->foundation, &lcand->foundation)==0) 
    10701411            { 
    10711412                /* Unfreeze and start check */ 
    1072                 PJ_LOG(5,(ice->obj_name, "Unfreezing check %d", i)); 
    1073                 c->check_state = PJ_ICE_CHECK_STATE_WAITING; 
    1074                 perform_check(ice, clist, i); 
     1413                check_set_state(ice, c, PJ_ICE_CHECK_STATE_WAITING,  
     1414                                PJ_SUCCESS); 
     1415                unfrozen = PJ_TRUE; 
    10751416            } 
    10761417        } 
    10771418 
     1419        if (unfrozen && clist->timer.id == PJ_FALSE) 
     1420            start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer); 
    10781421    }  
     1422 
    10791423    /* If the pair had a component ID equal to the number of components 
    10801424     * for the media stream (where this is the actual number of 
     
    10951439    } 
    10961440 
    1097 } 
     1441    pj_mutex_unlock(ice->mutex); 
     1442} 
     1443 
     1444 
     1445static pj_status_t on_stun_rx_request(pj_stun_session *sess, 
     1446                                      const pj_uint8_t *pkt, 
     1447                                      unsigned pkt_len, 
     1448                                      const pj_stun_msg *msg, 
     1449                                      const pj_sockaddr_t *src_addr, 
     1450                                      unsigned src_addr_len) 
     1451{ 
     1452    stun_data *sd; 
     1453    pj_ice *ice; 
     1454    pj_stun_priority_attr *ap; 
     1455    pj_ice_comp *comp; 
     1456    pj_ice_cand *lcand; 
     1457    pj_ice_cand *rcand; 
     1458    unsigned i; 
     1459    pj_stun_tx_data *tdata; 
     1460    pj_bool_t is_relayed; 
     1461    pj_status_t status; 
     1462 
     1463    PJ_UNUSED_ARG(pkt); 
     1464    PJ_UNUSED_ARG(pkt_len); 
     1465 
     1466    /* Only accepts Binding request */ 
     1467    if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) { 
     1468        LOG((ice->obj_name, "Received non-Binding request, ignored")); 
     1469        return PJ_SUCCESS; 
     1470    } 
     1471 
     1472    sd = (stun_data*) pj_stun_session_get_user_data(sess); 
     1473    ice = sd->ice; 
     1474    comp = sd->comp; 
     1475 
     1476    pj_mutex_lock(ice->mutex); 
     1477 
     1478    /* Get PRIORITY attribute */ 
     1479    ap = (pj_stun_priority_attr*) 
     1480         pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0); 
     1481    if (ap == 0) { 
     1482        LOG((ice->obj_name, "Received Binding request with no PRIORITY")); 
     1483        pj_mutex_unlock(ice->mutex); 
     1484        return PJ_SUCCESS; 
     1485    } 
     1486 
     1487    /* For simplicity, ignore incoming requests when we don't have remote 
     1488     * candidates yet. The peer agent should retransmit the STUN request 
     1489     * and we'll receive it again later. 
     1490     */ 
     1491    if (ice->rcand_cnt == 0) { 
     1492        pj_mutex_unlock(ice->mutex); 
     1493        return PJ_SUCCESS; 
     1494    } 
     1495 
     1496 
     1497    /* Find remote candidate based on the source transport address of  
     1498     * the request. 
     1499     */ 
     1500    for (i=0; i<ice->rcand_cnt; ++i) { 
     1501        if (sockaddr_cmp((const pj_sockaddr*)src_addr, &ice->rcand[i].addr)==0) 
     1502            break; 
     1503    } 
     1504 
     1505    /* If the source transport address of the request does not match any 
     1506     * existing remote candidates, it represents a new peer reflexive remote 
     1507     * candidate. 
     1508     */ 
     1509    if (i == ice->rcand_cnt) { 
     1510        rcand = &ice->rcand[ice->rcand_cnt++]; 
     1511        rcand->comp_id = comp->comp_id; 
     1512        rcand->type = PJ_ICE_CAND_TYPE_PEER_MAPPED; 
     1513        rcand->prio = ap->value; 
     1514        pj_memcpy(&rcand->addr, src_addr, src_addr_len); 
     1515 
     1516        /* Foundation is random, unique from other foundation */ 
     1517        rcand->foundation.ptr = pj_pool_alloc(ice->pool, 32); 
     1518        rcand->foundation.slen = pj_ansi_snprintf(rcand->foundation.ptr, 32, 
     1519                                                  "f%p",  
     1520                                                  rcand->foundation.ptr); 
     1521    } else { 
     1522        /* Remote candidate found */ 
     1523        rcand = &ice->rcand[i]; 
     1524    } 
     1525 
     1526    /*  
     1527     * Create candidate pair for this request.  
     1528     */ 
     1529    /* First check if the source address is the source address of the  
     1530     * STUN relay, to determine if local candidate is relayed candidate. 
     1531     */ 
     1532    PJ_TODO(DETERMINE_IF_REQUEST_COMES_FROM_RELAYED_CANDIDATE); 
     1533    is_relayed = PJ_FALSE; 
     1534 
     1535    /* Next find local candidate */ 
     1536    /* Just pick up  
     1537 
     1538 
     1539 
     1540    /* 7.2.1.2.  Learning Peer Reflexive Candidates */ 
     1541    PJ_TODO(LEARN_PEER_REFLEXIVE_CANDIDATES); 
     1542 
     1543    /* Reject any requests except Binding request */ 
     1544    if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) { 
     1545        status = pj_stun_session_create_response(sess, msg,  
     1546                                                 PJ_STUN_SC_BAD_REQUEST, 
     1547                                                 NULL, &tdata); 
     1548        if (status != PJ_SUCCESS) { 
     1549            pj_mutex_unlock(ice->mutex); 
     1550            return status; 
     1551        } 
     1552 
     1553        status = pj_stun_session_send_msg(sess, PJ_TRUE,  
     1554                                          src_addr, src_addr_len, tdata); 
     1555 
     1556        pj_mutex_unlock(ice->mutex); 
     1557        return status; 
     1558    } 
     1559 
     1560    status = pj_stun_session_create_response(sess, msg, 0, NULL, &tdata); 
     1561    if (status != PJ_SUCCESS) { 
     1562        pj_mutex_unlock(ice->mutex); 
     1563        return status; 
     1564    } 
     1565 
     1566    status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,  
     1567                                           PJ_STUN_ATTR_XOR_MAPPED_ADDR, 
     1568                                           PJ_TRUE, src_addr, src_addr_len); 
     1569 
     1570    status = pj_stun_session_send_msg(sess, PJ_TRUE,  
     1571                                      src_addr, src_addr_len, tdata); 
     1572 
     1573    /* 7.2.1.3.  Triggered Checks: 
     1574     * Next, the agent constructs a pair whose local candidate is equal to 
     1575     * the transport address on which the STUN request was received, and a 
     1576     * remote candidate equal to the source transport address where the 
     1577     * request came from (which may be peer-reflexive remote candidate that 
     1578     * was just learned).  
     1579     */ 
     1580     
     1581    pj_mutex_unlock(ice->mutex); 
     1582    return status; 
     1583} 
     1584 
    10981585 
    10991586static pj_status_t on_stun_rx_indication(pj_stun_session *sess, 
     
    11041591                                         unsigned src_addr_len) 
    11051592{ 
     1593    PJ_UNUSED_ARG(sess); 
     1594    PJ_UNUSED_ARG(pkt); 
     1595    PJ_UNUSED_ARG(pkt_len); 
     1596    PJ_UNUSED_ARG(msg); 
     1597    PJ_UNUSED_ARG(src_addr); 
     1598    PJ_UNUSED_ARG(src_addr_len); 
     1599 
    11061600    PJ_TODO(SUPPORT_RX_BIND_REQUEST_AS_INDICATION); 
     1601 
    11071602    return PJ_ENOTSUP; 
    11081603} 
  • pjproject/trunk/pjnath/src/pjnath/stun_auth.c

    r1080 r1089  
    186186        int data_type = 0; 
    187187        pj_status_t rc; 
    188         rc = cred->data.dyn_cred.get_password(cred->data.dyn_cred.user_data, 
     188        rc = cred->data.dyn_cred.get_password(msg,  
     189                                              cred->data.dyn_cred.user_data, 
    189190                                              (arealm?&arealm->value:NULL), 
    190191                                              &auser->value, pool, 
     
    270271 
    271272        if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) { 
    272             ok=cred->data.dyn_cred.verify_nonce(cred->data.dyn_cred.user_data, 
     273            ok=cred->data.dyn_cred.verify_nonce(msg,  
     274                                                cred->data.dyn_cred.user_data, 
    273275                                                (arealm?&arealm->value:NULL), 
    274276                                                &auser->value, 
  • pjproject/trunk/pjnath/src/pjnath/stun_session.c

    r1080 r1089  
    207207} 
    208208 
    209 static pj_str_t *get_passwd(pj_stun_session *sess) 
    210 { 
    211     if (sess->cred == NULL) 
     209static pj_str_t *get_passwd(pj_stun_session *sess, pj_pool_t *pool, 
     210                            const pj_stun_msg *msg) 
     211{ 
     212    if (sess->cred == NULL) { 
    212213        return NULL; 
    213     else if (sess->cred->type == PJ_STUN_AUTH_CRED_STATIC) 
     214    } else if (sess->cred->type == PJ_STUN_AUTH_CRED_STATIC) { 
    214215        return &sess->cred->data.static_cred.data; 
    215     else 
     216    } else if (sess->cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) { 
     217        pj_str_t realm, username, nonce; 
     218        pj_str_t *password; 
     219        void *user_data = sess->cred->data.dyn_cred.user_data; 
     220        int data_type = 0; 
     221        pj_status_t status; 
     222 
     223        realm.slen = username.slen = nonce.slen = 0; 
     224        password = PJ_POOL_ZALLOC_T(pool, pj_str_t); 
     225        status = (*sess->cred->data.dyn_cred.get_cred)(msg, user_data, pool, 
     226                                                       &realm, &username, 
     227                                                       &nonce, &data_type, 
     228                                                       password); 
     229        return password; 
     230 
     231    } else { 
    216232        return NULL; 
     233    } 
    217234} 
    218235 
     
    222239{ 
    223240    pj_status_t status = 0; 
     241    pj_str_t realm, username, nonce, password; 
     242    int data_type = 0; 
     243 
     244    realm.slen = username.slen = nonce.slen = password.slen = 0; 
    224245 
    225246    /* The server SHOULD include a SERVER attribute in all responses */ 
     
    239260        !PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))  
    240261    { 
    241         const pj_str_t *username; 
    242  
    243         /* Create and add USERNAME attribute */ 
    244         username = &sess->cred->data.static_cred.username; 
     262        realm = sess->cred->data.static_cred.realm; 
     263        username = sess->cred->data.static_cred.username; 
     264        data_type = sess->cred->data.static_cred.data_type; 
     265        password = sess->cred->data.static_cred.data; 
     266        nonce = sess->cred->data.static_cred.nonce; 
     267 
     268    } else if (sess->cred && sess->cred->type == PJ_STUN_AUTH_CRED_DYNAMIC && 
     269               !PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))  
     270    { 
     271        void *user_data = sess->cred->data.dyn_cred.user_data; 
     272 
     273        status = (*sess->cred->data.dyn_cred.get_cred)(msg, user_data, pool, 
     274                                                       &realm, &username, 
     275                                                       &nonce, &data_type, 
     276                                                       &password); 
     277        if (status != PJ_SUCCESS) 
     278            return status; 
     279    } 
     280 
     281 
     282    /* Create and add USERNAME attribute */ 
     283    status = pj_stun_msg_add_string_attr(pool, msg, 
     284                                         PJ_STUN_ATTR_USERNAME, 
     285                                         &username); 
     286    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     287 
     288    /* Add REALM only when long term credential is used */ 
     289    if (realm.slen) { 
    245290        status = pj_stun_msg_add_string_attr(pool, msg, 
    246                                              PJ_STUN_ATTR_USERNAME, 
    247                                              username); 
     291                                            PJ_STUN_ATTR_REALM, 
     292                                            &realm); 
    248293        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    249  
    250         /* Add REALM only when long term credential is used */ 
    251         if (sess->cred->data.static_cred.realm.slen) { 
    252             const pj_str_t *realm = &sess->cred->data.static_cred.realm; 
    253             status = pj_stun_msg_add_string_attr(pool, msg, 
    254                                                 PJ_STUN_ATTR_REALM, 
    255                                                 realm); 
    256         } 
    257  
    258         /* Add MESSAGE-INTEGRITY attribute */ 
    259         status = pj_stun_msg_add_msgint_attr(pool, msg); 
    260         PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
    261  
    262     }  
     294    } 
     295 
     296    /* Add NONCE when desired */ 
     297    if (nonce.slen) { 
     298        status = pj_stun_msg_add_string_attr(pool, msg, 
     299                                            PJ_STUN_ATTR_NONCE, 
     300                                            &nonce); 
     301    } 
     302 
     303    /* Add MESSAGE-INTEGRITY attribute */ 
     304    status = pj_stun_msg_add_msgint_attr(pool, msg); 
     305    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     306 
    263307 
    264308    /* Add FINGERPRINT attribute if necessary */ 
     
    543587    /* Encode message */ 
    544588    status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len, 
    545                                 0, get_passwd(sess), &tdata->pkt_size); 
     589                                0, get_passwd(sess, tdata->pool, tdata->msg), 
     590                                &tdata->pkt_size); 
    546591    if (status != PJ_SUCCESS) { 
    547592        pj_stun_msg_destroy_tdata(sess, tdata); 
     
    640685    pj_status_t status; 
    641686 
     687    /* Apply options */ 
     688    if (!retransmission) { 
     689        status = apply_msg_options(sess, pool, response); 
     690        if (status != PJ_SUCCESS) 
     691            return status; 
     692    } 
     693 
    642694    /* Alloc packet buffer */ 
    643695    out_max_len = PJ_STUN_MAX_PKT_LEN; 
    644696    out_pkt = pj_pool_alloc(pool, out_max_len); 
    645697 
    646     /* Apply options */ 
    647     if (!retransmission) { 
    648         apply_msg_options(sess, pool, response); 
    649     } 
    650  
    651698    /* Encode */ 
    652699    status = pj_stun_msg_encode(response, out_pkt, out_max_len, 0,  
    653                                 get_passwd(sess), &out_len); 
     700                                get_passwd(sess, pool, response), 
     701                                &out_len); 
    654702    if (status != PJ_SUCCESS) { 
    655703        LOG_ERR_(sess, "Error encoding message", status); 
Note: See TracChangeset for help on using the changeset viewer.