Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 428405) +++ channels/chan_sip.c (working copy) @@ -1623,7 +1623,7 @@ static void set_destination(struct sip_pvt *p, char *uri); static void add_date(struct sip_request *req); static void add_expires(struct sip_request *req, int expires); -static void build_contact(struct sip_pvt *p); +static void build_contact(struct sip_pvt *p, struct sip_request *req, int incoming); /*------Request handling functions */ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int *recount, int *nounlock); @@ -13666,22 +13666,110 @@ if (!ast_strlen_zero(c)) { ast_string_field_set(p, uri, c); } +} +/*! + * \brief Determine if, as a UAS, we need to use a SIPS contact. + * + * This uses the rules defined in RFC 3261 section 12.1.1 to + * determine if a SIPS URI should be used as the Contact header + * when responding to incoming SIP requests. + * + * \param req The incoming SIP request + * \retval 0 SIPS is not required + * \retval 1 SIPS is required + */ +static int uas_sips_contact(struct sip_request *req) +{ + const char *record_route = sip_get_header(req, "Record-Route"); + + if (record_route) { + char *record_route_uri = get_in_brackets(ast_strdupa(record_route)); + + if (!strncmp(record_route_uri, "sips:", 5)) { + return 1; + } + } else { + const char *contact = sip_get_header(req, "Contact"); + char *contact_uri = get_in_brackets(ast_strdupa(contact)); + + if (!strncmp(contact_uri, "sips:", 5)) { + return 1; + } + } + + return 0; } +/*! + * \brief Determine if, as a UAC, we need to use a SIPS Contact. + * + * This uses the rules defined in RFC 3621 sectcion 8.1.1.8 to + * determine if a SIPS URI should be used as the Contact header + * on our outgoing request. + * + * \param req The outgoing SIP request + * \param 0 SIPS is not required + * \param 1 SIPS is required + */ +static int uac_sips_contact(struct sip_request *req) +{ + const char *route = sip_get_header(req, "Route"); + + if (route) { + char *route_uri = get_in_brackets(ast_strdupa(route)); + + if (!strncmp(route_uri, "sips:", 5)) { + return 1; + } + } + + return 0; +} + /*! \brief Build contact header - the contact header we send out */ -static void build_contact(struct sip_pvt *p) +/*! + * \brief Build contact header + * + * This is the Contact header that we send out in SIP requests and responses + * involving this sip_pvt. + * + * The incoming parameter is used to tell if we are building the request parameter + * is an incoming SIP request that we are building the Contact header in response to, + * or if the req parameter is an outbound SIP request that we will later be adding + * the Contact header to. + * + * \param p The sip_pvt where the built Contact will be saved. + * \param req The request that triggered the creation of a Contact header. + * \praram incoming Indicates if the Contact header is being created for a response to an incoming request + */ +static void build_contact(struct sip_pvt *p, struct sip_request *req, int incoming) { char tmp[SIPBUFSIZE]; char *user = ast_uri_encode(p->exten, tmp, sizeof(tmp), ast_uri_sip_user); + int use_sips = 0; + /* All requests to SIPS URIs must have a SIPS Contact URI */ + if (!strncmp(REQ_OFFSET_TO_STR(req, rlpart2), "sips:", 5)) { + use_sips = 1; + } + + if (!use_sips) { + if (incoming) { + use_sips = uas_sips_contact(req); + } else { + use_sips = uac_sips_contact(req); + } + } + if (p->socket.type == SIP_TRANSPORT_UDP) { - ast_string_field_build(p, our_contact, "", user, - ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip)); + ast_string_field_build(p, our_contact, "<%s:%s%s%s>", use_sips ? "sips" : "sip", + user, ast_strlen_zero(user) ? "" : "@", + ast_sockaddr_stringify_remote(&p->ourip)); } else { - ast_string_field_build(p, our_contact, "", user, - ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip), - sip_get_transport(p->socket.type)); + ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>", + use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@", + ast_sockaddr_stringify_remote(&p->ourip), sip_get_transport(p->socket.type)); } } @@ -13877,7 +13965,7 @@ add_header(req, "From", from); add_header(req, "To", to); ast_string_field_set(p, exten, l); - build_contact(p); + build_contact(p, req, 0); add_header(req, "Contact", p->our_contact); add_header(req, "Call-ID", p->callid); add_header(req, "CSeq", tmp_n); @@ -14288,7 +14376,6 @@ set_socket_transport(&mwi->call->socket, mwi->transport); mwi->call->socket.port = htons(mwi->portno); ast_sip_ouraddrfor(&mwi->call->sa, &mwi->call->ourip, mwi->call); - build_contact(mwi->call); build_via(mwi->call); /* Change the dialog callid. */ @@ -15250,7 +15337,6 @@ internal network so we can register through nat */ ast_sip_ouraddrfor(&p->sa, &p->ourip, p); - build_contact(p); } /* set up a timeout */ @@ -15329,6 +15415,7 @@ } add_expires(&req, r->expiry); + build_contact(p, &req, 0); add_header(&req, "Contact", p->our_contact); initialize_initreq(p, &req); @@ -16853,7 +16940,7 @@ } ast_string_field_set(p, exten, name); - build_contact(p); + build_contact(p, req, 1); if (req->ignore) { /* Expires is a special case, where we only want to load the peer if this isn't a deregistration attempt */ const char *expires = sip_get_header(req, "Expires"); @@ -18332,8 +18419,9 @@ if (t) *t = '\0'; - if (ast_strlen_zero(p->our_contact)) - build_contact(p); + if (ast_strlen_zero(p->our_contact)) { + build_contact(p, req, 1); + } } of = get_in_brackets(of); @@ -24764,7 +24852,7 @@ /* must go through authentication before getting here */ gotdest = get_destination(p, req, NULL); - build_contact(p); + build_contact(p, req, 1); if (ast_strlen_zero(p->context)) ast_string_field_set(p, context, sip_cfg.default_context); @@ -25623,7 +25711,7 @@ } gotdest = get_destination(p, NULL, &cc_recall_core_id); /* Get destination right away */ extract_uri(p, req); /* Get the Contact URI */ - build_contact(p); /* Build our contact header */ + build_contact(p, req, 1); /* Build our contact header */ if (p->rtp) { ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833); @@ -27745,7 +27833,7 @@ /* Get full contact header - this needs to be used as a request URI in NOTIFY's */ parse_ok_contact(p, req); - build_contact(p); + build_contact(p, req, 1); /* Initialize tag for new subscriptions */ if (ast_strlen_zero(p->tag)) {