/*! \brief Function which applies a negotiated stream */ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream, const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream) { RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free); char host[NI_MAXHOST]; struct t38_state *state; if (!session_media->udptl) { return 0; } if (!(state = t38_state_get_or_alloc(session))) { return -1; } ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host)); /* Ensure that the address provided is valid */ if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) { /* The provided host was actually invalid so we error out this negotiation */ return -1; } ast_sockaddr_set_port(addrs, remote_stream->desc.port); ast_udptl_set_peer(session_media->udptl, addrs); t38_interpret_sdp(state, session, session_media, remote_stream); return 0; }
/*! \brief Function which negotiates an incoming media stream */ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream) { char host[NI_MAXHOST]; RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr); enum ast_format_type media_type = stream_to_media_type(session_media->stream_type); /* If no type formats have been configured reject this stream */ if (!ast_format_cap_has_type(session->endpoint->media.codecs, media_type)) { return 0; } /* Ensure incoming transport is compatible with the endpoint's configuration */ if (!session->endpoint->media.rtp.use_received_transport && check_endpoint_media_transport(session->endpoint, stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) { return -1; } ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host)); /* Ensure that the address provided is valid */ if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) { /* The provided host was actually invalid so we error out this negotiation */ return -1; } /* Using the connection information create an appropriate RTP instance */ if (!session_media->rtp && create_rtp(session, session_media, ast_sockaddr_is_ipv6(addrs))) { return -1; } if (session->endpoint->media.rtp.use_received_transport) { pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport); } if (setup_media_encryption(session, session_media, stream)) { return -1; } if (set_caps(session, session_media, stream)) { return -1; } if (media_type == AST_FORMAT_TYPE_AUDIO) { apply_packetization(session, session_media, stream); } return 1; }
static int extract_contact_addr(pjsip_contact_hdr *contact, struct ast_sockaddr **addrs) { pjsip_sip_uri *sip_uri; char host[256]; if (!contact || contact->star) { *addrs = NULL; return 0; } if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) { *addrs = NULL; return 0; } sip_uri = pjsip_uri_get_uri(contact->uri); ast_copy_pj_str(host, &sip_uri->host, sizeof(host)); return ast_sockaddr_resolve(addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC); }
/*! \brief Return the first entry from ast_sockaddr_resolve filtered by address family * * \warning Using this function probably means you have a faulty design. * \note This function was taken from the function of the same name in chan_sip.c */ static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr, const char* name, int flag, int family) { struct ast_sockaddr *addrs; int addrs_cnt; addrs_cnt = ast_sockaddr_resolve(&addrs, name, flag, family); if (addrs_cnt <= 0) { return 1; } if (addrs_cnt > 1) { ast_debug(1, "Multiple addresses, using the first one only\n"); } ast_sockaddr_copy(addr, &addrs[0]); ast_free(addrs); return 0; }
/*! \brief Function which negotiates an incoming media stream */ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream) { struct t38_state *state; char host[NI_MAXHOST]; RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free); if (!session->endpoint->media.t38.enabled) { ast_debug(3, "Declining; T.38 not enabled on session\n"); return -1; } if (!(state = t38_state_get_or_alloc(session))) { return -1; } if ((session->t38state == T38_REJECTED) || (session->t38state == T38_DISABLED)) { ast_debug(3, "Declining; T.38 state is rejected or declined\n"); t38_change_state(session, session_media, state, T38_DISABLED); return -1; } ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host)); /* Ensure that the address provided is valid */ if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_INET) <= 0) { /* The provided host was actually invalid so we error out this negotiation */ ast_debug(3, "Declining; provided host is invalid\n"); return -1; } /* Check the address family to make sure it matches configured */ if ((ast_sockaddr_is_ipv6(addrs) && !session->endpoint->media.t38.ipv6) || (ast_sockaddr_is_ipv4(addrs) && session->endpoint->media.t38.ipv6)) { /* The address does not match configured */ ast_debug(3, "Declining, provided host does not match configured address family\n"); return -1; } return 1; }
/*! \brief Function which negotiates an incoming media stream */ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream) { char host[NI_MAXHOST]; RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free); enum ast_media_type media_type = stream_to_media_type(session_media->stream_type); enum ast_sip_session_media_encryption encryption = AST_SIP_MEDIA_ENCRYPT_NONE; int res; /* If port is 0, ignore this media stream */ if (!stream->desc.port) { ast_debug(3, "Media stream '%s' is already declined\n", session_media->stream_type); return 0; } /* If no type formats have been configured reject this stream */ if (!ast_format_cap_has_type(session->endpoint->media.codecs, media_type)) { ast_debug(3, "Endpoint has no codecs for media type '%s', declining stream\n", session_media->stream_type); return 0; } /* Ensure incoming transport is compatible with the endpoint's configuration */ if (!session->endpoint->media.rtp.use_received_transport) { encryption = check_endpoint_media_transport(session->endpoint, stream); if (encryption == AST_SIP_MEDIA_TRANSPORT_INVALID) { return -1; } } ast_copy_pj_str(host, stream->conn ? &stream->conn->addr : &sdp->conn->addr, sizeof(host)); /* Ensure that the address provided is valid */ if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) { /* The provided host was actually invalid so we error out this negotiation */ return -1; } /* Using the connection information create an appropriate RTP instance */ if (!session_media->rtp && create_rtp(session, session_media, ast_sockaddr_is_ipv6(addrs))) { return -1; } res = setup_media_encryption(session, session_media, sdp, stream); if (res) { if (!session->endpoint->media.rtp.encryption_optimistic) { /* If optimistic encryption is disabled and crypto should have been enabled * but was not this session must fail. */ return -1; } /* There is no encryption, sad. */ session_media->encryption = AST_SIP_MEDIA_ENCRYPT_NONE; } /* If we've been explicitly configured to use the received transport OR if * encryption is on and crypto is present use the received transport. * This is done in case of optimistic because it may come in as RTP/AVP or RTP/SAVP depending * on the configuration of the remote endpoint (optimistic themselves or mandatory). */ if ((session->endpoint->media.rtp.use_received_transport) || ((encryption == AST_SIP_MEDIA_ENCRYPT_SDES) && !res)) { pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport); } if (set_caps(session, session_media, stream)) { return 0; } return 1; }