END_TEST START_TEST(notify_6_3_5) { nua_handle_t *nh; struct message *notify; struct event *response; sip_t *sip; S2_CASE("6.3.4", "NOTIFY server - terminate with error response to NOTIFY", "NUA receives SUBSCRIBE, sends 202 and NOTIFY. " "The subscription terminates when watcher " "returns 481 to NOTIFY."); nh = subscribe_to_nua("presence", SIPTAG_EXPIRES_STR("300"), TAG_END()); nua_notify(nh, SIPTAG_SUBSCRIPTION_STATE_STR("active"), SIPTAG_PAYLOAD_STR(presence_closed), TAG_END()); notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); fail_unless(notify != NULL); sip = notify->sip; fail_unless(sip->sip_subscription_state != NULL); fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, "active")); s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); fail_unless_event(nua_r_notify, 200); nua_notify(nh, SIPTAG_SUBSCRIPTION_STATE_STR("active"), SIPTAG_PAYLOAD_STR(presence_open), TAG_END()); notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); fail_unless(notify != NULL); sip = notify->sip; fail_unless(sip->sip_subscription_state != NULL); fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, "active")); nua_notify(nh, NUTAG_NEWSUB(1), SIPTAG_SUBSCRIPTION_STATE_STR("active"), SIPTAG_PAYLOAD_STR(presence_open), TAG_END()); s2_sip_respond_to(notify, dialog, SIP_481_NO_TRANSACTION, TAG_END()); response = s2_wait_for_event(nua_r_notify, 481); fail_unless(s2_event_substate(response) == nua_substate_terminated); notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); s2_sip_respond_to(notify, dialog, SIP_481_NO_TRANSACTION, TAG_END()); response = s2_wait_for_event(nua_r_notify, 481); fail_unless(s2_event_substate(response) == nua_substate_terminated); nua_handle_destroy(nh); }
/**Compare two SIP addresses ( @From or @To headers). * * @retval nonzero if matching. * @retval zero if not matching. */ int sip_addr_match(sip_addr_t const *a, sip_addr_t const *b) { return (a->a_tag == NULL || b->a_tag == NULL || su_casematch(a->a_tag, b->a_tag)) && su_casematch(a->a_host, b->a_host) && su_strmatch(a->a_user, b->a_user) && su_strmatch(a->a_url->url_scheme, b->a_url->url_scheme); }
int nua_subscribe_server_preprocess(nua_server_request_t *sr) { nua_handle_t *nh = sr->sr_owner; nua_dialog_state_t *ds = nh->nh_ds; nua_dialog_usage_t *du; struct notifier_usage *nu; sip_t const *sip = sr->sr_request.sip; sip_event_t *o = sip->sip_event; char const *event = o ? o->o_type : NULL; /* Maximum expiration time */ unsigned long expires = sip->sip_expires ? sip->sip_expires->ex_delta : 3600; sip_time_t now = sip_now(); sip_allow_events_t *appl_event = NH_PGET(nh, appl_event); assert(nh && nh->nh_nua->nua_dhandle != nh); du = nua_dialog_usage_get(ds, nua_notify_usage, o); if (du == NULL) { /* Create a new subscription */ du = nua_dialog_usage_add(nh, ds, nua_notify_usage, o); if (du == NULL) return SR_STATUS1(sr, SIP_500_INTERNAL_SERVER_ERROR); } else if (!msg_header_find_param((void *)appl_event, event)) { unsigned max_expires; /* Refresh existing subscription */ if (su_strmatch(event, "refer")) max_expires = NH_PGET(nh, refer_expires); else max_expires = NH_PGET(nh, sub_expires); if (expires >= max_expires) expires = max_expires; SR_STATUS1(sr, SIP_200_OK); } nu = nua_dialog_usage_private(du); if (now + expires >= now) nu->nu_requested = now + expires; else nu->nu_requested = SIP_TIME_MAX - 1; #if SU_HAVE_EXPERIMENTAL nu->nu_etags = sip_suppress_body_if_match(sip) || sip_suppress_notify_if_match(sip) || sip_has_feature(sr->sr_request.sip->sip_supported, "etags"); #endif sr->sr_usage = du; return sr->sr_status <= 100 ? 0 : sr->sr_status; }
END_TEST START_TEST(notify_6_3_2) { nua_handle_t *nh; struct message *notify; sip_t *sip; S2_CASE("6.3.2", "NOTIFY server - automatic subscription termination", "NUA receives SUBSCRIBE, sends 202 and NOTIFY. " "The subscription terminates with timeout. "); nh = subscribe_to_nua("presence", SIPTAG_EXPIRES_STR("300"), TAG_END()); nua_notify(nh, NUTAG_SUBSTATE(nua_substate_active), SIPTAG_PAYLOAD_STR(presence_closed), TAG_END()); notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); fail_unless(notify != NULL); sip = notify->sip; fail_unless(sip->sip_subscription_state != NULL); fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, "active")); s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); fail_unless_event(nua_r_notify, 200); s2_nua_fast_forward(300, s2base->root); notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); fail_unless(notify != NULL); sip = notify->sip; fail_unless(sip->sip_subscription_state != NULL); fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, "terminated")); s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); fail_unless_event(nua_r_notify, 200); nua_handle_destroy(nh); }
/** Select best mechanism from @SecurityClient header. * * @note We assume that @SecurityServer header in @a s is sorted by * preference. */ sip_security_client_t const * sip_security_client_select(sip_security_client_t const *client, sip_security_server_t const *server) { sip_security_server_t const *c, *s; if (server == NULL || client == NULL) return NULL; for (s = server; s; s = s->sa_next) { for (c = client; c; c = c->sa_next) { if (su_strmatch(s->sa_mec, c->sa_mec)) return c; } } return NULL; }
/**Perform sanity check on a SIP message * * Check that the SIP message has all the mandatory fields. * * @param sip SIP message to be checked * * @return * When the SIP message fulfills the minimum requirements, return zero, * otherwise a negative status code. */ int sip_sanity_check(sip_t const *sip) { if (!sip || !((sip->sip_request != NULL) ^ (sip->sip_status != NULL)) || !sip->sip_to || !sip->sip_from || !sip->sip_call_id || !sip->sip_cseq || !sip->sip_via || (sip->sip_flags & MSG_FLG_TRUNC)) return -1; /* Bad request */ if (sip->sip_request) { url_t const *ruri = sip->sip_request->rq_url; switch (ruri->url_type) { case url_invalid: return -1; case url_sip: case url_sips: case url_im: case url_pres: if (!ruri->url_host || strlen(ruri->url_host) == 0) return -1; break; case url_tel: if (!ruri->url_user || strlen(ruri->url_user) == 0) return -1; break; } if (sip->sip_request->rq_method != sip->sip_cseq->cs_method) return -1; if (sip->sip_request->rq_method == sip_method_unknown && !su_strmatch(sip->sip_request->rq_method_name, sip->sip_cseq->cs_method_name)) return -1; } return 0; }
int nua_subscribe_server_init(nua_server_request_t *sr) { nua_handle_t *nh = sr->sr_owner; nua_dialog_state_t *ds = nh->nh_ds; sip_allow_events_t const *allow_events = NH_PGET(nh, allow_events); sip_t const *sip = sr->sr_request.sip; sip_event_t *o = sip->sip_event; char const *event = o ? o->o_type : NULL; if (sr->sr_initial || !nua_dialog_usage_get(ds, nua_notify_usage, o)) { if (su_strmatch(event, "refer")) /* refer event subscription should be initiated with REFER */ return SR_STATUS1(sr, SIP_403_FORBIDDEN); /* XXX - event is case-sensitive, should use msg_header_find_item() */ if (!event || !msg_header_find_param(allow_events->k_common, event)) return SR_STATUS1(sr, SIP_489_BAD_EVENT); } return 0; }
END_TEST START_TEST(message_6_4_3) { nua_handle_t *nh; struct message *message; struct event *response; sip_call_id_t *i; S2_CASE("6.4.1", "SIMPLE MESSAGE", "Send MESSAGE"); nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END()); nua_message(nh, SIPTAG_CONTENT_TYPE_STR("text/plain"), SIPTAG_PAYLOAD_STR("hello"), TAG_END()); message = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); s2_sip_respond_to(message, NULL, SIP_407_PROXY_AUTH_REQUIRED, SIPTAG_PROXY_AUTHENTICATE_STR(s2_auth_digest_str), TAG_END()); i = sip_call_id_dup(NULL, message->sip->sip_call_id); fail_unless(i != NULL); s2_sip_free_message(message); fail_unless_event(nua_r_message, 407); nua_authenticate(nh, NUTAG_AUTH(s2_auth_credentials), TAG_END()); message = s2_sip_wait_for_request(SIP_METHOD_MESSAGE); s2_sip_respond_to(message, NULL, SIP_202_ACCEPTED, TAG_END()); fail_unless(su_strmatch(i->i_id, message->sip->sip_call_id->i_id)); s2_sip_free_message(message); response = s2_wait_for_event(nua_r_message, 202); s2_free_event(response); nua_handle_destroy(nh); }
static int test_strmatch(void) { BEGIN(); TEST_1(!su_strmatch(NULL, "")); TEST_1(su_strmatch(NULL, NULL)); TEST_1(!su_strmatch("", NULL)); TEST_1(!su_strnmatch(NULL, "", 1)); TEST_1(su_strnmatch(NULL, NULL, 1)); TEST_1(!su_strnmatch("", NULL, 1)); TEST_1(su_strnmatch(NULL, "", 0)); TEST_1(su_strnmatch(NULL, NULL, 0)); TEST_1(su_strnmatch("", NULL, 0)); TEST_1(su_strnmatch("foo", "foo", 3)); TEST_1(!su_strnmatch("FOO", "foo", 3)); TEST_1(!su_strnmatch("foo", "FOO", 3)); TEST_1(su_strnmatch("foo", "foo", 4)); TEST_1(!su_strnmatch("FOO", "foo", 4)); TEST_1(!su_strnmatch("foo", "FOO", 4)); TEST_1(su_strmatch("foo", "foo")); TEST_1(!su_strmatch("FOO", "foo")); TEST_1(!su_strmatch("foo", "FOO")); TEST_1(!su_strmatch("foo_", "foo")); TEST_1(su_strnmatch("foo\0X", "foo\0z", 5)); TEST_1(!su_strnmatch("FOO\0X", "foo\0z", 5)); TEST_1(!su_strnmatch("foo\0X", "FOO\0z", 5)); END(); }
/** 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(sdp_session_t const *user, int const *s2u, sdp_session_t *session, sdp_session_t const *remote, char const *hold, int dryrun) { sdp_media_t *sm; sdp_media_t const *rm, *rm_next, *um; int retval = 0, i, j; int hold_all; int inactive_all; char const *hold_media = NULL; sdp_mode_t send_mode, recv_mode; SU_DEBUG_7(("soa_sdp_mode_set(%p, %p, \"%s\"): called\n", (void *)session, (void *)remote, hold ? hold : "")); if (!session || !session->sdp_media) return 0; rm = remote ? remote->sdp_media : NULL, rm_next = NULL; hold_all = su_strmatch(hold, "*"); inactive_all = su_strmatch(hold, "#"); i = 0; for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next, i++) { rm_next = rm ? rm->m_next : NULL; if (sm->m_rejected) continue; assert(s2u); for (j = 0, um = user->sdp_media; j != s2u[i]; um = um->m_next, j++) { if (!um) break; } if (um == NULL) { if (dryrun) return 1; else retval = 1; sm->m_rejected = 1; sm->m_mode = sdp_inactive; sm->m_port = 0; continue; } send_mode = (sdp_mode_t)(um->m_mode & sdp_sendonly); if (rm) send_mode = (rm->m_mode & sdp_recvonly) ? sdp_sendonly : 0; recv_mode = (sdp_mode_t)(um->m_mode & sdp_recvonly); if (rm && rm->m_mode == sdp_inactive) { send_mode = recv_mode = (sdp_mode_t)0; } else if (inactive_all) { send_mode = recv_mode = (sdp_mode_t)0; } else if (hold_all) { recv_mode = (sdp_mode_t)0; } else if (hold && (hold_media = su_strcasestr(hold, sm->m_type_name))) { recv_mode = (sdp_mode_t)0; hold_media += strlen(sm->m_type_name); hold_media += strspn(hold_media, " \t"); if (hold_media[0] == '=') { hold_media += strspn(hold, " \t"); if (su_casenmatch(hold_media, "inactive", strlen("inactive"))) recv_mode = send_mode = (sdp_mode_t)0; } } if (sm->m_mode != (unsigned)(recv_mode | send_mode)) { if (dryrun) return 1; else retval = 1; sm->m_mode = recv_mode | send_mode; } } return retval; }
END_TEST START_TEST(notify_6_3_6) { nua_handle_t *nh; struct event *subscribe; struct message *notify, *response; sip_t *sip; S2_CASE("6.3.6", "Explicit refresh with NUTAG_APPL_EVENT()", "Process subscription refresh by application"); nua_set_params(nua, NUTAG_APPL_METHOD("SUBSCRIBE"), NUTAG_APPL_EVENT("presence"), SIPTAG_ALLOW_EVENTS_STR("presence"), TAG_END()); fail_unless_event(nua_r_set_params, 200); s2_sip_request_to(dialog, SIP_METHOD_SUBSCRIBE, NULL, SIPTAG_EVENT_STR("presence"), TAG_END()); subscribe = s2_wait_for_event(nua_i_subscribe, 100); nh = subscribe->nh; nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_SAVED(subscribe->event), TAG_END()); s2_free_event(subscribe); response = s2_sip_wait_for_response(202, SIP_METHOD_SUBSCRIBE); s2_sip_update_dialog(dialog, response); fail_unless(response->sip->sip_expires != NULL); s2_sip_free_message(response); nua_notify(nh, NUTAG_SUBSTATE(nua_substate_active), SIPTAG_PAYLOAD_STR(presence_closed), TAG_END()); notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); fail_unless(notify != NULL); sip = notify->sip; fail_unless(sip->sip_subscription_state != NULL); fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, "active")); s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); fail_unless_event(nua_r_notify, 200); s2_sip_request_to(dialog, SIP_METHOD_SUBSCRIBE, NULL, SIPTAG_EVENT_STR("presence"), TAG_END()); subscribe = s2_wait_for_event(nua_i_subscribe, 100); nh = subscribe->nh; nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_SAVED(subscribe->event), TAG_END()); s2_free_event(subscribe); response = s2_sip_wait_for_response(202, SIP_METHOD_SUBSCRIBE); s2_sip_update_dialog(dialog, response); fail_unless(response->sip->sip_expires != NULL); s2_sip_free_message(response); notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); fail_unless(notify != NULL); sip = notify->sip; fail_unless(sip->sip_subscription_state != NULL); fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, "active")); s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); fail_unless_event(nua_r_notify, 200); /* Now clear list of application events */ nua_set_params(nua, NUTAG_APPL_EVENT(NULL), NUTAG_SUB_EXPIRES(360), TAG_END()); fail_unless_event(nua_r_set_params, 200); s2_sip_request_to(dialog, SIP_METHOD_SUBSCRIBE, NULL, SIPTAG_EVENT_STR("presence"), TAG_END()); /* Automatically responded && refreshed */ subscribe = s2_wait_for_event(nua_i_subscribe, 200); s2_free_event(subscribe); response = s2_sip_wait_for_response(200, SIP_METHOD_SUBSCRIBE); s2_sip_update_dialog(dialog, response); fail_unless(response->sip->sip_expires != NULL); fail_unless(response->sip->sip_expires->ex_delta == 360); s2_sip_free_message(response); notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); fail_unless(notify != NULL); sip = notify->sip; fail_unless(sip->sip_subscription_state != NULL); fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, "active")); s2_sip_respond_to(notify, dialog, SIP_200_OK, TAG_END()); fail_unless_event(nua_r_notify, 200); nua_handle_destroy(nh); notify = s2_sip_wait_for_request(SIP_METHOD_NOTIFY); sip = notify->sip; fail_unless(sip->sip_subscription_state != NULL); fail_unless(su_strmatch(sip->sip_subscription_state->ss_substate, "terminated")); s2_sip_respond_to(notify, dialog, SIP_481_NO_TRANSACTION, TAG_END()); }
int main(int argc, char *argv[]) { int i, failed = 0, selected = 0; int threading, single_thread, multi_thread; char const *xml = NULL; Suite *suite = suite_create("Unit tests for Sofia-SIP UA Engine"); SRunner *runner; s2_tester = "check_nua"; s2_suite("N2"); if (getenv("CHECK_NUA_VERBOSE")) s2_start_stop = strtoul(getenv("CHECK_NUA_VERBOSE"), NULL, 10); for (i = 1; argv[i]; i++) { if (su_strnmatch(argv[i], "--xml=", strlen("--xml="))) { xml = argv[i] + strlen("--xml="); } else if (su_strmatch(argv[i], "--xml")) { if (!(xml = argv[++i])) usage(2); } else if (su_strmatch(argv[i], "-v")) { s2_start_stop = 1; } else if (su_strmatch(argv[i], "-?") || su_strmatch(argv[i], "-h") || su_strmatch(argv[i], "--help")) usage(0); else { s2_select_tests(argv[i]); selected = 1; } } if (!selected) s2_select_tests(getenv("CHECK_NUA_CASES")); if (getenv("CHECK_NUA_THREADING")) { single_thread = strcmp(getenv("CHECK_NUA_THREADING"), "no"); multi_thread = !single_thread; } else { single_thread = multi_thread = 1; } if (single_thread) { check_register_cases(suite, threading = 0); check_simple_cases(suite, threading = 0); check_session_cases(suite, threading = 0); check_etsi_cases(suite, threading = 0); } if (multi_thread) { check_register_cases(suite, threading = 1); check_session_cases(suite, threading = 1); check_etsi_cases(suite, threading = 1); check_simple_cases(suite, threading = 1); } runner = srunner_create(suite); if (xml) srunner_set_xml(runner, argv[1]); srunner_run_all(runner, CK_ENV); failed = srunner_ntests_failed(runner); srunner_free(runner); exit(failed ? EXIT_FAILURE : EXIT_SUCCESS); }