Changeset 1711


Ignore:
Timestamp:
Jan 18, 2008 8:42:15 PM (11 years ago)
Author:
nanang
Message:
  • implemented new flow based on new SRTP transport interface and data structure
  • applied 3 SRTP operation mode: DISABLED, OPTIONAL, MANDATORY
  • applied new error codes
Location:
pjproject/branches/users/nanang/pjmedia
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/users/nanang/pjmedia/include/pjmedia/transport_srtp.h

    r1702 r1711  
    5454 
    5555    /** Crypto name.   */ 
    56     pj_str_t    crypto; 
     56    pj_str_t    name; 
    5757 
    5858    /* Flags, bitmask from #pjmedia_srtp_crypto_option */ 
     
    169169 */ 
    170170PJ_DECL(pj_status_t) pjmedia_transport_srtp_start( 
    171                                             pjmedia_transport *srtp, 
     171                                            pjmedia_transport *tp, 
    172172                                            const pjmedia_srtp_crypto *tx, 
    173173                                            const pjmedia_srtp_crypto *rx); 
     
    182182 * @see #pjmedia_transport_srtp_start()  
    183183 */ 
    184 PJ_DECL(pj_status_t) pjmedia_transport_srtp_stop(pjmedia_transport *srtp); 
     184PJ_DECL(pj_status_t) pjmedia_transport_srtp_stop(pjmedia_transport *tp); 
    185185 
    186186 
     
    193193 */ 
    194194PJ_DECL(pjmedia_transport*) pjmedia_transport_srtp_get_member( 
    195                                                     pjmedia_transport *srtp); 
     195                                                    pjmedia_transport *tp); 
    196196 
    197197 
  • pjproject/branches/users/nanang/pjmedia/src/pjmedia/transport_srtp.c

    r1702 r1711  
    3333#define MAX_BUFFER_LEN  1500 
    3434#define MAX_KEY_LEN     32 
    35 #define SRTP_ERROR(e)   -1 
    36  
    37 static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 }; 
     35#define DEACTIVATE_MEDIA(pool, m) {\ 
     36            attr = pjmedia_sdp_attr_create(pool, ID_INACTIVE.ptr, NULL); \ 
     37            m->attr[m->attr_count++] = attr; \ 
     38            m->desc.port = 0; \ 
     39        } 
     40 
     41static const pj_str_t ID_RTP_AVP  = { "RTP/AVP", 7 }; 
    3842static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 }; 
     43static const pj_str_t ID_INACTIVE = { "inactive", 8 }; 
    3944 
    4045typedef struct crypto_suite 
     
    7681    char                 tx_buffer[MAX_BUFFER_LEN]; 
    7782    char                 rx_buffer[MAX_BUFFER_LEN]; 
    78     unsigned             options;   /**< Transport options.        */ 
    7983 
    8084    pjmedia_srtp_setting setting; 
     
    8286    pj_bool_t            session_inited; 
    8387    pj_bool_t            offerer_side; 
     88    pj_bool_t            bypass_srtp; 
    8489    char                 tx_key[MAX_KEY_LEN]; 
    8590    char                 rx_key[MAX_KEY_LEN]; 
    86     pjmedia_srtp_stream_crypto tx_policy; 
    87     pjmedia_srtp_stream_crypto rx_policy; 
     91    pjmedia_srtp_crypto tx_policy; 
     92    pjmedia_srtp_crypto rx_policy; 
    8893 
    8994    /* libSRTP contexts */ 
     
    144149                                       pj_pool_t *pool, 
    145150                                       pjmedia_sdp_session *sdp_local, 
    146                                        const pjmedia_sdp_session *sdp_remote); 
     151                                       const pjmedia_sdp_session *sdp_remote, 
     152                                       unsigned media_index); 
    147153static pj_status_t transport_media_start (pjmedia_transport *tp, 
    148154                                       pj_pool_t *pool, 
     
    174180char * octet_string_hex_string(const void *s, int length); 
    175181 
     182 
     183pj_str_t srtp_transport_getliberrstr(int err) 
     184{ 
     185    pj_str_t msg = {NULL, 0}; 
     186 
     187#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0) 
     188    static char *liberr[] = { 
     189        "nothing to report                       ", /* err_status_ok           = 0,   */ 
     190        "unspecified failure                     ", /* err_status_fail         = 1,   */ 
     191        "unsupported parameter                   ", /* err_status_bad_param    = 2,   */ 
     192        "couldn't allocate memory                ", /* err_status_alloc_fail   = 3,   */ 
     193        "couldn't deallocate properly            ", /* err_status_dealloc_fail = 4,   */ 
     194        "couldn't initialize                     ", /* err_status_init_fail    = 5,   */ 
     195        "can't process as much data as requested ", /* err_status_terminus     = 6,   */ 
     196        "authentication failure                  ", /* err_status_auth_fail    = 7,   */ 
     197        "cipher failure                          ", /* err_status_cipher_fail  = 8,   */ 
     198        "replay check failed (bad index)         ", /* err_status_replay_fail  = 9,   */ 
     199        "replay check failed (index too old)     ", /* err_status_replay_old   = 10,  */ 
     200        "algorithm failed test routine           ", /* err_status_algo_fail    = 11,  */ 
     201        "unsupported operation                   ", /* err_status_no_such_op   = 12,  */ 
     202        "no appropriate context found            ", /* err_status_no_ctx       = 13,  */ 
     203        "unable to perform desired validation    ", /* err_status_cant_check   = 14,  */ 
     204        "can't use key any more                  ", /* err_status_key_expired  = 15,  */ 
     205        "error in use of socket                  ", /* err_status_socket_err   = 16,  */ 
     206        "error in use POSIX signals              ", /* err_status_signal_err   = 17,  */ 
     207        "nonce check failed                      ", /* err_status_nonce_bad    = 18,  */ 
     208        "couldn't read data                      ", /* err_status_read_fail    = 19,  */ 
     209        "couldn't write data                     ", /* err_status_write_fail   = 20,  */ 
     210        "error pasring data                      ", /* err_status_parse_err    = 21,  */ 
     211        "error encoding data                     ", /* err_status_encode_err   = 22,  */ 
     212        "error while using semaphores            ", /* err_status_semaphore_err = 23,  */ 
     213        "error while using pfkey                 " /* err_status_pfkey_err    = 24,   */ 
     214    }; 
     215    if (err >= 0 && err <= 24) { 
     216        msg.ptr = liberr[err]; 
     217        msg.slen = 40; 
     218    } 
     219#endif 
     220 
     221    return msg; 
     222} 
     223 
    176224static pj_status_t pjmedia_srtp_init_lib(void) 
    177225{ 
     
    183231        if (err != err_status_ok) {  
    184232            PJ_LOG(4, (THIS_FILE, "Failed to init libsrtp.")); 
    185             return SRTP_ERROR(err); 
     233            return PJMEDIA_ERRNO_FROM_LIBSRTP(err); 
    186234        } 
    187235 
     
    192240     
    193241    return PJ_SUCCESS; 
     242} 
     243 
     244static int get_crypto_idx(const pj_str_t* crypto_name) 
     245{ 
     246    int i; 
     247    int cs_cnt = sizeof(crypto_suites)/sizeof(crypto_suites[0]); 
     248     
     249    for (i=0; i<cs_cnt; ++i) { 
     250        if (!pj_stricmp2(crypto_name, crypto_suites[i].name)) 
     251            return i; 
     252    } 
     253 
     254    return -1; 
     255} 
     256 
     257PJ_DEF(void) pjmedia_srtp_setting_default(pjmedia_srtp_setting *opt) 
     258{ 
     259    int i; 
     260 
     261    pj_bzero(opt, sizeof(pjmedia_srtp_setting)); 
     262    opt->close_member_tp = PJ_TRUE; 
     263    opt->use = PJMEDIA_SRTP_OPTIONAL; 
     264    opt->crypto_count = sizeof(crypto_suites)/sizeof(crypto_suites[0]); 
     265    for (i=0; i<opt->crypto_count; ++i) 
     266        opt->crypto[i].name = pj_str(crypto_suites[i].name); 
    194267} 
    195268 
     
    198271 * Create an SRTP media transport. 
    199272 */ 
    200 PJ_DEF(pj_status_t) pjmedia_transport_srtp_create( pjmedia_endpt *endpt,  
    201                                          pjmedia_transport *tp, 
    202                                          unsigned options, 
    203                                          pjmedia_transport **p_srtp) 
     273PJ_DEF(pj_status_t) pjmedia_transport_srtp_create( 
     274                                       pjmedia_endpt *endpt, 
     275                                       pjmedia_transport *tp, 
     276                                       const pjmedia_srtp_setting *opt, 
     277                                       pjmedia_transport **p_tp) 
    204278{ 
    205279    pj_pool_t *pool; 
    206280    transport_srtp *srtp; 
    207281    pj_status_t status; 
    208  
    209     PJ_ASSERT_RETURN(endpt && p_srtp, PJ_EINVAL); 
     282    int i; 
     283 
     284    PJ_ASSERT_RETURN(endpt && p_tp, PJ_EINVAL); 
    210285 
    211286    /* Init libsrtp. */ 
     
    219294    srtp->pool = pool; 
    220295    srtp->session_inited = PJ_FALSE; 
    221     srtp->offerer_side = PJ_TRUE; 
    222     srtp->options = options; 
     296    srtp->bypass_srtp = PJ_TRUE; 
     297 
     298    if (opt) { 
     299        srtp->setting = *opt; 
     300        for (i=0; i < opt->crypto_count; ++i) { 
     301            int cs_idx = get_crypto_idx(&opt->crypto[i].name); 
     302            if (cs_idx == -1) 
     303                return PJMEDIA_SRTP_ENOTSUPCRYPTO; 
     304 
     305            srtp->setting.crypto[i].name = pj_str(crypto_suites[cs_idx].name); 
     306            pj_strdup(pool, &srtp->setting.crypto[i].key, &opt->crypto[i].key); 
     307        } 
     308    } else { 
     309        pjmedia_srtp_setting_default(&srtp->setting); 
     310    } 
     311 
     312    if (srtp->setting.crypto_count==0 &&  
     313        srtp->setting.use == PJMEDIA_SRTP_MANDATORY) 
     314        return PJMEDIA_SRTP_ESDPREQCRYPTO; 
    223315 
    224316    status = pj_lock_create_null_mutex(pool, pool->obj_name, &srtp->mutex); 
     
    237329 
    238330    /* Done */ 
    239     *p_srtp = &srtp->base; 
     331    *p_tp = &srtp->base; 
    240332 
    241333    return PJ_SUCCESS; 
     
    247339 */ 
    248340PJ_DEF(pj_status_t) pjmedia_transport_srtp_start( 
    249                            pjmedia_transport *srtp,  
    250                            const pjmedia_srtp_stream_crypto *policy_tx, 
    251                            const pjmedia_srtp_stream_crypto *policy_rx) 
    252 { 
    253     transport_srtp  *p_srtp = (transport_srtp*) srtp; 
    254     srtp_policy_t    policy_tx_; 
    255     srtp_policy_t    policy_rx_; 
     341                           pjmedia_transport *tp,  
     342                           const pjmedia_srtp_crypto *tx, 
     343                           const pjmedia_srtp_crypto *rx) 
     344{ 
     345    transport_srtp  *srtp = (transport_srtp*) tp; 
     346    srtp_policy_t    tx_; 
     347    srtp_policy_t    rx_; 
    256348    err_status_t     err; 
    257     int              i; 
    258     int              cs_tx_idx = -1; 
    259     int              cs_rx_idx = -1; 
     349    int              cr_tx_idx = 0; 
     350    int              au_tx_idx = 0; 
     351    int              cr_rx_idx = 0; 
     352    int              au_rx_idx = 0; 
    260353    int              crypto_suites_cnt; 
    261354 
    262     if (p_srtp->session_inited) { 
     355    if (srtp->session_inited) { 
    263356        PJ_LOG(4, (THIS_FILE, "SRTP could not be re-init'd before deinit'd")); 
    264357        return PJ_EINVALIDOP; 
     
    268361 
    269362    /* Check whether the crypto-suite requested is supported */ 
    270     for (i=0; i<crypto_suites_cnt; ++i) { 
    271         if ((cs_rx_idx == -1) &&  
    272             !pj_stricmp2(&policy_rx->crypto_suite, crypto_suites[i].name)) 
    273             cs_rx_idx = i; 
    274          
    275         if ((cs_tx_idx == -1) &&  
    276             !pj_stricmp2(&policy_tx->crypto_suite, crypto_suites[i].name)) 
    277             cs_tx_idx = i; 
    278     } 
    279  
    280     if ((cs_tx_idx == -1) || (cs_rx_idx == -1)) { 
    281         PJ_LOG(4, (THIS_FILE, "Crypto-suite specified is not supported.")); 
    282         return PJ_ENOTSUP; 
    283     } 
     363    cr_tx_idx = au_tx_idx = get_crypto_idx(&tx->name); 
     364    if (tx->flags && PJMEDIA_SRTP_NO_ENCRYPTION) 
     365        cr_tx_idx = 0; 
     366    if (tx->flags && PJMEDIA_SRTP_NO_AUTHENTICATION) 
     367        au_tx_idx = 0; 
     368 
     369    /* Check whether the crypto-suite requested is supported */ 
     370    cr_rx_idx = au_rx_idx = get_crypto_idx(&rx->name); 
     371    if (rx->flags && PJMEDIA_SRTP_NO_ENCRYPTION) 
     372        cr_rx_idx = 0; 
     373    if (rx->flags && PJMEDIA_SRTP_NO_AUTHENTICATION) 
     374        au_rx_idx = 0; 
     375 
     376    if (cr_tx_idx == -1 || cr_rx_idx == -1 || au_tx_idx == -1 || au_rx_idx == -1) 
     377        return PJMEDIA_SRTP_ENOTSUPCRYPTO; 
    284378 
    285379    /* Init transmit direction */ 
    286     pj_bzero(&policy_tx_, sizeof(srtp_policy_t)); 
    287     pj_memmove(p_srtp->tx_key, policy_tx->key.ptr, policy_tx->key.slen); 
    288     policy_tx_.key                = (uint8_t*)p_srtp->tx_key; 
    289     policy_tx_.ssrc.type          = ssrc_any_outbound; 
    290     policy_tx_.ssrc.value         = 0; 
    291     policy_tx_.rtp.sec_serv       = crypto_suites[cs_tx_idx].service; 
    292     policy_tx_.rtp.cipher_type    = crypto_suites[cs_tx_idx].cipher_type; 
    293     policy_tx_.rtp.cipher_key_len = crypto_suites[cs_tx_idx].cipher_key_len; 
    294     policy_tx_.rtp.auth_type      = crypto_suites[cs_tx_idx].auth_type; 
    295     policy_tx_.rtp.auth_key_len   = crypto_suites[cs_tx_idx].auth_key_len; 
    296     policy_tx_.rtp.auth_tag_len   = crypto_suites[cs_tx_idx].srtp_auth_tag_len; 
    297     policy_tx_.rtcp               = policy_tx_.rtp; 
    298     policy_tx_.rtcp.auth_tag_len  = crypto_suites[cs_tx_idx].srtcp_auth_tag_len; 
    299     policy_tx_.next               = NULL; 
    300     err = srtp_create(&p_srtp->srtp_tx_ctx, &policy_tx_); 
     380    pj_bzero(&tx_, sizeof(srtp_policy_t)); 
     381    pj_memmove(srtp->tx_key, tx->key.ptr, tx->key.slen); 
     382    tx_.key                 = (uint8_t*)srtp->tx_key; 
     383    tx_.ssrc.type           = ssrc_any_outbound; 
     384    tx_.ssrc.value          = 0; 
     385    tx_.rtp.sec_serv        = crypto_suites[cr_tx_idx].service; 
     386    tx_.rtp.cipher_type     = crypto_suites[cr_tx_idx].cipher_type; 
     387    tx_.rtp.cipher_key_len  = crypto_suites[cr_tx_idx].cipher_key_len; 
     388    tx_.rtp.auth_type       = crypto_suites[au_tx_idx].auth_type; 
     389    tx_.rtp.auth_key_len    = crypto_suites[au_tx_idx].auth_key_len; 
     390    tx_.rtp.auth_tag_len    = crypto_suites[au_tx_idx].srtp_auth_tag_len; 
     391    tx_.rtcp                = tx_.rtp; 
     392    tx_.rtcp.auth_tag_len   = crypto_suites[au_tx_idx].srtcp_auth_tag_len; 
     393    tx_.next                = NULL; 
     394    err = srtp_create(&srtp->srtp_tx_ctx, &tx_); 
    301395    if (err != err_status_ok) { 
    302         return SRTP_ERROR(err); 
    303     } 
    304  
    305     pj_strset(&p_srtp->tx_policy.key,  p_srtp->tx_key, policy_tx->key.slen); 
    306     p_srtp->tx_policy.crypto_suite = pj_str(crypto_suites[cs_tx_idx].name); 
     396        return PJMEDIA_ERRNO_FROM_LIBSRTP(err); 
     397    } 
     398    srtp->tx_policy = *tx; 
     399    pj_strset(&srtp->tx_policy.key,  srtp->tx_key, tx->key.slen); 
     400    srtp->tx_policy.name =  
     401                        pj_str(crypto_suites[get_crypto_idx(&tx->name)].name); 
    307402 
    308403 
    309404    /* Init receive direction */ 
    310     pj_bzero(&policy_rx_, sizeof(srtp_policy_t)); 
    311     pj_memmove(p_srtp->rx_key, policy_rx->key.ptr, policy_rx->key.slen); 
    312     policy_rx_.key                = (uint8_t*)p_srtp->rx_key; 
    313     policy_rx_.ssrc.type          = ssrc_any_inbound; 
    314     policy_rx_.ssrc.value         = 0; 
    315     policy_rx_.rtp.sec_serv       = crypto_suites[cs_rx_idx].service; 
    316     policy_rx_.rtp.cipher_type    = crypto_suites[cs_rx_idx].cipher_type; 
    317     policy_rx_.rtp.cipher_key_len = crypto_suites[cs_rx_idx].cipher_key_len; 
    318     policy_rx_.rtp.auth_type      = crypto_suites[cs_rx_idx].auth_type; 
    319     policy_rx_.rtp.auth_key_len   = crypto_suites[cs_rx_idx].auth_key_len; 
    320     policy_rx_.rtp.auth_tag_len   = crypto_suites[cs_rx_idx].srtp_auth_tag_len; 
    321     policy_rx_.rtcp               = policy_rx_.rtp; 
    322     policy_rx_.rtcp.auth_tag_len  = crypto_suites[cs_rx_idx].srtcp_auth_tag_len; 
    323     policy_rx_.next               = NULL; 
    324     err = srtp_create(&p_srtp->srtp_rx_ctx, &policy_rx_); 
     405    pj_bzero(&rx_, sizeof(srtp_policy_t)); 
     406    pj_memmove(srtp->rx_key, rx->key.ptr, rx->key.slen); 
     407    rx_.key                 = (uint8_t*)srtp->rx_key; 
     408    rx_.ssrc.type           = ssrc_any_inbound; 
     409    rx_.ssrc.value          = 0; 
     410    rx_.rtp.sec_serv        = crypto_suites[cr_rx_idx].service; 
     411    rx_.rtp.cipher_type     = crypto_suites[cr_rx_idx].cipher_type; 
     412    rx_.rtp.cipher_key_len  = crypto_suites[cr_rx_idx].cipher_key_len; 
     413    rx_.rtp.auth_type       = crypto_suites[au_rx_idx].auth_type; 
     414    rx_.rtp.auth_key_len    = crypto_suites[au_rx_idx].auth_key_len; 
     415    rx_.rtp.auth_tag_len    = crypto_suites[au_rx_idx].srtp_auth_tag_len; 
     416    rx_.rtcp                = rx_.rtp; 
     417    rx_.rtcp.auth_tag_len   = crypto_suites[au_rx_idx].srtcp_auth_tag_len; 
     418    rx_.next                = NULL; 
     419    err = srtp_create(&srtp->srtp_rx_ctx, &rx_); 
    325420    if (err != err_status_ok) { 
    326         srtp_dealloc(p_srtp->srtp_tx_ctx); 
    327         return SRTP_ERROR(err); 
    328     } 
    329  
    330     pj_strset(&p_srtp->rx_policy.key,  p_srtp->rx_key, policy_rx->key.slen); 
    331     p_srtp->rx_policy.crypto_suite = pj_str(crypto_suites[i].name); 
     421        srtp_dealloc(srtp->srtp_tx_ctx); 
     422        return PJMEDIA_ERRNO_FROM_LIBSRTP(err); 
     423    } 
     424    srtp->rx_policy = *rx; 
     425    pj_strset(&srtp->rx_policy.key,  srtp->rx_key, rx->key.slen); 
     426    srtp->rx_policy.name =  
     427                        pj_str(crypto_suites[get_crypto_idx(&rx->name)].name); 
    332428 
    333429    /* Declare SRTP session initialized */ 
    334     p_srtp->session_inited = PJ_TRUE; 
    335  
    336     PJ_LOG(5, (THIS_FILE, "TX %s key=%s", crypto_suites[cs_tx_idx].name, 
    337            octet_string_hex_string(policy_tx->key.ptr, policy_tx->key.slen))); 
    338     PJ_LOG(5, (THIS_FILE, "RX %s key=%s", crypto_suites[cs_rx_idx].name, 
    339            octet_string_hex_string(policy_rx->key.ptr, policy_rx->key.slen))); 
     430    srtp->session_inited = PJ_TRUE; 
     431    srtp->bypass_srtp = PJ_FALSE; 
     432 
     433    PJ_LOG(5, (THIS_FILE, "TX: %s key=%s", srtp->tx_policy.name.ptr, 
     434            octet_string_hex_string(tx->key.ptr, tx->key.slen))); 
     435    if (srtp->tx_policy.flags) { 
     436        PJ_LOG(5, (THIS_FILE, "TX: disable%s%s", (cr_tx_idx?"":" enc"), 
     437                                                 (au_tx_idx?"":" auth"))); 
     438    } 
     439 
     440    PJ_LOG(5, (THIS_FILE, "RX: %s key=%s", srtp->rx_policy.name.ptr, 
     441            octet_string_hex_string(rx->key.ptr, rx->key.slen))); 
     442    if (srtp->rx_policy.flags) { 
     443        PJ_LOG(5, (THIS_FILE, "RX: disable%s%s", (cr_rx_idx?"":" enc"), 
     444                                                 (au_rx_idx?"":" auth"))); 
     445    } 
    340446 
    341447    return PJ_SUCCESS; 
     
    438544    err_status_t err; 
    439545 
     546    if (srtp->bypass_srtp) 
     547        return pjmedia_transport_send_rtp(srtp->real_tp, srtp->tx_buffer, len); 
     548 
    440549    if (!srtp->session_inited) 
    441550        return PJ_SUCCESS; 
    442551 
    443     PJ_ASSERT_RETURN(size < sizeof(srtp->tx_buffer), PJ_ETOOBIG); 
     552    if (size > sizeof(srtp->tx_buffer)) 
     553        return PJ_ETOOBIG; 
    444554 
    445555    pj_lock_acquire(srtp->mutex); 
     
    450560        status = pjmedia_transport_send_rtp(srtp->real_tp, srtp->tx_buffer, len); 
    451561    } else { 
    452         status = SRTP_ERROR(err); 
     562        status = PJMEDIA_ERRNO_FROM_LIBSRTP(err); 
    453563    } 
    454564     
     
    467577    err_status_t err; 
    468578 
     579    if (srtp->bypass_srtp) 
     580        return pjmedia_transport_send_rtp(srtp->real_tp, srtp->tx_buffer, len); 
     581 
    469582    if (!srtp->session_inited) 
    470583        return PJ_SUCCESS; 
    471584 
    472     PJ_ASSERT_RETURN((size) < sizeof(srtp->tx_buffer), PJ_ETOOBIG); 
     585    if (size > sizeof(srtp->tx_buffer)) 
     586        return PJ_ETOOBIG; 
    473587 
    474588    pj_lock_acquire(srtp->mutex); 
     
    478592     
    479593    if (err == err_status_ok) { 
    480         status = pjmedia_transport_send_rtcp(srtp->real_tp, srtp->tx_buffer, len); 
     594        status = pjmedia_transport_send_rtcp(srtp->real_tp, srtp->tx_buffer,  
     595                                             len); 
    481596    } else { 
    482         status = SRTP_ERROR(err); 
     597        status = PJMEDIA_ERRNO_FROM_LIBSRTP(err); 
    483598    } 
    484599 
     
    525640    int len = size; 
    526641    err_status_t err; 
     642 
     643    if (srtp->bypass_srtp) { 
     644        srtp->rtp_cb(srtp->user_data, srtp->rx_buffer, len); 
     645        return; 
     646    } 
    527647 
    528648    if (size < 0 || size > sizeof(srtp->rx_buffer) || !srtp->session_inited) { 
     
    553673    err_status_t err; 
    554674 
     675    if (srtp->bypass_srtp) { 
     676        srtp->rtcp_cb(srtp->user_data, srtp->rx_buffer, len); 
     677        return; 
     678    } 
     679 
    555680    if (size < 0 || size > sizeof(srtp->rx_buffer) || !srtp->session_inited) { 
    556681        return; 
     
    575700 * and set buffer_len = 0. 
    576701 */ 
    577 static pj_status_t generate_crypto_attr_value(char *buffer, int *buffer_len,  
    578                                               int cs_idx, int cs_tag) 
    579 { 
    580     pj_uint8_t key[MAX_KEY_LEN]; 
     702static pj_status_t generate_crypto_attr_value(pj_pool_t *pool, 
     703                                              char *buffer, int *buffer_len,  
     704                                              pjmedia_srtp_crypto *crypto, 
     705                                              int tag) 
     706{ 
     707    pj_status_t status; 
     708    int cs_idx = get_crypto_idx(&crypto->name); 
    581709    char b64_key[PJ_BASE256_TO_BASE64_LEN(MAX_KEY_LEN)+1]; 
    582710    int b64_key_len = sizeof(b64_key); 
    583     err_status_t err; 
    584     pj_status_t status; 
    585     pj_bool_t key_ok; 
    586  
    587     PJ_ASSERT_RETURN(MAX_KEY_LEN >= crypto_suites[cs_idx].cipher_key_len, 
    588                      PJ_ETOOSMALL); 
     711 
     712    if (cs_idx == -1) 
     713        return PJMEDIA_SRTP_ENOTSUPCRYPTO; 
    589714 
    590715    /* Crypto-suite NULL. */ 
     
    594719    } 
    595720 
    596     /* Generate key. */ 
    597     do { 
    598         unsigned i; 
    599         key_ok = PJ_TRUE; 
    600  
    601         err = crypto_get_random(key, crypto_suites[cs_idx].cipher_key_len); 
    602         if (err != err_status_ok) { 
    603             PJ_LOG(5,(THIS_FILE, "Failed generating random key")); 
    604             return SRTP_ERROR(err); 
    605         } 
    606         for (i=0; i<crypto_suites[cs_idx].cipher_key_len && key_ok; ++i) 
    607             if (key[i] == 0) key_ok = PJ_FALSE; 
    608  
    609     } while (!key_ok); 
     721    /* Generate key if not specified. */ 
     722    if (crypto->key.slen == 0) { 
     723        pj_bool_t key_ok; 
     724        char key[MAX_KEY_LEN]; 
     725        err_status_t err; 
     726        int i; 
     727 
     728        PJ_ASSERT_RETURN(MAX_KEY_LEN >= crypto_suites[cs_idx].cipher_key_len, 
     729                         PJ_ETOOSMALL); 
     730 
     731        do { 
     732            key_ok = PJ_TRUE; 
     733 
     734            err = crypto_get_random((unsigned char*)key,  
     735                                     crypto_suites[cs_idx].cipher_key_len); 
     736            if (err != err_status_ok) { 
     737                PJ_LOG(5,(THIS_FILE, "Failed generating random key")); 
     738                return PJMEDIA_ERRNO_FROM_LIBSRTP(err); 
     739            } 
     740            for (i=0; i<crypto_suites[cs_idx].cipher_key_len && key_ok; ++i) 
     741                if (key[i] == 0) key_ok = PJ_FALSE; 
     742 
     743        } while (!key_ok); 
     744        key[crypto_suites[cs_idx].cipher_key_len] = '\0'; 
     745        pj_strdup2(pool, &crypto->key, key); 
     746    } 
     747 
     748    if ((unsigned)crypto->key.slen != crypto_suites[cs_idx].cipher_key_len) 
     749        return PJMEDIA_SRTP_EINKEYLEN; 
    610750 
    611751    /* Key transmitted via SDP should be base64 encoded. */ 
    612     status = pj_base64_encode(key, crypto_suites[cs_idx].cipher_key_len, 
     752    status = pj_base64_encode((pj_uint8_t*)crypto->key.ptr, crypto->key.slen, 
    613753                              b64_key, &b64_key_len); 
    614754    if (status != PJ_SUCCESS) { 
     
    618758 
    619759    b64_key[b64_key_len] = '\0'; 
    620  
    621760     
    622     PJ_ASSERT_RETURN((unsigned)*buffer_len >=  
    623                      (pj_ansi_strlen(crypto_suites[cs_idx].name) + 
     761    PJ_ASSERT_RETURN((unsigned)*buffer_len >= (crypto->name.slen + \ 
    624762                     b64_key_len + 16), PJ_ETOOSMALL); 
    625763 
    626764    /* Print the crypto attribute value. */ 
    627765    *buffer_len = pj_ansi_snprintf(buffer, *buffer_len, "%d %s inline:%s", 
    628                                    cs_tag,  
     766                                   tag,  
    629767                                   crypto_suites[cs_idx].name, 
    630768                                   b64_key); 
    631769 
    632770    return PJ_SUCCESS; 
    633 } 
    634  
    635 static pj_status_t transport_media_create(pjmedia_transport *tp, 
    636                                           pj_pool_t *pool, 
    637                                           pjmedia_sdp_session *sdp_local, 
    638                                           const pjmedia_sdp_session *sdp_remote) 
    639 { 
    640     struct transport_srtp *srtp = (struct transport_srtp*) tp; 
    641     enum { MAXLEN = 512 }; 
    642     char buffer[MAXLEN]; 
    643     pj_status_t status; 
    644     unsigned i, j; 
    645     unsigned cs_cnt = sizeof(crypto_suites)/sizeof(crypto_suites[0]); 
    646  
    647     /* If we are the answerer side, skip generating crypto-suites offer */ 
    648     if (sdp_remote) { 
    649         srtp->offerer_side = PJ_FALSE; 
    650         return PJ_SUCCESS; 
    651     } 
    652      
    653     srtp->offerer_side = PJ_TRUE; 
    654  
    655     for (i=0; i<sdp_local->media_count; ++i) { 
    656         /* Change "RTP/AVP" transport to "RTP/SAVP" */ 
    657         if (pj_stricmp(&sdp_local->media[i]->desc.transport, &ID_RTP_AVP) == 0) { 
    658             sdp_local->media[i]->desc.transport = ID_RTP_SAVP; 
    659  
    660         /* Skip media transport that is not appropriate for SRTP */ 
    661         } else if (pj_stricmp(&sdp_local->media[i]->desc.transport,  
    662                    &ID_RTP_SAVP) != 0) 
    663         { 
    664             continue; 
    665         } 
    666  
    667         /* Generate "crypto" attribute(s) */ 
    668         for (j=1; j<cs_cnt; ++j) { 
    669             /* Offer all our crypto-suites. */ 
    670             pj_str_t attr_value; 
    671             int buffer_len = MAXLEN; 
    672             pjmedia_sdp_attr *attr; 
    673  
    674             status = generate_crypto_attr_value(buffer, &buffer_len, j, j); 
    675             if (status != PJ_SUCCESS) 
    676                 return status; 
    677  
    678             /* If buffer_len==0, just skip the crypto attribute. */ 
    679             if (buffer_len) { 
    680                 pj_strset(&attr_value, buffer, buffer_len); 
    681                 attr = pjmedia_sdp_attr_create(pool, "crypto", &attr_value); 
    682                 sdp_local->media[i]->attr[sdp_local->media[i]->attr_count++] = attr; 
    683             } 
    684         } 
    685     } 
    686  
    687     return pjmedia_transport_media_create(srtp->real_tp, pool, sdp_local,  
    688                                            sdp_remote); 
    689771} 
    690772 
     
    692774static pj_status_t parse_attr_crypto(pj_pool_t *pool, 
    693775                                     const pjmedia_sdp_attr *attr, 
    694                                      pjmedia_srtp_stream_crypto *policy, 
     776                                     pjmedia_srtp_crypto *crypto, 
    695777                                     int *tag) 
    696778{ 
    697779    pj_str_t input; 
    698780    char *token; 
    699  
    700     pj_bzero(policy, sizeof(*policy)); 
     781    pj_str_t tmp; 
     782    pj_status_t status; 
     783    int itmp; 
     784 
     785    pj_bzero(crypto, sizeof(*crypto)); 
    701786    pj_strdup_with_null(pool, &input, &attr->value); 
    702787 
     
    708793    } 
    709794    *tag = atoi(token); 
     795    if (*tag == 0) 
     796        return PJMEDIA_SDP_EINATTR; 
    710797 
    711798    /* Crypto-suite */ 
     
    715802        return PJMEDIA_SDP_EINATTR; 
    716803    } 
    717     policy->crypto_suite = pj_str(token); 
     804    crypto->name = pj_str(token); 
    718805 
    719806    /* Key method */ 
     
    734821        return PJMEDIA_SDP_EINATTR; 
    735822    } 
    736     policy->key = pj_str(token); 
     823    tmp = pj_str(token); 
     824    crypto->key.ptr = pj_pool_zalloc(pool, MAX_KEY_LEN); 
     825 
     826    /* Decode key */ 
     827    itmp = MAX_KEY_LEN; 
     828    status = pj_base64_decode(&tmp, (pj_uint8_t*)crypto->key.ptr,  
     829                              &itmp); 
     830    if (status != PJ_SUCCESS) { 
     831        PJ_LOG(5,(THIS_FILE, "Failed decoding key from base64")); 
     832        return status; 
     833    } 
     834    crypto->key.slen = itmp; 
    737835 
    738836    return PJ_SUCCESS; 
    739837} 
     838 
     839static pj_status_t transport_media_create(pjmedia_transport *tp, 
     840                                          pj_pool_t *pool, 
     841                                          pjmedia_sdp_session *sdp_local, 
     842                                          const pjmedia_sdp_session *sdp_remote, 
     843                                          unsigned media_index) 
     844{ 
     845    struct transport_srtp *srtp = (struct transport_srtp*) tp; 
     846    pjmedia_sdp_media *m_rem, *m_loc; 
     847    enum { MAXLEN = 512 }; 
     848    char buffer[MAXLEN]; 
     849    int buffer_len = MAXLEN; 
     850    pj_status_t status; 
     851    pjmedia_sdp_attr *attr; 
     852    pj_str_t attr_value; 
     853    int i, j; 
     854 
     855    PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL); 
     856 
     857    pj_bzero(&srtp->rx_policy, sizeof(srtp->rx_policy)); 
     858    pj_bzero(&srtp->tx_policy, sizeof(srtp->rx_policy)); 
     859 
     860    m_rem = sdp_remote ? sdp_remote->media[media_index] : NULL; 
     861    m_loc = sdp_local->media[media_index]; 
     862 
     863    /* bypass if media transport is not RTP/AVP or RTP/SAVP */ 
     864    if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP)  != 0 &&  
     865        pj_stricmp(&m_loc->desc.transport, &ID_RTP_SAVP) != 0) 
     866        goto PROPAGATE_MEDIA_CREATE; 
     867 
     868    /* If the media is inactive, do nothing. */ 
     869    if (pjmedia_sdp_media_find_attr(m_loc, &ID_INACTIVE, NULL) ||  
     870        (m_rem && pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL))) 
     871    { 
     872        goto PROPAGATE_MEDIA_CREATE; 
     873    } 
     874 
     875    srtp->offerer_side = !sdp_remote; 
     876 
     877    /* Check remote media transport & set local media transport  
     878     * based on SRTP usage option. 
     879     */ 
     880    if (srtp->offerer_side) { 
     881        if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 
     882            goto PROPAGATE_MEDIA_CREATE; 
     883        } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 
     884            m_loc->desc.transport = ID_RTP_AVP; 
     885        } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 
     886            m_loc->desc.transport = ID_RTP_SAVP; 
     887        } 
     888    } else { 
     889        if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 
     890            if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0) { 
     891                DEACTIVATE_MEDIA(pool, m_loc); 
     892                return PJMEDIA_SRTP_ESDPINTRANSPORT; 
     893            } 
     894        } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 
     895                m_loc->desc.transport = m_rem->desc.transport; 
     896        } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 
     897            if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0) { 
     898                DEACTIVATE_MEDIA(pool, m_loc); 
     899                return PJMEDIA_SRTP_ESDPINTRANSPORT; 
     900            } 
     901        } 
     902    } 
     903 
     904    /* Generate crypto attribute */ 
     905    if (srtp->offerer_side) { 
     906        for (i=0; i<srtp->setting.crypto_count; ++i) { 
     907            /* Offer crypto-suites based on setting. */ 
     908            status = generate_crypto_attr_value(pool, buffer, &buffer_len, 
     909                                                &srtp->setting.crypto[i], 
     910                                                i+1); 
     911            if (status != PJ_SUCCESS) 
     912                return status; 
     913 
     914            /* If buffer_len==0, just skip the crypto attribute. */ 
     915            if (buffer_len) { 
     916                pj_strset(&attr_value, buffer, buffer_len); 
     917                attr = pjmedia_sdp_attr_create(pool, "crypto", &attr_value); 
     918                m_loc->attr[m_loc->attr_count++] = attr; 
     919            } 
     920        } 
     921    } else { 
     922        /* find supported crypto-suite, get the tag, and assign policy_local */ 
     923        pjmedia_srtp_crypto tmp_rx_crypto; 
     924        pj_bool_t has_crypto_attr = PJ_FALSE; 
     925        pj_bool_t has_match = PJ_FALSE; 
     926        int chosen_tag = 0; 
     927        int tags[8]; 
     928        int cr_count = 0; 
     929        int k; 
     930 
     931        for (i=0; i<m_rem->attr_count; ++i) { 
     932            if (pj_stricmp2(&m_rem->attr[i]->name, "crypto") != 0) 
     933                continue; 
     934 
     935            if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 
     936                DEACTIVATE_MEDIA(pool, m_loc); 
     937                return PJMEDIA_SRTP_ESDPINTRANSPORT; 
     938            } 
     939 
     940            has_crypto_attr = PJ_TRUE; 
     941 
     942            status = parse_attr_crypto(pool, m_rem->attr[i],  
     943                                       &tmp_rx_crypto, &tags[cr_count]); 
     944            if (status != PJ_SUCCESS) 
     945                return status; 
     946          
     947            /* Check duplicated tag */ 
     948            for (k=0; k<cr_count; ++k) { 
     949                if (tags[k] == tags[cr_count]) { 
     950                    DEACTIVATE_MEDIA(pool, m_loc); 
     951                    return PJMEDIA_SRTP_ESDPDUPCRYPTOTAG; 
     952                } 
     953            } 
     954 
     955            if (!has_match) { 
     956                /* lets see if the crypto-suite offered is supported */ 
     957                for (j=0; j<srtp->setting.crypto_count; ++j) 
     958                    if (pj_stricmp(&tmp_rx_crypto.name,  
     959                                   &srtp->setting.crypto[j].name) == 0) 
     960                    { 
     961                        srtp->tx_policy = srtp->setting.crypto[j]; 
     962                        srtp->rx_policy = tmp_rx_crypto; 
     963                        chosen_tag = tags[cr_count]; 
     964                        has_match = PJ_TRUE; 
     965                        break; 
     966                    } 
     967            } 
     968            cr_count++; 
     969        } 
     970 
     971        if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 
     972            /* At this point, it is ensured remote has no crypto attr */ 
     973            goto PROPAGATE_MEDIA_CREATE; 
     974        } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 
     975            if (!has_crypto_attr) 
     976                goto PROPAGATE_MEDIA_CREATE;; 
     977        } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 
     978            if (!has_crypto_attr) { 
     979                DEACTIVATE_MEDIA(pool, m_loc); 
     980                return PJMEDIA_SRTP_ESDPREQCRYPTO; 
     981            } 
     982        } 
     983 
     984        /* No crypto match? */ 
     985        if (!has_match) { 
     986            DEACTIVATE_MEDIA(pool, m_loc); 
     987            return PJMEDIA_SRTP_ENOTSUPCRYPTO; 
     988        } 
     989 
     990        /* we have to generate crypto answer,  
     991         * with srtp->tx_policy matched the offer 
     992         * and rem_tag contains matched offer tag. 
     993         */ 
     994        status = generate_crypto_attr_value(pool, buffer, &buffer_len, 
     995                                            &srtp->tx_policy, 
     996                                            chosen_tag); 
     997        if (status != PJ_SUCCESS) 
     998            return status; 
     999 
     1000        /* If buffer_len==0, just skip the crypto attribute. */ 
     1001        if (buffer_len) { 
     1002            pj_strset(&attr_value, buffer, buffer_len); 
     1003            attr = pjmedia_sdp_attr_create(pool, "crypto", &attr_value); 
     1004            m_loc->attr[m_loc->attr_count++] = attr; 
     1005        } 
     1006 
     1007        /* At this point, 
     1008         * we should have valid rx_policy & tx_policy. 
     1009         */ 
     1010    } 
     1011 
     1012PROPAGATE_MEDIA_CREATE: 
     1013    return pjmedia_transport_media_create(srtp->real_tp, pool, sdp_local,  
     1014                                           sdp_remote, media_index); 
     1015} 
     1016 
     1017 
    7401018 
    7411019static pj_status_t transport_media_start(pjmedia_transport *tp, 
     
    7461024{ 
    7471025    struct transport_srtp *srtp = (struct transport_srtp*) tp; 
    748     pjmedia_sdp_media *media_remote = sdp_remote->media[media_index]; 
    749     pjmedia_sdp_media *media_local  = sdp_local->media[media_index]; 
     1026    pjmedia_sdp_media *m_rem, *m_loc; 
     1027    pj_status_t status; 
    7501028    pjmedia_sdp_attr *attr; 
    751     pjmedia_srtp_stream_crypto policy_remote; 
    752     pjmedia_srtp_stream_crypto policy_local; 
    753     pj_status_t status; 
    754     unsigned cs_cnt = sizeof(crypto_suites)/sizeof(crypto_suites[0]); 
    755     int cs_tag = -1; 
    756     unsigned i, j; 
     1029    int i; 
     1030 
     1031    PJ_ASSERT_RETURN(tp && pool && sdp_local && sdp_remote, PJ_EINVAL); 
     1032 
     1033    m_rem = sdp_remote->media[media_index]; 
     1034    m_loc = sdp_local->media[media_index]; 
     1035 
     1036    /* bypass if media transport is not RTP/AVP or RTP/SAVP */ 
     1037    if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP)  != 0 &&  
     1038        pj_stricmp(&m_loc->desc.transport, &ID_RTP_SAVP) != 0) 
     1039        goto PROPAGATE_MEDIA_START; 
    7571040 
    7581041    /* If the media is inactive, do nothing. */ 
    759     if (pjmedia_sdp_media_find_attr2(media_remote, "inactive", NULL) || 
    760         pjmedia_sdp_media_find_attr2(media_local, "inactive", NULL)) 
     1042    if (pjmedia_sdp_media_find_attr(m_loc, &ID_INACTIVE, NULL) ||  
     1043        (m_rem && pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL))) 
    7611044    { 
    762         return PJ_SUCCESS; 
    763     } 
    764  
    765     /* default crypto-suite = crypto 'NULL' */ 
    766     pj_bzero(&policy_remote, sizeof(policy_remote)); 
    767     policy_remote.crypto_suite = pj_str(crypto_suites[0].name); 
    768     pj_bzero(&policy_local, sizeof(policy_local)); 
    769     policy_remote.crypto_suite = pj_str(crypto_suites[0].name); 
    770  
    771     /* If the media transport is not RTP/SAVP, just apply crypto default */ 
    772     if (pj_stricmp(&media_local->desc.transport, &ID_RTP_SAVP) || 
    773         pj_stricmp(&media_remote->desc.transport, &ID_RTP_SAVP)) 
    774     { 
    775         return PJMEDIA_SRTP_ESDPREQSECTP; 
    776     } 
    777  
    778     /* 
    779      * In this stage, we need to make sure the crypto-suite negotiation 
    780      * is completed, and also parse the key from SDP. 
     1045        goto PROPAGATE_MEDIA_START; 
     1046    } 
     1047 
     1048    /* For answerer side, this function will just have to start SRTP */ 
     1049 
     1050    /* Check remote media transport & set local media transport  
     1051     * based on SRTP usage option. 
    7811052     */ 
    7821053    if (srtp->offerer_side) { 
    783         /* If we are at the offerer side:  
    784          * 1. Get what crypto-suite selected by remote, we use the same one. 
    785          * 2. Get what key we offered in the offering stage for  
    786          *    the selected crypto-suite. 
    787          * 3. If no crypto-suite answered, assume the answerer want plain RTP. 
    788          *    (perhaps this will abuse RFC 4568) 
    789          */ 
    790  
    791         /* Make sure only thera is ONLY ONE crypto attribute in the answer. */ 
    792         attr = NULL; 
    793         for (i=0; i<media_remote->attr_count; ++i) { 
    794             if (!pj_stricmp2(&media_local->attr[i]->name, "crypto")) { 
    795                 if (attr) { 
    796                     PJ_LOG(5,(THIS_FILE, "More than one crypto attr in " \ 
    797                                          "the SDP answer.")); 
    798                     return PJMEDIA_SRTP_ESDPAMBIGUEANS; 
    799                 } 
    800  
    801                 attr = media_local->attr[i]; 
    802             } 
    803         } 
    804         if (!attr) { 
    805             /* the answer got no crypto-suite attribute, huh! */ 
    806             PJ_LOG(5,(THIS_FILE, "Crypto attribute cannot be found in" \ 
    807                                  "remote SDP, using NULL crypto.")); 
    808         } else { 
    809  
    810             /* get policy_remote */ 
    811             status = parse_attr_crypto(pool, attr, &policy_remote, &cs_tag); 
     1054        if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 
     1055            if (pjmedia_sdp_media_find_attr2(m_rem, "crypto", NULL)) { 
     1056                DEACTIVATE_MEDIA(pool, m_loc); 
     1057                return PJMEDIA_SRTP_ESDPINCRYPTO; 
     1058            } 
     1059            goto PROPAGATE_MEDIA_START;; 
     1060        } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 
     1061            if (pj_stricmp(&m_rem->desc.transport, &m_loc->desc.transport)) { 
     1062                DEACTIVATE_MEDIA(pool, m_loc); 
     1063                return PJMEDIA_SDP_EINPROTO; 
     1064            } 
     1065        } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 
     1066            if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP)) { 
     1067                DEACTIVATE_MEDIA(pool, m_loc); 
     1068                return PJMEDIA_SDP_EINPROTO; 
     1069            } 
     1070        } 
     1071    } 
     1072     
     1073    if (srtp->offerer_side) { 
     1074        /* find supported crypto-suite, get the tag, and assign policy_local */ 
     1075        pj_bool_t has_crypto_attr = PJ_FALSE; 
     1076        int rem_tag; 
     1077 
     1078        for (i=0; i<m_rem->attr_count; ++i) { 
     1079            if (pj_stricmp2(&m_rem->attr[i]->name, "crypto") != 0) 
     1080                continue; 
     1081 
     1082            /* more than one crypto attribute in media answer */ 
     1083            if (has_crypto_attr) { 
     1084                DEACTIVATE_MEDIA(pool, m_loc); 
     1085                return PJMEDIA_SRTP_ESDPAMBIGUEANS; 
     1086            } 
     1087 
     1088            has_crypto_attr = PJ_TRUE; 
     1089 
     1090            status = parse_attr_crypto(pool, m_rem->attr[i],  
     1091                                       &srtp->rx_policy, &rem_tag); 
    8121092            if (status != PJ_SUCCESS) 
    8131093                return status; 
    8141094 
    815             /* lets see what crypto-suite chosen, we will use the same one */ 
    816             for (i=1; i<cs_cnt; ++i) { 
    817                 if (!pj_stricmp2(&policy_remote.crypto_suite,  
    818                                  crypto_suites[i].name)) 
    819                     break; 
    820             } 
    821  
    822             /* The crypto-suite answered is not supported, 
    823              * this SHOULD NEVER happen, since we only offer what we support, 
    824              * except the answerer is trying to force us use his crypto-suite! 
    825              * Let's return non-PJ_SUCCESS and cancel the call. 
    826              */ 
    827             if (i == cs_cnt) { 
    828                 return PJ_ENOTSUP; 
    829             } 
    830  
    831             /* check whether the answer is match to our offers, 
    832              * then get our own offered key along with the crypto-suite 
    833              * and put it in policy_local. 
    834              */ 
    835             for (i=0; i<media_local->attr_count; ++i) { 
    836                 int tmp_cs_tag; 
    837              
    838                 if (pj_stricmp2(&media_local->attr[i]->name, "crypto")) 
    839                     continue; 
    840  
    841                 status = parse_attr_crypto(pool, media_local->attr[i],  
    842                                            &policy_local, &tmp_cs_tag); 
    843                 if (status != PJ_SUCCESS) 
    844                     return status; 
    845  
    846                 /* Selected crypto-suite is marked by same crypto attr tag */ 
    847                 if (tmp_cs_tag == cs_tag) 
    848                     break; 
    849             } 
    850             /* This SHOULD NEVER happen. */ 
    851             if (i == media_local->attr_count) { 
    852                 return PJMEDIA_SDPNEG_ENOMEDIA; 
    853             } 
    854  
    855             /* Check if crypto-suite name match, crypto tag was ensured same */ 
    856             if (pj_stricmp(&policy_local.crypto_suite,  
    857                            &policy_remote.crypto_suite)) 
     1095 
     1096            /* our offer tag is always ordered by setting */ 
     1097            if (rem_tag<1 || rem_tag>srtp->setting.crypto_count) { 
     1098                DEACTIVATE_MEDIA(pool, m_loc); 
     1099                return PJMEDIA_SRTP_ESDPINCRYPTOTAG; 
     1100            } 
     1101 
     1102            /* match the crypto name */ 
     1103            if (pj_stricmp(&srtp->rx_policy.name,  
     1104                &srtp->setting.crypto[rem_tag-1].name) != 0) 
    8581105            { 
    859                 return PJMEDIA_ERROR; 
    860             } 
    861         } 
    862     } else { 
    863         /* If we are at the answerer side:  
    864          * 1. Negotiate: check if any offered crypto-suite matches  
    865          *    our capability. 
    866          * 2. If there is one, generate key and media attribute. 
    867          * 3. If there isn't, return error. 
    868          * 4. If no crypto-suite offered, apply NULL crypto-suite. 
    869          *    (perhaps this will abuse RFC 4568) 
    870          * 
    871          * Please note that we need to consider the existance of other media, 
    872          * so instead of returning non-PJ_SUCCESS on failed negotiation, 
    873          * which will cancel the call, perhaps it is wiser to mark the media  
    874          * as inactive. 
     1106                DEACTIVATE_MEDIA(pool, m_loc); 
     1107                return PJMEDIA_SRTP_ECRYPTONOTMATCH; 
     1108            } 
     1109 
     1110            srtp->tx_policy = srtp->setting.crypto[rem_tag-1]; 
     1111        } 
     1112 
     1113        if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 
     1114            /* should never reach here */ 
     1115            goto PROPAGATE_MEDIA_START; 
     1116        } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 
     1117            if (!has_crypto_attr) 
     1118                goto PROPAGATE_MEDIA_START; 
     1119        } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 
     1120            if (!has_crypto_attr) { 
     1121                DEACTIVATE_MEDIA(pool, m_loc); 
     1122                return PJMEDIA_SRTP_ESDPREQCRYPTO; 
     1123            } 
     1124        } 
     1125 
     1126        /* At this point, 
     1127         * we should have valid rx_policy & tx_policy. 
    8751128         */ 
    876  
    877         enum { MAXLEN = 512 }; 
    878         char buffer[MAXLEN]; 
    879         int  buffer_len = MAXLEN; 
    880         pj_str_t attr_value; 
    881         pj_bool_t no_crypto_attr = PJ_TRUE; 
    882         int cs_idx = -1; 
    883  
    884         /* find supported crypto-suite, get the tag, and assign policy_local */ 
    885         for (i=0; (i<media_remote->attr_count) && (cs_idx == -1); ++i) { 
    886             if (pj_stricmp2(&media_remote->attr[i]->name, "crypto")) 
    887                 continue; 
    888  
    889             no_crypto_attr = PJ_FALSE; 
    890  
    891             status = parse_attr_crypto(pool, media_remote->attr[i],  
    892                                        &policy_remote, &cs_tag); 
    893             if (status != PJ_SUCCESS) 
    894                 return status; 
    895           
    896             /* lets see if the crypto-suite offered is supported */ 
    897             for (j=1; j<cs_cnt; ++j) { 
    898                 if (!pj_stricmp2(&policy_remote.crypto_suite,  
    899                                  crypto_suites[j].name)) 
    900                 { 
    901                     cs_idx = j; 
    902                     break; 
    903                 } 
    904             } 
    905         } 
    906  
    907         if (!no_crypto_attr) { 
    908             /* No crypto-suites offered is supported by us. 
    909              * What should we do? 
    910              * By now, let's just deactivate the media. 
    911              */ 
    912             if (i == media_remote->attr_count) { 
    913                 attr = pjmedia_sdp_attr_create(pool, "inactive", NULL); 
    914                 media_local->attr[media_local->attr_count++] = attr; 
    915                 media_local->desc.port = 0; 
    916  
    917                 return PJ_SUCCESS; 
    918             } 
    919  
    920             /* there is crypto-suite supported 
    921              * let's generate crypto attribute and also the key, 
    922              * dont forget to use offerer cs_tag. 
    923              */ 
    924             status = generate_crypto_attr_value(buffer, &buffer_len, cs_idx, cs_tag); 
    925             if (status != PJ_SUCCESS) 
    926                 return status; 
    927  
    928             /* If buffer_len==0, just skip the crypto attribute. */ 
    929             if (buffer_len) { 
    930                 pj_strset(&attr_value, buffer, buffer_len); 
    931                 attr = pjmedia_sdp_attr_create(pool, "crypto", &attr_value); 
    932                 media_local->attr[media_local->attr_count++] = attr; 
    933  
    934                 /* put our key & crypto-suite name to policy_local */ 
    935                 status = parse_attr_crypto(pool, attr, &policy_local, &cs_tag); 
    936                 if (status != PJ_SUCCESS) 
    937                     return status; 
    938             } 
    939         } 
    940     } 
    941  
    942     /* in the SDP, all keys are in base64, they have to be decoded back 
    943      * to base256 before used. 
    944      */ 
    945     if (policy_local.key.slen) { 
    946         char key[MAX_KEY_LEN]; 
    947         int  key_len = MAX_KEY_LEN; 
    948          
    949         status = pj_base64_decode(&policy_local.key,  
    950                                   (pj_uint8_t*)key, &key_len); 
    951         if (status != PJ_SUCCESS) 
    952             return status; 
    953  
    954         pj_memcpy(policy_local.key.ptr, key, key_len); 
    955         policy_local.key.slen = key_len; 
    956     } 
    957  
    958     if (policy_remote.key.slen) { 
    959         char key[MAX_KEY_LEN]; 
    960         int  key_len = MAX_KEY_LEN; 
    961          
    962         status = pj_base64_decode(&policy_remote.key,  
    963                                   (pj_uint8_t*)key, &key_len); 
    964         if (status != PJ_SUCCESS) 
    965             return status; 
    966  
    967         pj_memcpy(policy_remote.key.ptr, key, key_len); 
    968         policy_remote.key.slen = key_len; 
    9691129    } 
    9701130 
    9711131    /* Got policy_local & policy_remote, let's initalize the SRTP */ 
    972     status = pjmedia_transport_srtp_start(tp, &policy_local, &policy_remote); 
     1132    status = pjmedia_transport_srtp_start(tp, &srtp->tx_policy, &srtp->rx_policy); 
    9731133    if (status != PJ_SUCCESS) 
    9741134        return status; 
    9751135 
     1136PROPAGATE_MEDIA_START: 
    9761137    return pjmedia_transport_media_start(srtp->real_tp, pool,  
    9771138                                         sdp_local, sdp_remote, 
Note: See TracChangeset for help on using the changeset viewer.