static void mrcp_sofia_on_resource_discover(mrcp_sofia_agent_t *sofia_agent, nua_handle_t *nh, mrcp_sofia_session_t *sofia_session, sip_t const *sip, tagi_t tags[]) { char sdp_str[2048]; const char *local_sdp_str = NULL; const char *ip = sofia_agent->config->ext_ip ? sofia_agent->config->ext_ip : sofia_agent->config->local_ip; if(sdp_resource_discovery_string_generate(ip,sofia_agent->config->origin,sdp_str,sizeof(sdp_str)) > 0) { local_sdp_str = sdp_str; apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Resource Discovery SDP\n[%s]\n", local_sdp_str); } nua_respond(nh, SIP_200_OK, NUTAG_WITH_CURRENT(sofia_agent->nua), TAG_IF(sofia_agent->sip_contact_str,SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str)), TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)), SOATAG_AUDIO_AUX("telephone-event"), TAG_END()); }
int nth_site_get_params(nth_site_t const *site, tag_type_t tag, tag_value_t value, ...) { int n; ta_list ta; server_t *server; int master; msg_mclass_t const *mclass; if (site == NULL) return (errno = EINVAL), -1; server = site->site_server; master = site == server->srv_sites; if (master && server->srv_mclass != http_default_mclass()) mclass = server->srv_mclass; else mclass = NULL; ta_start(ta, tag, value); n = tl_tgets(ta_args(ta), TAG_IF(master, NTHTAG_MCLASS(mclass)), TAG_IF(master, NTHTAG_MFLAGS(server->srv_mflags)), TAG_END()); ta_end(ta); return n; }
static void mrcp_sofia_task_initialize(apt_task_t *task) { mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task); mrcp_sofia_client_config_t *sofia_config = sofia_agent->config; /* Initialize Sofia-SIP library and create event loop */ su_init(); sofia_agent->root = su_root_create(NULL); /* Create a user agent instance. The stack will call the 'event_callback()' * callback when events such as succesful registration to network, * an incoming call, etc, occur. */ sofia_agent->nua = nua_create( sofia_agent->root, /* Event loop */ mrcp_sofia_event_callback, /* Callback for processing events */ sofia_agent, /* Additional data to pass to callback */ NUTAG_URL(sofia_agent->sip_bind_str), /* Address to bind to */ TAG_END()); /* Last tag should always finish the sequence */ if(sofia_agent->nua) { nua_set_params( sofia_agent->nua, NUTAG_AUTOANSWER(0), NUTAG_APPL_METHOD("OPTIONS"), TAG_IF(sofia_config->sip_t1,NTATAG_SIP_T1(sofia_config->sip_t1)), TAG_IF(sofia_config->sip_t2,NTATAG_SIP_T2(sofia_config->sip_t2)), TAG_IF(sofia_config->sip_t4,NTATAG_SIP_T4(sofia_config->sip_t4)), TAG_IF(sofia_config->sip_t1x64,NTATAG_SIP_T1X64(sofia_config->sip_t1x64)), SIPTAG_USER_AGENT_STR(sofia_config->user_agent_name), TAG_END()); } }
static int nua_publish_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags) { nua_dialog_usage_t *du = cr->cr_usage; int un, done; sip_etag_t const *etag = NULL; un = cr->cr_terminating || cr->cr_event != nua_r_publish || (du && du->du_shutdown) || (sip->sip_expires && sip->sip_expires->ex_delta == 0); nua_client_set_terminating(cr, un); done = un; if (du) { struct publish_usage *pu = nua_dialog_usage_private(du); if (nua_client_bind(cr, du) < 0) return -1; if (pu->pu_published) done = 1; etag = pu->pu_etag; } return nua_base_client_trequest(cr, msg, sip, SIPTAG_IF_MATCH(etag), TAG_IF(done, SIPTAG_PAYLOAD(NONE)), TAG_IF(done, SIPTAG_CONTENT_TYPE(NONE)), TAG_IF(un, SIPTAG_EXPIRES_STR("0")), TAG_NEXT(tags)); }
static gboolean farsight_netsocket_stun_map (FarsightNetsocket *netsocket) { FarsightNetsocketStun *self = FARSIGHT_NETSOCKET_STUN (netsocket); FarsightNetsocket *parent = FARSIGHT_NETSOCKET(self); gboolean res = TRUE; int stun_res = 0; g_return_val_if_fail(parent->sockfd != -1, FALSE); g_debug("%s", __func__); g_debug("server:%s domain:%s.", self->stun_server, self->stun_domain); self->stunh = stun_handle_init(self->root, TAG_IF(self->stun_server, STUNTAG_SERVER(self->stun_server)), TAG_IF(self->stun_domain, STUNTAG_DOMAIN(self->stun_domain)), TAG_NULL()); if (self->stunh) { stun_res = stun_obtain_shared_secret(self->stunh, cb_stun_state, self, TAG_NULL()); if (stun_res < 0) { if (self->strict_msgint) { res = FALSE; stun_handle_destroy(self->stunh), self->stunh = NULL; g_debug("STUN shared-secret request failed, unable to use STUN (strict msgint mode)."); } else { if (stun_bind(self->stunh, cb_stun_state, self, STUNTAG_SOCKET(parent->sockfd), STUNTAG_REGISTER_EVENTS(1), TAG_NULL()) < 0) { res = FALSE; stun_handle_destroy(self->stunh), self->stunh = NULL; g_debug("Failed to start stun_bind()."); } } } } else { res = FALSE; g_debug("Failed to start connection to a STUN server."); } return res; }
static apt_bool_t mrcp_sofia_session_offer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor) { char sdp_str[2048]; char *local_sdp_str = NULL; mrcp_sofia_session_t *sofia_session = session->obj; if(!sofia_session || !sofia_session->nh) { return FALSE; } if(session->signaling_agent) { mrcp_sofia_agent_t *sofia_agent = session->signaling_agent->obj; if(sofia_agent && sofia_agent->config->origin) { apt_string_set(&descriptor->origin,sofia_agent->config->origin); } } if(sdp_string_generate_by_mrcp_descriptor(sdp_str,sizeof(sdp_str),descriptor,TRUE) > 0) { local_sdp_str = sdp_str; apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Local SDP\n%s", local_sdp_str); } nua_invite(sofia_session->nh, TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)), TAG_END()); return TRUE; }
static apt_bool_t mrcp_sofia_on_session_answer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor) { mrcp_sofia_session_t *sofia_session = session->obj; mrcp_sofia_agent_t *sofia_agent = session->signaling_agent->obj; const char *local_sdp_str = NULL; char sdp_str[2048]; if(!sofia_agent || !sofia_session || !sofia_session->nh) { return FALSE; } if(sofia_agent->config->origin) { apt_string_set(&descriptor->origin,sofia_agent->config->origin); } if(sdp_string_generate_by_mrcp_descriptor(sdp_str,sizeof(sdp_str),descriptor,FALSE) > 0) { local_sdp_str = sdp_str; apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Local SDP\n%s", local_sdp_str); } nua_respond(sofia_session->nh, SIP_200_OK, SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str), TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)), NUTAG_AUTOANSWER(0), TAG_END()); return TRUE; }
/** Send request. * * @retval 0 success * @retval -1 if error occurred, but event has not been sent, * and caller has to destroy request message @ msg * @retval -2 if error occurred, event has not been sent * @retval >=1 if error event has been sent */ int nua_base_client_request(nua_client_request_t *cr, msg_t *msg, sip_t *sip, tagi_t const *tags) { nua_handle_t *nh = cr->cr_owner; int proxy_is_set = NH_PISSET(nh, proxy); url_string_t * proxy = NH_PGET(nh, proxy); if (nh->nh_auth) { if (cr->cr_challenged || NH_PGET(nh, auth_cache) == nua_auth_cache_dialog) { if (auc_authorize(&nh->nh_auth, msg, sip) < 0) return nua_client_return(cr, 900, "Cannot add credentials", msg); } } cr->cr_seq = sip->sip_cseq->cs_seq; /* Save last sequence number */ assert(cr->cr_orq == NULL); cr->cr_orq = nta_outgoing_mcreate(nh->nh_nua->nua_nta, nua_client_orq_response, nua_client_request_ref(cr), NULL, msg, TAG_IF(proxy_is_set, NTATAG_DEFAULT_PROXY(proxy)), TAG_NEXT(tags)); if (cr->cr_orq == NULL) { nua_client_request_unref(cr); return -1; } return 0; }
/** * Create a new leg object * * @param agent agent object * @param callback function which is called for each * incoming request belonging to this leg * @param magic call leg context * @param i optional @CallID * (if @c NULL, an ID generated by @b NTA is used) * @param from optional @From (local address) * @param to optional @To (remote address) * @param extra optional extra header * @param headers va_list of optional extra headers * * @deprecated Use nta_leg_tcreate() instead. */ nta_leg_t *nta_leg_vcreate(nta_agent_t *agent, nta_request_f *callback, nta_leg_magic_t *magic, sip_call_id_t const *i, sip_from_t const *from, sip_to_t const *to, void const *extra, va_list headers) { sip_route_t const *route = NULL; sip_cseq_t const *cseq = NULL; for (; extra ; extra = va_arg(headers, void *)) { sip_header_t const *h = (sip_header_t const *)extra; if (h == SIP_NONE) continue; else if (sip_call_id_p(h)) { if (i == NULL) i = h->sh_call_id; } else if (sip_from_p(h)) { if (from == NULL) from = h->sh_from; } else if (sip_to_p(h)) { if (to == NULL) to = h->sh_to; } else if (sip_route_p(h)) { route = h->sh_route; } else if (sip_cseq_p(h)) { cseq = h->sh_cseq; } else { SU_DEBUG_3(("nta_leg_create: extra header %s\n", sip_header_name(h, 0))); } } return nta_leg_tcreate(agent, callback, magic, NTATAG_NO_DIALOG(i == SIP_NONE->sh_call_id), TAG_IF(i != SIP_NONE->sh_call_id, SIPTAG_CALL_ID(i)), TAG_IF(from != SIP_NONE->sh_from, SIPTAG_FROM(from)), TAG_IF(to != SIP_NONE->sh_to, SIPTAG_TO(to)), SIPTAG_ROUTE(route), SIPTAG_CSEQ(cseq), TAG_END()); }
int nth_site_set_params(nth_site_t *site, tag_type_t tag, tag_value_t value, ...) { int n; ta_list ta; server_t *server; int master; msg_mclass_t const *mclass; int mflags; auth_mod_t *am; if (site == NULL) return (errno = EINVAL), -1; server = site->site_server; master = site == server->srv_sites; am = site->site_auth; mclass = server->srv_mclass; mflags = server->srv_mflags; ta_start(ta, tag, value); n = tl_gets(ta_args(ta), TAG_IF(master, NTHTAG_MCLASS_REF(mclass)), TAG_IF(master, NTHTAG_MFLAGS_REF(mflags)), NTHTAG_AUTH_MODULE_REF(am), TAG_END()); if (n > 0) { if (mclass) server->srv_mclass = mclass; else server->srv_mclass = http_default_mclass(); server->srv_mflags = mflags; auth_mod_ref(am), auth_mod_unref(site->site_auth), site->site_auth = am; } ta_end(ta); return n; }
static void mrcp_sofia_task_initialize(apt_task_t *task) { mrcp_sofia_agent_t *sofia_agent = apt_task_object_get(task); mrcp_sofia_server_config_t *sofia_config = sofia_agent->config; /* Initialize Sofia-SIP library and create event loop */ su_init(); sofia_agent->root = su_root_create(NULL); /* Create a user agent instance. The stack will call the 'event_callback()' * callback when events such as succesful registration to network, * an incoming call, etc, occur. */ sofia_agent->nua = nua_create( sofia_agent->root, /* Event loop */ mrcp_sofia_event_callback, /* Callback for processing events */ sofia_agent, /* Additional data to pass to callback */ NUTAG_URL(sofia_agent->sip_bind_str), /* Address to bind to */ NUTAG_AUTOANSWER(0), NUTAG_APPL_METHOD("OPTIONS"), TAG_IF(sofia_config->sip_t1,NTATAG_SIP_T1(sofia_config->sip_t1)), TAG_IF(sofia_config->sip_t2,NTATAG_SIP_T2(sofia_config->sip_t2)), TAG_IF(sofia_config->sip_t4,NTATAG_SIP_T4(sofia_config->sip_t4)), TAG_IF(sofia_config->sip_t1x64,NTATAG_SIP_T1X64(sofia_config->sip_t1x64)), SIPTAG_USER_AGENT_STR(sofia_config->user_agent_name), TAG_IF(sofia_config->tport_log == TRUE,TPTAG_LOG(1)), /* Print out SIP messages to the console */ TAG_IF(sofia_config->tport_dump_file,TPTAG_DUMP(sofia_config->tport_dump_file)), /* Dump SIP messages to the file */ TAG_END()); /* Last tag should always finish the sequence */ if(!sofia_agent->nua) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Create NUA [%s] %s", apt_task_name_get(task), sofia_agent->sip_bind_str); } }
static apt_bool_t mrcp_sofia_on_session_answer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor) { mrcp_sofia_session_t *sofia_session = session->obj; mrcp_sofia_agent_t *sofia_agent = session->signaling_agent->obj; const char *local_sdp_str = NULL; char sdp_str[2048]; if(!sofia_agent || !sofia_session || !sofia_session->nh) { return FALSE; } if(descriptor->status != MRCP_SESSION_STATUS_OK) { int status = sip_status_get(descriptor->status); nua_respond(sofia_session->nh, status, sip_status_phrase(status), TAG_IF(sofia_agent->sip_contact_str,SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str)), TAG_END()); return TRUE; } if(sofia_agent->config->origin) { apt_string_set(&descriptor->origin,sofia_agent->config->origin); } if(sdp_string_generate_by_mrcp_descriptor(sdp_str,sizeof(sdp_str),descriptor,FALSE) > 0) { local_sdp_str = sdp_str; apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Local SDP "APT_NAMESID_FMT"\n%s", session->name, MRCP_SESSION_SID(session), local_sdp_str); } nua_respond(sofia_session->nh, SIP_200_OK, TAG_IF(sofia_agent->sip_contact_str,SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str)), TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)), SOATAG_AUDIO_AUX("telephone-event"), NUTAG_AUTOANSWER(0), TAG_END()); return TRUE; }
static tagi_t *soa_static_get_paramlist(soa_session_t const *ss, tag_type_t tag, tag_value_t value, ...) { soa_static_session_t *sss = (soa_static_session_t *)ss; ta_list ta; tagi_t *tl; ta_start(ta, tag, value); tl = soa_base_get_paramlist(ss, TAG_IF(sss->sss_audio_aux, SOATAG_AUDIO_AUX(sss->sss_audio_aux)), TAG_IF(sss->sss_ordered_user, SOATAG_ORDERED_USER(1)), TAG_IF(sss->sss_reuse_rejected, SOATAG_REUSE_REJECTED(1)), TAG_NEXT(ta_args(ta))); ta_end(ta); return tl; }
/** @internal Send a keepalive OPTIONS that probes the registration */ static int keepalive_options_with_registration_probe(outbound_t *ob) { msg_t *req; sip_t *sip; void *request_uri; if (ob->ob_keepalive.orq) return 0; req = msg_copy(ob->ob_keepalive.msg); if (!req) return -1; sip = sip_object(req); assert(sip); request_uri = sip->sip_to->a_url; if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta), SIP_METHOD_OPTIONS, request_uri) < 0) return msg_destroy(req), -1; if (ob->ob_keepalive.auc[0]) auc_authorization(ob->ob_keepalive.auc, req, (void *)sip, "OPTIONS", request_uri, sip->sip_payload); ob->ob_keepalive.orq = nta_outgoing_mcreate(ob->ob_nta, response_to_keepalive_options, ob, NULL, req, TAG_IF(ob->ob_proxy_override, NTATAG_DEFAULT_PROXY(ob->ob_proxy)), SIPTAG_SUBJECT_STR("REGISTRATION PROBE"), /* NONE is used to remove Max-Forwards: 0 found in ordinary keepalives */ SIPTAG_MAX_FORWARDS(SIP_NONE), TAG_END()); if (!ob->ob_keepalive.orq) return msg_destroy(req), -1; ob->ob_keepalive.validating = 1; ob->ob_keepalive.validated = 0; return 0; }
static apt_bool_t mrcp_sofia_session_create(mrcp_session_t *session, mrcp_sig_settings_t *settings) { mrcp_sofia_agent_t *sofia_agent = mrcp_sofia_agent_get(session); mrcp_sofia_session_t *sofia_session; session->request_vtable = &session_request_vtable; if(!sofia_agent->nua) { return FALSE; } sofia_session = apr_palloc(session->pool,sizeof(mrcp_sofia_session_t)); sofia_session->mutex = NULL; sofia_session->home = su_home_new(sizeof(*sofia_session->home)); sofia_session->session = session; sofia_session->sip_settings = settings; sofia_session->terminate_requested = FALSE; sofia_session->descriptor = NULL; session->obj = sofia_session; if(settings->user_name && settings->user_name != '\0') { sofia_session->sip_to_str = apr_psprintf(session->pool,"sip:%s@%s:%hu", settings->user_name, settings->server_ip, settings->server_port); } else { sofia_session->sip_to_str = apr_psprintf(session->pool,"sip:%s:%hu", settings->server_ip, settings->server_port); } sofia_session->nh = nua_handle( sofia_agent->nua, sofia_session, SIPTAG_TO_STR(sofia_session->sip_to_str), SIPTAG_FROM_STR(sofia_agent->sip_from_str), SIPTAG_CONTACT_STR(sofia_agent->sip_contact_str), TAG_IF(settings->feature_tags,SIPTAG_ACCEPT_CONTACT_STR(settings->feature_tags)), TAG_END()); sofia_session->nua_state = nua_callstate_init; apr_thread_mutex_create(&sofia_session->mutex,APR_THREAD_MUTEX_DEFAULT,session->pool); return TRUE; }
static int nua_refer_server_report(nua_server_request_t *sr, tagi_t const *tags) { nua_handle_t *nh = sr->sr_owner; struct notifier_usage *nu = nua_dialog_usage_private(sr->sr_usage); sip_t const *sip = sr->sr_request.sip; sip_referred_by_t *by = sip->sip_referred_by, default_by[1]; sip_event_t const *o = sr->sr_usage->du_event; enum nua_substate substate = nua_substate_terminated; int initial = sr->sr_initial, retval; if (nu) { if (!sr->sr_terminating) substate = nu->nu_substate; } if (by == NULL) { by = sip_referred_by_init(default_by); by->b_display = sip->sip_from->a_display; *by->b_url = *sip->sip_from->a_url; } retval = nua_base_server_treport(sr, NUTAG_SUBSTATE(substate), NUTAG_REFER_EVENT(o), TAG_IF(by, SIPTAG_REFERRED_BY(by)), TAG_END()); if (retval >= 2 || nu == NULL) return retval; if (initial) nua_stack_post_signal(nh, nua_r_notify, SIPTAG_EVENT(o), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), SIPTAG_PAYLOAD_STR("SIP/2.0 100 Trying\r\n"), TAG_END()); return retval; }
static apt_bool_t mrcp_sofia_session_offer(mrcp_session_t *session, mrcp_session_descriptor_t *descriptor) { char sdp_str[2048]; const char *local_sdp_str = NULL; apt_bool_t res = FALSE; mrcp_sofia_session_t *sofia_session = session->obj; if(!sofia_session) { return FALSE; } if(session->signaling_agent) { mrcp_sofia_agent_t *sofia_agent = mrcp_sofia_agent_get(session); if(sofia_agent) { if(sofia_agent->config->origin) { apt_string_set(&descriptor->origin,sofia_agent->config->origin); } } } if(sdp_string_generate_by_mrcp_descriptor(sdp_str,sizeof(sdp_str),descriptor,TRUE) > 0) { local_sdp_str = sdp_str; sofia_session->descriptor = descriptor; apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->log_obj,"Local SDP "APT_NAMESID_FMT"\n%s", session->name, MRCP_SESSION_SID(session), local_sdp_str); } apr_thread_mutex_lock(sofia_session->mutex); if(sofia_session->nh) { res = TRUE; nua_invite(sofia_session->nh, TAG_IF(local_sdp_str,SOATAG_USER_SDP_STR(local_sdp_str)), TAG_END()); } apr_thread_mutex_unlock(sofia_session->mutex); return res; }
static int keepalive_options(outbound_t *ob) { msg_t *req; sip_t *sip; if (ob->ob_keepalive.orq) return 0; if (ob->ob_prefs.validate && ob->ob_registered && !ob->ob_validated) return keepalive_options_with_registration_probe(ob); req = msg_copy(ob->ob_keepalive.msg); if (!req) return -1; sip = sip_object(req); assert(sip); assert(sip->sip_request); if (nta_msg_request_complete(req, nta_default_leg(ob->ob_nta), SIP_METHOD_UNKNOWN, NULL) < 0) return msg_destroy(req), -1; if (ob->ob_keepalive.auc[0]) auc_authorization(ob->ob_keepalive.auc, req, (void *)sip, "OPTIONS", sip->sip_request->rq_url, sip->sip_payload); ob->ob_keepalive.orq = nta_outgoing_mcreate(ob->ob_nta, response_to_keepalive_options, ob, NULL, req, TAG_IF(ob->ob_proxy_override, NTATAG_DEFAULT_PROXY(ob->ob_proxy)), TAG_END()); if (!ob->ob_keepalive.orq) return msg_destroy(req), -1; return 0; }
int nth_request_treply(nth_request_t *req, int status, char const *phrase, tag_type_t tag, tag_value_t value, ...) { msg_t *response, *next = NULL; http_t *http; int retval = -1; int req_close, close; ta_list ta; http_header_t const *as_info = NULL; if (req == NULL || status < 100 || status >= 600) { return -1; } response = req->req_response; http = http_object(response); if (status >= 200 && req->req_as) as_info = (http_header_t const *)req->req_as->as_info; ta_start(ta, tag, value); http_add_tl(response, http, HTTPTAG_SERVER(req->req_server->srv_server), HTTPTAG_HEADER(as_info), ta_tags(ta)); if (http->http_payload && !http->http_content_length) { http_content_length_t *l; http_payload_t *pl; size_t len = 0; for (pl = http->http_payload; pl; pl = pl->pl_next) len += pl->pl_len; if (len > UINT32_MAX) goto fail; l = http_content_length_create(msg_home(response), (uint32_t)len); msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)l); } if (req->req_method == http_method_head && http->http_payload) { http_payload_t *pl; for (pl = http->http_payload; pl; pl = pl->pl_next) msg_header_remove(response, (msg_pub_t *)http, (msg_header_t *)pl); } http_complete_response(response, status, phrase, http_object(req->req_request)); if (!http->http_date) { http_date_t date[1]; http_date_init(date)->d_time = msg_now(); msg_header_add_dup(response, (msg_pub_t *)http, (msg_header_t*)date); } if (status < 200) { close = 0; next = server_msg_create(req->req_server, 0, NULL, 0, NULL, NULL); } else { req_close = req->req_close; close = (http->http_connection && msg_params_find(http->http_connection->k_items, "close")); if (req_close && !close && status >= 200) { close = 1; http_add_tl(response, http, HTTPTAG_CONNECTION_STR("close"), TAG_END()); } } msg_serialize(response, (msg_pub_t *)http); retval = tport_tqsend(req->req_tport, response, next, TAG_IF(close, TPTAG_CLOSE_AFTER(1)), ta_tags(ta)); fail: ta_end(ta); if (retval == 0) req->req_status = status; return retval; }
/** @internal Create a message template for keepalive. */ static int create_keepalive_message(outbound_t *ob, sip_t const *regsip) { msg_t *msg = nta_msg_create(ob->ob_nta, MSG_FLG_COMPACT), *previous; sip_t *osip = sip_object(msg); sip_contact_t *m = ob->ob_rcontact; unsigned d = ob->ob_keepalive.interval; if (msg == NULL) return -1; assert(regsip); assert(regsip->sip_request); if (m && m->m_params) { sip_accept_contact_t *ac; size_t i; int features = 0; ac = sip_accept_contact_make(msg_home(msg), "*;require;explicit"); for (i = 0; m->m_params[i]; i++) { char const *s = m->m_params[i]; if (!sip_is_callerpref(s)) continue; features++; s = su_strdup(msg_home(msg), s); msg_header_add_param(msg_home(msg), ac->cp_common, s); } if (features) msg_header_insert(msg, NULL, (void *)ac); else msg_header_free(msg_home(msg), (void *)ac); } if (0 > /* Duplicate essential headers from REGISTER request: */ sip_add_tl(msg, osip, SIPTAG_TO(regsip->sip_to), SIPTAG_FROM(regsip->sip_from), /* XXX - we should only use loose routing here */ /* XXX - if we used strict routing, the route header/request_uri must be restored */ SIPTAG_ROUTE(regsip->sip_route), /* Add Max-Forwards 0 */ TAG_IF(d, SIPTAG_MAX_FORWARDS_STR("0")), TAG_IF(d, SIPTAG_SUBJECT_STR("KEEPALIVE")), SIPTAG_CALL_ID_STR(ob->ob_cookie), SIPTAG_ACCEPT_STR(outbound_content_type), TAG_END()) || /* Create request-line, Call-ID, CSeq */ nta_msg_request_complete(msg, nta_default_leg(ob->ob_nta), SIP_METHOD_OPTIONS, (void *)regsip->sip_to->a_url) < 0 || msg_serialize(msg, (void *)osip) < 0 || msg_prepare(msg) < 0) return msg_destroy(msg), -1; previous = ob->ob_keepalive.msg; ob->ob_keepalive.msg = msg; msg_destroy(previous); return 0; }
/** * Creates a new operation object and stores it the list of * active operations for 'cli'. */ ssc_oper_t *ssc_oper_create(ssc_t *ssc, sip_method_t method, char const *name, char const *address, tag_type_t tag, tag_value_t value, ...) { ssc_oper_t *op, *old; ta_list ta; enter; for (old = ssc->ssc_operations; old; old = old->op_next) if (!old->op_persistent) break; if (address) { int have_url = 1; sip_to_t *to; to = sip_to_make(ssc->ssc_home, address); if (to == NULL) { printf("%s: %s: invalid address: %s\n", ssc->ssc_name, name, address); return NULL; } /* Try to make sense out of the URL */ if (url_sanitize(to->a_url) < 0) { printf("%s: %s: invalid address\n", ssc->ssc_name, name); return NULL; } if (!(op = su_zalloc(ssc->ssc_home, sizeof(*op)))) { printf("%s: %s: cannot create handle\n", ssc->ssc_name, name); return NULL; } op->op_next = ssc->ssc_operations; op->op_prev_state = -1; op->op_ssc = ssc; ssc->ssc_operations = op; if (method == sip_method_register) have_url = 0; ta_start(ta, tag, value); op->op_handle = nua_handle(ssc->ssc_nua, op, TAG_IF(have_url, NUTAG_URL(to->a_url)), SIPTAG_TO(to), ta_tags(ta)); ta_end(ta); op->op_ident = sip_header_as_string(ssc->ssc_home, (sip_header_t *)to); ssc_oper_assign(op, method, name); if (!op->op_persistent) { ssc_oper_t *old_next; for (; old; old = old_next) { /* Clean old handles */ old_next = old->op_next; if (!old->op_persistent && !old->op_callstate) ssc_oper_destroy(ssc, old); } } su_free(ssc->ssc_home, to); } else if (method || name) ssc_oper_assign(op = old, method, name); else return old; if (!op) { if (address) printf("%s: %s: invalid destination\n", ssc->ssc_name, name); else printf("%s: %s: no destination\n", ssc->ssc_name, name); return NULL; } return op; }
/* Callback from nea_server asking nua to authorize subscription */ static void authorize_watcher(nea_server_t *nes, nua_handle_t *nh, nea_event_t *ev, nea_subnode_t *sn, sip_t const *sip) { nua_t *nua = nh->nh_nua; msg_t *msg = NULL; nta_incoming_t *irq = NULL; int substate = sn->sn_state; int status; char const *phrase; SET_STATUS1(SIP_200_OK); /* OK. In nhp (nua_handle_preferences_t) structure we have the current default action (or state) for incoming subscriptions. Action can now be modified by the application with NUTAG_SUBSTATE(). */ irq = nea_sub_get_request(sn->sn_subscriber); msg = nta_incoming_getrequest(irq); if (sn->sn_state == nea_embryonic) { char const *what; substate = NH_PGET(nh, substate); if (substate == nua_substate_embryonic) substate = nua_substate_pending; if (substate == nua_substate_terminated) { what = "rejected"; SET_STATUS1(SIP_403_FORBIDDEN); } else if (substate == nua_substate_pending) { what = "pending"; SET_STATUS1(SIP_202_ACCEPTED); } else { what = "active"; } SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", (void *)nh, what)); nea_sub_auth(sn->sn_subscriber, (nea_state_t)substate, TAG_IF(substate == nua_substate_pending, NEATAG_FAKE(1)), TAG_IF(substate == nua_substate_terminated, NEATAG_REASON("rejected")), TAG_END()); } else if (sn->sn_state == nea_terminated || sn->sn_expires == 0) { substate = nua_substate_terminated; nea_server_flush(nes, NULL); SU_DEBUG_7(("nua(%p): authorize_watcher: %s\n", (void *)nh, "watcher is removed")); } nua_stack_tevent(nua, nh, msg, nua_i_subscription, status, phrase, NUTAG_SUBSTATE(substate), NEATAG_SUB(sn->sn_subscriber), TAG_END()); }
/** Respond without creating a request structure */ static void server_reply(server_t *srv, tport_t *tport, msg_t *request, msg_t *response, int status, char const *phrase) { http_t *http; http_payload_t *pl; int close; http_status_t st[1]; char const *req_version = NULL; if (status < 200 || status >= 600) status = 500, phrase = http_500_internal_server; http = http_object(request); if (http && http->http_request) req_version = http->http_request->rq_version; close = status >= 200 && (!srv->srv_persistent || status == 400 || (http && http->http_request && http->http_request->rq_version != http_version_1_1) || (http && http->http_connection && msg_params_find(http->http_connection->k_items, "close"))); msg_destroy(request); http = http_object(response); pl = http_payload_format(msg_home(response), "<html>\n" "<head><title>%u %s</title></head>\n" "<body><h2>%u %s</h2></body>\n" "</html>\n", status, phrase, status, phrase); msg_header_insert(response, (msg_pub_t *)http, (msg_header_t *)pl); if (req_version != http_version_0_9) { http_status_init(st); st->st_version = http_version_1_1; st->st_status = status; st->st_phrase = phrase; http_add_tl(response, http, HTTPTAG_STATUS(st), HTTPTAG_SERVER(srv->srv_server), HTTPTAG_CONTENT_TYPE_STR("text/html"), HTTPTAG_SEPARATOR_STR("\r\n"), TAG_IF(close, HTTPTAG_CONNECTION_STR("close")), TAG_END()); msg_serialize(response, (msg_pub_t *)http); } else { /* Just send the response */ *msg_chain_head(response) = (msg_header_t *)pl; close = 1; } if (tport_tqsend(tport, response, NULL, TPTAG_CLOSE_AFTER(close), TAG_END()) == -1) { SU_DEBUG_3(("server_reply(): cannot queue response\n")); tport_shutdown(tport, 2); } msg_destroy(response); }
int test_extension(struct context *ctx) { BEGIN(); struct endpoint *a = &ctx->a, *b = &ctx->b; struct call *a_call = a->call, *b_call = b->call; struct event *e; sip_t const *sip; /* Test for EXTENSION A B |------EXTENSION---->| |<--------501--------| (method not recognized) | | |------EXTENSION---->| |<-------200---------| (method allowed, responded) | | */ if (print_headings) printf("TEST NUA-13.1: EXTENSION\n"); TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); /* Test first without NUTAG_METHOD() */ METHOD(a, a_call, a_call->nh, TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), TAG_END()); run_ab_until(ctx, -1, save_until_final_response, -1, NULL); /* Client events: nua_method(), nua_r_method */ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_method); TEST(e->data->e_status, 900); /* Internal error */ TEST_1(!e->data->e_msg); TEST_1(!e->next); free_events_in_list(ctx, a->events); nua_handle_destroy(a_call->nh), a_call->nh = NULL; TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); METHOD(a, a_call, a_call->nh, TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), NUTAG_METHOD("EXTENSION"), TAG_END()); run_ab_until(ctx, -1, save_until_final_response, -1, NULL); /* Client events: nua_method(), nua_r_method */ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_method); TEST(e->data->e_status, 501); TEST_1(!e->next); free_events_in_list(ctx, a->events); nua_handle_destroy(a_call->nh), a_call->nh = NULL; free_events_in_list(ctx, b->events); nua_handle_destroy(b_call->nh), b_call->nh = NULL; nua_set_params(b->nua, NUTAG_ALLOW("EXTENSION"), TAG_END()); run_b_until(ctx, nua_r_set_params, until_final_response); TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END())); METHOD(a, a_call, a_call->nh, TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)), NUTAG_METHOD("EXTENSION"), TAG_END()); run_ab_until(ctx, -1, save_until_final_response, -1, respond_to_extension); /* Client events: nua_method(), nua_r_method */ TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_r_method); TEST(e->data->e_status, 200); TEST_1(sip = sip_object(e->data->e_msg)); TEST_1(!e->next); /* Server events: nua_i_method */ TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_method); TEST(e->data->e_status, 100); TEST_1(!e->next); free_events_in_list(ctx, a->events); nua_handle_destroy(a_call->nh), a_call->nh = NULL; free_events_in_list(ctx, b->events); nua_handle_destroy(b_call->nh), b_call->nh = NULL; nua_set_params(b->nua, SIPTAG_ALLOW(b->allow), NUTAG_APPL_METHOD(NULL), NUTAG_APPL_METHOD(b->appl_method), TAG_END()); run_b_until(ctx, nua_r_set_params, until_final_response); if (print_headings) printf("TEST NUA-13.1: PASSED\n"); END(); }