Ejemplo n.º 1
0
void get_and_register_SDP_to_cloud(struct ice_trans_s* icetrans, ice_option_t opt, char *usrid)
{
    static char buffer[2048];
    int len;


    if (icetrans->icest == NULL) {
        PJ_LOG(1,(THIS_FILE, "Error: No ICE instance, create it first"));
        return;
    }

    PJ_LOG(4, (__FUNCTION__, "General info"));
    PJ_LOG(4, (__FUNCTION__,"---------------"));
    PJ_LOG(4, (__FUNCTION__,"Component count    : %d\n", opt.comp_cnt));
    PJ_LOG(4, (__FUNCTION__,"Status             : "));
    if (pj_ice_strans_sess_is_complete(icetrans->icest))
        puts("negotiation complete");
    else if (pj_ice_strans_sess_is_running(icetrans->icest))
        puts("negotiation is in progress");
    else if (pj_ice_strans_has_sess(icetrans->icest))
        puts("session ready");
    else
        puts("session not created");

    if (!pj_ice_strans_has_sess(icetrans->icest)) {
        puts("Create the session first to see more info");
        return;
    }

    printf("Negotiated comp_cnt: %d\n",
           pj_ice_strans_get_running_comp_cnt(icetrans->icest));
    printf("Role               : %s\n",
           pj_ice_strans_get_role(icetrans->icest)==PJ_ICE_SESS_ROLE_CONTROLLED ?
               "controlled" : "controlling");


    len = extract_sdp_to_xml(icetrans, buffer, 2048, opt, usrid);
    if (len < 0)
        err_exit("not enough buffer to show ICE status", -len, icetrans);

    // Register this local SDP to cloud
    char full_url[256];
    //printf("[DEBUG] %s, %d  \n", __FUNCTION__, __LINE__ );

    strcpy(full_url, gUrl); // plus URL
    strcpy(&full_url[strlen(full_url)], "/peer/registerPeer"); // plus API
    http_post_request(full_url, buffer);




    PJ_LOG(4, (__FUNCTION__,"Local SDP (paste this to remote host):\n"
           "--------------------------------------\n"
           "%s\n", buffer));
}
Ejemplo n.º 2
0
/* Verify incoming offer */
static pj_status_t verify_ice_sdp(struct transport_ice *tp_ice,
				  pj_pool_t *tmp_pool,
				  const pjmedia_sdp_session *rem_sdp,
				  unsigned media_index,
				  pj_ice_sess_role current_ice_role,
				  struct sdp_state *sdp_state)
{
    const pjmedia_sdp_media *rem_m;
    const pjmedia_sdp_attr *ufrag_attr, *pwd_attr;
    const pjmedia_sdp_conn *rem_conn;
    pj_bool_t comp1_found=PJ_FALSE, comp2_found=PJ_FALSE, has_rtcp=PJ_FALSE;
    pj_sockaddr rem_conn_addr, rtcp_addr;
    unsigned i;
    pj_status_t status;

    rem_m = rem_sdp->media[media_index];

    /* Get the "ice-ufrag" and "ice-pwd" attributes */
    get_ice_attr(rem_sdp, rem_m, &ufrag_attr, &pwd_attr);

    /* If "ice-ufrag" or "ice-pwd" are not found, disable ICE */
    if (ufrag_attr==NULL || pwd_attr==NULL) {
	sdp_state->match_comp_cnt = 0;
	return PJ_SUCCESS;
    }

    /* Verify that default target for each component matches one of the 
     * candidate for the component. Otherwise stop ICE with ICE ice_mismatch 
     * error.
     */

    /* Component 1 is the c= line */
    rem_conn = rem_m->conn;
    if (rem_conn == NULL)
	rem_conn = rem_sdp->conn;
    if (!rem_conn)
	return PJMEDIA_SDP_EMISSINGCONN;

    /* Verify address family matches */
    if ((tp_ice->af==pj_AF_INET() && 
	 pj_strcmp(&rem_conn->addr_type, &STR_IP4)!=0) ||
	(tp_ice->af==pj_AF_INET6() && 
	 pj_strcmp(&rem_conn->addr_type, &STR_IP6)!=0))
    {
	return PJMEDIA_SDP_ETPORTNOTEQUAL;
    }

    /* Assign remote connection address */
    status = pj_sockaddr_init(tp_ice->af, &rem_conn_addr, &rem_conn->addr,
			      (pj_uint16_t)rem_m->desc.port);
    if (status != PJ_SUCCESS)
	return status;

    if (tp_ice->comp_cnt > 1) {
	const pjmedia_sdp_attr *attr;

	/* Get default RTCP candidate from a=rtcp line, if present, otherwise
	 * calculate default RTCP candidate from default RTP target.
	 */
	attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, 
				     &STR_RTCP, NULL);
	has_rtcp = (attr != NULL);

	if (attr) {
	    pjmedia_sdp_rtcp_attr rtcp_attr;

	    status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp_attr);
	    if (status != PJ_SUCCESS) {
		/* Error parsing a=rtcp attribute */
		return status;
	    }
    	
	    if (rtcp_attr.addr.slen) {
		/* Verify address family matches */
		if ((tp_ice->af==pj_AF_INET() && 
		     pj_strcmp(&rtcp_attr.addr_type, &STR_IP4)!=0) ||
		    (tp_ice->af==pj_AF_INET6() && 
		     pj_strcmp(&rtcp_attr.addr_type, &STR_IP6)!=0))
		{
		    return PJMEDIA_SDP_ETPORTNOTEQUAL;
		}

		/* Assign RTCP address */
		status = pj_sockaddr_init(tp_ice->af, &rtcp_addr,
					  &rtcp_attr.addr,
					  (pj_uint16_t)rtcp_attr.port);
		if (status != PJ_SUCCESS) {
		    return PJMEDIA_SDP_EINRTCP;
		}
	    } else {
		/* Assign RTCP address */
		status = pj_sockaddr_init(tp_ice->af, &rtcp_addr, 
					  NULL, 
					  (pj_uint16_t)rtcp_attr.port);
		if (status != PJ_SUCCESS) {
		    return PJMEDIA_SDP_EINRTCP;
		}
		pj_sockaddr_copy_addr(&rtcp_addr, &rem_conn_addr);
	    }
	} else {
	    unsigned rtcp_port;
    	
	    rtcp_port = pj_sockaddr_get_port(&rem_conn_addr) + 1;
	    pj_sockaddr_cp(&rtcp_addr, &rem_conn_addr);
	    pj_sockaddr_set_port(&rtcp_addr, (pj_uint16_t)rtcp_port);
	}
    }

    /* Find the default addresses in a=candidate attributes. 
     */
    for (i=0; i<rem_m->attr_count; ++i) {
	pj_ice_sess_cand cand;

	if (pj_strcmp(&rem_m->attr[i]->name, &STR_CANDIDATE)!=0)
	    continue;

	status = parse_cand(tp_ice->base.name, tmp_pool, 
			    &rem_m->attr[i]->value, &cand);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(4,(tp_ice->base.name, 
		      "Error in parsing SDP candidate attribute '%.*s', "
		      "candidate is ignored",
		      (int)rem_m->attr[i]->value.slen, 
		      rem_m->attr[i]->value.ptr));
	    continue;
	}

	if (!comp1_found && cand.comp_id==COMP_RTP &&
	    pj_sockaddr_cmp(&rem_conn_addr, &cand.addr)==0) 
	{
	    comp1_found = PJ_TRUE;
	} else if (!comp2_found && cand.comp_id==COMP_RTCP &&
		    pj_sockaddr_cmp(&rtcp_addr, &cand.addr)==0) 
	{
	    comp2_found = PJ_TRUE;
	}

	if (cand.comp_id == COMP_RTCP)
	    has_rtcp = PJ_TRUE;

	if (comp1_found && (comp2_found || tp_ice->comp_cnt==1))
	    break;
    }

    /* Check matched component count and ice_mismatch */
    if (comp1_found && (tp_ice->comp_cnt==1 || !has_rtcp)) {
	sdp_state->match_comp_cnt = 1;
	sdp_state->ice_mismatch = PJ_FALSE;
    } else if (comp1_found && comp2_found) {
	sdp_state->match_comp_cnt = 2;
	sdp_state->ice_mismatch = PJ_FALSE;
    } else {
	sdp_state->match_comp_cnt = (tp_ice->comp_cnt > 1 && has_rtcp)? 2 : 1;
	sdp_state->ice_mismatch = PJ_TRUE;
    }


    /* Detect remote restarting session */
    if (pj_ice_strans_has_sess(tp_ice->ice_st) &&
	(pj_ice_strans_sess_is_running(tp_ice->ice_st) ||
	 pj_ice_strans_sess_is_complete(tp_ice->ice_st))) 
    {
	pj_str_t rem_run_ufrag, rem_run_pwd;
	pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, NULL, NULL,
				    &rem_run_ufrag, &rem_run_pwd);
	if (pj_strcmp(&ufrag_attr->value, &rem_run_ufrag) ||
	    pj_strcmp(&pwd_attr->value, &rem_run_pwd))
	{
	    /* Remote offers to restart ICE */
	    sdp_state->ice_restart = PJ_TRUE;
	} else {
	    sdp_state->ice_restart = PJ_FALSE;
	}
    } else {
	sdp_state->ice_restart = PJ_FALSE;
    }

    /* Detect our role */
    if (current_ice_role==PJ_ICE_SESS_ROLE_CONTROLLING) {
	sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLING;
    } else {
	if (pjmedia_sdp_attr_find(rem_sdp->attr_count, rem_sdp->attr,
				  &STR_ICE_LITE, NULL) != NULL)
	{
	    /* Remote is ICE Lite */
	    sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLING;
	} else {
	    sdp_state->local_role = PJ_ICE_SESS_ROLE_CONTROLLED;
	}
    }

    PJ_LOG(4,(tp_ice->base.name, 
	      "Processing SDP: support ICE=%u, common comp_cnt=%u, "
	      "ice_mismatch=%u, ice_restart=%u, local_role=%s",
	      (sdp_state->match_comp_cnt != 0), 
	      sdp_state->match_comp_cnt, 
	      sdp_state->ice_mismatch, 
	      sdp_state->ice_restart,
	      pj_ice_sess_role_name(sdp_state->local_role)));

    return PJ_SUCCESS;

}
Ejemplo n.º 3
0
/*
 * Show information contained in the ICE stream transport. This is
 * invoked from the menu.
 */
static void icedemo_show_ice(void)
{
    static char buffer[1000];
    int len;

    if (icedemo.icest == NULL) {
	PJ_LOG(1,(THIS_FILE, "Error: No ICE instance, create it first"));
	return;
    }

    puts("General info");
    puts("---------------");
    printf("Component count    : %d\n", icedemo.opt.comp_cnt);
    printf("Status             : ");
    if (pj_ice_strans_sess_is_complete(icedemo.icest))
	puts("negotiation complete");
    else if (pj_ice_strans_sess_is_running(icedemo.icest))
	puts("negotiation is in progress");
    else if (pj_ice_strans_has_sess(icedemo.icest))
	puts("session ready");
    else
	puts("session not created");

    if (!pj_ice_strans_has_sess(icedemo.icest)) {
	puts("Create the session first to see more info");
	return;
    }

    printf("Negotiated comp_cnt: %d\n", 
	   pj_ice_strans_get_running_comp_cnt(icedemo.icest));
    printf("Role               : %s\n",
	   pj_ice_strans_get_role(icedemo.icest)==PJ_ICE_SESS_ROLE_CONTROLLED ?
	   "controlled" : "controlling");

    len = encode_session(buffer, sizeof(buffer));
    if (len < 0)
	err_exit("not enough buffer to show ICE status", -len);

    puts("");
    printf("Local SDP (paste this to remote host):\n"
	   "--------------------------------------\n"
	   "%s\n", buffer);


    puts("");
    puts("Remote info:\n"
	 "----------------------");
    if (icedemo.rem.cand_cnt==0) {
	puts("No remote info yet");
    } else {
	unsigned i;

	printf("Remote ufrag       : %s\n", icedemo.rem.ufrag);
	printf("Remote password    : %s\n", icedemo.rem.pwd);
	printf("Remote cand. cnt.  : %d\n", icedemo.rem.cand_cnt);

	for (i=0; i<icedemo.rem.cand_cnt; ++i) {
	    len = print_cand(buffer, sizeof(buffer), &icedemo.rem.cand[i]);
	    if (len < 0)
		err_exit("not enough buffer to show ICE status", -len);

	    printf("  %s", buffer);
	}
    }
}
Ejemplo n.º 4
0
/*
 * Start ICE checks when both offer and answer have been negotiated
 * by SDP negotiator.
 */
static pj_status_t transport_media_start(pjmedia_transport *tp,
				         pj_pool_t *tmp_pool,
				         const pjmedia_sdp_session *sdp_local,
				         const pjmedia_sdp_session *rem_sdp,
				         unsigned media_index)
{
    struct transport_ice *tp_ice = (struct transport_ice*)tp;
    pjmedia_sdp_media *rem_m;
    enum oa_role current_oa_role;
    pj_bool_t initial_oa;
    pj_status_t status;

    PJ_ASSERT_RETURN(tp && tmp_pool && rem_sdp, PJ_EINVAL);
    PJ_ASSERT_RETURN(media_index < rem_sdp->media_count, PJ_EINVAL);

    rem_m = rem_sdp->media[media_index];

    initial_oa = tp_ice->initial_sdp;
    current_oa_role = tp_ice->oa_role;

    /* SDP has been negotiated */
    tp_ice->initial_sdp = PJ_FALSE;
    tp_ice->oa_role = ROLE_NONE;

    /* Nothing to do if we don't have ICE session */
    if (pj_ice_strans_has_sess(tp_ice->ice_st) == PJ_FALSE) {
	return PJ_SUCCESS;
    }

    /* Processing depends on the offer/answer role */
    if (current_oa_role == ROLE_OFFERER) {
	/*
	 * We are offerer. So this will be the first time we see the
	 * remote's SDP.
	 */
	struct sdp_state answer_state;

	/* Verify the answer */
	status = verify_ice_sdp(tp_ice, tmp_pool, rem_sdp, media_index, 
				PJ_ICE_SESS_ROLE_CONTROLLING, &answer_state);
	if (status != PJ_SUCCESS) {
	    /* Something wrong in the SDP answer */
	    set_no_ice(tp_ice, "Invalid remote SDP answer", status);
	    return status;
	}

	/* Does it have ICE? */
	if (answer_state.match_comp_cnt == 0) {
	    /* Remote doesn't support ICE */
	    set_no_ice(tp_ice, "Remote answer doesn't support ICE", 
		       PJ_SUCCESS);
	    return PJ_SUCCESS;
	}

	/* Check if remote has reported ice-mismatch */
	if (pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, 
				  &STR_ICE_MISMATCH, NULL) != NULL)
	{
	    /* Remote has reported ice-mismatch */
	    set_no_ice(tp_ice, 
		       "Remote answer contains 'ice-mismatch' attribute", 
		       PJ_SUCCESS);
	    return PJ_SUCCESS;
	}

	/* Check if remote has indicated a restart */
	if (answer_state.ice_restart) {
	    PJ_LOG(2,(tp_ice->base.name, 
		      "Warning: remote has signalled ICE restart in SDP "
		      "answer which is disallowed. Remote ICE negotiation"
		      " may fail."));
	}

	/* Check if the answer itself is mismatched */
	if (answer_state.ice_mismatch) {
	    /* This happens either when a B2BUA modified remote answer but
	     * strangely didn't modify our offer, or remote is not capable
	     * of detecting mismatch in our offer (it didn't put 
	     * 'ice-mismatch' attribute in the answer).
	     */
	    PJ_LOG(2,(tp_ice->base.name, 
		      "Warning: remote answer mismatch, but it does not "
		      "reject our offer with 'ice-mismatch'. ICE negotiation "
		      "may fail"));
	}

	/* Do nothing if ICE is complete or running */
	if (pj_ice_strans_sess_is_running(tp_ice->ice_st)) {
	    PJ_LOG(4,(tp_ice->base.name,
		      "Ignored offer/answer because ICE is running"));
	    return PJ_SUCCESS;
	}

	if (pj_ice_strans_sess_is_complete(tp_ice->ice_st)) {
	    PJ_LOG(4,(tp_ice->base.name, "ICE session unchanged"));
	    return PJ_SUCCESS;
	}

	/* Start ICE */

    } else {
	/*
	 * We are answerer. We've seen and negotiated remote's SDP
	 * before, and the result is in "rem_offer_state".
	 */
	const pjmedia_sdp_attr *ufrag_attr, *pwd_attr;

	/* Check for ICE in remote offer */
	if (tp_ice->rem_offer_state.match_comp_cnt == 0) {
	    /* No ICE attribute present */
	    set_no_ice(tp_ice, "Remote no longer offers ICE",
		       PJ_SUCCESS);
	    return PJ_SUCCESS;
	}

	/* Check for ICE ice_mismatch condition in the offer */
	if (tp_ice->rem_offer_state.ice_mismatch) {
	    set_no_ice(tp_ice, "Remote offer mismatch: ", 
		       PJNATH_EICEMISMATCH);
	    return PJ_SUCCESS;
	}

	/* If ICE is complete and remote doesn't request restart,
	 * then leave the session as is.
	 */
	if (!initial_oa && tp_ice->rem_offer_state.ice_restart == PJ_FALSE) {
	    /* Remote has not requested ICE restart, so session is
	     * unchanged.
	     */
	    PJ_LOG(4,(tp_ice->base.name, "ICE session unchanged"));
	    return PJ_SUCCESS;
	}

	/* Either remote has requested ICE restart or this is our
	 * first answer. 
	 */

	/* Stop ICE */
	if (!initial_oa) {
	    set_no_ice(tp_ice, "restarting by remote request..", PJ_SUCCESS);

	    /* We have put new ICE ufrag and pwd in the answer. Now
	     * create a new ICE session with that ufrag/pwd pair.
	     */
	    get_ice_attr(sdp_local, sdp_local->media[media_index], 
			 &ufrag_attr, &pwd_attr);
	    status = pj_ice_strans_init_ice(tp_ice->ice_st, 
					    tp_ice->rem_offer_state.local_role,
					    &ufrag_attr->value, 
					    &pwd_attr->value);
	    if (status != PJ_SUCCESS) {
		PJ_LOG(1,(tp_ice->base.name, 
			  "ICE re-initialization failed (status=%d)!",
			  status));
		return status;
	    }
	}

	/* start ICE */
    }

    /* Now start ICE */
    status = start_ice(tp_ice, tmp_pool, rem_sdp, media_index);
    if (status != PJ_SUCCESS) {
	PJ_LOG(1,(tp_ice->base.name, 
		  "ICE restart failed (status=%d)!",
		  status));
	return status;
    }

    /* Done */
    tp_ice->use_ice = PJ_TRUE;

    return PJ_SUCCESS;
}