/** Restart request. * * @retval 1 if restarted * @retval 0 otherwise */ int nua_client_restart(nua_client_request_t *cr, int status, char const *phrase) { nua_handle_t *nh = cr->cr_owner; nta_outgoing_t *orq; int error = -1, terminated, graceful; if (cr->cr_retry_count > NH_PGET(nh, retry_count)) return 0; orq = cr->cr_orq, cr->cr_orq = NULL; assert(orq); terminated = cr->cr_terminated, cr->cr_terminated = 0; graceful = cr->cr_graceful, cr->cr_graceful = 0; cr->cr_restarting = 1; error = nua_client_request_sendmsg(cr); cr->cr_restarting = 0; if (error) { cr->cr_graceful = graceful; cr->cr_terminated = terminated; assert(cr->cr_orq == NULL); cr->cr_orq = orq; return 0; } nua_client_report(cr, status, phrase, NULL, orq, NULL); nta_outgoing_destroy(orq); nua_client_request_unref(cr); /* ... reference used by old orq */ return 1; }
static int response_to_keepalive_options(outbound_t *ob, nta_outgoing_t *orq, sip_t const *sip) { int status = 408; char const *phrase = sip_408_Request_timeout; if (sip && sip->sip_status) { status = sip->sip_status->st_status; phrase = sip->sip_status->st_phrase; } if (status == 100) { /* This probably means that we are in trouble. whattodo, whattodo */ } if (status >= 200) { if (orq == ob->ob_keepalive.orq) ob->ob_keepalive.orq = NULL; process_response_to_keepalive_options(ob, orq, sip, status, phrase); nta_outgoing_destroy(orq); } return 0; }
END_TEST START_TEST(client_2_0_1) { nta_outgoing_t *orq; struct message *request; struct event *response; S2_CASE("client-2.0.1", "Send MESSAGE", "Basic non-INVITE transaction with " "numeric per-transaction outbound proxy"); orq = nta_outgoing_tcreate(s2->default_leg, s2_nta_orq_callback, NULL, (url_string_t *)s2sip->contact->m_url, SIP_METHOD_MESSAGE, URL_STRING_MAKE("sip:test2.0.example.org"), SIPTAG_FROM_STR("<sip:[email protected]>"), TAG_END()); fail_unless(orq != NULL); request = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); fail_unless(request != NULL); s2_sip_respond_to(request, NULL, 200, "OK 2.0.1", TAG_END()); response = s2_nta_wait_for(wait_for_orq, orq, wait_for_status, 200, 0); s2_sip_free_message(request); s2_nta_free_event(response); nta_outgoing_destroy(orq); }
int nua_client_request_clean(nua_client_request_t *cr) { if (cr->cr_orq) { nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL, cr->cr_acked = 0; return nua_client_request_unref(cr); } return 0; }
void outbound_unref(outbound_t *ob) { if (ob->ob_keepalive.timer) su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL; if (ob->ob_keepalive.orq) nta_outgoing_destroy(ob->ob_keepalive.orq), ob->ob_keepalive.orq = NULL; if (ob->ob_keepalive.msg) msg_destroy(ob->ob_keepalive.msg), ob->ob_keepalive.msg = NULL; su_home_unref(ob->ob_home); }
void outbound_stop_keepalive(outbound_t *ob) { if (!ob) return; ob->ob_keepalive.interval = 0; if (ob->ob_keepalive.timer) su_timer_destroy(ob->ob_keepalive.timer), ob->ob_keepalive.timer = NULL; if (ob->ob_keepalive.orq) nta_outgoing_destroy(ob->ob_keepalive.orq), ob->ob_keepalive.orq = NULL; if (ob->ob_keepalive.msg) msg_destroy(ob->ob_keepalive.msg), ob->ob_keepalive.msg = NULL; }
static void nua_client_request_destroy(nua_client_request_t *cr) { nua_handle_t *nh; if (cr == NULL) return; /* Possible references: */ assert(cr->cr_prev == NULL); /* queue */ assert(cr->cr_orq == NULL); /* transaction callback */ assert(cr->cr_timer == NULL); /* timer callback */ nh = cr->cr_owner; nua_destroy_signal(cr->cr_signal); nua_client_bind(cr, NULL); #if HAVE_MEMLEAK_LOG SU_DEBUG_0(("%p %s for %s\n", cr, __func__, cr->cr_methods->crm_method_name)); #endif if (cr->cr_msg) msg_destroy(cr->cr_msg); cr->cr_msg = NULL, cr->cr_sip = NULL; if (cr->cr_orq) nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL; if (cr->cr_target) su_free(nh->nh_home, cr->cr_target); su_free(nh->nh_home, cr); nua_handle_unref(nh); }
END_TEST START_TEST(client_2_0_2) { nta_outgoing_t *orq; struct message *request; struct event *response; char payload[2048]; S2_CASE("client-2.0.2", "Send MESSAGE", "Basic non-INVITE transaction exceeding " "default path MTU (1300 bytes)"); memset(payload, 'x', sizeof payload); payload[(sizeof payload) - 1] = '\0'; orq = nta_outgoing_tcreate(s2->default_leg, s2_nta_orq_callback, NULL, NULL, SIP_METHOD_MESSAGE, URL_STRING_MAKE("sip:test2.0.example.org"), SIPTAG_FROM_STR("<sip:[email protected]>"), SIPTAG_PAYLOAD_STR(payload), TAG_END()); fail_unless(orq != NULL); request = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); fail_unless(request != NULL); fail_unless(request->sip->sip_via->v_protocol == sip_transport_tcp); s2_sip_respond_to(request, NULL, 200, "OK 2.0.2", TAG_END()); response = s2_nta_wait_for(wait_for_orq, orq, wait_for_status, 200, 0); s2_nta_free_event(response); nta_outgoing_destroy(orq); }
int nua_base_client_check_restart(nua_client_request_t *cr, int status, char const *phrase, sip_t const *sip) { nua_handle_t *nh = cr->cr_owner; nta_outgoing_t *orq; #if 0 if (status == 302 || status == 305) { sip_route_t r[1]; if (!can_redirect(sip->sip_contact, cr->cr_method)) return 0; switch (status) { case 302: if (nua_dialog_zap(nh, nh->nh_ds) == 0 && nua_client_set_target(cr, sip->sip_contact->m_url) >= 0) return nua_client_restart(cr, 100, "Redirected"); break; case 305: sip_route_init(r); *r->r_url = *sip->sip_contact->m_url; if (nua_dialog_zap(nh, nh->nh_ds) == 0 && sip_add_dup(cr->cr_msg, cr->cr_sip, (sip_header_t *)r) >= 0) return nua_client_restart(cr, 100, "Redirected via a proxy"); break; default: break; } } #endif if (status == 423) { unsigned my_expires = 0; if (cr->cr_sip->sip_expires) my_expires = cr->cr_sip->sip_expires->ex_delta; if (sip->sip_min_expires && sip->sip_min_expires->me_delta > my_expires) { sip_expires_t ex[1]; sip_expires_init(ex); ex->ex_delta = sip->sip_min_expires->me_delta; if (sip_add_dup(cr->cr_msg, NULL, (sip_header_t *)ex) < 0) return 0; return nua_client_restart(cr, 100, "Re-Negotiating Expiration"); } } if ((status == 401 && sip->sip_www_authenticate) || (status == 407 && sip->sip_proxy_authenticate)) { int server = 0, proxy = 0; if (sip->sip_www_authenticate) server = auc_challenge(&nh->nh_auth, nh->nh_home, sip->sip_www_authenticate, sip_authorization_class); if (sip->sip_proxy_authenticate) proxy = auc_challenge(&nh->nh_auth, nh->nh_home, sip->sip_proxy_authenticate, sip_proxy_authorization_class); if (server >= 0 && proxy >= 0) { int invalid = cr->cr_challenged && server + proxy == 0; cr->cr_challenged = 1; if (invalid) { /* Bad username/password */ SU_DEBUG_7(("nua(%p): bad credentials, clearing them\n", (void *)nh)); auc_clear_credentials(&nh->nh_auth, NULL, NULL); } else if (auc_has_authorization(&nh->nh_auth)) return nua_client_restart(cr, 100, "Request Authorized by Cache"); orq = cr->cr_orq, cr->cr_orq = NULL; cr->cr_waiting = cr->cr_wait_for_cred = 1; nua_client_report(cr, status, phrase, NULL, orq, NULL); nta_outgoing_destroy(orq); cr->cr_status = 0, cr->cr_phrase = NULL; nua_client_request_unref(cr); return 1; } } if (0 && 500 <= status && status < 600 && sip->sip_retry_after && sip->sip_retry_after->af_delta < 32) { su_timer_t *timer; char phrase[18]; /* Retry After XXXX\0 */ timer = su_timer_create(su_root_task(nh->nh_nua->nua_root), 0); if (su_timer_set_interval(timer, nua_client_restart_after, cr, sip->sip_retry_after->af_delta * 1000) < 0) { su_timer_destroy(timer); return 0; /* Too bad */ } cr->cr_timer = timer; /* This takes over cr reference from orq */ snprintf(phrase, sizeof phrase, "Retry After %u", (unsigned)sip->sip_retry_after->af_delta); orq = cr->cr_orq, cr->cr_orq = NULL; cr->cr_waiting = 1; nua_client_report(cr, 100, phrase, NULL, orq, NULL); nta_outgoing_destroy(orq); cr->cr_status = 0, cr->cr_phrase = NULL; return 1; } return 0; /* This was a final response that cannot be restarted. */ }
END_TEST START_TEST(client_2_3_2) { nta_outgoing_t *orq, *tagged, *prack; struct message *request, *r_prack, *r_ack; sip_t *sip; struct event *response; S2_CASE("client-2.3.2", "INVITE with 100rel", "Forked INVITE transaction with 100rel"); orq = nta_outgoing_tcreate(leg, s2_nta_orq_callback, NULL, NULL, SIP_METHOD_INVITE, (url_string_t *)s2sip->udp.contact->m_url, SIPTAG_SUPPORTED_STR("100rel"), TAG_END()); fail_unless(orq != NULL); request = s2_sip_wait_for_request(SIP_METHOD_INVITE); fail_unless(request != NULL); s2_sip_respond_to(request, dialog, SIP_183_SESSION_PROGRESS, SIPTAG_RSEQ_STR("1"), SIPTAG_REQUIRE_STR("100rel"), TAG_END()); response = s2_nta_wait_for(wait_for_orq, orq, wait_for_status, 183, 0); sip = response->sip; tagged = nta_outgoing_tagged(orq, s2_nta_orq_callback, NULL, sip->sip_to->a_tag, sip->sip_rseq); fail_unless(tagged != NULL); fail_unless(nta_leg_rtag(leg, sip->sip_to->a_tag) != NULL); prack = nta_outgoing_prack(leg, tagged, s2_nta_orq_callback, NULL, NULL, sip, TAG_END()); r_prack = s2_sip_wait_for_request(SIP_METHOD_PRACK); fail_unless(r_prack != NULL); s2_sip_respond_to(r_prack, dialog, SIP_200_OK, TAG_END()); s2_sip_free_message(r_prack); response = s2_nta_wait_for(wait_for_orq, prack, wait_for_status, 200, 0); fail_unless(response != NULL); nta_outgoing_destroy(prack); s2_sip_respond_to(request, NULL, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END()); s2_nta_free_event(response); response = s2_nta_wait_for(wait_for_orq, orq, wait_for_status, 480, 0); fail_unless(response != NULL); s2_nta_free_event(response), response = NULL; r_ack = s2_sip_wait_for_request(SIP_METHOD_ACK); s2_sip_free_message(r_ack); nta_outgoing_destroy(orq), orq = NULL; s2_sip_free_message(request); /* 408 is eventually received by tagged transaction */ response = s2_nta_wait_for(wait_for_orq, tagged, wait_for_status, 408, 0); fail_unless(response != NULL); nta_outgoing_destroy(tagged); s2_nta_free_event(response); }
END_TEST START_TEST(client_2_1_2) { nta_outgoing_t *orq; struct message *request; struct event *response; url_t udpurl[1]; S2_CASE("client-2.1.2", "Send MESSAGE", "Non-INVITE transaction to TCP-only server"); client_setup_tcp_only_server(); *udpurl = *s2sip->tcp.contact->m_url; udpurl->url_params = "transport=udp"; /* Create DNS records for both UDP and TCP, resolver matches UDP */ s2_dns_domain("udptcp.org", 1, "s2", 1, udpurl, "s2", 2, s2sip->tcp.contact->m_url, NULL); /* Sent to tport selected by resolver */ orq = nta_outgoing_tcreate(s2->default_leg, s2_nta_orq_callback, NULL, URL_STRING_MAKE("sip:udptcp.org"), SIP_METHOD_MESSAGE, URL_STRING_MAKE("sip:test2.0.example.org"), SIPTAG_FROM_STR("<sip:[email protected]>"), TAG_END()); fail_unless(orq != NULL); response = s2_nta_wait_for(wait_for_orq, orq, wait_for_status, 503, 0); s2_nta_free_event(response); nta_outgoing_destroy(orq); /* Message size exceeds 1300, tries to use TCP even if NAPTR points to UDP */ orq = nta_outgoing_tcreate(s2->default_leg, s2_nta_orq_callback, NULL, URL_STRING_MAKE("sip:udptcp.org"), SIP_METHOD_MESSAGE, URL_STRING_MAKE("sip:test2.0.example.org"), SIPTAG_FROM_STR("<sip:[email protected]>"), #define ROW "012345678901234567890123456789012345678901234\n" SIPTAG_PAYLOAD_STR( /* > 1300 bytes */ "0000 " ROW "0050 " ROW "0100 " ROW "0150 " ROW "0200 " ROW "0250 " ROW "0300 " ROW "0350 " ROW "0400 " ROW "0450 " ROW "0500 " ROW "0550 " ROW "0600 " ROW "0650 " ROW "0700 " ROW "0750 " ROW "0800 " ROW "0850 " ROW "0900 " ROW "0950 " ROW "1000 " ROW "1050 " ROW "1100 " ROW "1150 " ROW "1200 " ROW "1250 " ROW ), #undef ROW TAG_END()); fail_unless(orq != NULL); request = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); fail_unless(request != NULL); fail_unless(request->sip->sip_via->v_protocol == sip_transport_tcp); s2_sip_respond_to(request, NULL, 200, "2.1.2", TAG_END()); s2_sip_free_message(request); response = s2_nta_wait_for(wait_for_orq, orq, wait_for_status, 200, 0); s2_nta_free_event(response); nta_outgoing_destroy(orq); }