Пример #1
0
/*! \brief Function which adds ICE attributes to a media stream */
static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
{
	struct ast_rtp_engine_ice *ice;
	struct ao2_container *candidates;
	const char *username, *password;
	pj_str_t stmp;
	pjmedia_sdp_attr *attr;
	struct ao2_iterator it_candidates;
	struct ast_rtp_engine_ice_candidate *candidate;

	if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp)) ||
		!(candidates = ice->get_local_candidates(session_media->rtp))) {
		return;
	}

	if ((username = ice->get_ufrag(session_media->rtp))) {
		attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", pj_cstr(&stmp, username));
		media->attr[media->attr_count++] = attr;
	}

	if ((password = ice->get_password(session_media->rtp))) {
		attr = pjmedia_sdp_attr_create(pool, "ice-pwd", pj_cstr(&stmp, password));
		media->attr[media->attr_count++] = attr;
	}

	it_candidates = ao2_iterator_init(candidates, 0);
	for (; (candidate = ao2_iterator_next(&it_candidates)); ao2_ref(candidate, -1)) {
		struct ast_str *attr_candidate = ast_str_create(128);

		ast_str_set(&attr_candidate, -1, "%s %u %s %d %s ", candidate->foundation, candidate->id, candidate->transport,
					candidate->priority, ast_sockaddr_stringify_addr_remote(&candidate->address));
		ast_str_append(&attr_candidate, -1, "%s typ ", ast_sockaddr_stringify_port(&candidate->address));

		switch (candidate->type) {
			case AST_RTP_ICE_CANDIDATE_TYPE_HOST:
				ast_str_append(&attr_candidate, -1, "host");
				break;
			case AST_RTP_ICE_CANDIDATE_TYPE_SRFLX:
				ast_str_append(&attr_candidate, -1, "srflx");
				break;
			case AST_RTP_ICE_CANDIDATE_TYPE_RELAYED:
				ast_str_append(&attr_candidate, -1, "relay");
				break;
		}

		if (!ast_sockaddr_isnull(&candidate->relay_address)) {
			ast_str_append(&attr_candidate, -1, " raddr %s rport", ast_sockaddr_stringify_addr_remote(&candidate->relay_address));
			ast_str_append(&attr_candidate, -1, " %s", ast_sockaddr_stringify_port(&candidate->relay_address));
		}

		attr = pjmedia_sdp_attr_create(pool, "candidate", pj_cstr(&stmp, ast_str_buffer(attr_candidate)));
		media->attr[media->attr_count++] = attr;

		ast_free(attr_candidate);
	}

	ao2_iterator_destroy(&it_candidates);
	ao2_ref(candidates, -1);
}
Пример #2
0
void Sdp::addZrtpAttribute(pjmedia_sdp_media* media, std::string hash)
{
    /* Format: ":version value" */
    std::string val = "1.10 " + hash;
    pj_str_t value = { (char*)val.c_str(), val.size() };
    pjmedia_sdp_attr *attr = pjmedia_sdp_attr_create(memPool_, "zrtp-hash", &value);

    if (pjmedia_sdp_media_add_attr(media, attr) != PJ_SUCCESS)
        throw SdpException("Could not add zrtp attribute to media");
}
Пример #3
0
void Sdp::addSdesAttribute(const std::vector<std::string>& crypto)
{
    for (std::vector<std::string>::const_iterator iter = crypto.begin();
            iter != crypto.end(); ++iter) {
        pj_str_t val = { (char*)(*iter).c_str(), (*iter).size() };
        pjmedia_sdp_attr *attr = pjmedia_sdp_attr_create(memPool_, "crypto", &val);

        for (unsigned i = 0; i < localSession_->media_count; i++)
            if (pjmedia_sdp_media_add_attr(localSession_->media[i], attr) != PJ_SUCCESS)
                throw SdpException("Could not add sdes attribute to media");
    }
}
Пример #4
0
pjmedia_sdp_media *Sdp::setMediaDescriptorLine()
{
    pjmedia_sdp_media *med = PJ_POOL_ZALLOC_T(memPool_, pjmedia_sdp_media);

    med->desc.media = pj_str((char*)"audio");
    med->desc.port_count = 1;
    med->desc.port = localAudioPort_;
    // in case of sdes, media are tagged as "RTP/SAVP", RTP/AVP elsewhere
    med->desc.transport = pj_str(srtpCrypto_.empty() ? (char*)"RTP/AVP" : (char*)"RTP/SAVP");

    med->desc.fmt_count = codec_list_.size();

    for (unsigned i=0; i<med->desc.fmt_count; i++) {
        sfl::Codec *codec = codec_list_[i];

        std::ostringstream result;
        result << (int)codec->getPayloadType();

        pj_strdup2(memPool_, &med->desc.fmt[i], result.str().c_str());

        // Add a rtpmap field for each codec
        // We could add one only for dynamic payloads because the codecs with static RTP payloads
        // are entirely defined in the RFC 3351, but if we want to add other attributes like an asymmetric
        // connection, the rtpmap attribute will be useful to specify for which codec it is applicable
        pjmedia_sdp_rtpmap rtpmap;
        rtpmap.pt = med->desc.fmt[i];
        rtpmap.enc_name = pj_str((char*) codec->getMimeSubtype().c_str());

        // G722 require G722/8000 media description even if it is 16000 codec
        if (codec->getPayloadType() == 9) {
            rtpmap.clock_rate = 8000;
        } else {
            rtpmap.clock_rate = codec->getClockRate();
        }

        rtpmap.param.ptr = ((char* const)"");
        rtpmap.param.slen = 0;

        pjmedia_sdp_attr *attr;
        pjmedia_sdp_rtpmap_to_attr(memPool_, &rtpmap, &attr);

        med->attr[med->attr_count++] = attr;
    }

    med->attr[ med->attr_count++] = pjmedia_sdp_attr_create(memPool_, "sendrecv", NULL);

    if (!zrtpHelloHash_.empty())
        addZrtpAttribute(med, zrtpHelloHash_);

    setTelephoneEventRtpmap(med);

    return med;
}
Пример #5
0
static pjmedia_sdp_attr* generate_fmtp_attr(pj_pool_t *pool, struct ast_format *format, int rtp_code)
{
	struct ast_str *fmtp0 = ast_str_alloca(256);
	pj_str_t fmtp1;
	pjmedia_sdp_attr *attr = NULL;
	char *tmp;

	ast_format_generate_sdp_fmtp(format, rtp_code, &fmtp0);
	if (ast_str_strlen(fmtp0)) {
		tmp = ast_str_buffer(fmtp0) + ast_str_strlen(fmtp0) - 1;
		/* remove any carriage return line feeds */
		while (*tmp == '\r' || *tmp == '\n') --tmp;
		*++tmp = '\0';
		/* ast...generate gives us everything, just need value */
		tmp = strchr(ast_str_buffer(fmtp0), ':');
		if (tmp && tmp + 1) {
			fmtp1 = pj_str(tmp + 1);
		} else {
			fmtp1 = pj_str(ast_str_buffer(fmtp0));
		}
		attr = pjmedia_sdp_attr_create(pool, "fmtp", &fmtp1);
	}
	return attr;
}
Пример #6
0
static int add_crypto_to_stream(struct ast_sip_session *session,
	struct ast_sip_session_media *session_media,
	pj_pool_t *pool, pjmedia_sdp_media *media)
{
	pj_str_t stmp;
	pjmedia_sdp_attr *attr;
	enum ast_rtp_dtls_hash hash;
	const char *crypto_attribute;
	struct ast_rtp_engine_dtls *dtls;
	static const pj_str_t STR_NEW = { "new", 3 };
	static const pj_str_t STR_EXISTING = { "existing", 8 };
	static const pj_str_t STR_ACTIVE = { "active", 6 };
	static const pj_str_t STR_PASSIVE = { "passive", 7 };
	static const pj_str_t STR_ACTPASS = { "actpass", 7 };
	static const pj_str_t STR_HOLDCONN = { "holdconn", 8 };

	switch (session_media->encryption) {
	case AST_SIP_MEDIA_ENCRYPT_NONE:
	case AST_SIP_MEDIA_TRANSPORT_INVALID:
		break;
	case AST_SIP_MEDIA_ENCRYPT_SDES:
		if (!session_media->srtp) {
			session_media->srtp = ast_sdp_srtp_alloc();
			if (!session_media->srtp) {
				return -1;
			}
		}

		crypto_attribute = ast_sdp_srtp_get_attrib(session_media->srtp,
			0 /* DTLS running? No */,
			session->endpoint->media.rtp.srtp_tag_32 /* 32 byte tag length? */);
		if (!crypto_attribute) {
			/* No crypto attribute to add, bad news */
			return -1;
		}

		attr = pjmedia_sdp_attr_create(pool, "crypto", pj_cstr(&stmp, crypto_attribute));
		media->attr[media->attr_count++] = attr;
		break;
	case AST_SIP_MEDIA_ENCRYPT_DTLS:
		if (setup_dtls_srtp(session, session_media)) {
			return -1;
		}

		dtls = ast_rtp_instance_get_dtls(session_media->rtp);
		if (!dtls) {
			return -1;
		}

		switch (dtls->get_connection(session_media->rtp)) {
		case AST_RTP_DTLS_CONNECTION_NEW:
			attr = pjmedia_sdp_attr_create(pool, "connection", &STR_NEW);
			media->attr[media->attr_count++] = attr;
			break;
		case AST_RTP_DTLS_CONNECTION_EXISTING:
			attr = pjmedia_sdp_attr_create(pool, "connection", &STR_EXISTING);
			media->attr[media->attr_count++] = attr;
			break;
		default:
			break;
		}

		switch (dtls->get_setup(session_media->rtp)) {
		case AST_RTP_DTLS_SETUP_ACTIVE:
			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTIVE);
			media->attr[media->attr_count++] = attr;
			break;
		case AST_RTP_DTLS_SETUP_PASSIVE:
			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_PASSIVE);
			media->attr[media->attr_count++] = attr;
			break;
		case AST_RTP_DTLS_SETUP_ACTPASS:
			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTPASS);
			media->attr[media->attr_count++] = attr;
			break;
		case AST_RTP_DTLS_SETUP_HOLDCONN:
			attr = pjmedia_sdp_attr_create(pool, "setup", &STR_HOLDCONN);
			media->attr[media->attr_count++] = attr;
			break;
		default:
			break;
		}

		hash = dtls->get_fingerprint_hash(session_media->rtp);
		crypto_attribute = dtls->get_fingerprint(session_media->rtp);
		if (crypto_attribute && (hash == AST_RTP_DTLS_HASH_SHA1 || hash == AST_RTP_DTLS_HASH_SHA256)) {
			RAII_VAR(struct ast_str *, fingerprint, ast_str_create(64), ast_free);
			if (!fingerprint) {
				return -1;
			}

			if (hash == AST_RTP_DTLS_HASH_SHA1) {
				ast_str_set(&fingerprint, 0, "SHA-1 %s", crypto_attribute);
			} else {
				ast_str_set(&fingerprint, 0, "SHA-256 %s", crypto_attribute);
			}

			attr = pjmedia_sdp_attr_create(pool, "fingerprint", pj_cstr(&stmp, ast_str_buffer(fingerprint)));
			media->attr[media->attr_count++] = attr;
		}
		break;
	}
Пример #7
0
static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
					pj_pool_t *sdp_pool,
					pjmedia_sdp_session *sdp_local,
					const pjmedia_sdp_session *sdp_remote,
					unsigned media_index)
{
    struct transport_srtp *srtp = (struct transport_srtp*) tp;
    pjmedia_sdp_media *m_rem, *m_loc;
    enum { MAXLEN = 512 };
    char buffer[MAXLEN];
    int buffer_len;
    pj_status_t status;
    pjmedia_sdp_attr *attr;
    pj_str_t attr_value;
    unsigned i, j;

    PJ_ASSERT_RETURN(tp && sdp_pool && sdp_local, PJ_EINVAL);
    
    srtp->offerer_side = sdp_remote == NULL;

    m_rem = sdp_remote ? sdp_remote->media[media_index] : NULL;
    m_loc = sdp_local->media[media_index];

    /* Bypass if media transport is not RTP/AVP or RTP/SAVP */
    if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP)  != 0 && 
	pj_stricmp(&m_loc->desc.transport, &ID_RTP_SAVP) != 0)
	goto BYPASS_SRTP;

    /* If the media is inactive, do nothing. */
    if (pjmedia_sdp_media_find_attr(m_loc, &ID_INACTIVE, NULL) || 
	(m_rem && pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL)))
	goto BYPASS_SRTP;

    /* Check remote media transport & set local media transport 
     * based on SRTP usage option.
     */
    if (srtp->offerer_side) {

	/* Generate transport */
	switch (srtp->setting.use) {
	    case PJMEDIA_SRTP_DISABLED:
		goto BYPASS_SRTP;
	    case PJMEDIA_SRTP_OPTIONAL:
		m_loc->desc.transport = 
				(srtp->peer_use == PJMEDIA_SRTP_MANDATORY)?
				ID_RTP_SAVP : ID_RTP_AVP;
		break;
	    case PJMEDIA_SRTP_MANDATORY:
		m_loc->desc.transport = ID_RTP_SAVP;
		break;
	}

	/* Generate crypto attribute if not yet */
	if (pjmedia_sdp_media_find_attr(m_loc, &ID_CRYPTO, NULL) == NULL) {
	    for (i=0; i<srtp->setting.crypto_count; ++i) {
		/* Offer crypto-suites based on setting. */
		buffer_len = MAXLEN;
		status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len,
						    &srtp->setting.crypto[i],
						    i+1);
		if (status != PJ_SUCCESS)
		    return status;

		/* If buffer_len==0, just skip the crypto attribute. */
		if (buffer_len) {
		    pj_strset(&attr_value, buffer, buffer_len);
		    attr = pjmedia_sdp_attr_create(srtp->pool, ID_CRYPTO.ptr, 
						   &attr_value);
		    m_loc->attr[m_loc->attr_count++] = attr;
		}
	    }
	}

    } else {
	/* Answerer side */

	pj_assert(sdp_remote && m_rem);

	/* Generate transport */
	switch (srtp->setting.use) {
	    case PJMEDIA_SRTP_DISABLED:
		if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
		    return PJMEDIA_SRTP_ESDPINTRANSPORT;
		goto BYPASS_SRTP;
	    case PJMEDIA_SRTP_OPTIONAL:
		m_loc->desc.transport = m_rem->desc.transport;
		break;
	    case PJMEDIA_SRTP_MANDATORY:
		if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0)
		    return PJMEDIA_SRTP_ESDPINTRANSPORT;
		m_loc->desc.transport = ID_RTP_SAVP;
		break;
	}

	/* Generate crypto attribute if not yet */
	if (pjmedia_sdp_media_find_attr(m_loc, &ID_CRYPTO, NULL) == NULL) {

	    pjmedia_srtp_crypto tmp_rx_crypto;
	    pj_bool_t has_crypto_attr = PJ_FALSE;
	    int matched_idx = -1;
	    int chosen_tag = 0;
	    int tags[64]; /* assume no more than 64 crypto attrs in a media */
	    unsigned cr_attr_count = 0;

	    /* Find supported crypto-suite, get the tag, and assign policy_local */
	    for (i=0; i<m_rem->attr_count; ++i) {
		if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0)
		    continue;

		has_crypto_attr = PJ_TRUE;

		status = parse_attr_crypto(srtp->pool, m_rem->attr[i], 
					   &tmp_rx_crypto, &tags[cr_attr_count]);
		if (status != PJ_SUCCESS)
		    return status;
    	 
		/* Check duplicated tag */
		for (j=0; j<cr_attr_count; ++j) {
		    if (tags[j] == tags[cr_attr_count]) {
			DEACTIVATE_MEDIA(sdp_pool, m_loc);
			return PJMEDIA_SRTP_ESDPDUPCRYPTOTAG;
		    }
		}

		if (matched_idx == -1) {
		    /* lets see if the crypto-suite offered is supported */
		    for (j=0; j<srtp->setting.crypto_count; ++j)
			if (pj_stricmp(&tmp_rx_crypto.name, 
				       &srtp->setting.crypto[j].name) == 0)
			{
			    int cs_idx = get_crypto_idx(&tmp_rx_crypto.name);

			    /* Force to use test key */
			    /* bad keys for snom: */
			    //char *hex_test_key = "58b29c5c8f42308120ce857e439f2d"
			    //		     "7810a8b10ad0b1446be5470faea496";
			    //char *hex_test_key = "20a26aac7ba062d356ff52b61e3993"
			    //		     "ccb78078f12c64db94b9c294927fd0";
			    //pj_str_t *test_key = &srtp->setting.crypto[j].key;
			    //char  *raw_test_key = pj_pool_zalloc(srtp->pool, 64);
			    //hex_string_to_octet_string(
			    //		raw_test_key,
			    //		hex_test_key,
			    //		strlen(hex_test_key));
			    //pj_strset(test_key, raw_test_key, 
			    //	  crypto_suites[cs_idx].cipher_key_len);
			    /* EO Force to use test key */

			    if (tmp_rx_crypto.key.slen != 
				(int)crypto_suites[cs_idx].cipher_key_len)
				return PJMEDIA_SRTP_EINKEYLEN;

			    srtp->rx_policy_neg = tmp_rx_crypto;
			    chosen_tag = tags[cr_attr_count];
			    matched_idx = j;
    			    break;
			}
		}
		cr_attr_count++;
	    }

	    /* Check crypto negotiation result */
	    switch (srtp->setting.use) {
		case PJMEDIA_SRTP_DISABLED:
		    pj_assert(!"Should never reach here");
		    break;

		case PJMEDIA_SRTP_OPTIONAL:
		    /* bypass SRTP when no crypto-attr and remote uses RTP/AVP */
		    if (!has_crypto_attr && 
			pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0)
			goto BYPASS_SRTP;
		    /* bypass SRTP when nothing match and remote uses RTP/AVP */
		    else if (matched_idx == -1 && 
			pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0)
			goto BYPASS_SRTP;
		    break;

		case PJMEDIA_SRTP_MANDATORY:
		    /* Do nothing, intentional */
		    break;
	    }

	    /* No crypto attr */
	    if (!has_crypto_attr) {
		DEACTIVATE_MEDIA(sdp_pool, m_loc);
		return PJMEDIA_SRTP_ESDPREQCRYPTO;
	    }

	    /* No crypto match */
	    if (matched_idx == -1) {
		DEACTIVATE_MEDIA(sdp_pool, m_loc);
		return PJMEDIA_SRTP_ENOTSUPCRYPTO;
	    }

	    /* we have to generate crypto answer, 
	     * with srtp->tx_policy_neg matched the offer
	     * and rem_tag contains matched offer tag.
	     */
	    buffer_len = MAXLEN;
	    status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len,
						&srtp->setting.crypto[matched_idx],
						chosen_tag);
	    if (status != PJ_SUCCESS)
		return status;

	    srtp->tx_policy_neg = srtp->setting.crypto[matched_idx];
	    
	    /* If buffer_len==0, just skip the crypto attribute. */
	    if (buffer_len) {
		pj_strset(&attr_value, buffer, buffer_len);
		attr = pjmedia_sdp_attr_create(sdp_pool, ID_CRYPTO.ptr, 
					       &attr_value);
		m_loc->attr[m_loc->attr_count++] = attr;
	    }

	    /* At this point, we get valid rx_policy_neg & tx_policy_neg. */
	}
	    
    }
    goto PROPAGATE_MEDIA_CREATE;

BYPASS_SRTP:
    srtp->bypass_srtp = PJ_TRUE;

PROPAGATE_MEDIA_CREATE:
    return pjmedia_transport_encode_sdp(srtp->member_tp, sdp_pool, 
					sdp_local, sdp_remote, media_index);
}
Пример #8
0
/* Update media direction based on peer's media direction */
static void update_media_direction(pj_pool_t *pool,
				   const pjmedia_sdp_media *remote,
				   pjmedia_sdp_media *local)
{
    pjmedia_dir old_dir = PJMEDIA_DIR_ENCODING_DECODING,
	        new_dir;

    /* Get the media direction of local SDP */
    if (pjmedia_sdp_media_find_attr2(local, "sendonly", NULL))
	old_dir = PJMEDIA_DIR_ENCODING;
    else if (pjmedia_sdp_media_find_attr2(local, "recvonly", NULL))
	old_dir = PJMEDIA_DIR_DECODING;
    else if (pjmedia_sdp_media_find_attr2(local, "inactive", NULL))
	old_dir = PJMEDIA_DIR_NONE;

    new_dir = old_dir;

    /* Adjust local media direction based on remote media direction */
    if (pjmedia_sdp_media_find_attr2(remote, "inactive", NULL) != NULL) {
	/* If remote has "a=inactive", then local is inactive too */

	new_dir = PJMEDIA_DIR_NONE;

    } else if(pjmedia_sdp_media_find_attr2(remote, "sendonly", NULL) != NULL) {
	/* If remote has "a=sendonly", then set local to "recvonly" if
	 * it is currently "sendrecv". Otherwise if local is NOT "recvonly",
	 * then set local direction to "inactive".
	 */
	switch (old_dir) {
	case PJMEDIA_DIR_ENCODING_DECODING:
	    new_dir = PJMEDIA_DIR_DECODING;
	    break;
	case PJMEDIA_DIR_DECODING:
	    /* No change */
	    break;
	default:
	    new_dir = PJMEDIA_DIR_NONE;
	    break;
	}

    } else if(pjmedia_sdp_media_find_attr2(remote, "recvonly", NULL) != NULL) {
	/* If remote has "a=recvonly", then set local to "sendonly" if
	 * it is currently "sendrecv". Otherwise if local is NOT "sendonly",
	 * then set local direction to "inactive"
	 */
    
	switch (old_dir) {
	case PJMEDIA_DIR_ENCODING_DECODING:
	    new_dir = PJMEDIA_DIR_ENCODING;
	    break;
	case PJMEDIA_DIR_ENCODING:
	    /* No change */
	    break;
	default:
	    new_dir = PJMEDIA_DIR_NONE;
	    break;
	}

    } else {
	/* Remote indicates "sendrecv" capability. No change to local 
	 * direction 
	 */
    }

    if (new_dir != old_dir) {
	pjmedia_sdp_attr *a = NULL;

	remove_all_media_directions(local);

	switch (new_dir) {
	case PJMEDIA_DIR_NONE:
	    a = pjmedia_sdp_attr_create(pool, "inactive", NULL);
	    break;
	case PJMEDIA_DIR_ENCODING:
	    a = pjmedia_sdp_attr_create(pool, "sendonly", NULL);
	    break;
	case PJMEDIA_DIR_DECODING:
	    a = pjmedia_sdp_attr_create(pool, "recvonly", NULL);
	    break;
	default:
	    /* sendrecv */
	    break;
	}
	
	if (a) {
	    pjmedia_sdp_media_add_attr(local, a);
	}
    }
}
Пример #9
0
/*
 * The encode_sdp() is called when we're about to send SDP to remote party,
 * either as SDP offer or as SDP answer.
 */
static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
                                        pj_pool_t *sdp_pool,
                                        pjmedia_sdp_session *local_sdp,
                                        const pjmedia_sdp_session *rem_sdp,
                                        unsigned media_index)
{
    struct tp_zrtp *zrtp = (struct tp_zrtp*)tp;
    int32_t numVersions, i;
    
    PJ_ASSERT_RETURN(tp, PJ_EINVAL);
    
    /* If "rem_sdp" is not NULL, it means we're encoding SDP answer. You may
     * do some more checking on the SDP's once again to make sure that
     * everything is okay before we send SDP.
     */
    if (rem_sdp)
    {
        /* Do checking stuffs here.. */
    }

    /* Add zrtp-hash attributes to both INVITE and 200 OK. */
    numVersions = zrtp_getNumberSupportedVersions(zrtp->zrtpCtx);
    for (i = 0; i < numVersions; i++) {
        char *zrtp_hello_hash = zrtp_getHelloHash(zrtp->zrtpCtx, i);
        if (zrtp_hello_hash && *zrtp_hello_hash) {
            int zrtp_hello_hash_len = strlen(zrtp_hello_hash);
            pj_str_t *zrtp_hash_str = PJ_POOL_ALLOC_T(sdp_pool, pj_str_t);
            pjmedia_sdp_attr *zrtp_hash = NULL;

            zrtp_hash_str->ptr = zrtp_hello_hash;
            zrtp_hash_str->slen = zrtp_hello_hash_len;

            zrtp_hash = pjmedia_sdp_attr_create(sdp_pool, "zrtp-hash", zrtp_hash_str);
            if (zrtp_hash && 
                pjmedia_sdp_attr_add(&local_sdp->media[media_index]->attr_count, local_sdp->media[media_index]->attr, zrtp_hash) == PJ_SUCCESS) {
                PJ_LOG(4, (THIS_FILE, "attribute added: a=zrtp-hash:%s", zrtp_hello_hash));
            }
            else {
                PJ_LOG(4, (THIS_FILE, "error adding attribute: a=zrtp-hash:%s", zrtp_hello_hash));
            }
        }
    }

    /* You may do anything to the local_sdp, e.g. adding new attributes, or
     * even modifying the SDP if you want.
     */
    if (0)
    {
        /* Say we add a proprietary attribute here.. */
        pjmedia_sdp_attr *my_attr;

        my_attr = PJ_POOL_ALLOC_T(sdp_pool, pjmedia_sdp_attr);
        pj_strdup2(sdp_pool, &my_attr->name, "X-zrtp");
        pj_strdup2(sdp_pool, &my_attr->value, "some value");

        pjmedia_sdp_attr_add(&local_sdp->media[media_index]->attr_count,
                             local_sdp->media[media_index]->attr,
                             my_attr);
    }

    /* And then pass the call to slave transport to let it encode its
     * information in the SDP. You may choose to call encode_sdp() to slave
     * first before adding your custom attributes if you want.
     */
    return pjmedia_transport_encode_sdp(zrtp->slave_tp, sdp_pool, local_sdp, rem_sdp, media_index);
}
Пример #10
0
/*! \brief Function which creates an outgoing stream */
static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
				      struct pjmedia_sdp_session *sdp)
{
	pj_pool_t *pool = session->inv_session->pool_prov;
	static const pj_str_t STR_IN = { "IN", 2 };
	static const pj_str_t STR_IP4 = { "IP4", 3};
	static const pj_str_t STR_IP6 = { "IP6", 3};
	static const pj_str_t STR_UDPTL = { "udptl", 5 };
	static const pj_str_t STR_T38 = { "t38", 3 };
	static const pj_str_t STR_TRANSFERREDTCF = { "transferredTCF", 14 };
	static const pj_str_t STR_LOCALTCF = { "localTCF", 8 };
	static const pj_str_t STR_T38UDPFEC = { "t38UDPFEC", 9 };
	static const pj_str_t STR_T38UDPREDUNDANCY = { "t38UDPRedundancy", 16 };
	struct t38_state *state;
	pjmedia_sdp_media *media;
	const char *hostip = NULL;
	struct ast_sockaddr addr;
	char tmp[512];
	pj_str_t stmp;

	if (!session->endpoint->media.t38.enabled) {
		return 1;
	} else if ((session->t38state != T38_LOCAL_REINVITE) && (session->t38state != T38_PEER_REINVITE) &&
		(session->t38state != T38_ENABLED)) {
		return 1;
	} else if (!(state = t38_state_get_or_alloc(session))) {
		return -1;
	} else if (t38_initialize_session(session, session_media)) {
		return -1;
	}

	if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
		!(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
		return -1;
	}

	media->desc.media = pj_str(session_media->stream_type);
	media->desc.transport = STR_UDPTL;

	if (ast_strlen_zero(session->endpoint->media.address)) {
		hostip = ast_sip_get_host_ip_string(session->endpoint->media.t38.ipv6 ? pj_AF_INET6() : pj_AF_INET());
	} else {
		hostip = session->endpoint->media.address;
	}

	if (ast_strlen_zero(hostip)) {
		return -1;
	}

	media->conn->net_type = STR_IN;
	media->conn->addr_type = session->endpoint->media.t38.ipv6 ? STR_IP6 : STR_IP4;
	pj_strdup2(pool, &media->conn->addr, hostip);
	ast_udptl_get_us(session_media->udptl, &addr);
	media->desc.port = (pj_uint16_t) ast_sockaddr_port(&addr);
	media->desc.port_count = 1;
	media->desc.fmt[media->desc.fmt_count++] = STR_T38;

	snprintf(tmp, sizeof(tmp), "%u", state->our_parms.version);
	media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxVersion", pj_cstr(&stmp, tmp));

	snprintf(tmp, sizeof(tmp), "%u", t38_get_rate(state->our_parms.rate));
	media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38MaxBitRate", pj_cstr(&stmp, tmp));

	if (state->our_parms.fill_bit_removal) {
		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxFillBitRemoval", NULL);
	}

	if (state->our_parms.transcoding_mmr) {
		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingMMR", NULL);
	}

	if (state->our_parms.transcoding_jbig) {
		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxTranscodingJBIG", NULL);
	}

	switch (state->our_parms.rate_management) {
	case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF:
		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_TRANSFERREDTCF);
		break;
	case AST_T38_RATE_MANAGEMENT_LOCAL_TCF:
		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxRateManagement", &STR_LOCALTCF);
		break;
	}

	snprintf(tmp, sizeof(tmp), "%u", ast_udptl_get_local_max_datagram(session_media->udptl));
	media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxMaxDatagram", pj_cstr(&stmp, tmp));

	switch (ast_udptl_get_error_correction_scheme(session_media->udptl)) {
	case UDPTL_ERROR_CORRECTION_NONE:
		break;
	case UDPTL_ERROR_CORRECTION_FEC:
		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPFEC);
		break;
	case UDPTL_ERROR_CORRECTION_REDUNDANCY:
		media->attr[media->attr_count++] = pjmedia_sdp_attr_create(pool, "T38FaxUdpEC", &STR_T38UDPREDUNDANCY);
		break;
	}

	sdp->media[sdp->media_count++] = media;

	return 1;
}
Пример #11
0
/* Encode ICE information in SDP */
static pj_status_t encode_session_in_sdp(struct transport_ice *tp_ice,
					 pj_pool_t *sdp_pool,
					 pjmedia_sdp_session *sdp_local,
					 unsigned media_index,
					 unsigned comp_cnt,
					 pj_bool_t restart_session)
{
    enum { 
	ATTR_BUF_LEN = 160,	/* Max len of a=candidate attr */
	RATTR_BUF_LEN= 160	/* Max len of a=remote-candidates attr */
    };
    pjmedia_sdp_media *m = sdp_local->media[media_index];
    pj_str_t local_ufrag, local_pwd;
    pjmedia_sdp_attr *attr;
    pj_status_t status;

    /* Must have a session */
    PJ_ASSERT_RETURN(pj_ice_strans_has_sess(tp_ice->ice_st), PJ_EBUG);

    /* Get ufrag and pwd from current session */
    pj_ice_strans_get_ufrag_pwd(tp_ice->ice_st, &local_ufrag, &local_pwd,
				NULL, NULL);

    /* The listing of candidates depends on whether ICE has completed
     * or not. When ICE has completed:
     *
     * 9.1.2.2: Existing Media Streams with ICE Completed
     *   The agent MUST include a candidate attributes for candidates
     *   matching the default destination for each component of the 
     *   media stream, and MUST NOT include any other candidates.
     *
     * When ICE has not completed, we shall include all candidates.
     *
     * Except when we have detected that remote is offering to restart
     * the session, in this case we will answer with full ICE SDP and
     * new ufrag/pwd pair.
     */
    if (!restart_session && pj_ice_strans_sess_is_complete(tp_ice->ice_st)) {
	const pj_ice_sess_check *check;
	char *attr_buf;
	pjmedia_sdp_conn *conn;
	pjmedia_sdp_attr *a_rtcp;
	pj_str_t rem_cand;
	unsigned comp;

	/* Encode ice-ufrag attribute */
	attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr,
				       &local_ufrag);
	pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	/* Encode ice-pwd attribute */
	attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, 
				       &local_pwd);
	pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	/* Prepare buffer */
	attr_buf = (char*) pj_pool_alloc(sdp_pool, ATTR_BUF_LEN);
	rem_cand.ptr = (char*) pj_pool_alloc(sdp_pool, RATTR_BUF_LEN);
	rem_cand.slen = 0;

	/* 9.1.2.2: Existing Media Streams with ICE Completed
	 *   The default destination for media (i.e., the values of 
	 *   the IP addresses and ports in the m and c line used for
	 *   that media stream) MUST be the local candidate from the
	 *   highest priority nominated pair in the valid list for each
	 *   component.
	 */
	check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, 1);
	if (check == NULL) {
	    pj_assert(!"Shouldn't happen");
	    return PJ_EBUG;
	}

	/* Override connection line address and media port number */
	conn = m->conn;
	if (conn == NULL)
	    conn = sdp_local->conn;

	conn->addr.ptr = (char*) pj_pool_alloc(sdp_pool, 
					       PJ_INET6_ADDRSTRLEN);
	pj_sockaddr_print(&check->lcand->addr, conn->addr.ptr, 
			  PJ_INET6_ADDRSTRLEN, 0);
	conn->addr.slen = pj_ansi_strlen(conn->addr.ptr);
	m->desc.port = pj_sockaddr_get_port(&check->lcand->addr);

	/* Override address RTCP attribute if it's present */
	if (comp_cnt == 2 &&
	    (check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, 
						  COMP_RTCP)) != NULL &&
	    (a_rtcp = pjmedia_sdp_attr_find(m->attr_count, m->attr, 
					    &STR_RTCP, 0)) != NULL) 
	{
	    pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a_rtcp);

	    a_rtcp = pjmedia_sdp_attr_create_rtcp(sdp_pool, 
						  &check->lcand->addr);
	    if (a_rtcp)
		pjmedia_sdp_attr_add(&m->attr_count, m->attr, a_rtcp);
	}

	/* Encode only candidates matching the default destination 
	 * for each component 
	 */
	for (comp=0; comp < comp_cnt; ++comp) {
	    int len;
	    pj_str_t value;

	    /* Get valid pair for this component */
	    check = pj_ice_strans_get_valid_pair(tp_ice->ice_st, comp+1);
	    if (check == NULL)
		continue;

	    /* Print and add local candidate in the pair */
	    value.ptr = attr_buf;
	    value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN, 
					     check->lcand);
	    if (value.slen < 0) {
		pj_assert(!"Not enough attr_buf to print candidate");
		return PJ_EBUG;
	    }

	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_CANDIDATE.ptr,
					   &value);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	    /* Append to a=remote-candidates attribute */
	    if (pj_ice_strans_get_role(tp_ice->ice_st) == 
				    PJ_ICE_SESS_ROLE_CONTROLLING) 
	    {
		char rem_addr[PJ_INET6_ADDRSTRLEN];

		pj_sockaddr_print(&check->rcand->addr, rem_addr, 
				  sizeof(rem_addr), 0);
		len = pj_ansi_snprintf(
			   rem_cand.ptr + rem_cand.slen,
			   RATTR_BUF_LEN - rem_cand.slen,
			   "%s%u %s %u", 
			   (rem_cand.slen==0? "" : " "),
			   comp+1, rem_addr,
			   pj_sockaddr_get_port(&check->rcand->addr)
			   );
		if (len < 1 || len >= RATTR_BUF_LEN) {
		    pj_assert(!"Not enough buffer to print "
			       "remote-candidates");
		    return PJ_EBUG;
		}

		rem_cand.slen += len;
	    }
	}

	/* 9.1.2.2: Existing Media Streams with ICE Completed
	 *   In addition, if the agent is controlling, it MUST include
	 *   the a=remote-candidates attribute for each media stream 
	 *   whose check list is in the Completed state.  The attribute
	 *   contains the remote candidates from the highest priority 
	 *   nominated pair in the valid list for each component of that
	 *   media stream.
	 */
	if (pj_ice_strans_get_role(tp_ice->ice_st) == 
				    PJ_ICE_SESS_ROLE_CONTROLLING) 
	{
	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_REM_CAND.ptr, 
					   &rem_cand);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
	}

    } else if (pj_ice_strans_has_sess(tp_ice->ice_st)) {
	/* Encode all candidates to SDP media */
	char *attr_buf;
	unsigned comp;

	/* If ICE is not restarted, encode current ICE ufrag/pwd.
	 * Otherwise generate new one.
	 */
	if (!restart_session) {
	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr,
					   &local_ufrag);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, 
					   &local_pwd);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	} else {
	    pj_str_t str;

	    str.slen = PJ_ICE_UFRAG_LEN;
	    str.ptr = (char*) pj_pool_alloc(sdp_pool, str.slen);
	    pj_create_random_string(str.ptr, str.slen);
	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_UFRAG.ptr, &str);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);

	    str.ptr = (char*) pj_pool_alloc(sdp_pool, str.slen);
	    pj_create_random_string(str.ptr, str.slen);
	    attr = pjmedia_sdp_attr_create(sdp_pool, STR_ICE_PWD.ptr, &str);
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
	}

	/* Create buffer to encode candidates as SDP attribute */
	attr_buf = (char*) pj_pool_alloc(sdp_pool, ATTR_BUF_LEN);

	for (comp=0; comp < comp_cnt; ++comp) {
	    unsigned cand_cnt;
	    pj_ice_sess_cand cand[PJ_ICE_ST_MAX_CAND];
	    unsigned i;

	    cand_cnt = PJ_ARRAY_SIZE(cand);
	    status = pj_ice_strans_enum_cands(tp_ice->ice_st, comp+1,
					      &cand_cnt, cand);
	    if (status != PJ_SUCCESS)
		return status;

	    for (i=0; i<cand_cnt; ++i) {
		pj_str_t value;

		value.slen = print_sdp_cand_attr(attr_buf, ATTR_BUF_LEN, 
						 &cand[i]);
		if (value.slen < 0) {
		    pj_assert(!"Not enough attr_buf to print candidate");
		    return PJ_EBUG;
		}

		value.ptr = attr_buf;
		attr = pjmedia_sdp_attr_create(sdp_pool, 
					       STR_CANDIDATE.ptr,
					       &value);
		pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
	    }
	}
    } else {
	/* ICE has failed, application should have terminated this call */
    }

    /* Removing a=rtcp line when there is only one component. */
    if (comp_cnt == 1) {
	attr = pjmedia_sdp_attr_find(m->attr_count, m->attr, &STR_RTCP, NULL);
	if (attr)
	    pjmedia_sdp_attr_remove(&m->attr_count, m->attr, attr);
    }
    

    return PJ_SUCCESS;
}
Пример #12
0
void Sdp::addAttributeToLocalAudioMedia(const char *attr)
{
    if (localSession_)
        pjmedia_sdp_media_add_attr(localSession_->media[0], pjmedia_sdp_attr_create(memPool_, attr, NULL));
}