Changeset 2032 for pjproject/trunk
- Timestamp:
- Jun 19, 2008 2:10:28 PM (16 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/include/pjmedia/sdp.h
r1810 r2032 318 318 pjmedia_sdp_rtcp_attr *rtcp); 319 319 320 321 /** 322 * Create a=rtcp attribute. 323 * 324 * @param pool Pool to create the attribute. 325 * @param a Socket address. 326 * 327 * @return SDP RTCP attribute. 328 */ 329 PJ_DECL(pjmedia_sdp_attr*) pjmedia_sdp_attr_create_rtcp(pj_pool_t *pool, 330 const pj_sockaddr *a); 320 331 321 332 -
pjproject/trunk/pjmedia/include/pjmedia/transport.h
r1998 r2032 321 321 322 322 /** 323 * Prepare the transport for a new media session. 324 * 325 * Application should call #pjmedia_transport_media_create() instead of 326 * calling this function directly. 327 */ 328 pj_status_t (*media_create)(pjmedia_transport *tp, 329 pj_pool_t *sdp_pool, 330 unsigned options, 331 const pjmedia_sdp_session *remote_sdp, 332 unsigned media_index); 333 334 /** 323 335 * This function is called by application to generate the SDP parts 324 336 * related to transport type, e.g: ICE, SRTP. 325 337 * 326 * Application should call #pjmedia_transport_media_create() instead of 327 * calling this function directly. 328 */ 329 pj_status_t (*media_create)(pjmedia_transport *tp, 330 pj_pool_t *pool, 331 unsigned options, 332 pjmedia_sdp_session *sdp_local, 333 const pjmedia_sdp_session *sdp_remote, 334 unsigned media_index); 338 * Application should call #pjmedia_transport_encode_sdp() instead of 339 * calling this function directly. 340 */ 341 pj_status_t (*encode_sdp)(pjmedia_transport *tp, 342 pj_pool_t *sdp_pool, 343 pjmedia_sdp_session *sdp_local, 344 const pjmedia_sdp_session *rem_sdp, 345 unsigned media_index); 335 346 336 347 /** … … 342 353 */ 343 354 pj_status_t (*media_start) (pjmedia_transport *tp, 344 pj_pool_t * pool,345 pjmedia_sdp_session *sdp_local,355 pj_pool_t *tmp_pool, 356 const pjmedia_sdp_session *sdp_local, 346 357 const pjmedia_sdp_session *sdp_remote, 347 358 unsigned media_index); … … 627 638 628 639 /** 629 * Generate local SDP parts that are related to the specified media transport. 630 * Remote SDP might be needed as reference when application is in deciding 631 * side of negotiation (callee side), otherwise it should be NULL. 632 * 633 * This API is provided to allow the media transport to add more information 634 * in the SDP offer, before the offer is sent to remote. Additionally, for 635 * answerer side, this callback allows the media transport to reject the 636 * offer before this offer is processed by the SDP negotiator. 640 * Prepare the media transport for a new media session, and optionally 641 * encode the relevant information in the \a sdp_local. Application must 642 * call this function before starting a new media session using this 643 * transport. 637 644 * 638 645 * This is just a simple wrapper which calls <tt>media_create()</tt> member … … 640 647 * 641 648 * @param tp The media transport. 642 * @param pool The memory pool. 649 * @param sdp_pool Pool object to allocate memory related to SDP 650 * messaging components. 643 651 * @param option Option flags, from #pjmedia_tranport_media_option 644 * @param sdp_local Local SDP. 645 * @param sdp_remote Remote SDP. 652 * @param rem_sdp Remote SDP if it's available. 646 653 * @param media_index Media index in SDP. 647 654 * … … 649 656 */ 650 657 PJ_INLINE(pj_status_t) pjmedia_transport_media_create(pjmedia_transport *tp, 651 pj_pool_t * pool,658 pj_pool_t *sdp_pool, 652 659 unsigned options, 653 pjmedia_sdp_session *sdp_local, 654 const pjmedia_sdp_session *sdp_remote, 660 const pjmedia_sdp_session *rem_sdp, 655 661 unsigned media_index) 656 662 { 657 return (*tp->op->media_create)(tp, pool, options, sdp_local, sdp_remote,663 return (*tp->op->media_create)(tp, sdp_pool, options, rem_sdp, 658 664 media_index); 659 665 } 666 667 668 /** 669 * Put transport specific information into the SDP. This function can be 670 * called to create SDP offer or answer, depending whether \a rem_sdp 671 * parameter is present. 672 * 673 * This is just a simple wrapper which calls <tt>encode_sdp()</tt> member 674 * of the transport. 675 * 676 * @param tp The media transport. 677 * @param sdp_pool Pool object to allocate memory related to SDP 678 * messaging components. 679 * @param sdp The local SDP to be filled in information from the 680 * media transport. 681 * @param rem_sdp Remote SDP if it's available. 682 * @param media_index Media index in SDP. 683 * 684 * @return PJ_SUCCESS on success, or the appropriate error code. 685 */ 686 PJ_INLINE(pj_status_t) pjmedia_transport_encode_sdp(pjmedia_transport *tp, 687 pj_pool_t *sdp_pool, 688 pjmedia_sdp_session *sdp, 689 const pjmedia_sdp_session *rem_sdp, 690 unsigned media_index) 691 { 692 return (*tp->op->encode_sdp)(tp, sdp_pool, sdp, rem_sdp, media_index); 693 } 694 660 695 661 696 /** … … 674 709 * 675 710 * @param tp The media transport. 676 * @param pool The memory pool.711 * @param tmp_pool The memory pool for allocating temporary objects. 677 712 * @param option The media transport option. 678 713 * @param sdp_local Local SDP. … … 683 718 */ 684 719 PJ_INLINE(pj_status_t) pjmedia_transport_media_start(pjmedia_transport *tp, 685 pj_pool_t * pool,686 pjmedia_sdp_session *sdp_local,720 pj_pool_t *tmp_pool, 721 const pjmedia_sdp_session *sdp_local, 687 722 const pjmedia_sdp_session *sdp_remote, 688 723 unsigned media_index) 689 724 { 690 return (*tp->op->media_start)(tp, pool, sdp_local, sdp_remote, media_index); 725 return (*tp->op->media_start)(tp, tmp_pool, sdp_local, sdp_remote, 726 media_index); 691 727 } 692 728 -
pjproject/trunk/pjmedia/src/pjmedia/endpoint.c
r1813 r2032 363 363 #if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0 364 364 if (sock_info->rtcp_addr_name.addr.sa_family != 0) { 365 const pj_sockaddr *rtcp_addr = &sock_info->rtcp_addr_name; 366 367 attr = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_attr); 368 attr->name = pj_str("rtcp"); 369 attr->value.ptr = (char*) pj_pool_alloc(pool, 80); 370 if (rtcp_addr->addr.sa_family == pj_AF_INET()) { 371 attr->value.slen = 372 pj_ansi_snprintf(attr->value.ptr, 80, 373 "%u IN IP4 %s", 374 pj_ntohs(rtcp_addr->ipv4.sin_port), 375 pj_inet_ntoa(rtcp_addr->ipv4.sin_addr)); 376 } else if (rtcp_addr->addr.sa_family == pj_AF_INET6()) { 377 char tmp_addr[PJ_INET6_ADDRSTRLEN]; 378 attr->value.slen = 379 pj_ansi_snprintf(attr->value.ptr, 80, 380 "%u IN IP6 %s", 381 pj_sockaddr_get_port(rtcp_addr), 382 pj_sockaddr_print(rtcp_addr, tmp_addr, 383 sizeof(tmp_addr), 0)); 384 385 } else { 386 pj_assert(!"Unsupported address family"); 387 return PJ_EAFNOTSUP; 388 } 389 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 365 attr = pjmedia_sdp_attr_create_rtcp(pool, &sock_info->rtcp_addr_name); 366 if (attr) 367 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 390 368 } 391 369 #endif -
pjproject/trunk/pjmedia/src/pjmedia/sdp.c
r1967 r2032 414 414 } 415 415 416 417 PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_create_rtcp(pj_pool_t *pool, 418 const pj_sockaddr *a) 419 { 420 enum { 421 ATTR_LEN = PJ_INET6_ADDRSTRLEN+16 422 }; 423 pjmedia_sdp_attr *attr; 424 425 attr = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_attr); 426 attr->name = pj_str("rtcp"); 427 attr->value.ptr = (char*) pj_pool_alloc(pool, ATTR_LEN); 428 if (a->addr.sa_family == pj_AF_INET()) { 429 attr->value.slen = 430 pj_ansi_snprintf(attr->value.ptr, ATTR_LEN, 431 "%u IN IP4 %s", 432 pj_ntohs(a->ipv4.sin_port), 433 pj_inet_ntoa(a->ipv4.sin_addr)); 434 } else if (a->addr.sa_family == pj_AF_INET6()) { 435 char tmp_addr[PJ_INET6_ADDRSTRLEN]; 436 attr->value.slen = 437 pj_ansi_snprintf(attr->value.ptr, ATTR_LEN, 438 "%u IN IP6 %s", 439 pj_sockaddr_get_port(a), 440 pj_sockaddr_print(a, tmp_addr, 441 sizeof(tmp_addr), 0)); 442 443 } else { 444 pj_assert(!"Unsupported address family"); 445 return NULL; 446 } 447 448 return attr; 449 } 416 450 417 451 -
pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
r1989 r2032 24 24 25 25 #define THIS_FILE "transport_ice.c" 26 27 static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 }; 26 #if 0 27 # define TRACE__(expr) PJ_LOG(5,expr) 28 #else 29 # define TRACE__(expr) 30 #endif 31 32 enum oa_role 33 { 34 ROLE_NONE, 35 ROLE_OFFERER, 36 ROLE_ANSWERER 37 }; 38 39 struct sdp_state 40 { 41 unsigned match_comp_cnt; /* Matching number of components */ 42 pj_bool_t ice_mismatch; /* Address doesn't match candidates */ 43 pj_bool_t ice_restart; /* Offer to restart ICE */ 44 pj_ice_sess_role local_role; /* Our role */ 45 }; 28 46 29 47 struct transport_ice … … 32 50 pj_pool_t *pool; 33 51 int af; 52 34 53 unsigned comp_cnt; 35 54 pj_ice_strans *ice_st; 55 36 56 pjmedia_ice_cb cb; 37 57 unsigned media_option; 58 59 pj_bool_t initial_sdp; 60 enum oa_role oa_role; /**< Last role in SDP offer/answer */ 61 struct sdp_state rem_offer_state;/**< Describes the remote offer */ 38 62 39 63 void *stream; … … 85 109 pj_pool_t *pool, 86 110 unsigned options, 87 pjmedia_sdp_session *sdp_local,88 111 const pjmedia_sdp_session *rem_sdp, 89 112 unsigned media_index); 90 static pj_status_t transport_media_start (pjmedia_transport *tp, 113 static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 114 pj_pool_t *tmp_pool, 115 pjmedia_sdp_session *sdp_local, 116 const pjmedia_sdp_session *rem_sdp, 117 unsigned media_index); 118 static pj_status_t transport_media_start(pjmedia_transport *tp, 91 119 pj_pool_t *pool, 92 pjmedia_sdp_session *sdp_local,120 const pjmedia_sdp_session *sdp_local, 93 121 const pjmedia_sdp_session *rem_sdp, 94 122 unsigned media_index); … … 121 149 &transport_send_rtcp2, 122 150 &transport_media_create, 151 &transport_encode_sdp, 123 152 &transport_media_start, 124 153 &transport_media_stop, … … 127 156 }; 128 157 129 static const pj_str_t STR_CANDIDATE = {"candidate", 9}; 130 static const pj_str_t STR_ICE_LITE = {"ice-lite", 8}; 131 static const pj_str_t STR_ICE_MISMATCH = {"ice-mismatch", 12}; 132 158 static const pj_str_t STR_RTP_AVP = { "RTP/AVP", 7 }; 159 static const pj_str_t STR_CANDIDATE = { "candidate", 9}; 160 static const pj_str_t STR_REM_CAND = { "remote-candidates", 17 }; 161 static const pj_str_t STR_ICE_LITE = { "ice-lite", 8}; 162 static const pj_str_t STR_ICE_MISMATCH = { "ice-mismatch", 12}; 163 static const pj_str_t STR_ICE_UFRAG = { "ice-ufrag", 9 }; 164 static const pj_str_t STR_ICE_PWD = { "ice-pwd", 7 }; 165 static const pj_str_t STR_IP4 = { "IP4", 3 }; 166 static const pj_str_t STR_IP6 = { "IP6", 3 }; 167 static const pj_str_t STR_RTCP = { "rtcp", 4 }; 168 169 enum { 170 COMP_RTP = 1, 171 COMP_RTCP = 2 172 }; 133 173 134 174 /* … … 158 198 tp_ice->base.op = &transport_ice_op; 159 199 tp_ice->base.type = PJMEDIA_TRANSPORT_TYPE_ICE; 200 tp_ice->initial_sdp = PJ_TRUE; 201 tp_ice->oa_role = ROLE_NONE; 160 202 161 203 if (cb) … … 184 226 return PJ_SUCCESS; 185 227 } 228 229 /* Disable ICE when SDP from remote doesn't contain a=candidate line */ 230 static void set_no_ice(struct transport_ice *tp_ice, const char *reason, 231 pj_status_t err) 232 { 233 if (err != PJ_SUCCESS) { 234 char errmsg[PJ_ERR_MSG_SIZE]; 235 pj_strerror(err, errmsg, sizeof(errmsg)); 236 PJ_LOG(4,(tp_ice->base.name, 237 "Stopping ICE, reason=%s:%s", reason, errmsg)); 238 } else { 239 PJ_LOG(4,(tp_ice->base.name, 240 "Stopping ICE, reason=%s", reason)); 241 } 242 243 pj_ice_strans_stop_ice(tp_ice->ice_st); 244 } 245 186 246 187 247 /* Create SDP candidate attribute */ … … 228 288 } 229 289 290 291 /* Get ice-ufrag and ice-pwd attribute */ 292 static void get_ice_attr(const pjmedia_sdp_session *rem_sdp, 293 const pjmedia_sdp_media *rem_m, 294 const pjmedia_sdp_attr **p_ice_ufrag, 295 const pjmedia_sdp_attr **p_ice_pwd) 296 { 297 pjmedia_sdp_attr *attr; 298 299 /* Find ice-ufrag attribute in media descriptor */ 300 attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, 301 &STR_ICE_UFRAG, NULL); 302 if (attr == NULL) { 303 /* Find ice-ufrag attribute in session descriptor */ 304 attr = pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr, 305 &STR_ICE_UFRAG, NULL); 306 } 307 *p_ice_ufrag = attr; 308 309 /* Find ice-pwd attribute in media descriptor */ 310 attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, 311 &STR_ICE_PWD, NULL); 312 if (attr == NULL) { 313 /* Find ice-pwd attribute in session descriptor */ 314 attr = pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr, 315 &STR_ICE_PWD, NULL); 316 } 317 *p_ice_pwd = attr; 318 } 319 320 321 /* Encode and add "a=ice-mismatch" attribute in the SDP */ 322 static void encode_ice_mismatch(pj_pool_t *sdp_pool, 323 pjmedia_sdp_session *sdp_local, 324 unsigned media_index) 325 { 326 pjmedia_sdp_attr *attr; 327 pjmedia_sdp_media *m = sdp_local->media[media_index]; 328 329 attr = PJ_POOL_ALLOC_T(sdp_pool, pjmedia_sdp_attr); 330 attr->name = STR_ICE_MISMATCH; 331 attr->value.slen = 0; 332 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 333 } 334 335 336 /* Encode ICE information in SDP */ 337 static pj_status_t encode_session_in_sdp(struct transport_ice *tp_ice, 338 pj_pool_t *sdp_pool, 339 pjmedia_sdp_session *sdp_local, 340 unsigned media_index, 341 unsigned comp_cnt, 342 pj_bool_t restart_session) 343 { 344 enum { 345 ATTR_BUF_LEN = 160, /* Max len of a=candidate attr */ 346 RATTR_BUF_LEN= 160 /* Max len of a=remote-candidates attr */ 347 }; 348 pjmedia_sdp_media *m = sdp_local->media[media_index]; 349 pj_str_t local_ufrag, local_pwd; 350 pjmedia_sdp_attr *attr; 351 pj_status_t status; 352 353 /* Must have a session */ 354 PJ_ASSERT_RETURN(pj_ice_strans_has_sess(tp_ice->ice_st), PJ_EBUG); 355 356 /* Get ufrag and pwd from current session */ 357 pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, &local_ufrag, &local_pwd, 358 NULL, NULL); 359 360 /* The listing of candidates depends on whether ICE has completed 361 * or not. When ICE has completed: 362 * 363 * 9.1.2.2: Existing Media Streams with ICE Completed 364 * The agent MUST include a candidate attributes for candidates 365 * matching the default destination for each component of the 366 * media stream, and MUST NOT include any other candidates. 367 * 368 * When ICE has not completed, we shall include all candidates. 369 * 370 * Except when we have detected that remote is offering to restart 371 * the session, in this case we will answer with full ICE SDP and 372 * new ufrag/pwd pair. 373 */ 374 if (!restart_session && pj_ice_strans_sess_is_complete(tp_ice->ice_st)) { 375 const pj_ice_sess_check *check; 376 char *attr_buf; 377 pjmedia_sdp_conn *conn; 378 pjmedia_sdp_attr *a_rtcp; 379 pj_str_t rem_cand; 380 unsigned comp; 381 382 /* Encode ice-ufrag attribute */ 383 attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr, 384 &local_ufrag); 385 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 386 387 /* Encode ice-pwd attribute */ 388 attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, 389 &local_pwd); 390 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 391 392 /* Prepare buffer */ 393 attr_buf = (char*) pj_pool_alloc(sdp_pool, ATTR_BUF_LEN); 394 rem_cand.ptr = (char*) pj_pool_alloc(sdp_pool, RATTR_BUF_LEN); 395 rem_cand.slen = 0; 396 397 /* 9.1.2.2: Existing Media Streams with ICE Completed 398 * The default destination for media (i.e., the values of 399 * the IP addresses and ports in the m and c line used for 400 * that media stream) MUST be the local candidate from the 401 * highest priority nominated pair in the valid list for each 402 * component. 403 */ 404 check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, 1); 405 if (check == NULL) { 406 pj_assert(!"Shouldn't happen"); 407 return PJ_EBUG; 408 } 409 410 /* Override connection line address and media port number */ 411 conn = m->conn; 412 if (conn == NULL) 413 conn = sdp_local->conn; 414 415 conn->addr.ptr = (char*) pj_pool_alloc(sdp_pool, 416 PJ_INET6_ADDRSTRLEN); 417 pj_sockaddr_print(&check->lcand->addr, conn->addr.ptr, 418 PJ_INET6_ADDRSTRLEN, 0); 419 conn->addr.slen = pj_ansi_strlen(conn->addr.ptr); 420 m->desc.port = pj_sockaddr_get_port(&check->lcand->addr); 421 422 /* Override address RTCP attribute if it's present */ 423 if (comp_cnt == 2 && 424 (check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, 425 COMP_RTCP)) != NULL && 426 (a_rtcp = pjmedia_sdp_attr_find(m->attr_count, m->attr, 427 &STR_RTCP, 0)) != NULL) 428 { 429 pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a_rtcp); 430 431 a_rtcp = pjmedia_sdp_attr_create_rtcp(sdp_pool, 432 &check->lcand->addr); 433 if (a_rtcp) 434 pjmedia_sdp_attr_add(&m->attr_count, m->attr, a_rtcp); 435 } 436 437 /* Encode only candidates matching the default destination 438 * for each component 439 */ 440 for (comp=0; comp < comp_cnt; ++comp) { 441 int len; 442 pj_str_t value; 443 444 /* Get valid pair for this component */ 445 check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, comp+1); 446 if (check == NULL) 447 continue; 448 449 /* Print and add local candidate in the pair */ 450 value.ptr = attr_buf; 451 value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN, 452 check->lcand); 453 if (value.slen < 0) { 454 pj_assert(!"Not enough attr_buf to print candidate"); 455 return PJ_EBUG; 456 } 457 458 attr = pjmedia_sdp_attr_create(sdp_pool, STR_CANDIDATE.ptr, 459 &value); 460 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 461 462 /* Append to a=remote-candidates attribute */ 463 if (pj_ice_strans_get_role(tp_ice->ice_st) == 464 PJ_ICE_SESS_ROLE_CONTROLLING) 465 { 466 char rem_addr[PJ_INET6_ADDRSTRLEN]; 467 468 pj_sockaddr_print(&check->rcand->addr, rem_addr, 469 sizeof(rem_addr), 0); 470 len = pj_ansi_snprintf( 471 rem_cand.ptr + rem_cand.slen, 472 RATTR_BUF_LEN - rem_cand.slen, 473 "%s%u %s %u", 474 (rem_cand.slen==0? "" : " "), 475 comp+1, rem_addr, 476 pj_sockaddr_get_port(&check->rcand->addr) 477 ); 478 if (len < 1 || len >= RATTR_BUF_LEN) { 479 pj_assert(!"Not enough buffer to print " 480 "remote-candidates"); 481 return PJ_EBUG; 482 } 483 484 rem_cand.slen += len; 485 } 486 } 487 488 /* 9.1.2.2: Existing Media Streams with ICE Completed 489 * In addition, if the agent is controlling, it MUST include 490 * the a=remote-candidates attribute for each media stream 491 * whose check list is in the Completed state. The attribute 492 * contains the remote candidates from the highest priority 493 * nominated pair in the valid list for each component of that 494 * media stream. 495 */ 496 if (pj_ice_strans_get_role(tp_ice->ice_st) == 497 PJ_ICE_SESS_ROLE_CONTROLLING) 498 { 499 attr = pjmedia_sdp_attr_create(sdp_pool, STR_REM_CAND.ptr, 500 &rem_cand); 501 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 502 } 503 504 } else if (pj_ice_strans_has_sess(tp_ice->ice_st)) { 505 /* Encode all candidates to SDP media */ 506 char *attr_buf; 507 unsigned comp; 508 509 /* If ICE is not restarted, encode current ICE ufrag/pwd. 510 * Otherwise generate new one. 511 */ 512 if (!restart_session) { 513 attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr, 514 &local_ufrag); 515 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 516 517 attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, 518 &local_pwd); 519 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 520 521 } else { 522 pj_str_t str; 523 524 str.slen = PJ_ICE_UFRAG_LEN; 525 str.ptr = (char*) pj_pool_alloc(sdp_pool, str.slen); 526 pj_create_random_string(str.ptr, str.slen); 527 attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr, &str); 528 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 529 530 str.ptr = (char*) pj_pool_alloc(sdp_pool, str.slen); 531 pj_create_random_string(str.ptr, str.slen); 532 attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, &str); 533 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 534 } 535 536 /* Create buffer to encode candidates as SDP attribute */ 537 attr_buf = (char*) pj_pool_alloc(sdp_pool, ATTR_BUF_LEN); 538 539 for (comp=0; comp < comp_cnt; ++comp) { 540 unsigned cand_cnt; 541 pj_ice_sess_cand cand[PJ_ICE_ST_MAX_CAND]; 542 unsigned i; 543 544 cand_cnt = PJ_ARRAY_SIZE(cand); 545 status = pj_ice_strans_enum_cands(tp_ice->ice_st, comp+1, 546 &cand_cnt, cand); 547 if (status != PJ_SUCCESS) 548 return status; 549 550 for (i=0; i<cand_cnt; ++i) { 551 pj_str_t value; 552 553 value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN, 554 &cand[i]); 555 if (value.slen < 0) { 556 pj_assert(!"Not enough attr_buf to print candidate"); 557 return PJ_EBUG; 558 } 559 560 value.ptr = attr_buf; 561 attr = pjmedia_sdp_attr_create(sdp_pool, 562 STR_CANDIDATE.ptr, 563 &value); 564 pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr); 565 } 566 } 567 } else { 568 /* ICE has failed, application should have terminated this call */ 569 } 570 571 return PJ_SUCCESS; 572 } 573 574 575 /* Parse a=candidate line */ 576 static pj_status_t parse_cand(const char *obj_name, 577 pj_pool_t *pool, 578 const pj_str_t *orig_input, 579 pj_ice_sess_cand *cand) 580 { 581 pj_str_t input; 582 char *token, *host; 583 int af; 584 pj_str_t s; 585 pj_status_t status = PJNATH_EICEINCANDSDP; 586 587 pj_bzero(cand, sizeof(*cand)); 588 pj_strdup_with_null(pool, &input, orig_input); 589 590 PJ_UNUSED_ARG(obj_name); 591 592 /* Foundation */ 593 token = strtok(input.ptr, " "); 594 if (!token) { 595 TRACE__((obj_name, "Expecting ICE foundation in candidate")); 596 goto on_return; 597 } 598 pj_strdup2(pool, &cand->foundation, token); 599 600 /* Component ID */ 601 token = strtok(NULL, " "); 602 if (!token) { 603 TRACE__((obj_name, "Expecting ICE component ID in candidate")); 604 goto on_return; 605 } 606 cand->comp_id = (pj_uint8_t) atoi(token); 607 608 /* Transport */ 609 token = strtok(NULL, " "); 610 if (!token) { 611 TRACE__((obj_name, "Expecting ICE transport in candidate")); 612 goto on_return; 613 } 614 if (pj_ansi_stricmp(token, "UDP") != 0) { 615 TRACE__((obj_name, 616 "Expecting ICE UDP transport only in candidate")); 617 goto on_return; 618 } 619 620 /* Priority */ 621 token = strtok(NULL, " "); 622 if (!token) { 623 TRACE__((obj_name, "Expecting ICE priority in candidate")); 624 goto on_return; 625 } 626 cand->prio = atoi(token); 627 628 /* Host */ 629 host = strtok(NULL, " "); 630 if (!host) { 631 TRACE__((obj_name, "Expecting ICE host in candidate")); 632 goto on_return; 633 } 634 /* Detect address family */ 635 if (pj_ansi_strchr(host, ':')) 636 af = pj_AF_INET6(); 637 else 638 af = pj_AF_INET(); 639 /* Assign address */ 640 if (pj_sockaddr_init(af, &cand->addr, pj_cstr(&s, host), 0)) { 641 TRACE__((obj_name, "Invalid ICE candidate address")); 642 goto on_return; 643 } 644 645 /* Port */ 646 token = strtok(NULL, " "); 647 if (!token) { 648 TRACE__((obj_name, "Expecting ICE port number in candidate")); 649 goto on_return; 650 } 651 pj_sockaddr_set_port(&cand->addr, (pj_uint16_t)atoi(token)); 652 653 /* typ */ 654 token = strtok(NULL, " "); 655 if (!token) { 656 TRACE__((obj_name, "Expecting ICE \"typ\" in candidate")); 657 goto on_return; 658 } 659 if (pj_ansi_stricmp(token, "typ") != 0) { 660 TRACE__((obj_name, "Expecting ICE \"typ\" in candidate")); 661 goto on_return; 662 } 663 664 /* candidate type */ 665 token = strtok(NULL, " "); 666 if (!token) { 667 TRACE__((obj_name, "Expecting ICE candidate type in candidate")); 668 goto on_return; 669 } 670 671 if (pj_ansi_stricmp(token, "host") == 0) { 672 cand->type = PJ_ICE_CAND_TYPE_HOST; 673 674 } else if (pj_ansi_stricmp(token, "srflx") == 0) { 675 cand->type = PJ_ICE_CAND_TYPE_SRFLX; 676 677 } else if (pj_ansi_stricmp(token, "relay") == 0) { 678 cand->type = PJ_ICE_CAND_TYPE_RELAYED; 679 680 } else if (pj_ansi_stricmp(token, "prflx") == 0) { 681 cand->type = PJ_ICE_CAND_TYPE_PRFLX; 682 683 } else { 684 PJ_LOG(5,(obj_name, "Invalid ICE candidate type %s in candidate", 685 token)); 686 goto on_return; 687 } 688 689 status = PJ_SUCCESS; 690 691 on_return: 692 return status; 693 } 694 695 696 /* Create initial SDP offer */ 697 static pj_status_t create_initial_offer(struct transport_ice *tp_ice, 698 pj_pool_t *sdp_pool, 699 pjmedia_sdp_session *loc_sdp, 700 unsigned media_index) 701 { 702 pj_status_t status; 703 704 /* Encode ICE in SDP */ 705 status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index, 706 tp_ice->comp_cnt, PJ_FALSE); 707 if (status != PJ_SUCCESS) { 708 set_no_ice(tp_ice, "Error encoding SDP answer", status); 709 return status; 710 } 711 712 return PJ_SUCCESS; 713 } 714 715 716 /* Verify incoming offer */ 717 static pj_status_t verify_ice_sdp(struct transport_ice *tp_ice, 718 pj_pool_t *tmp_pool, 719 const pjmedia_sdp_session *rem_sdp, 720 unsigned media_index, 721 pj_ice_sess_role current_ice_role, 722 struct sdp_state *sdp_state) 723 { 724 const pjmedia_sdp_media *rem_m; 725 const pjmedia_sdp_attr *attr, *ufrag_attr, *pwd_attr; 726 const pjmedia_sdp_conn *rem_conn; 727 pj_bool_t comp1_found=PJ_FALSE, comp2_found=PJ_FALSE; 728 pj_sockaddr rem_conn_addr, rtcp_addr; 729 unsigned i; 730 pj_status_t status; 731 732 rem_m = rem_sdp->media[media_index]; 733 734 /* Get the "ice-ufrag" and "ice-pwd" attributes */ 735 get_ice_attr(rem_sdp, rem_m, &ufrag_attr, &pwd_attr); 736 737 /* If "ice-ufrag" or "ice-pwd" are not found, disable ICE */ 738 if (ufrag_attr==NULL || pwd_attr==NULL) { 739 sdp_state->match_comp_cnt = 0; 740 return PJ_SUCCESS; 741 } 742 743 /* Verify that default target for each component matches one of the 744 * candidatefor the component. Otherwise stop ICE with ICE ice_mismatch 745 * error. 746 */ 747 748 /* Component 1 is the c= line */ 749 rem_conn = rem_m->conn; 750 if (rem_conn == NULL) 751 rem_conn = rem_sdp->conn; 752 if (!rem_conn) 753 return PJMEDIA_SDP_EMISSINGCONN; 754 755 /* Verify address family matches */ 756 if ((tp_ice->af==pj_AF_INET() && 757 pj_strcmp(&rem_conn->addr_type, &STR_IP4)!=0) || 758 (tp_ice->af==pj_AF_INET6() && 759 pj_strcmp(&rem_conn->addr_type, &STR_IP6)!=0)) 760 { 761 return PJMEDIA_SDP_ETPORTNOTEQUAL; 762 } 763 764 /* Assign remote connection address */ 765 status = pj_sockaddr_init(tp_ice->af, &rem_conn_addr, &rem_conn->addr, 766 (pj_uint16_t)rem_m->desc.port); 767 if (status != PJ_SUCCESS) 768 return status; 769 770 /* Component 2 is a=rtcp line, if present. */ 771 attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, 772 &STR_RTCP, NULL); 773 if (attr && tp_ice->comp_cnt > 1) { 774 pjmedia_sdp_rtcp_attr rtcp_attr; 775 776 status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp_attr); 777 if (status != PJ_SUCCESS) { 778 /* Error parsing a=rtcp attribute */ 779 return status; 780 } 781 782 /* Verify address family matches */ 783 if ((tp_ice->af==pj_AF_INET() && 784 pj_strcmp(&rtcp_attr.addr_type, &STR_IP4)!=0) || 785 (tp_ice->af==pj_AF_INET6() && 786 pj_strcmp(&rtcp_attr.addr_type, &STR_IP6)!=0)) 787 { 788 return PJMEDIA_SDP_ETPORTNOTEQUAL; 789 } 790 791 /* Assign RTCP address */ 792 status = pj_sockaddr_init(tp_ice->af, &rtcp_addr, 793 &rtcp_attr.addr, 794 (pj_uint16_t)rtcp_attr.port); 795 if (status != PJ_SUCCESS) { 796 return PJMEDIA_SDP_EINRTCP; 797 } 798 799 sdp_state->match_comp_cnt = 2; 800 801 } else { 802 /* Don't have RTCP component */ 803 comp2_found = PJ_TRUE; 804 sdp_state->match_comp_cnt = 1; 805 } 806 807 /* Find the default address in a=candidate attributes. 808 */ 809 for (i=0; i<rem_m->attr_count; ++i) { 810 pj_ice_sess_cand cand; 811 812 if (pj_strcmp(&rem_m->attr[i]->name, &STR_CANDIDATE)!=0) 813 continue; 814 815 status = parse_cand(tp_ice->base.name, tmp_pool, 816 &rem_m->attr[i]->value, &cand); 817 if (status != PJ_SUCCESS) { 818 PJ_LOG(4,(tp_ice->base.name, 819 "Error in parsing SDP candidate attribute '%.*s', " 820 "candidate is ignored", 821 (int)rem_m->attr[i]->value.slen, 822 rem_m->attr[i]->value.ptr)); 823 continue; 824 } 825 826 if (!comp1_found && cand.comp_id==COMP_RTP && 827 pj_sockaddr_cmp(&rem_conn_addr, &cand.addr)==0) 828 { 829 /* Found */ 830 comp1_found = PJ_TRUE; 831 if (comp1_found && comp2_found) 832 break; 833 } else if (!comp2_found && cand.comp_id==COMP_RTCP && 834 pj_sockaddr_cmp(&rtcp_addr, &cand.addr)==0) 835 { 836 /* Found */ 837 comp2_found = PJ_TRUE; 838 if (comp1_found && comp2_found) 839 break; 840 } 841 842 } 843 844 if (!comp1_found || !comp2_found) { 845 /* ICE ice_mismatch */ 846 sdp_state->ice_mismatch = PJ_TRUE; 847 } else { 848 sdp_state->ice_mismatch = PJ_FALSE; 849 } 850 851 /* Detect remote restarting session */ 852 if (pj_ice_strans_has_sess(tp_ice->ice_st) && 853 (pj_ice_strans_sess_is_running(tp_ice->ice_st) || 854 pj_ice_strans_sess_is_complete(tp_ice->ice_st))) 855 { 856 pj_str_t rem_run_ufrag, rem_run_pwd; 857 pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, NULL, NULL, 858 &rem_run_ufrag, &rem_run_pwd); 859 if (pj_strcmp(&ufrag_attr->value, &rem_run_ufrag) || 860 pj_strcmp(&pwd_attr->value, &rem_run_pwd)) 861 { 862 /* Remote offers to restart ICE */ 863 sdp_state->ice_restart = PJ_TRUE; 864 } else { 865 sdp_state->ice_restart = PJ_FALSE; 866 } 867 } else { 868 sdp_state->ice_restart = PJ_FALSE; 869 } 870 871 /* Detect our role */ 872 if (current_ice_role==PJ_ICE_SESS_ROLE_CONTROLLING) { 873 sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLING; 874 } else { 875 if (pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr, 876 &STR_ICE_LITE, NULL) != NULL) 877 { 878 /* Remote is ICE Lite */ 879 sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLING; 880 } else { 881 sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLED; 882 } 883 } 884 885 PJ_LOG(4,(tp_ice->base.name, 886 "Processing SDP: support ICE=%u, common comp_cnt=%u, " 887 "ice_mismatch=%u, ice_restart=%u, local_role=%s", 888 (sdp_state->match_comp_cnt != 0), 889 sdp_state->match_comp_cnt, 890 sdp_state->ice_mismatch, 891 sdp_state->ice_restart, 892 pj_ice_sess_role_name(sdp_state->local_role))); 893 894 return PJ_SUCCESS; 895 896 } 897 898 899 /* Verify incoming offer and create initial answer */ 900 static pj_status_t create_initial_answer(struct transport_ice *tp_ice, 901 pj_pool_t *sdp_pool, 902 pjmedia_sdp_session *loc_sdp, 903 const pjmedia_sdp_session *rem_sdp, 904 unsigned media_index) 905 { 906 const pjmedia_sdp_media *rem_m = rem_sdp->media[media_index]; 907 pj_status_t status; 908 909 /* Check if media is removed (just in case) */ 910 if (rem_m->desc.port == 0) { 911 return PJ_SUCCESS; 912 } 913 914 /* Verify the offer */ 915 status = verify_ice_sdp(tp_ice, sdp_pool, rem_sdp, media_index, 916 PJ_ICE_SESS_ROLE_CONTROLLED, 917 &tp_ice->rem_offer_state); 918 if (status != PJ_SUCCESS) { 919 set_no_ice(tp_ice, "Invalid SDP offer", status); 920 return status; 921 } 922 923 /* Does remote support ICE? */ 924 if (tp_ice->rem_offer_state.match_comp_cnt==0) { 925 set_no_ice(tp_ice, "No ICE found in SDP offer", PJ_SUCCESS); 926 return PJ_SUCCESS; 927 } 928 929 /* ICE ice_mismatch? */ 930 if (tp_ice->rem_offer_state.ice_mismatch) { 931 set_no_ice(tp_ice, "ICE ice_mismatch in remote offer", PJ_SUCCESS); 932 encode_ice_mismatch(sdp_pool, loc_sdp, media_index); 933 return PJ_SUCCESS; 934 } 935 936 /* Encode ICE in SDP */ 937 status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index, 938 tp_ice->rem_offer_state.match_comp_cnt, 939 PJ_FALSE); 940 if (status != PJ_SUCCESS) { 941 set_no_ice(tp_ice, "Error encoding SDP answer", status); 942 return status; 943 } 944 945 return PJ_SUCCESS; 946 } 947 948 949 /* Create subsequent SDP offer */ 950 static pj_status_t create_subsequent_offer(struct transport_ice *tp_ice, 951 pj_pool_t *sdp_pool, 952 pjmedia_sdp_session *loc_sdp, 953 unsigned media_index) 954 { 955 unsigned comp_cnt; 956 957 if (pj_ice_strans_has_sess(tp_ice->ice_st) == PJ_FALSE) { 958 /* We don't have ICE */ 959 return PJ_SUCCESS; 960 } 961 962 comp_cnt = pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st); 963 return encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index, 964 comp_cnt, PJ_FALSE); 965 } 966 967 968 /* Create subsequent SDP answer */ 969 static pj_status_t create_subsequent_answer(struct transport_ice *tp_ice, 970 pj_pool_t *sdp_pool, 971 pjmedia_sdp_session *loc_sdp, 972 const pjmedia_sdp_session *rem_sdp, 973 unsigned media_index) 974 { 975 pj_status_t status; 976 977 /* We have a session */ 978 status = verify_ice_sdp(tp_ice, sdp_pool, rem_sdp, media_index, 979 PJ_ICE_SESS_ROLE_CONTROLLED, 980 &tp_ice->rem_offer_state); 981 if (status != PJ_SUCCESS) { 982 /* Something wrong with the offer */ 983 return status; 984 } 985 986 if (pj_ice_strans_has_sess(tp_ice->ice_st)) { 987 /* 988 * Received subsequent offer while we have ICE active. 989 */ 990 991 if (tp_ice->rem_offer_state.match_comp_cnt == 0) { 992 /* Remote no longer offers ICE */ 993 return PJ_SUCCESS; 994 } 995 996 if (tp_ice->rem_offer_state.ice_mismatch) { 997 encode_ice_mismatch(sdp_pool, loc_sdp, media_index); 998 return PJ_SUCCESS; 999 } 1000 1001 status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index, 1002 tp_ice->rem_offer_state.match_comp_cnt, 1003 tp_ice->rem_offer_state.ice_restart); 1004 if (status != PJ_SUCCESS) 1005 return status; 1006 1007 /* Done */ 1008 1009 } else { 1010 /* 1011 * Received subsequent offer while we DON'T have ICE active. 1012 */ 1013 1014 if (tp_ice->rem_offer_state.match_comp_cnt == 0) { 1015 /* Remote does not support ICE */ 1016 return PJ_SUCCESS; 1017 } 1018 1019 if (tp_ice->rem_offer_state.ice_mismatch) { 1020 encode_ice_mismatch(sdp_pool, loc_sdp, media_index); 1021 return PJ_SUCCESS; 1022 } 1023 1024 /* Looks like now remote is offering ICE, so we need to create 1025 * ICE session now. 1026 */ 1027 status = pj_ice_strans_init_ice(tp_ice->ice_st, 1028 PJ_ICE_SESS_ROLE_CONTROLLED, 1029 NULL, NULL); 1030 if (status != PJ_SUCCESS) { 1031 /* Fail to create new ICE session */ 1032 return status; 1033 } 1034 1035 status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index, 1036 tp_ice->rem_offer_state.match_comp_cnt, 1037 tp_ice->rem_offer_state.ice_restart); 1038 if (status != PJ_SUCCESS) 1039 return status; 1040 1041 /* Done */ 1042 } 1043 1044 return PJ_SUCCESS; 1045 } 1046 1047 230 1048 /* 231 1049 * For both UAC and UAS, pass in the SDP before sending it to remote. … … 233 1051 */ 234 1052 static pj_status_t transport_media_create(pjmedia_transport *tp, 235 pj_pool_t * pool,1053 pj_pool_t *sdp_pool, 236 1054 unsigned options, 237 pjmedia_sdp_session *sdp_local,238 1055 const pjmedia_sdp_session *rem_sdp, 239 1056 unsigned media_index) 240 1057 { 241 1058 struct transport_ice *tp_ice = (struct transport_ice*)tp; 242 pj_bool_t init_ice; 243 unsigned i; 1059 pj_ice_sess_role ice_role; 244 1060 pj_status_t status; 245 1061 1062 PJ_UNUSED_ARG(media_index); 1063 PJ_UNUSED_ARG(sdp_pool); 1064 246 1065 tp_ice->media_option = options; 1066 tp_ice->oa_role = ROLE_NONE; 1067 tp_ice->initial_sdp = PJ_TRUE; 1068 1069 /* Init ICE, the initial role is set now based on availability of 1070 * rem_sdp, but it will be checked again later. 1071 */ 1072 ice_role = (rem_sdp==NULL ? PJ_ICE_SESS_ROLE_CONTROLLING : 1073 PJ_ICE_SESS_ROLE_CONTROLLED); 1074 status = pj_ice_strans_init_ice(tp_ice->ice_st, ice_role, NULL, NULL); 1075 1076 /* Done */ 1077 return status; 1078 } 1079 1080 1081 static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 1082 pj_pool_t *sdp_pool, 1083 pjmedia_sdp_session *sdp_local, 1084 const pjmedia_sdp_session *rem_sdp, 1085 unsigned media_index) 1086 { 1087 struct transport_ice *tp_ice = (struct transport_ice*)tp; 1088 pj_status_t status; 247 1089 248 1090 /* Validate media transport */ 249 1091 /* For now, this transport only support RTP/AVP transport */ 250 1092 if ((tp_ice->media_option & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) { 251 pjmedia_sdp_media * m_rem, *m_loc;252 253 m_rem = rem_sdp? rem_sdp->media[media_index] : NULL;254 m_loc= sdp_local->media[media_index];255 256 if (pj_stricmp(& m_loc->desc.transport, &ID_RTP_AVP) ||257 ( m_rem && pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP)))1093 pjmedia_sdp_media *loc_m, *rem_m; 1094 1095 rem_m = rem_sdp? rem_sdp->media[media_index] : NULL; 1096 loc_m = sdp_local->media[media_index]; 1097 1098 if (pj_stricmp(&loc_m->desc.transport, &STR_RTP_AVP) || 1099 (rem_m && pj_stricmp(&rem_m->desc.transport, &STR_RTP_AVP))) 258 1100 { 259 pjmedia_sdp_media_deactivate( pool, m_loc);1101 pjmedia_sdp_media_deactivate(sdp_pool, loc_m); 260 1102 return PJMEDIA_SDP_EINPROTO; 261 1103 } 262 1104 } 263 1105 264 /* If we are UAS, check that the incoming SDP contains support for ICE. */ 265 if (rem_sdp) { 266 const pjmedia_sdp_media *rem_m; 267 268 rem_m = rem_sdp->media[media_index]; 269 270 init_ice = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, 271 "ice-ufrag", NULL) != NULL; 272 if (init_ice == PJ_FALSE) { 273 init_ice = pjmedia_sdp_attr_find2(rem_sdp->attr_count, 274 rem_sdp->attr, 275 "ice-ufrag", NULL) != NULL; 276 } 277 278 if (init_ice) { 279 init_ice = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, 280 "candidate", NULL) != NULL; 1106 if (tp_ice->initial_sdp) { 1107 if (rem_sdp) { 1108 status = create_initial_answer(tp_ice, sdp_pool, sdp_local, 1109 rem_sdp, media_index); 1110 } else { 1111 status = create_initial_offer(tp_ice, sdp_pool, sdp_local, 1112 media_index); 281 1113 } 282 1114 } else { 283 init_ice = PJ_TRUE; 284 } 285 286 /* Init ICE */ 287 if (init_ice) { 288 pj_ice_sess_role ice_role; 289 enum { MAXLEN = 256 }; 290 pj_str_t ufrag, pass; 291 char *buffer; 1115 if (rem_sdp) { 1116 status = create_subsequent_answer(tp_ice, sdp_pool, sdp_local, 1117 rem_sdp, media_index); 1118 } else { 1119 status = create_subsequent_offer(tp_ice, sdp_pool, sdp_local, 1120 media_index); 1121 } 1122 } 1123 1124 if (status==PJ_SUCCESS) { 1125 if (rem_sdp) 1126 tp_ice->oa_role = ROLE_ANSWERER; 1127 else 1128 tp_ice->oa_role = ROLE_OFFERER; 1129 } 1130 1131 return status; 1132 } 1133 1134 1135 /* Start ICE session with the specified remote SDP */ 1136 static pj_status_t start_ice(struct transport_ice *tp_ice, 1137 pj_pool_t *tmp_pool, 1138 const pjmedia_sdp_session *rem_sdp, 1139 unsigned media_index) 1140 { 1141 pjmedia_sdp_media *rem_m = rem_sdp->media[media_index]; 1142 pjmedia_sdp_attr *ufrag_attr, *pwd_attr; 1143 pj_ice_sess_cand *cand; 1144 unsigned i, cand_cnt; 1145 pj_status_t status; 1146 1147 get_ice_attr(rem_sdp, rem_m, &ufrag_attr, &pwd_attr); 1148 1149 /* Allocate candidate array */ 1150 cand = (pj_ice_sess_cand*) 1151 pj_pool_calloc(tmp_pool, PJ_ICE_MAX_CAND, 1152 sizeof(pj_ice_sess_cand)); 1153 1154 /* Get all candidates in the media */ 1155 cand_cnt = 0; 1156 for (i=0; i<rem_m->attr_count && cand_cnt < PJ_ICE_MAX_CAND; ++i) { 292 1157 pjmedia_sdp_attr *attr; 293 unsigned comp; 294 295 ice_role = (rem_sdp==NULL ? PJ_ICE_SESS_ROLE_CONTROLLING : 296 PJ_ICE_SESS_ROLE_CONTROLLED); 297 298 ufrag.ptr = (char*) pj_pool_alloc(pool, PJ_ICE_UFRAG_LEN); 299 pj_create_random_string(ufrag.ptr, PJ_ICE_UFRAG_LEN); 300 ufrag.slen = PJ_ICE_UFRAG_LEN; 301 302 pass.ptr = (char*) pj_pool_alloc(pool, PJ_ICE_UFRAG_LEN); 303 pj_create_random_string(pass.ptr, PJ_ICE_UFRAG_LEN); 304 pass.slen = PJ_ICE_UFRAG_LEN; 305 306 status = pj_ice_strans_init_ice(tp_ice->ice_st, ice_role, 307 &ufrag, &pass); 308 if (status != PJ_SUCCESS) 309 return status; 310 311 /* Create ice-ufrag attribute */ 312 attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", &ufrag); 313 sdp_local->attr[sdp_local->attr_count++] = attr; 314 315 /* Create ice-pwd attribute */ 316 attr = pjmedia_sdp_attr_create(pool, "ice-pwd", &pass); 317 sdp_local->attr[sdp_local->attr_count++] = attr; 318 319 /* Encode all candidates to SDP media */ 320 321 buffer = (char*) pj_pool_alloc(pool, MAXLEN); 322 323 for (comp=0; comp < tp_ice->comp_cnt; ++comp) { 324 unsigned cand_cnt; 325 pj_ice_sess_cand cand[PJ_ICE_ST_MAX_CAND]; 326 327 cand_cnt = PJ_ARRAY_SIZE(cand); 328 status = pj_ice_strans_enum_cands(tp_ice->ice_st, comp+1, 329 &cand_cnt, cand); 330 if (status != PJ_SUCCESS) 331 return status; 332 333 for (i=0; i<cand_cnt; ++i) { 334 pjmedia_sdp_media *m; 335 pj_str_t value; 336 337 value.slen = print_sdp_cand_attr(buffer, MAXLEN, &cand[i]); 338 if (value.slen < 0) { 339 pj_assert(!"Not enough buffer to print candidate"); 340 return PJ_EBUG; 341 } 342 343 value.ptr = buffer; 344 attr = pjmedia_sdp_attr_create(pool, "candidate", &value); 345 m = sdp_local->media[media_index]; 346 m->attr[m->attr_count++] = attr; 347 } 348 } 349 } 350 351 /* Done */ 352 return PJ_SUCCESS; 353 } 354 355 356 /* Parse a=candidate line */ 357 static pj_status_t parse_cand(pj_pool_t *pool, 358 const pj_str_t *orig_input, 359 pj_ice_sess_cand *cand) 360 { 361 pj_str_t input; 362 char *token, *host; 363 pj_str_t s; 364 pj_status_t status = PJNATH_EICEINCANDSDP; 365 366 pj_bzero(cand, sizeof(*cand)); 367 pj_strdup_with_null(pool, &input, orig_input); 368 369 /* Foundation */ 370 token = strtok(input.ptr, " "); 371 if (!token) { 372 PJ_LOG(5,(THIS_FILE, "Expecting ICE foundation in candidate")); 373 goto on_return; 374 } 375 pj_strdup2(pool, &cand->foundation, token); 376 377 /* Component ID */ 378 token = strtok(NULL, " "); 379 if (!token) { 380 PJ_LOG(5,(THIS_FILE, "Expecting ICE component ID in candidate")); 381 goto on_return; 382 } 383 cand->comp_id = (pj_uint8_t) atoi(token); 384 385 /* Transport */ 386 token = strtok(NULL, " "); 387 if (!token) { 388 PJ_LOG(5,(THIS_FILE, "Expecting ICE transport in candidate")); 389 goto on_return; 390 } 391 if (pj_ansi_stricmp(token, "UDP") != 0) { 392 PJ_LOG(5,(THIS_FILE, 393 "Expecting ICE UDP transport only in candidate")); 394 goto on_return; 395 } 396 397 /* Priority */ 398 token = strtok(NULL, " "); 399 if (!token) { 400 PJ_LOG(5,(THIS_FILE, "Expecting ICE priority in candidate")); 401 goto on_return; 402 } 403 cand->prio = atoi(token); 404 405 /* Host */ 406 host = strtok(NULL, " "); 407 if (!host) { 408 PJ_LOG(5,(THIS_FILE, "Expecting ICE host in candidate")); 409 goto on_return; 410 } 411 if (pj_sockaddr_in_init(&cand->addr.ipv4, pj_cstr(&s, host), 0)) { 412 PJ_LOG(5,(THIS_FILE, 413 "Expecting ICE IPv4 transport address in candidate")); 414 goto on_return; 415 } 416 417 /* Port */ 418 token = strtok(NULL, " "); 419 if (!token) { 420 PJ_LOG(5,(THIS_FILE, "Expecting ICE port number in candidate")); 421 goto on_return; 422 } 423 cand->addr.ipv4.sin_port = pj_htons((pj_uint16_t)atoi(token)); 424 425 /* typ */ 426 token = strtok(NULL, " "); 427 if (!token) { 428 PJ_LOG(5,(THIS_FILE, "Expecting ICE \"typ\" in candidate")); 429 goto on_return; 430 } 431 if (pj_ansi_stricmp(token, "typ") != 0) { 432 PJ_LOG(5,(THIS_FILE, "Expecting ICE \"typ\" in candidate")); 433 goto on_return; 434 } 435 436 /* candidate type */ 437 token = strtok(NULL, " "); 438 if (!token) { 439 PJ_LOG(5,(THIS_FILE, "Expecting ICE candidate type in candidate")); 440 goto on_return; 441 } 442 443 if (pj_ansi_stricmp(token, "host") == 0) { 444 cand->type = PJ_ICE_CAND_TYPE_HOST; 445 446 } else if (pj_ansi_stricmp(token, "srflx") == 0) { 447 cand->type = PJ_ICE_CAND_TYPE_SRFLX; 448 449 } else if (pj_ansi_stricmp(token, "relay") == 0) { 450 cand->type = PJ_ICE_CAND_TYPE_RELAYED; 451 452 } else if (pj_ansi_stricmp(token, "prflx") == 0) { 453 cand->type = PJ_ICE_CAND_TYPE_PRFLX; 454 455 } else { 456 PJ_LOG(5,(THIS_FILE, "Invalid ICE candidate type %s in candidate", 457 token)); 458 goto on_return; 459 } 460 461 462 status = PJ_SUCCESS; 463 464 on_return: 465 return status; 466 } 467 468 469 /* Disable ICE when SDP from remote doesn't contain a=candidate line */ 470 static void set_no_ice(struct transport_ice *tp_ice, const char *reason) 471 { 472 PJ_LOG(4,(tp_ice->base.name, 473 "Disabling local ICE, reason=%s", reason)); 474 transport_media_stop(&tp_ice->base); 1158 1159 attr = rem_m->attr[i]; 1160 1161 if (pj_strcmp(&attr->name, &STR_CANDIDATE)!=0) 1162 continue; 1163 1164 /* Parse candidate */ 1165 status = parse_cand(tp_ice->base.name, tmp_pool, &attr->value, 1166 &cand[cand_cnt]); 1167 if (status != PJ_SUCCESS) { 1168 PJ_LOG(4,(tp_ice->base.name, 1169 "Error in parsing SDP candidate attribute '%.*s', " 1170 "candidate is ignored", 1171 (int)attr->value.slen, attr->value.ptr)); 1172 continue; 1173 } 1174 1175 cand_cnt++; 1176 } 1177 1178 /* Start ICE */ 1179 return pj_ice_strans_start_ice(tp_ice->ice_st, &ufrag_attr->value, 1180 &pwd_attr->value, cand_cnt, cand); 475 1181 } 476 1182 477 1183 478 1184 /* 479 * Start ICE checks when both offer and answer are available. 1185 * Start ICE checks when both offer and answer have been negotiated 1186 * by SDP negotiator. 480 1187 */ 481 1188 static pj_status_t transport_media_start(pjmedia_transport *tp, 482 pj_pool_t * pool,483 pjmedia_sdp_session *sdp_local,1189 pj_pool_t *tmp_pool, 1190 const pjmedia_sdp_session *sdp_local, 484 1191 const pjmedia_sdp_session *rem_sdp, 485 1192 unsigned media_index) 486 1193 { 487 1194 struct transport_ice *tp_ice = (struct transport_ice*)tp; 488 const pjmedia_sdp_attr *attr; 489 unsigned i, cand_cnt; 490 pj_ice_sess_cand *cand; 491 const pjmedia_sdp_media *sdp_med; 492 pj_bool_t remote_is_lite = PJ_FALSE; 493 pj_bool_t ice_mismatch = PJ_FALSE; 494 pjmedia_sdp_conn *conn = NULL; 495 pj_sockaddr conn_addr; 496 pj_bool_t conn_found_in_candidate = PJ_FALSE; 497 pj_str_t uname, pass; 1195 pjmedia_sdp_media *rem_m; 1196 enum oa_role current_oa_role; 1197 pj_bool_t initial_oa; 498 1198 pj_status_t status; 499 1199 500 PJ_ASSERT_RETURN(tp && pool && rem_sdp, PJ_EINVAL);1200 PJ_ASSERT_RETURN(tp && tmp_pool && rem_sdp, PJ_EINVAL); 501 1201 PJ_ASSERT_RETURN(media_index < rem_sdp->media_count, PJ_EINVAL); 502 1202 503 sdp_med = rem_sdp->media[media_index]; 504 505 /* Validate media transport */ 506 /* By now, this transport only support RTP/AVP transport */ 507 if ((tp_ice->media_option & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) { 508 pjmedia_sdp_media *m_rem, *m_loc; 509 510 m_rem = rem_sdp->media[media_index]; 511 m_loc = sdp_local->media[media_index]; 512 513 if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) || 514 (pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP))) 1203 rem_m = rem_sdp->media[media_index]; 1204 1205 initial_oa = tp_ice->initial_sdp; 1206 current_oa_role = tp_ice->oa_role; 1207 1208 /* SDP has been negotiated */ 1209 tp_ice->initial_sdp = PJ_FALSE; 1210 tp_ice->oa_role = ROLE_NONE; 1211 1212 /* Nothing to do if we don't have ICE session */ 1213 if (pj_ice_strans_has_sess(tp_ice->ice_st) == PJ_FALSE) { 1214 return PJ_SUCCESS; 1215 } 1216 1217 /* Processing depends on the offer/answer role */ 1218 if (current_oa_role == ROLE_OFFERER) { 1219 /* 1220 * We are offerer. So this will be the first time we see the 1221 * remote's SDP. 1222 */ 1223 struct sdp_state answer_state; 1224 1225 /* Verify the answer */ 1226 status = verify_ice_sdp(tp_ice, tmp_pool, rem_sdp, media_index, 1227 PJ_ICE_SESS_ROLE_CONTROLLING, &answer_state); 1228 if (status != PJ_SUCCESS) { 1229 /* Something wrong in the SDP answer */ 1230 set_no_ice(tp_ice, "Invalid remote SDP answer", status); 1231 return status; 1232 } 1233 1234 /* Does it have ICE? */ 1235 if (answer_state.match_comp_cnt == 0) { 1236 /* Remote doesn't support ICE */ 1237 set_no_ice(tp_ice, "Remote answer doesn't support ICE", 1238 PJ_SUCCESS); 1239 return PJ_SUCCESS; 1240 } 1241 1242 /* Check if remote has reported ice-mismatch */ 1243 if (pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, 1244 &STR_ICE_MISMATCH, NULL) != NULL) 515 1245 { 516 pjmedia_sdp_media_deactivate(pool, m_loc); 517 return PJMEDIA_SDP_EINPROTO; 518 } 519 } 520 521 /* Get the SDP connection for the media stream. 522 * We'll verify later if the SDP connection address is specified 523 * as one of the candidate. 524 */ 525 conn = sdp_med->conn; 526 if (conn == NULL) 527 conn = rem_sdp->conn; 528 529 if (conn == NULL) { 530 /* Unable to find SDP connection */ 531 return PJMEDIA_SDP_EMISSINGCONN; 532 } 533 534 pj_sockaddr_in_init(&conn_addr.ipv4, &conn->addr, 535 (pj_uint16_t)sdp_med->desc.port); 536 537 /* Find ice-ufrag attribute in media descriptor */ 538 attr = pjmedia_sdp_attr_find2(sdp_med->attr_count, sdp_med->attr, 539 "ice-ufrag", NULL); 540 if (attr == NULL) { 541 /* Find ice-ufrag attribute in session descriptor */ 542 attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr, 543 "ice-ufrag", NULL); 544 if (attr == NULL) { 545 set_no_ice(tp_ice, "ice-ufrag attribute not found"); 1246 /* Remote has reported ice-mismatch */ 1247 set_no_ice(tp_ice, 1248 "Remote answer contains 'ice-mismatch' attribute", 1249 PJ_SUCCESS); 546 1250 return PJ_SUCCESS; 547 1251 } 548 } 549 uname = attr->value; 550 551 /* Find ice-pwd attribute in media descriptor */ 552 attr = pjmedia_sdp_attr_find2(sdp_med->attr_count, sdp_med->attr, 553 "ice-pwd", NULL); 554 if (attr == NULL) { 555 /* Find ice-pwd attribute in session descriptor */ 556 attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr, 557 "ice-pwd", NULL); 558 if (attr == NULL) { 559 set_no_ice(tp_ice, "ice-pwd attribute not found"); 1252 1253 /* Check if remote has indicated a restart */ 1254 if (answer_state.ice_restart) { 1255 PJ_LOG(2,(tp_ice->base.name, 1256 "Warning: remote has signalled ICE restart in SDP " 1257 "answer which is disallowed. Remote ICE negotiation" 1258 " may fail.")); 1259 } 1260 1261 /* Check if the answer itself is mismatched */ 1262 if (answer_state.ice_mismatch) { 1263 /* This happens either when a B2BUA modified remote answer but 1264 * strangely didn't modify our offer, or remote is not capable 1265 * of detecting mismatch in our offer (it didn't put 1266 * 'ice-mismatch' attribute in the answer). 1267 */ 1268 PJ_LOG(2,(tp_ice->base.name, 1269 "Warning: remote answer mismatch, but it does not " 1270 "reject our offer with 'ice-mismatch'. ICE negotiation " 1271 "may fail")); 1272 } 1273 1274 /* Do nothing if ICE is complete or running */ 1275 if (pj_ice_strans_sess_is_running(tp_ice->ice_st)) { 1276 PJ_LOG(4,(tp_ice->base.name, 1277 "Ignored offer/answer because ICE is running")); 560 1278 return PJ_SUCCESS; 561 1279 } 562 } 563 pass = attr->value; 564 565 /* Allocate candidate array */ 566 cand = (pj_ice_sess_cand*) 567 pj_pool_calloc(pool, PJ_ICE_MAX_CAND, sizeof(pj_ice_sess_cand)); 568 569 /* Get all candidates in the media */ 570 cand_cnt = 0; 571 for (i=0; i<sdp_med->attr_count && cand_cnt < PJ_ICE_MAX_CAND; ++i) { 572 pjmedia_sdp_attr *attr; 573 574 attr = sdp_med->attr[i]; 575 576 /* Detect if remote is ICE lite */ 577 if (pj_stricmp(&attr->name, &STR_ICE_LITE)==0) { 578 remote_is_lite = PJ_TRUE; 579 continue; 580 } 581 582 /* Detect if remote has reported ICE mismatch */ 583 if (pj_stricmp(&attr->name, &STR_ICE_MISMATCH)==0) { 584 ice_mismatch = PJ_TRUE; 585 continue; 586 } 587 588 if (pj_stricmp(&attr->name, &STR_CANDIDATE)!=0) 589 continue; 590 591 /* Parse candidate */ 592 status = parse_cand(pool, &attr->value, &cand[cand_cnt]); 593 if (status != PJ_SUCCESS) { 594 PJ_LOG(4,(THIS_FILE, 595 "Error in parsing SDP candidate attribute, " 596 "candidate is ignored")); 597 continue; 598 } 599 600 /* Check if this candidate is equal to the connection line */ 601 if (!conn_found_in_candidate && 602 pj_memcmp(&conn_addr.ipv4, &cand[cand_cnt].addr.ipv4, 603 sizeof(pj_sockaddr_in))==0) 604 { 605 conn_found_in_candidate = PJ_TRUE; 606 } 607 608 cand_cnt++; 609 } 610 611 /* Handle ice-mismatch case */ 612 if (ice_mismatch) { 613 set_no_ice(tp_ice, "remote reported ice-mismatch"); 614 return PJ_SUCCESS; 615 } 616 617 /* Handle case where SDP connection address is not specified as 618 * one of the candidate. 619 */ 620 if (!conn_found_in_candidate) { 621 set_no_ice(tp_ice, "local reported ice-mismatch"); 622 return PJ_SUCCESS; 623 } 624 625 /* If our role was controlled but it turns out that remote is 626 * a lite implementation, change our role to controlling. 627 */ 628 if (remote_is_lite && 629 pj_ice_strans_get_role(tp_ice->ice_st) == PJ_ICE_SESS_ROLE_CONTROLLED) 630 { 631 pj_ice_strans_change_role(tp_ice->ice_st, 632 PJ_ICE_SESS_ROLE_CONTROLLING); 633 } 634 635 /* Start ICE */ 636 return pj_ice_strans_start_ice(tp_ice->ice_st, &uname, &pass, 637 cand_cnt, cand); 1280 1281 if (pj_ice_strans_sess_is_complete(tp_ice->ice_st)) { 1282 PJ_LOG(4,(tp_ice->base.name, "ICE session unchanged")); 1283 return PJ_SUCCESS; 1284 } 1285 1286 /* Start ICE */ 1287 1288 } else { 1289 /* 1290 * We are answerer. We've seen and negotiated remote's SDP 1291 * before, and the result is in "rem_offer_state". 1292 */ 1293 const pjmedia_sdp_attr *ufrag_attr, *pwd_attr; 1294 1295 /* Check for ICE in remote offer */ 1296 if (tp_ice->rem_offer_state.match_comp_cnt == 0) { 1297 /* No ICE attribute present */ 1298 set_no_ice(tp_ice, "Remote no longer offers ICE", 1299 PJ_SUCCESS); 1300 return PJ_SUCCESS; 1301 } 1302 1303 /* Check for ICE ice_mismatch condition in the offer */ 1304 if (tp_ice->rem_offer_state.ice_mismatch) { 1305 set_no_ice(tp_ice, "Remote offer mismatch: ", 1306 PJNATH_EICEMISMATCH); 1307 return PJ_SUCCESS; 1308 } 1309 1310 /* If ICE is complete and remote doesn't request restart, 1311 * then leave the session as is. 1312 */ 1313 if (!initial_oa && tp_ice->rem_offer_state.ice_restart == PJ_FALSE) { 1314 /* Remote has not requested ICE restart, so session is 1315 * unchanged. 1316 */ 1317 PJ_LOG(4,(tp_ice->base.name, "ICE session unchanged")); 1318 return PJ_SUCCESS; 1319 } 1320 1321 /* Either remote has requested ICE restart or this is our 1322 * first answer. 1323 */ 1324 1325 /* Stop ICE */ 1326 if (!initial_oa) { 1327 set_no_ice(tp_ice, "restarting by remote request..", PJ_SUCCESS); 1328 1329 /* We have put new ICE ufrag and pwd in the answer. Now 1330 * create a new ICE session with that ufrag/pwd pair. 1331 */ 1332 get_ice_attr(sdp_local, sdp_local->media[media_index], 1333 &ufrag_attr, &pwd_attr); 1334 status = pj_ice_strans_init_ice(tp_ice->ice_st, 1335 tp_ice->rem_offer_state.local_role, 1336 &ufrag_attr->value, 1337 &pwd_attr->value); 1338 if (status != PJ_SUCCESS) { 1339 PJ_LOG(1,(tp_ice->base.name, 1340 "ICE re-initialization failed (status=%d)!", 1341 status)); 1342 return status; 1343 } 1344 } 1345 1346 /* start ICE */ 1347 } 1348 1349 /* Now start ICE */ 1350 status = start_ice(tp_ice, tmp_pool, rem_sdp, media_index); 1351 if (status != PJ_SUCCESS) { 1352 PJ_LOG(1,(tp_ice->base.name, 1353 "ICE restart failed (status=%d)!", 1354 status)); 1355 return status; 1356 } 1357 1358 /* Done */ 1359 1360 return PJ_SUCCESS; 638 1361 } 639 1362 … … 642 1365 { 643 1366 struct transport_ice *tp_ice = (struct transport_ice*)tp; 644 return pj_ice_strans_stop_ice(tp_ice->ice_st); 1367 1368 set_no_ice(tp_ice, "media stop requested", PJ_SUCCESS); 1369 1370 return PJ_SUCCESS; 645 1371 } 646 1372 -
pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c
r2015 r2032 92 92 pjmedia_srtp_crypto rx_policy; 93 93 94 /* Temporary policy for negotiation */ 95 pjmedia_srtp_crypto tx_policy_neg; 96 pjmedia_srtp_crypto rx_policy_neg; 97 94 98 /* libSRTP contexts */ 95 99 srtp_t srtp_tx_ctx; … … 106 110 107 111 /* Transport information */ 108 pjmedia_transport *real_tp; /**< Underlying transport. */ 112 pjmedia_transport *member_tp; /**< Underlying transport. */ 113 114 /* When in SRTP optional mode, instead of always offering RTP/AVP, 115 * we should create offer based on remote preference. At the first time, 116 * remote preference is unknown, it is known after media_start() called. 117 * So next time the same session need to create an offer, it will create 118 * SDP with transport type based on remote preference. 119 */ 120 pj_bool_t remote_prefer_rtp_savp; 109 121 110 122 } transport_srtp; … … 152 164 pj_size_t size); 153 165 static pj_status_t transport_media_create(pjmedia_transport *tp, 154 pj_pool_t * pool,166 pj_pool_t *sdp_pool, 155 167 unsigned options, 168 const pjmedia_sdp_session *sdp_remote, 169 unsigned media_index); 170 static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 171 pj_pool_t *sdp_pool, 156 172 pjmedia_sdp_session *sdp_local, 157 173 const pjmedia_sdp_session *sdp_remote, … … 159 175 static pj_status_t transport_media_start (pjmedia_transport *tp, 160 176 pj_pool_t *pool, 161 pjmedia_sdp_session *sdp_local,177 const pjmedia_sdp_session *sdp_local, 162 178 const pjmedia_sdp_session *sdp_remote, 163 179 unsigned media_index); … … 179 195 &transport_send_rtcp2, 180 196 &transport_media_create, 197 &transport_encode_sdp, 181 198 &transport_media_start, 182 199 &transport_media_stop, … … 332 349 srtp->session_inited = PJ_FALSE; 333 350 srtp->bypass_srtp = PJ_FALSE; 351 srtp->remote_prefer_rtp_savp = PJ_FALSE; 334 352 335 353 if (opt) { … … 368 386 369 387 /* Set underlying transport */ 370 srtp-> real_tp = tp;388 srtp->member_tp = tp; 371 389 372 390 /* Done */ … … 458 476 srtp->tx_policy = *tx; 459 477 pj_strset(&srtp->tx_policy.key, srtp->tx_key, tx->key.slen); 460 srtp->tx_policy.name = 461 pj_str(crypto_suites[get_crypto_idx(&tx->name)].name); 478 srtp->tx_policy.name=pj_str(crypto_suites[get_crypto_idx(&tx->name)].name); 462 479 463 480 … … 492 509 srtp->rx_policy = *rx; 493 510 pj_strset(&srtp->rx_policy.key, srtp->rx_key, rx->key.slen); 494 srtp->rx_policy.name = 495 pj_str(crypto_suites[get_crypto_idx(&rx->name)].name); 511 srtp->rx_policy.name=pj_str(crypto_suites[get_crypto_idx(&rx->name)].name); 496 512 497 513 /* Declare SRTP session initialized */ … … 551 567 PJ_ASSERT_RETURN(tp, NULL); 552 568 553 return srtp-> real_tp;569 return srtp->member_tp; 554 570 } 555 571 … … 578 594 sizeof(srtp_info)); 579 595 580 return pjmedia_transport_get_info(srtp-> real_tp, info);596 return pjmedia_transport_get_info(srtp->member_tp, info); 581 597 } 582 598 … … 595 611 596 612 /* Attach itself to transport */ 597 status = pjmedia_transport_attach(srtp-> real_tp, srtp, rem_addr, rem_rtcp,613 status = pjmedia_transport_attach(srtp->member_tp, srtp, rem_addr, rem_rtcp, 598 614 addr_len, &srtp_rtp_cb, &srtp_rtcp_cb); 599 615 if (status != PJ_SUCCESS) … … 615 631 PJ_ASSERT_ON_FAIL(tp, return); 616 632 617 if (srtp-> real_tp) {618 pjmedia_transport_detach(srtp-> real_tp, srtp);633 if (srtp->member_tp) { 634 pjmedia_transport_detach(srtp->member_tp, srtp); 619 635 } 620 636 … … 635 651 636 652 if (srtp->bypass_srtp) 637 return pjmedia_transport_send_rtp(srtp-> real_tp, pkt, size);653 return pjmedia_transport_send_rtp(srtp->member_tp, pkt, size); 638 654 639 655 if (!srtp->session_inited) … … 648 664 err = srtp_protect(srtp->srtp_tx_ctx, srtp->tx_buffer, &len); 649 665 if (err == err_status_ok) { 650 status = pjmedia_transport_send_rtp(srtp-> real_tp, srtp->tx_buffer, len);666 status = pjmedia_transport_send_rtp(srtp->member_tp, srtp->tx_buffer, len); 651 667 } else { 652 668 status = PJMEDIA_ERRNO_FROM_LIBSRTP(err); … … 677 693 678 694 if (srtp->bypass_srtp) { 679 return pjmedia_transport_send_rtcp2(srtp-> real_tp, addr, addr_len,695 return pjmedia_transport_send_rtcp2(srtp->member_tp, addr, addr_len, 680 696 pkt, size); 681 697 } … … 693 709 694 710 if (err == err_status_ok) { 695 status = pjmedia_transport_send_rtcp2(srtp-> real_tp, addr, addr_len,711 status = pjmedia_transport_send_rtcp2(srtp->member_tp, addr, addr_len, 696 712 srtp->tx_buffer, len); 697 713 } else { … … 711 727 transport_srtp *srtp = (transport_srtp *) tp; 712 728 713 return pjmedia_transport_simulate_lost(srtp-> real_tp, dir, pct_lost);729 return pjmedia_transport_simulate_lost(srtp->member_tp, dir, pct_lost); 714 730 } 715 731 … … 723 739 pjmedia_transport_detach(tp, NULL); 724 740 725 if (srtp->setting.close_member_tp && srtp-> real_tp) {726 pjmedia_transport_close(srtp-> real_tp);741 if (srtp->setting.close_member_tp && srtp->member_tp) { 742 pjmedia_transport_close(srtp->member_tp); 727 743 } 728 744 … … 956 972 957 973 static pj_status_t transport_media_create(pjmedia_transport *tp, 958 pj_pool_t * pool,974 pj_pool_t *sdp_pool, 959 975 unsigned options, 960 pjmedia_sdp_session *sdp_local,961 976 const pjmedia_sdp_session *sdp_remote, 962 977 unsigned media_index) 978 { 979 struct transport_srtp *srtp = (struct transport_srtp*) tp; 980 unsigned member_tp_option; 981 982 PJ_ASSERT_RETURN(tp, PJ_EINVAL); 983 984 pj_bzero(&srtp->rx_policy_neg, sizeof(srtp->rx_policy_neg)); 985 pj_bzero(&srtp->tx_policy_neg, sizeof(srtp->tx_policy_neg)); 986 987 srtp->media_option = options; 988 member_tp_option = options | PJMEDIA_TPMED_NO_TRANSPORT_CHECKING; 989 990 srtp->offerer_side = sdp_remote == NULL; 991 992 /* Validations */ 993 if (srtp->offerer_side) { 994 995 if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) 996 goto BYPASS_SRTP; 997 998 } else { 999 1000 pjmedia_sdp_media *m_rem; 1001 1002 m_rem = sdp_remote->media[media_index]; 1003 1004 /* Nothing to do on inactive media stream */ 1005 if (pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL)) 1006 goto BYPASS_SRTP; 1007 1008 /* Validate remote media transport based on SRTP usage option. 1009 */ 1010 switch (srtp->setting.use) { 1011 case PJMEDIA_SRTP_DISABLED: 1012 if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0) 1013 return PJMEDIA_SRTP_ESDPINTRANSPORT; 1014 goto BYPASS_SRTP; 1015 case PJMEDIA_SRTP_OPTIONAL: 1016 break; 1017 case PJMEDIA_SRTP_MANDATORY: 1018 if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0) 1019 return PJMEDIA_SRTP_ESDPINTRANSPORT; 1020 break; 1021 } 1022 1023 } 1024 goto PROPAGATE_MEDIA_CREATE; 1025 1026 BYPASS_SRTP: 1027 srtp->bypass_srtp = PJ_TRUE; 1028 member_tp_option &= ~PJMEDIA_TPMED_NO_TRANSPORT_CHECKING; 1029 1030 PROPAGATE_MEDIA_CREATE: 1031 return pjmedia_transport_media_create(srtp->member_tp, sdp_pool, 1032 member_tp_option, sdp_remote, 1033 media_index); 1034 } 1035 1036 static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 1037 pj_pool_t *sdp_pool, 1038 pjmedia_sdp_session *sdp_local, 1039 const pjmedia_sdp_session *sdp_remote, 1040 unsigned media_index) 963 1041 { 964 1042 struct transport_srtp *srtp = (struct transport_srtp*) tp; … … 971 1049 pj_str_t attr_value; 972 1050 unsigned i, j; 973 unsigned member_tp_option; 974 975 PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL); 1051 1052 PJ_ASSERT_RETURN(tp && sdp_pool && sdp_local, PJ_EINVAL); 976 1053 977 srtp->media_option = options; 978 member_tp_option = options | PJMEDIA_TPMED_NO_TRANSPORT_CHECKING; 979 980 pj_bzero(&srtp->rx_policy, sizeof(srtp->tx_policy)); 981 pj_bzero(&srtp->tx_policy, sizeof(srtp->rx_policy)); 1054 srtp->offerer_side = sdp_remote == NULL; 982 1055 983 1056 m_rem = sdp_remote ? sdp_remote->media[media_index] : NULL; 984 1057 m_loc = sdp_local->media[media_index]; 985 1058 986 /* bypass if media transport is not RTP/AVP or RTP/SAVP */1059 /* Bypass if media transport is not RTP/AVP or RTP/SAVP */ 987 1060 if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) != 0 && 988 1061 pj_stricmp(&m_loc->desc.transport, &ID_RTP_SAVP) != 0) … … 992 1065 if (pjmedia_sdp_media_find_attr(m_loc, &ID_INACTIVE, NULL) || 993 1066 (m_rem && pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL))) 994 {995 1067 goto BYPASS_SRTP; 996 }997 998 srtp->offerer_side = !sdp_remote;999 1068 1000 1069 /* Check remote media transport & set local media transport … … 1002 1071 */ 1003 1072 if (srtp->offerer_side) { 1004 if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 1005 goto BYPASS_SRTP; 1006 } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 1007 m_loc->desc.transport = ID_RTP_AVP; 1008 } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 1009 m_loc->desc.transport = ID_RTP_SAVP; 1073 1074 /* Generate transport */ 1075 switch (srtp->setting.use) { 1076 case PJMEDIA_SRTP_DISABLED: 1077 goto BYPASS_SRTP; 1078 case PJMEDIA_SRTP_OPTIONAL: 1079 m_loc->desc.transport = srtp->remote_prefer_rtp_savp? 1080 ID_RTP_SAVP : ID_RTP_AVP; 1081 break; 1082 case PJMEDIA_SRTP_MANDATORY: 1083 m_loc->desc.transport = ID_RTP_SAVP; 1084 break; 1010 1085 } 1086 1087 /* Generate crypto attribute if not yet */ 1088 if (pjmedia_sdp_media_find_attr(m_loc, &ID_CRYPTO, NULL) == NULL) { 1089 for (i=0; i<srtp->setting.crypto_count; ++i) { 1090 /* Offer crypto-suites based on setting. */ 1091 buffer_len = MAXLEN; 1092 status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len, 1093 &srtp->setting.crypto[i], 1094 i+1); 1095 if (status != PJ_SUCCESS) 1096 return status; 1097 1098 /* If buffer_len==0, just skip the crypto attribute. */ 1099 if (buffer_len) { 1100 pj_strset(&attr_value, buffer, buffer_len); 1101 attr = pjmedia_sdp_attr_create(srtp->pool, ID_CRYPTO.ptr, 1102 &attr_value); 1103 m_loc->attr[m_loc->attr_count++] = attr; 1104 } 1105 } 1106 } 1107 1011 1108 } else { 1012 if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 1013 if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0) { 1014 DEACTIVATE_MEDIA(pool, m_loc); 1015 return PJMEDIA_SRTP_ESDPINTRANSPORT; 1109 /* Answerer side */ 1110 1111 pj_assert(sdp_remote && m_rem); 1112 1113 /* Generate transport */ 1114 switch (srtp->setting.use) { 1115 case PJMEDIA_SRTP_DISABLED: 1116 if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0) 1117 return PJMEDIA_SRTP_ESDPINTRANSPORT; 1118 goto BYPASS_SRTP; 1119 case PJMEDIA_SRTP_OPTIONAL: 1120 m_loc->desc.transport = m_rem->desc.transport; 1121 break; 1122 case PJMEDIA_SRTP_MANDATORY: 1123 if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0) 1124 return PJMEDIA_SRTP_ESDPINTRANSPORT; 1125 m_loc->desc.transport = ID_RTP_SAVP; 1126 break; 1127 } 1128 1129 /* Generate crypto attribute if not yet */ 1130 if (pjmedia_sdp_media_find_attr(m_loc, &ID_CRYPTO, NULL) == NULL) { 1131 1132 pjmedia_srtp_crypto tmp_rx_crypto; 1133 pj_bool_t has_crypto_attr = PJ_FALSE; 1134 int matched_idx = -1; 1135 int chosen_tag = 0; 1136 int tags[64]; /* assume no more than 64 crypto attrs in a media */ 1137 int cr_attr_count = 0; 1138 1139 /* Find supported crypto-suite, get the tag, and assign policy_local */ 1140 for (i=0; i<m_rem->attr_count; ++i) { 1141 if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0) 1142 continue; 1143 1144 has_crypto_attr = PJ_TRUE; 1145 1146 status = parse_attr_crypto(srtp->pool, m_rem->attr[i], 1147 &tmp_rx_crypto, &tags[cr_attr_count]); 1148 if (status != PJ_SUCCESS) 1149 return status; 1150 1151 /* Check duplicated tag */ 1152 for (j=0; j<cr_attr_count; ++j) { 1153 if (tags[j] == tags[cr_attr_count]) { 1154 DEACTIVATE_MEDIA(sdp_pool, m_loc); 1155 return PJMEDIA_SRTP_ESDPDUPCRYPTOTAG; 1156 } 1157 } 1158 1159 if (matched_idx == -1) { 1160 /* lets see if the crypto-suite offered is supported */ 1161 for (j=0; j<srtp->setting.crypto_count; ++j) 1162 if (pj_stricmp(&tmp_rx_crypto.name, 1163 &srtp->setting.crypto[j].name) == 0) 1164 { 1165 int cs_idx = get_crypto_idx(&tmp_rx_crypto.name); 1166 1167 /* Force to use test key */ 1168 /* bad keys for snom: */ 1169 //char *hex_test_key = "58b29c5c8f42308120ce857e439f2d" 1170 // "7810a8b10ad0b1446be5470faea496"; 1171 //char *hex_test_key = "20a26aac7ba062d356ff52b61e3993" 1172 // "ccb78078f12c64db94b9c294927fd0"; 1173 //pj_str_t *test_key = &srtp->setting.crypto[j].key; 1174 //char *raw_test_key = pj_pool_zalloc(srtp->pool, 64); 1175 //hex_string_to_octet_string( 1176 // raw_test_key, 1177 // hex_test_key, 1178 // strlen(hex_test_key)); 1179 //pj_strset(test_key, raw_test_key, 1180 // crypto_suites[cs_idx].cipher_key_len); 1181 /* EO Force to use test key */ 1182 1183 if (tmp_rx_crypto.key.slen != 1184 (int)crypto_suites[cs_idx].cipher_key_len) 1185 return PJMEDIA_SRTP_EINKEYLEN; 1186 1187 srtp->rx_policy_neg = tmp_rx_crypto; 1188 chosen_tag = tags[cr_attr_count]; 1189 matched_idx = j; 1190 break; 1191 } 1192 } 1193 cr_attr_count++; 1016 1194 } 1017 goto BYPASS_SRTP; 1018 } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 1019 m_loc->desc.transport = m_rem->desc.transport; 1020 } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 1021 if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0) { 1022 DEACTIVATE_MEDIA(pool, m_loc); 1023 return PJMEDIA_SRTP_ESDPINTRANSPORT; 1195 1196 /* Check crypto negotiation result */ 1197 switch (srtp->setting.use) { 1198 case PJMEDIA_SRTP_DISABLED: 1199 pj_assert(!"Should never reach here"); 1200 break; 1201 1202 case PJMEDIA_SRTP_OPTIONAL: 1203 /* bypass SRTP when no crypto-attr and remote uses RTP/AVP */ 1204 if (!has_crypto_attr && 1205 pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0) 1206 goto BYPASS_SRTP; 1207 /* bypass SRTP when nothing match and remote uses RTP/AVP */ 1208 else if (matched_idx == -1 && 1209 pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0) 1210 goto BYPASS_SRTP; 1211 break; 1212 1213 case PJMEDIA_SRTP_MANDATORY: 1214 /* Do nothing, intentional */ 1215 break; 1024 1216 } 1025 m_loc->desc.transport = ID_RTP_SAVP; 1026 } 1027 } 1028 1029 /* Generate crypto attribute */ 1030 if (srtp->offerer_side) { 1031 for (i=0; i<srtp->setting.crypto_count; ++i) { 1032 /* Offer crypto-suites based on setting. */ 1217 1218 /* No crypto attr */ 1219 if (!has_crypto_attr) { 1220 DEACTIVATE_MEDIA(sdp_pool, m_loc); 1221 return PJMEDIA_SRTP_ESDPREQCRYPTO; 1222 } 1223 1224 /* No crypto match */ 1225 if (matched_idx == -1) { 1226 DEACTIVATE_MEDIA(sdp_pool, m_loc); 1227 return PJMEDIA_SRTP_ENOTSUPCRYPTO; 1228 } 1229 1230 /* we have to generate crypto answer, 1231 * with srtp->tx_policy_neg matched the offer 1232 * and rem_tag contains matched offer tag. 1233 */ 1033 1234 buffer_len = MAXLEN; 1034 1235 status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len, 1035 &srtp->setting.crypto[ i],1036 i+1);1236 &srtp->setting.crypto[matched_idx], 1237 chosen_tag); 1037 1238 if (status != PJ_SUCCESS) 1038 1239 return status; 1039 1240 1241 srtp->tx_policy_neg = srtp->setting.crypto[matched_idx]; 1242 1040 1243 /* If buffer_len==0, just skip the crypto attribute. */ 1041 1244 if (buffer_len) { 1042 1245 pj_strset(&attr_value, buffer, buffer_len); 1043 attr = pjmedia_sdp_attr_create(s rtp->pool, ID_CRYPTO.ptr,1246 attr = pjmedia_sdp_attr_create(sdp_pool, ID_CRYPTO.ptr, 1044 1247 &attr_value); 1045 1248 m_loc->attr[m_loc->attr_count++] = attr; 1046 1249 } 1250 1251 /* At this point, we get valid rx_policy_neg & tx_policy_neg. */ 1047 1252 } 1048 } else { 1049 /* find supported crypto-suite, get the tag, and assign policy_local */ 1050 pjmedia_srtp_crypto tmp_rx_crypto; 1051 pj_bool_t has_crypto_attr = PJ_FALSE; 1052 pj_bool_t has_match = PJ_FALSE; 1053 int chosen_tag = 0; 1054 int tags[64]; /* assume no more than 64 crypto attrs in a media */ 1055 int cr_attr_count = 0; 1056 int k; 1057 1058 for (i=0; i<m_rem->attr_count; ++i) { 1059 if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0) 1060 continue; 1061 1062 has_crypto_attr = PJ_TRUE; 1063 1064 status = parse_attr_crypto(srtp->pool, m_rem->attr[i], 1065 &tmp_rx_crypto, &tags[cr_attr_count]); 1066 if (status != PJ_SUCCESS) 1067 return status; 1068 1069 /* Check duplicated tag */ 1070 for (k=0; k<cr_attr_count; ++k) { 1071 if (tags[k] == tags[cr_attr_count]) { 1072 DEACTIVATE_MEDIA(pool, m_loc); 1073 return PJMEDIA_SRTP_ESDPDUPCRYPTOTAG; 1074 } 1075 } 1076 1077 if (!has_match) { 1078 /* lets see if the crypto-suite offered is supported */ 1079 for (j=0; j<srtp->setting.crypto_count; ++j) 1080 if (pj_stricmp(&tmp_rx_crypto.name, 1081 &srtp->setting.crypto[j].name) == 0) 1082 { 1083 int cs_idx = get_crypto_idx(&tmp_rx_crypto.name); 1084 1085 /* Force to use test key */ 1086 /* bad keys for snom: */ 1087 //char *hex_test_key = "58b29c5c8f42308120ce857e439f2d" 1088 // "7810a8b10ad0b1446be5470faea496"; 1089 //char *hex_test_key = "20a26aac7ba062d356ff52b61e3993" 1090 // "ccb78078f12c64db94b9c294927fd0"; 1091 //pj_str_t *test_key = &srtp->setting.crypto[j].key; 1092 //char *raw_test_key = pj_pool_zalloc(srtp->pool, 64); 1093 //hex_string_to_octet_string( 1094 // raw_test_key, 1095 // hex_test_key, 1096 // strlen(hex_test_key)); 1097 //pj_strset(test_key, raw_test_key, 1098 // crypto_suites[cs_idx].cipher_key_len); 1099 /* EO Force to use test key */ 1100 1101 if (tmp_rx_crypto.key.slen != 1102 (int)crypto_suites[cs_idx].cipher_key_len) 1103 return PJMEDIA_SRTP_EINKEYLEN; 1104 1105 srtp->tx_policy = srtp->setting.crypto[j]; 1106 srtp->rx_policy = tmp_rx_crypto; 1107 chosen_tag = tags[cr_attr_count]; 1108 has_match = PJ_TRUE; 1109 break; 1110 } 1111 } 1112 cr_attr_count++; 1113 } 1114 1115 if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) { 1116 /* bypass when remote uses RTP/AVP and we disable SRTP */ 1117 goto BYPASS_SRTP; 1118 } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) { 1119 /* bypass SRTP when no crypto-attr but remote uses RTP/AVP */ 1120 if (!has_crypto_attr && 1121 pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0) 1122 goto BYPASS_SRTP; 1123 /* bypass SRTP when nothing match but remote uses RTP/AVP */ 1124 if (!has_match && 1125 pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0) 1126 goto BYPASS_SRTP; 1127 } else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) { 1128 /* do nothing, this is intended */ 1129 } 1130 1131 /* No crypto attr */ 1132 if (!has_crypto_attr) { 1133 DEACTIVATE_MEDIA(pool, m_loc); 1134 return PJMEDIA_SRTP_ESDPREQCRYPTO; 1135 } 1136 1137 /* No crypto match */ 1138 if (!has_match) { 1139 DEACTIVATE_MEDIA(pool, m_loc); 1140 return PJMEDIA_SRTP_ENOTSUPCRYPTO; 1141 } 1142 1143 /* we have to generate crypto answer, 1144 * with srtp->tx_policy matched the offer 1145 * and rem_tag contains matched offer tag. 1146 */ 1147 buffer_len = MAXLEN; 1148 status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len, 1149 &srtp->tx_policy, 1150 chosen_tag); 1151 if (status != PJ_SUCCESS) 1152 return status; 1153 1154 /* If buffer_len==0, just skip the crypto attribute. */ 1155 if (buffer_len) { 1156 pj_strset(&attr_value, buffer, buffer_len); 1157 attr = pjmedia_sdp_attr_create(srtp->pool, ID_CRYPTO.ptr, 1158 &attr_value); 1159 m_loc->attr[m_loc->attr_count++] = attr; 1160 } 1161 1162 /* At this point, 1163 * we should have valid rx_policy & tx_policy. 1164 */ 1253 1165 1254 } 1166 1255 goto PROPAGATE_MEDIA_CREATE; … … 1168 1257 BYPASS_SRTP: 1169 1258 srtp->bypass_srtp = PJ_TRUE; 1170 member_tp_option &= ~PJMEDIA_TPMED_NO_TRANSPORT_CHECKING;1171 1259 1172 1260 PROPAGATE_MEDIA_CREATE: 1173 return pjmedia_transport_media_create(srtp->real_tp, pool, 1174 member_tp_option, 1175 sdp_local, sdp_remote, media_index); 1261 return pjmedia_transport_encode_sdp(srtp->member_tp, sdp_pool, 1262 sdp_local, sdp_remote, media_index); 1176 1263 } 1177 1264 … … 1180 1267 static pj_status_t transport_media_start(pjmedia_transport *tp, 1181 1268 pj_pool_t *pool, 1182 pjmedia_sdp_session *sdp_local,1269 const pjmedia_sdp_session *sdp_local, 1183 1270 const pjmedia_sdp_session *sdp_remote, 1184 1271 unsigned media_index) … … 1196 1283 m_rem = sdp_remote->media[media_index]; 1197 1284 m_loc = sdp_local->media[media_index]; 1285 1286 srtp->remote_prefer_rtp_savp = (pj_stricmp(&m_rem->desc.transport, 1287 &ID_RTP_SAVP) == 0); 1198 1288 1199 1289 /* For answerer side, this function will just have to start SRTP */ … … 1264 1354 } 1265 1355 1266 srtp->tx_policy = srtp->setting.crypto[rem_tag-1];1267 srtp->rx_policy = tmp_tx_crypto;1356 srtp->tx_policy_neg = srtp->setting.crypto[rem_tag-1]; 1357 srtp->rx_policy_neg = tmp_tx_crypto; 1268 1358 } 1269 1359 … … 1281 1371 } 1282 1372 1283 /* At this point, 1284 * we should have valid rx_policy & tx_policy. 1285 */ 1373 /* At this point, we get valid rx_policy_neg & tx_policy_neg. */ 1286 1374 } 1287 1375 1288 1376 /* Got policy_local & policy_remote, let's initalize the SRTP */ 1289 status = pjmedia_transport_srtp_start(tp, &srtp->tx_policy , &srtp->rx_policy);1377 status = pjmedia_transport_srtp_start(tp, &srtp->tx_policy_neg, &srtp->rx_policy_neg); 1290 1378 if (status != PJ_SUCCESS) 1291 1379 return status; … … 1297 1385 1298 1386 PROPAGATE_MEDIA_START: 1299 return pjmedia_transport_media_start(srtp-> real_tp, pool,1387 return pjmedia_transport_media_start(srtp->member_tp, pool, 1300 1388 sdp_local, sdp_remote, 1301 1389 media_index); … … 1307 1395 pj_status_t status; 1308 1396 1309 status = pjmedia_transport_media_stop(srtp-> real_tp);1397 status = pjmedia_transport_media_stop(srtp->member_tp); 1310 1398 if (status != PJ_SUCCESS) 1311 1399 PJ_LOG(4, (srtp->pool->obj_name, -
pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
r1944 r2032 130 130 pj_pool_t *pool, 131 131 unsigned options, 132 pjmedia_sdp_session *sdp_local,133 132 const pjmedia_sdp_session *sdp_remote, 134 133 unsigned media_index); 134 static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 135 pj_pool_t *pool, 136 pjmedia_sdp_session *sdp_local, 137 const pjmedia_sdp_session *rem_sdp, 138 unsigned media_index); 135 139 static pj_status_t transport_media_start (pjmedia_transport *tp, 136 140 pj_pool_t *pool, 137 pjmedia_sdp_session *sdp_local,141 const pjmedia_sdp_session *sdp_local, 138 142 const pjmedia_sdp_session *sdp_remote, 139 143 unsigned media_index); … … 154 158 &transport_send_rtcp2, 155 159 &transport_media_create, 160 &transport_encode_sdp, 156 161 &transport_media_start, 157 162 &transport_media_stop, … … 791 796 pj_pool_t *pool, 792 797 unsigned options, 793 pjmedia_sdp_session *sdp_local,794 798 const pjmedia_sdp_session *sdp_remote, 795 799 unsigned media_index) … … 797 801 struct transport_udp *udp = (struct transport_udp*)tp; 798 802 799 PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL);803 PJ_ASSERT_RETURN(tp && pool, PJ_EINVAL); 800 804 udp->media_options = options; 805 806 PJ_UNUSED_ARG(sdp_remote); 807 PJ_UNUSED_ARG(media_index); 808 809 return PJ_SUCCESS; 810 } 811 812 static pj_status_t transport_encode_sdp(pjmedia_transport *tp, 813 pj_pool_t *pool, 814 pjmedia_sdp_session *sdp_local, 815 const pjmedia_sdp_session *rem_sdp, 816 unsigned media_index) 817 { 818 struct transport_udp *udp = (struct transport_udp*)tp; 801 819 802 820 /* Validate media transport */ … … 805 823 pjmedia_sdp_media *m_rem, *m_loc; 806 824 807 m_rem = sdp_remote? sdp_remote->media[media_index] : NULL;825 m_rem = rem_sdp? rem_sdp->media[media_index] : NULL; 808 826 m_loc = sdp_local->media[media_index]; 809 827 … … 821 839 static pj_status_t transport_media_start(pjmedia_transport *tp, 822 840 pj_pool_t *pool, 823 pjmedia_sdp_session *sdp_local,841 const pjmedia_sdp_session *sdp_local, 824 842 const pjmedia_sdp_session *sdp_remote, 825 843 unsigned media_index) 826 844 { 827 struct transport_udp *udp = (struct transport_udp*)tp;828 829 845 PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL); 830 846 831 /* Validate media transport */ 832 /* By now, this transport only support RTP/AVP transport */ 833 if ((udp->media_options & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) { 834 pjmedia_sdp_media *m_rem, *m_loc; 835 836 m_rem = sdp_remote->media[media_index]; 837 m_loc = sdp_local->media[media_index]; 838 839 if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) || 840 pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP)) 841 { 842 pjmedia_sdp_media_deactivate(pool, m_loc); 843 return PJMEDIA_SDP_EINPROTO; 844 } 845 } 847 PJ_UNUSED_ARG(tp); 848 PJ_UNUSED_ARG(pool); 849 PJ_UNUSED_ARG(sdp_local); 850 PJ_UNUSED_ARG(sdp_remote); 851 PJ_UNUSED_ARG(media_index); 846 852 847 853 return PJ_SUCCESS; -
pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
r2018 r2032 26 26 27 27 PJ_BEGIN_DECL 28 29 /** 30 * Media transport state. 31 */ 32 typedef enum pjsua_med_tp_st 33 { 34 /** Not initialized */ 35 PJSUA_MED_TP_IDLE, 36 37 /** Initialized (media_create() has been called) */ 38 PJSUA_MED_TP_INIT, 39 40 /** Running (media_start() has been called) */ 41 PJSUA_MED_TP_RUNNING 42 43 } pjsua_med_tp_st; 28 44 29 45 /** … … 53 69 call was triggered by xfer. */ 54 70 pjmedia_transport *med_tp; /**< Current media transport. */ 55 pj_status_t med_tp_ st;/**< Media transport status. */71 pj_status_t med_tp_ready;/**< Media transport status. */ 56 72 pjmedia_transport *med_orig; /**< Original media transport */ 73 pjsua_med_tp_st med_tp_st; /**< Media transport state */ 57 74 pj_timer_entry refresh_tm;/**< Timer to send re-INVITE. */ 58 75 pj_timer_entry hangup_tm; /**< Timer to hangup call. */ … … 322 339 pjsip_role_e role, 323 340 int security_level, 341 pj_pool_t *tmp_pool, 342 const pjmedia_sdp_session *rem_sdp, 324 343 int *sip_err_code); 325 344 pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, … … 329 348 int *sip_err_code); 330 349 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 331 pjmedia_sdp_session *local_sdp,350 const pjmedia_sdp_session *local_sdp, 332 351 const pjmedia_sdp_session *remote_sdp); 333 352 pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id); -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
r2027 r2032 213 213 214 214 215 #define LATE_SDP 0216 217 215 /* Allocate one call id */ 218 216 static pjsua_call_id alloc_call_id(void) … … 288 286 } 289 287 288 /* 290 289 static int call_get_secure_level(pjsua_call *call) 291 290 { … … 317 316 return 0; 318 317 } 318 */ 319 319 320 320 … … 450 450 /* Init media channel */ 451 451 status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC, 452 call->secure_level, NULL); 452 call->secure_level, dlg->pool, 453 NULL, NULL); 453 454 if (status != PJ_SUCCESS) { 454 455 pjsua_perror(THIS_FILE, "Error initializing media channel", status); … … 456 457 } 457 458 458 /* Create SDP offer */ 459 #if LATE_SDP 460 offer = NULL; 461 #else 462 status = pjsua_media_channel_create_sdp(call->index, dlg->pool, NULL, 459 /* Create offer */ 460 status = pjsua_media_channel_create_sdp(call->index, dlg->pool, NULL, 463 461 &offer, NULL); 464 462 if (status != PJ_SUCCESS) { 465 pjsua_perror(THIS_FILE, " pjmedia unable to create SDP", status);463 pjsua_perror(THIS_FILE, "Error initializing media channel", status); 466 464 goto on_error; 467 465 } 468 #endif469 466 470 467 /* Create the INVITE session: */ … … 719 716 call->secure_level = 0; 720 717 721 /* Init media channel */722 status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS,723 call->secure_level, &sip_err_code);724 if (status != PJ_SUCCESS) {725 pjsua_perror(THIS_FILE, "Error initializing media channel", status);726 pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata,727 sip_err_code, NULL,728 NULL, NULL);729 PJSUA_UNLOCK();730 return PJ_TRUE;731 }732 733 718 /* Parse SDP from incoming request */ 734 719 if (rdata->msg_info.msg->body) { … … 740 725 pjsua_perror(THIS_FILE, "Error parsing SDP in incoming INVITE", 741 726 status); 742 pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 400, &reason, 743 NULL, NULL); 744 pjsua_media_channel_deinit(call->index); 727 pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 400, 728 &reason, NULL, NULL, NULL); 745 729 PJSUA_UNLOCK(); 746 730 return PJ_TRUE; … … 762 746 } 763 747 764 /* Get media capability from media endpoint: */ 748 /* Init media channel */ 749 status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS, 750 call->secure_level, 751 rdata->tp_info.pool, offer, 752 &sip_err_code); 753 if (status != PJ_SUCCESS) { 754 pjsua_perror(THIS_FILE, "Error initializing media channel", status); 755 pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 756 sip_err_code, NULL, NULL, NULL, NULL); 757 PJSUA_UNLOCK(); 758 return PJ_TRUE; 759 } 760 761 /* Create answer */ 765 762 status = pjsua_media_channel_create_sdp(call->index, rdata->tp_info.pool, 766 763 offer, &answer, &sip_err_code); 767 764 if (status != PJ_SUCCESS) { 768 765 pjsua_perror(THIS_FILE, "Error creating SDP answer", status); 769 pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 770 sip_err_code, NULL, 771 NULL, NULL); 772 pjsua_media_channel_deinit(call->index); 766 pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 767 sip_err_code, NULL, NULL, NULL, NULL); 773 768 PJSUA_UNLOCK(); 774 769 return PJ_TRUE; 775 770 } 771 776 772 777 773 /* Verify that we can handle the request. */ … … 795 791 796 792 } else { 797 798 793 /* Respond with 500 (Internal Server Error) */ 799 pjsip_endpt_respond _stateless(pjsua_var.endpt, rdata, 500, NULL,800 794 pjsip_endpt_respond(pjsua_var.endpt, NULL, rdata, 500, NULL, 795 NULL, NULL, NULL); 801 796 } 802 797 … … 1475 1470 } 1476 1471 1477 /* Update call secure level */1478 call->secure_level = call_get_secure_level(call);1479 1480 /* Init media channel */1481 status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC,1482 call->secure_level, NULL);1483 if (status != PJ_SUCCESS) {1484 pjsua_perror(THIS_FILE, "Error initializing media channel", status);1485 pjsip_dlg_dec_lock(dlg);1486 return PJSIP_ESESSIONSTATE;1487 }1488 1489 1472 /* Create SDP */ 1490 1473 PJ_UNUSED_ARG(unhold); … … 1548 1531 return status; 1549 1532 1550 /* Update call's secure level */1551 call->secure_level = call_get_secure_level(call);1552 1553 /* Init media channel */1554 status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC,1555 call->secure_level, NULL);1556 if (status != PJ_SUCCESS) {1557 pjsua_perror(THIS_FILE, "Error initializing media channel", status);1558 pjsip_dlg_dec_lock(dlg);1559 return PJSIP_ESESSIONSTATE;1560 }1561 1562 1533 /* Create SDP */ 1563 1534 status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, … … 1570 1541 } 1571 1542 1572 /* Create re-INVITE with new offer */ 1543 update_sdp_version(call, sdp); 1544 1545 /* Create UPDATE with new offer */ 1573 1546 status = pjsip_inv_update(call->inv, NULL, sdp, &tdata); 1574 1547 if (status != PJ_SUCCESS) { … … 2538 2511 { 2539 2512 pjsua_call *call; 2540 const pjmedia_sdp_session *c_local; 2541 pjmedia_sdp_session *local_sdp; 2513 const pjmedia_sdp_session *local_sdp; 2542 2514 const pjmedia_sdp_session *remote_sdp; 2543 2515 … … 2568 2540 2569 2541 /* Get local and remote SDP */ 2570 status = pjmedia_sdp_neg_get_active_local(call->inv->neg, & c_local);2542 status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp); 2571 2543 if (status != PJ_SUCCESS) { 2572 2544 pjsua_perror(THIS_FILE, … … 2577 2549 return; 2578 2550 } 2579 local_sdp = (pjmedia_sdp_session*) c_local;2580 2551 2581 2552 status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp); … … 2713 2684 call->index)); 2714 2685 2715 /* Update call's secure level */2716 call->secure_level = call_get_secure_level(call);2717 2718 /* Init media channel */2719 status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS,2720 call->secure_level, NULL);2721 if (status != PJ_SUCCESS) {2722 pjsua_perror(THIS_FILE, "Error initializing media channel", status);2723 PJSUA_UNLOCK();2724 return;2725 }2726 2727 2686 status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, 2728 2687 offer, &answer, NULL); … … 2768 2727 PJ_LOG(4,(THIS_FILE, "Call %d: asked to send a new offer", 2769 2728 call->index)); 2770 2771 /* Update call's secure level */2772 call->secure_level = call_get_secure_level(call);2773 2774 /* Init media channel */2775 status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC,2776 call->secure_level, NULL);2777 if (status != PJ_SUCCESS) {2778 pjsua_perror(THIS_FILE, "Error initializing media channel", status);2779 PJSUA_UNLOCK();2780 return;2781 }2782 2729 2783 2730 status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
r2027 r2032 653 653 switch (op) { 654 654 case PJ_ICE_STRANS_OP_INIT: 655 pjsua_var.calls[id].med_tp_ st= result;655 pjsua_var.calls[id].med_tp_ready = result; 656 656 break; 657 657 case PJ_ICE_STRANS_OP_NEGOTIATION: … … 753 753 ice_cb.on_ice_complete = &on_ice_complete; 754 754 pj_ansi_snprintf(name, sizeof(name), "icetp%02d", i); 755 pjsua_var.calls[i].med_tp_ st= PJ_EPENDING;755 pjsua_var.calls[i].med_tp_ready = PJ_EPENDING; 756 756 757 757 comp_cnt = 1; … … 770 770 /* Wait until transport is initialized, or time out */ 771 771 PJSUA_UNLOCK(); 772 while (pjsua_var.calls[i].med_tp_ st== PJ_EPENDING) {772 while (pjsua_var.calls[i].med_tp_ready == PJ_EPENDING) { 773 773 pjsua_handle_events(100); 774 774 } 775 775 PJSUA_LOCK(); 776 if (pjsua_var.calls[i].med_tp_ st!= PJ_SUCCESS) {776 if (pjsua_var.calls[i].med_tp_ready != PJ_SUCCESS) { 777 777 pjsua_perror(THIS_FILE, "Error initializing ICE media transport", 778 pjsua_var.calls[i].med_tp_ st);779 status = pjsua_var.calls[i].med_tp_ st;778 pjsua_var.calls[i].med_tp_ready); 779 status = pjsua_var.calls[i].med_tp_ready; 780 780 goto on_error; 781 781 } … … 848 848 pjsip_role_e role, 849 849 int security_level, 850 pj_pool_t *tmp_pool, 851 const pjmedia_sdp_session *rem_sdp, 850 852 int *sip_err_code) 851 853 { 854 enum { MEDIA_IDX = 0 }; 852 855 pjsua_call *call = &pjsua_var.calls[call_id]; 856 pj_status_t status; 853 857 854 858 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) … … 856 860 pjmedia_srtp_setting srtp_opt; 857 861 pjmedia_transport *srtp; 858 pj_status_t status;859 862 #endif 860 863 … … 905 908 #endif 906 909 910 /* Create the media transport */ 911 status = pjmedia_transport_media_create(call->med_tp, tmp_pool, 0, 912 rem_sdp, MEDIA_IDX); 913 if (status != PJ_SUCCESS) { 914 if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE; 915 pjsua_media_channel_deinit(call_id); 916 return status; 917 } 918 919 call->med_tp_st = PJSUA_MED_TP_INIT; 907 920 return PJ_SUCCESS; 908 921 } … … 927 940 } 928 941 942 /* Create media if it's not created. This could happen when call is 943 * currently on-hold 944 */ 945 if (call->med_tp_st == PJSUA_MED_TP_IDLE) { 946 pjsip_role_e role; 947 role = (rem_sdp ? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC); 948 status = pjsua_media_channel_init(call_id, role, call->secure_level, 949 pool, rem_sdp, sip_status_code); 950 if (status != PJ_SUCCESS) 951 return status; 952 } 953 929 954 /* Get media socket info */ 930 955 pjmedia_transport_info_init(&tpinfo); … … 936 961 if (status != PJ_SUCCESS) { 937 962 if (sip_status_code) *sip_status_code = 500; 938 goto on_error;963 return status; 939 964 } 940 965 … … 964 989 965 990 /* Give the SDP to media transport */ 966 status = pjmedia_transport_ media_create(call->med_tp, pool, 0,967 sdp, rem_sdp,MEDIA_IDX);991 status = pjmedia_transport_encode_sdp(call->med_tp, pool, sdp, rem_sdp, 992 MEDIA_IDX); 968 993 if (status != PJ_SUCCESS) { 969 994 if (sip_status_code) *sip_status_code = PJSIP_SC_NOT_ACCEPTABLE; 970 goto on_error;995 return status; 971 996 } 972 997 973 998 *p_sdp = sdp; 974 999 return PJ_SUCCESS; 975 976 on_error:977 pjsua_media_channel_deinit(call_id);978 return status;979 980 1000 } 981 1001 … … 984 1004 { 985 1005 pjsua_call *call = &pjsua_var.calls[call_id]; 986 987 //see ticket #525988 //pjmedia_transport_media_stop(call->med_tp);989 1006 990 1007 if (call->conf_slot != PJSUA_INVALID_ID) { … … 1017 1034 stop_media_session(call_id); 1018 1035 1019 pjmedia_transport_media_stop(call->med_tp); 1036 if (call->med_tp_st != PJSUA_MED_TP_IDLE) { 1037 pjmedia_transport_media_stop(call->med_tp); 1038 call->med_tp_st = PJSUA_MED_TP_IDLE; 1039 } 1020 1040 1021 1041 if (call->med_orig && call->med_tp != call->med_orig) { … … 1049 1069 1050 1070 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, 1051 pjmedia_sdp_session *local_sdp,1071 const pjmedia_sdp_session *local_sdp, 1052 1072 const pjmedia_sdp_session *remote_sdp) 1053 1073 { … … 1113 1133 /* Shutdown transport's session */ 1114 1134 pjmedia_transport_media_stop(call->med_tp); 1135 call->med_tp_st = PJSUA_MED_TP_IDLE; 1115 1136 1116 1137 /* No need because we need keepalive? */ … … 1123 1144 1124 1145 } else { 1125 /* Start media transport */1146 /* Start/restart media transport */ 1126 1147 status = pjmedia_transport_media_start(call->med_tp, 1127 1148 call->inv->pool, … … 1129 1150 if (status != PJ_SUCCESS) 1130 1151 return status; 1152 1153 call->med_tp_st = PJSUA_MED_TP_RUNNING; 1131 1154 1132 1155 /* Override ptime, if this option is specified. */
Note: See TracChangeset
for help on using the changeset viewer.