From 5e85c15cd7ebf20283859e57be893f57c3e0556e Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Sat, 26 Jan 2008 19:48:14 +0000 Subject: [PATCH] Update back to sofia tree now that we have identified the cause of the segfaults: Fri Jan 11 09:12:01 EST 2008 Bernhard Suttner * Using # in SOATAG_HOLD to set media as inactive instead of sendonly Fri Jan 11 09:15:18 EST 2008 Pekka.Pessi@nokia.com * soa_tag.c: documented SOATAG_HOLD() inactive mode Fri Jan 11 09:28:46 EST 2008 Pekka.Pessi@nokia.com * su_addrinfo.c: if su_getaddrinfo() service is NULL, try both with "0" and NULL Fri Jan 11 12:11:12 EST 2008 Pekka.Pessi@nokia.com * nta.c: NetModule hack re-prioritizing SRV records Original hack by Stefan Leuenberger . The hack reprioritizes the SRV records used with transaction in case a server refuses connection or it does not answer. Thu Jan 17 11:40:46 EST 2008 Pekka Pessi * soa_static.c: cleaned inactive hold, added tests Mon Jan 21 14:06:35 EST 2008 Pekka.Pessi@nokia.com * soa.c: using session state in soa_set_activity() The media mode bits are set using (local) session description instead of remote offer/answer when O/A has been completed. Mon Jan 21 14:08:08 EST 2008 Pekka.Pessi@nokia.com * soa_static.c: soa_sdp_mode_set() now includes wanted media state in offer The wanted media state is based on original user SDP and SOATAG_HOLD() content. Removed soa_sdp_mode_set_is_needed(), using dry-run parameter instead. Tue Jan 22 11:15:04 EST 2008 Pekka.Pessi@nokia.com * sip_util.c: updated sip_response_terminates_dialog() as per RFC 5057. Changes handling of 423 in case of SUBSCRIBE. Tue Jan 22 11:35:44 EST 2008 Pekka.Pessi@nokia.com * test_soa.c: testing hold with inactive, offered mode and setting remote activity flags while in hold Tue Jan 22 13:57:38 EST 2008 Pekka.Pessi@nokia.com * sres: added ttl parameter to sres_set_cached_srv_priority() and sres_cache_set_srv_priority(). Tue Jan 22 13:59:44 EST 2008 Pekka.Pessi@nokia.com * nta.c: added NTATAG_GRAYLIST(). Use NTATAG_GRAYLIST() as ttl value for sres_set_cached_srv_priority(). Wed Jan 23 10:07:30 EST 2008 Pekka Pessi * soa_static.c: fixed signedness error Wed Jan 23 11:05:23 EST 2008 Pekka.Pessi@nokia.com * nta.c: ignore tags in nta_leg_by_dialog() if they are empty strings Wed Jan 23 11:05:58 EST 2008 Pekka.Pessi@nokia.com * nta.c: asserting in proper place when handling queue tail git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7368 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- libs/sofia-sip/libsofia-sip-ua/nta/nta.c | 92 +++++++++++-- .../libsofia-sip-ua/nta/nta_internal.h | 2 + libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c | 27 +++- .../libsofia-sip-ua/nta/sofia-sip/nta_tag.h | 6 + libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c | 9 +- libs/sofia-sip/libsofia-sip-ua/soa/soa.c | 94 ++++++++------ .../libsofia-sip-ua/soa/soa_static.c | 121 ++++++++++-------- libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c | 22 +++- .../soa/sofia-sip/soa_session.h | 5 +- libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c | 57 ++++++++- .../sresolv/sofia-resolv/sres.h | 12 +- .../sresolv/sofia-resolv/sres_cache.h | 3 +- libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c | 5 +- .../libsofia-sip-ua/sresolv/sres_cache.c | 24 +++- .../su/sofia-sip/su_addrinfo.h | 2 +- .../libsofia-sip-ua/su/su_addrinfo.c | 4 + 16 files changed, 338 insertions(+), 147 deletions(-) diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c index 818d5afa4e..3107ca88b6 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c @@ -338,7 +338,7 @@ su_log_t nta_log[] = { SU_LOG_INIT("nta", "NTA_DEBUG", SU_DEBUG) }; * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(), * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(), * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(), - * NTATAG_EXTRA_100(), + * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(), * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS() * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(), * NTATAG_REL100(), @@ -400,6 +400,7 @@ nta_agent_t *nta_agent_create(su_root_t *root, agent->sa_t4 = NTA_SIP_T4; agent->sa_t1x64 = 64 * NTA_SIP_T1; agent->sa_timer_c = 185 * 1000; + agent->sa_graylist = 600; agent->sa_drop_prob = 0; agent->sa_is_a_uas = 0; agent->sa_progress = 60 * 1000; @@ -894,7 +895,7 @@ void agent_kill_terminator(nta_agent_t *agent) * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(), * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(), * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(), - * NTATAG_EXTRA_100(), + * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(), * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS() * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(), * NTATAG_REL100(), @@ -944,6 +945,7 @@ int agent_set_params(nta_agent_t *agent, tagi_t *tags) unsigned sip_t4 = agent->sa_t4; unsigned sip_t1x64 = agent->sa_t1x64; unsigned timer_c = agent->sa_timer_c; + unsigned graylist = agent->sa_graylist; unsigned blacklist = agent->sa_blacklist; int ua = agent->sa_is_a_uas; unsigned progress = agent->sa_progress; @@ -987,6 +989,7 @@ int agent_set_params(nta_agent_t *agent, tagi_t *tags) NTATAG_DEBUG_DROP_PROB_REF(drop_prob), NTATAG_DEFAULT_PROXY_REF(proxy), NTATAG_EXTRA_100_REF(extra_100), + NTATAG_GRAYLIST_REF(graylist), NTATAG_MAXSIZE_REF(maxsize), NTATAG_MAX_PROCEEDING_REF(max_proceeding), NTATAG_MAX_FORWARDS_REF(max_forwards), @@ -1140,6 +1143,12 @@ int agent_set_params(nta_agent_t *agent, tagi_t *tags) outgoing_queue_adjust(agent, agent->sa_out.inv_proceeding, timer_c); } + if (graylist > 24 * 60 * 60) + graylist = 24 * 60 * 60; + agent->sa_graylist = graylist; + + if (blacklist > 24 * 60 * 60) + blacklist = 24 * 60 * 60; agent->sa_blacklist = blacklist; if (progress == 0) @@ -1202,7 +1211,7 @@ void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu) * NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(), * NTATAG_CLIENT_RPORT_REF(), NTATAG_CONTACT_REF(), * NTATAG_DEBUG_DROP_PROB_REF(), NTATAG_DEFAULT_PROXY_REF(), - * NTATAG_EXTRA_100_REF(), + * NTATAG_EXTRA_100_REF(), NTATAG_GRAYLIST_REF(), * NTATAG_MAXSIZE_REF(), NTATAG_MAX_FORWARDS_REF(), NTATAG_MCLASS_REF(), * NTATAG_MERGE_482_REF(), NTATAG_MAX_PROCEEDING_REF(), * NTATAG_PASS_100_REF(), NTATAG_PASS_408_REF(), NTATAG_PRELOAD_REF(), @@ -1251,6 +1260,7 @@ int agent_get_params(nta_agent_t *agent, tagi_t *tags) NTATAG_DEBUG_DROP_PROB(agent->sa_drop_prob), NTATAG_DEFAULT_PROXY(agent->sa_default_proxy), NTATAG_EXTRA_100(agent->sa_extra_100), + NTATAG_GRAYLIST(agent->sa_graylist), NTATAG_MAXSIZE(agent->sa_maxsize), NTATAG_MAX_PROCEEDING(agent->sa_max_proceeding), NTATAG_MAX_FORWARDS(agent->sa_max_forwards->mf_count), @@ -4123,6 +4133,9 @@ int addr_cmp(url_t const *a, url_t const *b) * it must math * @param local_uri ignored * + * @note + * If @a remote_tag or @a local_tag is an empty string (""), the tag is + * ignored when matching legs. */ nta_leg_t *nta_leg_by_dialog(nta_agent_t const *agent, url_t const *request_uri, @@ -4224,9 +4237,9 @@ nta_leg_t *leg_find(nta_agent_t const *sa, if (!remote_tag != !from_tag && !local_tag != !to_tag) continue; - if (local_tag && to_tag && strcasecmp(local_tag, to_tag)) + if (local_tag && to_tag && strcasecmp(local_tag, to_tag) && to_tag[0]) continue; - if (remote_tag && from_tag && strcasecmp(remote_tag, from_tag)) + if (remote_tag && from_tag && strcasecmp(remote_tag, from_tag) && from_tag[0]) continue; if (leg_url && request_uri && url_cmp(leg_url, request_uri)) @@ -7649,6 +7662,7 @@ void outgoing_queue(outgoing_queue_t *queue, if (outgoing_is_queued(orq)) outgoing_remove(orq); + assert(orq->orq_next == NULL); assert(*queue->q_tail == NULL); orq->orq_timeout = set_timeout(orq->orq_agent, queue->q_timeout); @@ -7672,7 +7686,7 @@ void outgoing_remove(nta_outgoing_t *orq) if ((*orq->orq_prev = orq->orq_next)) orq->orq_next->orq_prev = orq->orq_prev; else - orq->orq_queue->q_tail = orq->orq_prev, assert(!*orq->orq_queue->q_tail); + orq->orq_queue->q_tail = orq->orq_prev; orq->orq_queue->q_length--; orq->orq_next = NULL; @@ -8828,8 +8842,8 @@ struct sipdns_query char const *sq_proto; char const *sq_domain; char sq_port[6]; /* port number */ - - uint16_t sq_type; + uint16_t sq_otype; /* origin type of query data (0 means request) */ + uint16_t sq_type; /* query type */ uint16_t sq_priority; /* priority or preference */ uint16_t sq_weight; /* preference or weight */ }; @@ -9060,6 +9074,65 @@ outgoing_try_another(nta_outgoing_t *orq) outgoing_reset_timer(orq); outgoing_queue(orq->orq_agent->sa_out.resolving, orq); + if (orq->orq_status > 0) + /* PP: don't hack priority if a preliminary response has been received */ + ; + else if (orq->orq_agent->sa_graylist == 0) + /* PP: priority hacking disabled */ + ; + /* NetModule hack: + * Move server that did not work to end of queue in sres cache + * + * the next request does not try to use the server that is currently down + * + * @TODO: fix cases with only A or AAAA answering, or all servers down. + */ + else if (sr && sr->sr_target) { + struct sipdns_query *sq; + + /* find latest A/AAAA record */ + sq = sr->sr_head; + if (!sq || (sr->sr_a_aaaa1 != sr->sr_a_aaaa2 && sq->sq_type == sr->sr_a_aaaa1)) + sq = sr->sr_done; + + if (sq && sq->sq_otype == sres_type_srv) { + char const *target = sq->sq_domain, *proto = sq->sq_proto; + unsigned prio = sq->sq_priority, maxprio = prio; + + SU_DEBUG_5(("nta: no response from %s:%s;transport=%s\n", target, sq->sq_port, proto)); + + for (sq = sr->sr_head; sq; sq = sq->sq_next) + if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio) + maxprio = sq->sq_priority; + + for (sq = sr->sr_done; sq; sq = sq->sq_next) + if (sq->sq_otype == sres_type_srv && sq->sq_priority > maxprio) + maxprio = sq->sq_priority; + + for (sq = sr->sr_done; sq; sq = sq->sq_next) { + int modified; + + if (sq->sq_type != sres_type_srv || strcmp(proto, sq->sq_proto)) + continue; + + /* modify the SRV record(s) corresponding to the latest A/AAAA record */ + modified = sres_set_cached_srv_priority( + orq->orq_agent->sa_resolver, + sq->sq_domain, + target, + sq->sq_port[0] ? (uint16_t)strtoul(sq->sq_port, NULL, 10) : 0, + orq->orq_agent->sa_graylist, + maxprio + 1); + + if (modified >= 0) + SU_DEBUG_3(("nta: reduced priority of %d %s SRV records (increase value to %u)\n", + modified, sq->sq_domain, maxprio + 1)); + else + SU_DEBUG_3(("nta: failed to reduce %s SRV priority\n", sq->sq_domain)); + } + } + } + return outgoing_resolve_next(orq); } @@ -9338,6 +9411,7 @@ void outgoing_answer_naptr(sres_context_t *orq, sq = su_zalloc(home, (sizeof *sq) + rlen); *tail = sq, tail = &sq->sq_next; + sq->sq_otype = sres_type_naptr; sq->sq_priority = na->na_prefer; sq->sq_weight = j; sq->sq_type = type; @@ -9438,11 +9512,11 @@ outgoing_answer_srv(sres_context_t *orq, sres_query_t *q, if (sq) { *tail = sq, tail = &sq->sq_next; + sq->sq_otype = sres_type_srv; sq->sq_type = sr->sr_a_aaaa1; sq->sq_proto = sq0->sq_proto; sq->sq_domain = memcpy(sq + 1, srv->srv_target, tlen); snprintf(sq->sq_port, sizeof(sq->sq_port), "%u", srv->srv_port); - sq->sq_priority = srv->srv_priority; sq->sq_weight = srv->srv_weight; } diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h b/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h index 613c5313fc..b8e29ff18b 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta_internal.h @@ -167,6 +167,8 @@ struct nta_agent_s /** SIP timer C - interval between provisional responses receivedxs */ unsigned sa_timer_c; + /** Graylisting period */ + unsigned sa_graylist; /** Blacklisting period */ unsigned sa_blacklist; diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c index 7b46e68ae3..58efc6f27a 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta_tag.c @@ -643,6 +643,31 @@ tag_typedef_t ntatag_progress = UINTTAG_TYPEDEF(progress); */ tag_typedef_t ntatag_timer_c = UINTTAG_TYPEDEF(timer_c); +/**@def NTATAG_GRAYLIST(x) + * + * Avoid failed servers. + * + * The NTATAG_GRAYLIST() provides the time that the servers are avoided + * after a request sent to them has been failed. Avoiding means that if a + * domain provides multiple servers, the failed servers are tried last. + * + * @par Used with + * nua_create(), nua_set_params(), + * nta_agent_create(), nta_agent_set_params() + * + * @par Parameter type + * unsigned int + * + * @par Values + * - Number of seconds that server is kept in graylist, from 0 to 86400. + * + * @par Default Value + * - 600 (graylist server for 10 minutes) + * + * @sa NTATAG_BLACKLIST(), NTATAG_TIMEOUT_408() + */ +tag_typedef_t ntatag_graylist = UINTTAG_TYPEDEF(graylist); + /**@def NTATAG_BLACKLIST(x) * * Add Retry-After header to error responses returned to application. @@ -660,7 +685,7 @@ tag_typedef_t ntatag_timer_c = UINTTAG_TYPEDEF(timer_c); * unsigned int * * @par Values - * - Value of delta-seconds in @RetryAfter header + * - Value of @i delta-seconds in @RetryAfter header, from 0 to 86400 * * @par Default Value * - 0 (no Retry-After is included) diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h b/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h index 82e4b1c969..0b7ffb4e93 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h +++ b/libs/sofia-sip/libsofia-sip-ua/nta/sofia-sip/nta_tag.h @@ -203,6 +203,12 @@ NTA_DLL extern tag_typedef_t ntatag_timer_c; NTA_DLL extern tag_typedef_t ntatag_timer_c_ref; #define NTATAG_TIMER_C_REF(x) ntatag_timer_c_ref, tag_uint_vr(&(x)) +NTA_DLL extern tag_typedef_t ntatag_graylist; +#define NTATAG_GRAYLIST(x) ntatag_graylist, tag_uint_v((x)) + +NTA_DLL extern tag_typedef_t ntatag_graylist_ref; +#define NTATAG_GRAYLIST_REF(x) ntatag_graylist_ref, tag_uint_vr(&(x)) + NTA_DLL extern tag_typedef_t ntatag_blacklist; #define NTATAG_BLACKLIST(x) ntatag_blacklist, tag_uint_v((x)) diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c index 5d371ea98e..3862de7f73 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c @@ -883,8 +883,7 @@ sip_security_client_select(sip_security_client_t const *client, * decide whether to gracefully terminate or not, the * @a *return_graceful_terminate_usage is left unmodified. * - * @sa - * http://www.ietf.org/internet-drafts/draft-ietf-sipping-dialogusage-02.txt + * @RFC 5057 */ int sip_response_terminates_dialog(int response_code, sip_method_t method, @@ -1060,8 +1059,6 @@ int sip_response_terminates_dialog(int response_code, usage in an existing dialog, no new usage is created and existing usages are unaffected. */ - *return_graceful_terminate_usage = 0; - return 0; case 423: /** @par 423 Interval Too Brief @@ -1070,8 +1067,6 @@ int sip_response_terminates_dialog(int response_code, subscribe usage is not destroyed (or otherwise affected). No other usages of the dialog are affected. */ - *return_graceful_terminate_usage = 0; - return sip_method_subscribe == method ? terminate_usage : no_effect; case 428: /** @par 428 Use Identity Header @@ -1079,8 +1074,6 @@ int sip_response_terminates_dialog(int response_code, the usage. The usage is not affected. The dialog is only affected by a change in its local @CSeq. No other usages of the dialog are affected. */ - *return_graceful_terminate_usage = 0; - return 0; case 429: /** @par 429 Provide Referrer Identity diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa.c index e5a6e2e7d6..8689800514 100644 --- a/libs/sofia-sip/libsofia-sip-ua/soa/soa.c +++ b/libs/sofia-sip/libsofia-sip-ua/soa/soa.c @@ -70,10 +70,6 @@ static char const __func__[] = "soa"; /* ======================================================================== */ /* Internal prototypes */ -void soa_set_activity(soa_session_t *ss, - sdp_media_t const *, - int remote); - su_inline int soa_media_is_ready(soa_session_t const *ss); enum soa_sdp_kind { @@ -1171,7 +1167,7 @@ int soa_base_set_remote_sdp(soa_session_t *ss, if (!new_version) return 0; - soa_set_activity(ss, sdp->sdp_media, 1); + soa_set_activity(ss, sdp->sdp_media, soa_activity_remote); ss->ss_remote_version++; @@ -1454,7 +1450,7 @@ int soa_base_generate_offer(soa_session_t *ss, if (!sdp) return -1; - soa_set_activity(ss, sdp->sdp_media, 0); + soa_set_activity(ss, sdp->sdp_media, soa_activity_local); /* Wanted activity */ ss->ss_offer_sent = 1; ss->ss_answer_recv = 0; @@ -1542,8 +1538,7 @@ int soa_base_generate_answer(soa_session_t *ss, su_free(ss->ss_home, ss->ss_rsession); ss->ss_rsession = rsession; - soa_set_activity(ss, l_sdp->sdp_media, 0); - soa_set_activity(ss, r_sdp->sdp_media, 1); + soa_set_activity(ss, l_sdp->sdp_media, soa_activity_session); ss->ss_offer_recv = 1; ss->ss_answer_sent = 1; @@ -1624,8 +1619,7 @@ int soa_base_process_answer(soa_session_t *ss, su_free(ss->ss_home, ss->ss_rsession); ss->ss_rsession = rsession; - soa_set_activity(ss, l_sdp->sdp_media, 0); - soa_set_activity(ss, r_sdp->sdp_media, 1); + soa_set_activity(ss, l_sdp->sdp_media, soa_activity_session); ss->ss_answer_recv = 1; ss->ss_complete = 1; @@ -1692,7 +1686,7 @@ int soa_base_process_reject(soa_session_t *ss, if (!l_sdp) return -1; - soa_set_activity(ss, l_sdp->sdp_media, 0); + soa_set_activity(ss, l_sdp->sdp_media, soa_activity_session); ss->ss_offer_sent = 0; @@ -1783,8 +1777,7 @@ void soa_base_terminate(soa_session_t *ss, char const *option) ss->ss_oa_rounds = 0; soa_description_free(ss, ss->ss_remote); - soa_set_activity(ss, NULL, 0); - soa_set_activity(ss, NULL, 1); + soa_set_activity(ss, NULL, soa_activity_session); } /** Return true if the SDP Offer/Answer negotation is complete. @@ -1889,56 +1882,75 @@ int soa_media_is_ready(soa_session_t const *ss) void soa_set_activity(soa_session_t *ss, sdp_media_t const *m, - int remote) + enum soa_activity activity) { struct soa_media_activity *ma; sdp_connection_t const *c; - int mode; - int ma_audio = SOA_ACTIVE_DISABLED; - int ma_video = SOA_ACTIVE_DISABLED; - int ma_chat = SOA_ACTIVE_DISABLED; - int ma_image = SOA_ACTIVE_DISABLED; - int *p; + int mode, swap; + int l_audio = SOA_ACTIVE_DISABLED, r_audio = SOA_ACTIVE_DISABLED; + int l_video = SOA_ACTIVE_DISABLED, r_video = SOA_ACTIVE_DISABLED; + int l_chat = SOA_ACTIVE_DISABLED, r_chat = SOA_ACTIVE_DISABLED; + int l_image = SOA_ACTIVE_DISABLED, r_image = SOA_ACTIVE_DISABLED; - remote = !!remote; - - ma = remote ? ss->ss_remote_activity : ss->ss_local_activity; + int *l, *r; for (; m; m = m->m_next) { if (m->m_type == sdp_media_audio) - p = &ma_audio; + l = &l_audio, r = &r_audio; else if (m->m_type == sdp_media_video) - p = &ma_video; + l = &l_video, r = &r_video; else if (m->m_type == sdp_media_image) - p = &ma_image; + l = &l_image, r = &r_image; else if (strcasecmp(m->m_type_name, "message") == 0) - p = &ma_chat; + l = &l_chat, r = &r_chat; else continue; if (m->m_rejected) { - if (*p < 0) - *p = SOA_ACTIVE_REJECTED; + if (*l < 0) *l = SOA_ACTIVE_REJECTED; + if (*r < 0) *r = SOA_ACTIVE_REJECTED; continue; } - mode = m->m_mode; + mode = m->m_mode, swap = ((mode << 1) & 2) | ((mode >> 1) & 1); c = sdp_media_connections((sdp_media_t *)m); - if (remote != (c && c->c_mcast)) - mode = ((mode << 1) & 2) | ((mode >> 1) & 1); - - if (*p < 0) - *p = mode; - else - *p |= mode; + switch (activity) { + case soa_activity_local: + *l &= SOA_ACTIVE_SENDRECV; + *l |= c && c->c_mcast ? swap : mode; + break; + case soa_activity_remote: + *r &= SOA_ACTIVE_SENDRECV; + *r = c && c->c_mcast ? mode : swap; + break; + case soa_activity_session: + *l &= SOA_ACTIVE_SENDRECV; + *l |= c && c->c_mcast ? swap : mode; + *r &= SOA_ACTIVE_SENDRECV; + *r = c && c->c_mcast ? swap : mode; + break; + } } - ma->ma_audio = ma_audio; - ma->ma_video = ma_video; - ma->ma_image = ma_image; - ma->ma_chat = ma_chat; + if (activity == soa_activity_local || + activity == soa_activity_session) { + ma = ss->ss_local_activity; + ma->ma_audio = l_audio; + ma->ma_video = l_video; + ma->ma_image = l_image; + ma->ma_chat = l_chat; + } + + if (activity == soa_activity_remote || + activity == soa_activity_session) { + ma = ss->ss_remote_activity; + ma->ma_audio = r_audio; + ma->ma_video = r_video; + ma->ma_image = r_image; + ma->ma_chat = r_chat; + } } /* ----------------------------------------------------------------------*/ diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c index fdeecdb556..99642a6070 100644 --- a/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c +++ b/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c @@ -974,58 +974,28 @@ int soa_sdp_reject(su_home_t *home, return 0; } -/** Check if @a session mode should be changed. */ + +/** Update mode within session. + * + * @sa soatag_hold + * + * @retval 1 if session was changed (or to be changed, if @a dryrun is nonzero) + */ static -int soa_sdp_mode_set_is_needed(sdp_session_t const *session, - sdp_session_t const *remote, - char const *hold) -{ - sdp_media_t const *sm, *rm, *rm_next; - int hold_all; - sdp_mode_t recv_mode; - - SU_DEBUG_7(("soa_sdp_mode_set_is_needed(%p, %p, \"%s\"): called\n", - (void *)session, (void *)remote, hold ? hold : "")); - - if (!session ) - return 0; - - hold_all = str0cmp(hold, "*") == 0; - - rm = remote ? remote->sdp_media : NULL, rm_next = NULL; - - for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next) { - rm_next = rm ? rm->m_next : NULL; - - if (sm->m_rejected) - continue; - - if (rm) { - /* Mode bits do not match */ - if (((rm->m_mode & sdp_recvonly) == sdp_recvonly) - != ((sm->m_mode & sdp_sendonly) == sdp_sendonly)) - return 1; - } - - recv_mode = sm->m_mode & sdp_recvonly; - if (recv_mode && hold && - (hold_all || strcasestr(hold, sm->m_type_name))) - return 1; - } - - return 0; -} - - -/** Update mode within session */ -static -int soa_sdp_mode_set(sdp_session_t *session, +int soa_sdp_mode_set(sdp_session_t const *user, + int const *s2u, + sdp_session_t *session, sdp_session_t const *remote, - char const *hold) + char const *hold, + int dryrun) { sdp_media_t *sm; - sdp_media_t const *rm, *rm_next; + sdp_media_t const *rm, *rm_next, *um; + int retval = 0, i, j; int hold_all; + int inactive_all; + int inactive = 0; + char const *hold_media = NULL; sdp_mode_t send_mode, recv_mode; SU_DEBUG_7(("soa_sdp_mode_set(%p, %p, \"%s\"): called\n", @@ -1037,25 +1007,58 @@ int soa_sdp_mode_set(sdp_session_t *session, rm = remote ? remote->sdp_media : NULL, rm_next = NULL; hold_all = str0cmp(hold, "*") == 0; + inactive_all = str0cmp(hold, "#") == 0; - for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next) { + i = 0; + + for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next, i++) { rm_next = rm ? rm->m_next : NULL; + inactive = 0; if (sm->m_rejected) continue; - send_mode = sdp_sendonly; + assert(s2u); + + for (j = 0, um = user->sdp_media; j != s2u[i]; um = um->m_next, j++) + assert(um); + assert(um); + + send_mode = um->m_mode & sdp_sendonly; if (rm) send_mode = (rm->m_mode & sdp_recvonly) ? sdp_sendonly : 0; - recv_mode = sm->m_mode & sdp_recvonly; - if (recv_mode && hold && (hold_all || strcasestr(hold, sm->m_type_name))) - recv_mode = 0; + recv_mode = um->m_mode & sdp_recvonly; - sm->m_mode = recv_mode | send_mode; + if (rm && rm->m_mode == sdp_inactive) { + send_mode = recv_mode = 0; + } + else if (inactive_all) { + send_mode = recv_mode = 0; + } + else if (hold_all) { + recv_mode = 0; + } + else if (hold && (hold_media = strcasestr(hold, sm->m_type_name))) { + recv_mode = 0; + hold_media += strlen(sm->m_type_name); + hold_media += strspn(hold_media, " \t"); + if (hold_media[0] == '=') { + hold_media += strspn(hold, " \t"); + if (strncasecmp(hold_media, "inactive", strlen("inactive")) == 0) + recv_mode = send_mode = 0; + } + } + + if (sm->m_mode != (unsigned)(recv_mode | send_mode)) + retval = 1; + + if (!dryrun) { + sm->m_mode = recv_mode | send_mode; + } } - return 0; + return retval; } enum offer_answer_action { @@ -1213,16 +1216,22 @@ static int offer_answer_step(soa_session_t *ss, /* Step D: Set media mode bits */ switch (action) { + int const *s2u_; + case generate_offer: case generate_answer: case process_answer: - if (soa_sdp_mode_set_is_needed(local, remote, ss->ss_hold)) { + s2u_ = s2u; + + if (!s2u_) s2u_ = sss->sss_s2u; + + if (soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 1)) { if (local != local0) { *local0 = *local, local = local0; DUP_LOCAL(local); } - soa_sdp_mode_set(local, remote, ss->ss_hold); + soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 0); } break; default: diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c index 29da494cdc..f3e000fb3f 100644 --- a/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c +++ b/libs/sofia-sip/libsofia-sip-ua/soa/soa_tag.c @@ -585,12 +585,22 @@ tag_typedef_t soatag_srtp_integrity = BOOLTAG_TYPEDEF(srtp_integrity); /**@def SOATAG_HOLD(x) * - * Hold media stream or streams. When putting a SIP session on hold, the - * application can include, e.g., SOATAG_HOLD("audio") or - * SOATAG_HOLD("video") or SOATAG_HOLD("audio, video") or SOATAG_HOLD("*") - * as @soa parameters. When resuming the session, it can include - * SOATAG_HOLD(NULL). Note that last SOATAG_HOLD() in the tag list will - * override the SOATAG_HOLD() tags before it. + * Hold media stream or streams. + * + * The hold media stream will have the attribute a=sendonly (meaning that + * some hold announcements or pause music is sent to the held party but that + * the held party should not generate any media) or a=inactive (meaning that + * no media is sent). + * + * When putting a SIP session on hold with sendonly, the application can + * include, e.g., SOATAG_HOLD("audio") or SOATAG_HOLD("video") or + * SOATAG_HOLD("audio, video") or SOATAG_HOLD("*") as @soa parameters. When + * using inactive instead, the application should use "#" or + * "audio=inactive" instead. When resuming the session, application should + * include the tag SOATAG_HOLD(NULL). + * + * Note that last SOATAG_HOLD() in the tag list will override the + * SOATAG_HOLD() tags before it. * * @par Used with * soa_set_params(), soa_get_params(), soa_get_paramlist() \n diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h b/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h index 8ff75d0773..f61bd74013 100644 --- a/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h +++ b/libs/sofia-sip/libsofia-sip-ua/soa/sofia-sip/soa_session.h @@ -238,8 +238,11 @@ SOFIAPUBFUN int soa_has_received_sdp(soa_session_t const *ss); SOFIAPUBFUN int soa_set_status(soa_session_t *ss, int status, char const *phrase); +enum soa_activity { soa_activity_local, soa_activity_remote, soa_activity_session }; + SOFIAPUBFUN void soa_set_activity(soa_session_t *ss, - sdp_media_t const *m, int remote); + sdp_media_t const *m, + enum soa_activity activity); SOFIAPUBFUN int soa_description_set(soa_session_t *ss, struct soa_description *ssd, diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c b/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c index 4054f18920..cbd808a468 100644 --- a/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c +++ b/libs/sofia-sip/libsofia-sip-ua/soa/test_soa.c @@ -451,20 +451,67 @@ int test_static_offer_answer(struct context *ctx) TEST(soa_is_audio_active(a), SOA_ACTIVE_SENDONLY); TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDONLY); - /* 'A' will release hold. */ - TEST(soa_set_params(a, SOATAG_HOLD(NULL), TAG_END()), 1); + /* 'A' will put call inactive */ + offer = NONE; + TEST(soa_set_params(a, SOATAG_HOLD("#"), TAG_END()), 1); TEST(soa_generate_offer(a, 1, test_completed), 0); TEST(soa_get_local_sdp(a, NULL, &offer, &offerlen), 1); TEST_1(offer != NULL && offer != NONE); - TEST_1(!strstr(offer, "a=sendonly")); + TEST_1(strstr(offer, "a=inactive")); TEST(soa_set_remote_sdp(b, 0, offer, offerlen), 1); TEST(soa_generate_answer(b, test_completed), 0); TEST_1(soa_is_complete(b)); TEST(soa_activate(b, NULL), 0); TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1); TEST_1(answer != NULL && answer != NONE); - TEST_1(!strstr(answer, "a=recvonly")); + TEST_1(strstr(answer, "a=inactive")); + TEST(soa_set_remote_sdp(a, 0, answer, -1), 1); + TEST(soa_process_answer(a, test_completed), 0); + TEST(soa_activate(a, NULL), 0); + + TEST(soa_is_audio_active(a), SOA_ACTIVE_INACTIVE); + TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_INACTIVE); + + /* B will send an offer to A, but there is no change in O/A status */ + TEST(soa_generate_offer(b, 1, test_completed), 0); + TEST(soa_get_local_sdp(b, NULL, &offer, &offerlen), 1); + TEST_1(offer != NULL && offer != NONE); + TEST_1(!strstr(offer, "a=inactive")); + printf("offer:\n%s", offer); + TEST(soa_set_remote_sdp(a, 0, offer, offerlen), 1); + TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_SENDRECV); + TEST(soa_generate_answer(a, test_completed), 0); + TEST(soa_is_audio_active(a), SOA_ACTIVE_INACTIVE); + TEST(soa_is_remote_audio_active(a), SOA_ACTIVE_INACTIVE); + TEST_1(soa_is_complete(a)); + TEST(soa_activate(a, NULL), 0); + TEST(soa_get_local_sdp(a, NULL, &answer, &answerlen), 1); + TEST_1(answer != NULL && answer != NONE); + TEST_1(strstr(answer, "a=inactive")); + printf("answer:\n%s", answer); + TEST(soa_set_remote_sdp(b, 0, answer, -1), 1); + TEST(soa_process_answer(b, test_completed), 0); + TEST(soa_activate(b, NULL), 0); + + + TEST(soa_is_audio_active(b), SOA_ACTIVE_INACTIVE); + TEST(soa_is_remote_audio_active(b), SOA_ACTIVE_INACTIVE); + + /* 'A' will release hold. */ + TEST(soa_set_params(a, SOATAG_HOLD(NULL), TAG_END()), 1); + + TEST(soa_generate_offer(a, 1, test_completed), 0); + TEST(soa_get_local_sdp(a, NULL, &offer, &offerlen), 1); + TEST_1(offer != NULL && offer != NONE); + TEST_1(!strstr(offer, "a=sendonly") && !strstr(offer, "a=inactive")); + TEST(soa_set_remote_sdp(b, 0, offer, offerlen), 1); + TEST(soa_generate_answer(b, test_completed), 0); + TEST_1(soa_is_complete(b)); + TEST(soa_activate(b, NULL), 0); + TEST(soa_get_local_sdp(b, NULL, &answer, &answerlen), 1); + TEST_1(answer != NULL && answer != NONE); + TEST_1(!strstr(answer, "a=recvonly") && !strstr(answer, "a=inactive")); TEST(soa_set_remote_sdp(a, 0, answer, -1), 1); TEST(soa_process_answer(a, test_completed), 0); TEST(soa_activate(a, NULL), 0); @@ -1329,7 +1376,7 @@ int test_asynch_offer_answer(struct context *ctx) { BEGIN(); -#if 0 +#if 0 /* This has never been implemented */ int n; char const *caps = NONE, *offer = NONE, *answer = NONE; diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h b/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h index 668bcb67ef..b8d33b59bd 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h +++ b/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres.h @@ -218,21 +218,13 @@ sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res, uint16_t type, struct sockaddr const *addr); -/**Modify the priority of the specified SRV records. - * - * @param res pointer to resolver object - * @param service domain name of the SRV records to search in cache - * @param target target to lower the prio - * @param port port number to lower the prio - * @param newprio new priority value - * - * @return Number of modified records on success, -1 otherwise - */ +/**Modify the priority of the specified SRV records. */ SRESPUBFUN int sres_set_cached_srv_priority(sres_resolver_t *res, char const *domain, char const *target, uint16_t port, + uint32_t newttl, uint16_t newprio); diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h b/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h index 19a0e612f7..2639ce0c37 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h +++ b/libs/sofia-sip/libsofia-sip-ua/sresolv/sofia-resolv/sres_cache.h @@ -107,7 +107,8 @@ SRESPUBFUN int sres_cache_set_srv_priority(sres_cache_t *, char const *domain, char const *target, uint16_t port, - uint16_t prio); + uint32_t newttl, + uint16_t newprio); #ifdef __cplusplus } diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c b/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c index ad2702aa65..a5bb9dc1ed 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c +++ b/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c @@ -1358,6 +1358,7 @@ sres_cached_answers_sockaddr(sres_resolver_t *res, * @param target SRV target of the SRV record(s) to modify * @param port port number of SRV record(s) to modify * (in host byte order) + * @param ttl new ttl for SRV records of the domain * @param priority new priority value (0=highest, 65535=lowest) * * @sa sres_cache_set_srv_priority() @@ -1368,6 +1369,7 @@ int sres_set_cached_srv_priority(sres_resolver_t *res, char const *domain, char const *target, uint16_t port, + uint32_t ttl, uint16_t priority) { char rooted_domain[SRES_MAXDNAME]; @@ -1381,7 +1383,8 @@ int sres_set_cached_srv_priority(sres_resolver_t *res, return -1; return sres_cache_set_srv_priority(res->res_cache, - domain, target, port, priority); + domain, target, port, + ttl, priority); } diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c b/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c index ab8c954c0b..5c2d6d2602 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c +++ b/libs/sofia-sip/libsofia-sip-ua/sresolv/sres_cache.c @@ -483,6 +483,7 @@ void sres_cache_clean(sres_cache_t *cache, time_t now) * @param target SRV target of the SRV record(s) to modify * @param port port number of SRV record(s) to modify * (in host byte order) + * @param ttl new ttl * @param priority new priority value (0=highest, 65535=lowest) * * @sa sres_set_cached_srv_priority() @@ -493,12 +494,14 @@ int sres_cache_set_srv_priority(sres_cache_t *cache, char const *domain, char const *target, uint16_t port, + uint32_t ttl, uint16_t priority) { int ret = 0; unsigned hash; sres_rr_hash_entry_t **iter; - + time_t expires; + if (cache == NULL || domain == NULL || target == NULL) return -1; @@ -507,6 +510,9 @@ int sres_cache_set_srv_priority(sres_cache_t *cache, if (!LOCK(cache)) return -1; + time(&expires); + expires += ttl; + for (iter = sres_htable_hash(cache->cache_hash, hash); iter && *iter; iter = sres_htable_next(cache->cache_hash, iter)) { @@ -514,13 +520,17 @@ int sres_cache_set_srv_priority(sres_cache_t *cache, if (rr && rr->sr_name && sres_type_srv == rr->sr_type && - (port == 0 || rr->sr_srv->srv_port == port) && - rr->sr_srv->srv_target && - strcasecmp(rr->sr_srv->srv_target, target) == 0 && strcasecmp(rr->sr_name, domain) == 0) { - /* record found --> change priority of server */ - rr->sr_srv->srv_priority = priority; - ret++; + + (*iter)->rr_expires = expires; + + if ((port == 0 || rr->sr_srv->srv_port == port) && + rr->sr_srv->srv_target && + strcasecmp(rr->sr_srv->srv_target, target) == 0) { + /* record found --> change priority of server */ + rr->sr_srv->srv_priority = priority; + ret++; + } } } diff --git a/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h b/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h index 45368a98ff..b13a695247 100644 --- a/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h +++ b/libs/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h @@ -126,7 +126,7 @@ struct addrinfo { #define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST) #endif -/** RFC 1576 address info structure. */ +/** @RFC1576 address info structure. */ typedef struct addrinfo su_addrinfo_t; /** Translate address and service. */ diff --git a/libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c b/libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c index 5ce50e0d96..f24e4f7dbb 100644 --- a/libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c +++ b/libs/sofia-sip/libsofia-sip-ua/su/su_addrinfo.c @@ -893,6 +893,7 @@ int su_getaddrinfo(char const *node, char const *service, { int retval; su_addrinfo_t *ai; + char const *realservice = service; if (!service || service[0] == '\0') service = "0"; @@ -932,6 +933,9 @@ int su_getaddrinfo(char const *node, char const *service, retval = getaddrinfo(node, service, hints, res); + if (service != realservice && retval == EAI_SERVICE) + retval = getaddrinfo(node, realservice, hints, res); + if (retval == 0) { for (ai = *res; ai; ai = ai->ai_next) { if (ai->ai_protocol)