/** Create transports for client engine */ static int he_create_tports(nth_engine_t * he, tagi_t *tags) { he->he_tports = tport_tcreate(he, http_client_class, he->he_root, TAG_END()); if (!he->he_tports) return -1; if (tport_tbind(he->he_tports, he_name, he_tports, TPTAG_SERVER(0), TAG_NEXT(tags)) >= 0) return 0; return tport_tbind(he->he_tports, he_name, he_no_tls_tports, TPTAG_SERVER(0), TAG_NEXT(tags)); }
int luasofia_nua_handle_create(lua_State *L, nua_t *nua) { luasofia_nua_handle_t *lnh = NULL; nua_handle_t *nh = NULL; su_home_t *home = su_home_create(); tagi_t *tags = luasofia_tags_table_to_taglist(L, 2, home); /* create a nua_handle object */ lnh = (luasofia_nua_handle_t*)lua_newuserdata(L, sizeof(luasofia_nua_handle_t)); /* create the nua_handle_t */ nh = nua_handle(nua, lnh, TAG_NEXT(tags)); if (!nh) luaL_error(L, "nua_handle failed!"); /* set Lua state */ lnh->L = L; lnh->nh = nh; /* set its metatable */ luaL_getmetatable(L, NUA_HANDLE_MTABLE); lua_setmetatable(L, -2); /* store nua handle at luasofia userdata table */ luasofia_userdata_table_set(L, nh); su_home_unref(home); return 1; }
void nua_stack_authenticate(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags) { nua_client_request_t *cr = nh->nh_ds->ds_cr; int status = nh_authorize(nh, TAG_NEXT(tags)); if (status > 0) { if (cr && cr->cr_wait_for_cred) { cr->cr_waiting = cr->cr_wait_for_cred = 0; nua_client_restart_request(cr, cr->cr_terminating, tags); } else { nua_stack_event(nua, nh, NULL, e, 202, "No operation to restart", NULL); } } else if (cr && cr->cr_wait_for_cred) { cr->cr_waiting = cr->cr_wait_for_cred = 0; if (status < 0) nua_client_response(cr, 900, "Operation cannot add credentials", NULL); else nua_client_response(cr, 904, "Operation has no matching challenge ", NULL); } else if (status < 0) { nua_stack_event(nua, nh, NULL, e, 900, "Cannot add credentials", NULL); } else { nua_stack_event(nua, nh, NULL, e, 904, "No matching challenge", NULL); } }
/** 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; }
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 int nua_notify_client_report(nua_client_request_t *cr, int status, char const *phrase, sip_t const *sip, nta_outgoing_t *orq, tagi_t const *tags) { nua_handle_t *nh = cr->cr_owner; nua_dialog_usage_t *du = cr->cr_usage; struct notifier_usage *nu = nua_dialog_usage_private(du); enum nua_substate substate = nua_substate_terminated; if (nu && !cr->cr_terminated) substate = nu->nu_substate; nua_stack_tevent(nh->nh_nua, nh, nta_outgoing_getresponse(orq), (enum nua_event_e)cr->cr_event, status, phrase, NUTAG_SUBSTATE(substate), SIPTAG_EVENT(du ? du->du_event : NULL), TAG_NEXT(tags)); if (du && du->du_cr == cr && !cr->cr_terminated) { if (nu->nu_requested) { /* Re-SUBSCRIBEd while NOTIFY was in progress, resend NOTIFY */ nua_client_resend_request(cr, 0); } else if (nu->nu_expires) { nua_dialog_usage_set_refresh_at(du, nu->nu_expires); } } return 0; }
static int luasofia_nua_create(lua_State *L) { luasofia_su_root_t *lroot = NULL; luasofia_nua_t *lnua = NULL; nua_t *nua = NULL; tagi_t *tags = NULL; su_home_t *home = su_home_create(); /* get and check first argument (should be a root_t) */ lroot = (luasofia_su_root_t*)luaL_checkudata(L, 1, SU_ROOT_MTABLE); /* check the callback table */ if (!lua_isnoneornil(L, 2)) luaL_checktype(L, 2, LUA_TTABLE); tags = luasofia_tags_table_to_taglist(L, 4, home); /* create a nua object */ lnua = (luasofia_nua_t*) lua_newuserdata(L, sizeof(luasofia_nua_t)); /* create the nua_t */ nua = nua_create(lroot->root, nua_event_callback, L, TAG_NEXT(tags)); if (!nua) { luaL_error(L, "nua_create failed!"); } /* save nua object */ lnua->nua = nua; /* set its metatable */ luaL_getmetatable(L, NUA_MTABLE); lua_setmetatable(L, -2); /* store nua at luasofia userdata table */ luasofia_userdata_table_set(L, nua); /* create env table */ lua_createtable(L, 2, 0); /* save second argument (callbacks) on env table */ if (!lua_isnoneornil(L, 2)) { lua_pushvalue(L, 2); lua_rawseti(L, -2, ENV_CALLBACK_INDEX); } /* save third argument (magic) on env table */ if (!lua_isnoneornil(L, 3)) { lua_pushvalue(L, 3); lua_rawseti(L, -2, ENV_MAGIC_INDEX); } /* set env table as environment for udata */ lua_setfenv(L, -2); su_home_unref(home); return 1; }
static int luasofia_nua_get_params(lua_State *L) { /* get and check first argument (should be a luasofia_nua_t) */ su_home_t *home = su_home_create(); luasofia_nua_t *lnua = (luasofia_nua_t*)luaL_checkudata(L, 1, NUA_MTABLE); tagi_t *tags = luasofia_tags_table_to_taglist(L, 2, home); nua_get_params(lnua->nua, TAG_NEXT(tags)); su_home_unref(home); return 0; }
static int luasofia_nua_handle_invite(lua_State *L) { /* get and check first argument (should be a luasofia_nua_handle_t) */ luasofia_nua_handle_t *lnh = (luasofia_nua_handle_t*)luaL_checkudata(L, 1, NUA_HANDLE_MTABLE); if (lnh->nh) { su_home_t *home = su_home_create(); tagi_t *tags = luasofia_tags_table_to_taglist(L, 2, home); nua_invite(lnh->nh, TAG_NEXT(tags)); su_home_unref(home); } return 0; }
int luasofia_nta_agent_create(lua_State * L) { luasofia_su_root_t *lroot = NULL; url_string_t * contact = NULL; luasofia_nta_agent_t* u_nta_agent = NULL; su_home_t *home = su_home_create(); tagi_t *tags = NULL; /* get and check first argument (should be a root_t) */ lroot = (luasofia_su_root_t*)luaL_checkudata(L, -4, SU_ROOT_MTABLE); if(lua_isuserdata (L, -3)) { //Since there is no metatable for url_t or url_string_t we cant perform a checkudata here. contact = (url_string_t *) lua_touserdata (L, -3); } else { contact = URL_STRING_MAKE(luaL_checkstring (L, -3)); } /* check the callback function */ if(!lua_isfunction(L, -2)) luaL_error(L, "nta_agent_create failed!, expected a callback function !"); /* check if there is tags */ tags = luasofia_tags_table_to_taglist(L, -1, home); u_nta_agent = (luasofia_nta_agent_t *) lua_newuserdata(L, sizeof(luasofia_nta_agent_t)); u_nta_agent->L = L; u_nta_agent->agent = nta_agent_create (lroot->root, (url_string_t const *)contact, nta_agent_message_callback, (nta_agent_magic_t *)u_nta_agent, TAG_NEXT(tags)); // lets hold the ref to the lua callback function. lua_pushvalue(L, -3); u_nta_agent->callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); if (!u_nta_agent->agent) luaL_error(L, "nta_agent_create failed!"); /* set its metatable */ luaL_getmetatable(L, NTA_AGENT_MTABLE); lua_setmetatable(L, -2); /* store nta_agent at luasofia userdata table userdata_table[nta_agent_lightudata] = nta_agent_fulludata */ luasofia_userdata_table_set(L, u_nta_agent->agent); su_home_unref(home); return 1; }
/** @internal Terminate notifier. */ void nua_stack_terminate(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags) { sip_event_t const *event = NULL; sip_content_type_t const *ct = NULL; sip_payload_t const *pl = NULL; char const *event_s = NULL, *ct_s = NULL, *pl_s = NULL; nea_event_t *nev = NULL; if (nh->nh_notifier == NULL) { UA_EVENT2(e, 900, "No event server to terminate"); return; } tl_gets(tags, SIPTAG_EVENT_REF(event), SIPTAG_EVENT_STR_REF(event_s), SIPTAG_CONTENT_TYPE_REF(ct), SIPTAG_CONTENT_TYPE_STR_REF(ct_s), SIPTAG_PAYLOAD_REF(pl), SIPTAG_PAYLOAD_STR_REF(pl_s), TAG_END()); nev = nea_event_get(nh->nh_notifier, event ? event->o_type : event_s); if (nev && (pl || pl_s) && (ct || ct_s)) { nea_server_update(nh->nh_notifier, nev, TAG_NEXT(tags)); } nh_notifier_shutdown(nh, NULL, NEATAG_REASON("noresource"), TAG_NEXT(tags)); nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL); }
void nua_stack_authorize(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags) { nea_sub_t *sub = NULL; int state = nea_extended; tl_gets(tags, NEATAG_SUB_REF(sub), NUTAG_SUBSTATE_REF(state), TAG_END()); if (sub && state > 0) { nea_sub_auth(sub, (nea_state_t)state, TAG_NEXT(tags)); nua_stack_event(nua, nh, NULL, e, SIP_200_OK, NULL); } else { nua_stack_event(nua, nh, NULL, e, NUA_ERROR_AT(__FILE__, __LINE__), NULL); } }
/**@internal * Save handle parameters and initial authentication info. * * @retval -1 upon an error * @retval 0 when successful */ int nua_stack_init_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags) { int retval = 0; if (nh == NULL) return -1; assert(nh != nua->nua_dhandle); if (nua_stack_set_params(nua, nh, nua_i_error, tags) < 0) retval = -1; if (retval || nh->nh_init) /* Already initialized? */ return retval; if (nh->nh_tags) nh_authorize(nh, TAG_NEXT(nh->nh_tags)); nh->nh_init = 1; return 0; }
static int luasofia_nua_handle_respond(lua_State *L) { /* get and check first argument (should be a luasofia_nua_handle_t) */ luasofia_nua_handle_t *lnh = (luasofia_nua_handle_t*) luaL_checkudata(L, 1, NUA_HANDLE_MTABLE); if (lnh->nh) { char const* phrase = NULL; su_home_t *home = su_home_create(); /* get and check second argument (should be a int) */ int status = luaL_checkinteger(L, 2); /* get and check fourth argument (should be a tag table) */ tagi_t *tags = luasofia_tags_table_to_taglist(L, 4, home); /* get and check third argument (should be a string) */ if (!lua_isnoneornil(L, 3)) phrase = luaL_checkstring (L, 3); nua_respond(lnh->nh, status, phrase, TAG_NEXT(tags)); su_home_unref(home); } return 0; }
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; }
int nua_stack_init(su_root_t *root, nua_t *nua) { su_home_t *home; nua_handle_t *dnh; static int initialized_logs = 0; enter; if (!initialized_logs) { extern su_log_t tport_log[]; extern su_log_t nta_log[]; extern su_log_t nea_log[]; extern su_log_t iptsec_log[]; su_log_init(tport_log); su_log_init(nta_log); su_log_init(nea_log); su_log_init(iptsec_log); initialized_logs = 1; } nua->nua_root = root; home = nua->nua_home; nua->nua_handles_tail = &nua->nua_handles; sip_from_init(nua->nua_from); dnh = su_home_clone(nua->nua_home, sizeof (*dnh) + sizeof(*dnh->nh_prefs)); if (!dnh) return -1; dnh->nh_prefs = (void *)(dnh + 1); dnh->nh_valid = nua_valid_handle_cookie; dnh->nh_nua = nua; nua_handle_ref(dnh); dnh->nh_ref_by_stack = 1; nua_handle_ref(dnh); dnh->nh_ref_by_user = 1; nh_append(nua, dnh); dnh->nh_identity = dnh; dnh->nh_ds->ds_local = nua->nua_from; dnh->nh_ds->ds_remote = nua->nua_from; if (nua_stack_set_defaults(dnh, dnh->nh_prefs) < 0) return -1; if (nua_stack_set_params(nua, dnh, nua_i_none, nua->nua_args) < 0) return -1; /* XXX - soa should know what it supports */ nua->nua_invite_accept = sip_accept_make(home, SDP_MIME_TYPE); nua->nua_accept_multipart = sip_accept_format(home, "%s, %s", SDP_MIME_TYPE, "multipart/*"); nua->nua_nta = nta_agent_create(root, NONE, NULL, NULL, NTATAG_MERGE_482(1), NTATAG_CLIENT_RPORT(1), NTATAG_UA(1), #if HAVE_SOFIA_SMIME NTATAG_SMIME(nua->sm), #endif TPTAG_STUN_SERVER(1), TAG_NEXT(nua->nua_args)); dnh->nh_ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, dnh, NTATAG_NO_DIALOG(1), TAG_END()); if (nua->nua_nta == NULL || dnh->nh_ds->ds_leg == NULL || nta_agent_set_params(nua->nua_nta, NTATAG_UA(1), TAG_END()) < 0 || nua_stack_init_transport(nua, nua->nua_args) < 0) { SU_DEBUG_1(("nua: initializing SIP stack failed\n")); return -1; } if (nua_stack_set_from(nua, 1, nua->nua_args) < 0) return -1; if (nua->nua_prefs->ngp_detect_network_updates) nua_stack_launch_network_change_detector(nua); return 0; }
}; /* ====================================================================== */ /* Internal prototypes */ tagi_t nth_client_tags[] = { {nthtag_mclass, 0}, {nthtag_message, 0}, {nthtag_mflags, 0}, {nthtag_proxy, 0}, {nthtag_error_msg, 0}, {nthtag_template, 0}, {nthtag_authentication, 0}, {TAG_NEXT(tport_tags)} }; /* ====================================================================== */ /* Internal prototypes */ static int he_create_tports(nth_engine_t * he, tagi_t *tags); static int he_timer_init(nth_engine_t * he); static void he_timer(su_root_magic_t *, su_timer_t *, nth_engine_t * he); static void hc_timer(nth_engine_t * he, nth_client_t * hc, uint32_t now); static uint32_t he_now(nth_engine_t const *he); static void he_recv_message(nth_engine_t * he, tport_t * tport, msg_t *msg, void *arg, su_time_t now); static msg_t *he_msg_create(nth_engine_t * he, int flags, char const data[], usize_t dlen, tport_t const *tport, nth_client_t * hc);
/**Create a client request. * * @retval 0 if request is pending * @retval > 0 if error event has been sent * @retval < 0 upon an error */ int nua_client_create(nua_handle_t *nh, int event, nua_client_methods_t const *methods, tagi_t const * const tags) { su_home_t *home = nh->nh_home; nua_client_request_t *cr; sip_method_t method; char const *name; method = methods->crm_method, name = methods->crm_method_name; if (!name) { tagi_t const *t = tl_find_last(tags, nutag_method); if (t) name = (char const *)t->t_value; } cr = su_zalloc(home, sizeof *cr + methods->crm_extra); if (!cr) { return nua_stack_event(nh->nh_nua, nh, NULL, (enum nua_event_e)event, NUA_ERROR_AT(__FILE__, __LINE__), NULL); } cr->cr_methods = methods; cr->cr_event = event; cr->cr_method = method; cr->cr_method_name = name; cr->cr_contactize = methods->crm_flags.target_refresh; cr->cr_dialog = methods->crm_flags.create_dialog; cr->cr_auto = 1; if (su_msg_is_non_null(nh->nh_nua->nua_signal)) { nua_event_data_t *e = su_msg_data(nh->nh_nua->nua_signal)->ee_data; if (tags == e->e_tags && event == e->e_event) { cr->cr_auto = 0; if (tags) { nua_move_signal(cr->cr_signal, nh->nh_nua->nua_signal); if (cr->cr_signal) { /* Steal reference from signal */ cr->cr_owner = e->e_nh, e->e_nh = NULL; cr->cr_tags = tags; } } } } if (cr->cr_owner == NULL) cr->cr_owner = nua_handle_ref(nh); if (tags && cr->cr_tags == NULL) cr->cr_tags = tl_tlist(nh->nh_home, TAG_NEXT(tags)); #if HAVE_MEMLEAK_LOG SU_DEBUG_0(("%p %s() for %s\n", cr, __func__, cr->cr_methods->crm_method_name)); #endif if (nua_client_request_queue(cr)) return 0; return nua_client_init_request(cr); }
void nua_stack_notifier(nua_t *nua, nua_handle_t *nh, nua_event_t e, tagi_t const *tags) { su_home_t home[1] = { SU_HOME_INIT(home) }; sip_event_t const *event = NULL; sip_content_type_t const *ct = NULL; sip_payload_t const *pl = NULL; url_string_t const *url = NULL; char const *event_s = NULL, *ct_s = NULL, *pl_s = NULL; nea_event_t *ev; int status = 900; char const *phrase = nua_internal_error; nua_stack_init_handle(nua, nh, tags); tl_gets(tags, NUTAG_URL_REF(url), SIPTAG_EVENT_REF(event), SIPTAG_EVENT_STR_REF(event_s), SIPTAG_CONTENT_TYPE_STR_REF(ct_s), SIPTAG_PAYLOAD_REF(pl), SIPTAG_PAYLOAD_STR_REF(pl_s), TAG_END()); if (!event && !event_s) status = 400, phrase = "Missing Event"; else if (!ct && !ct_s) status = 400, phrase = "Missing Content-Type"; else if (!nh->nh_notifier && !(nh->nh_notifier = nea_server_create(nua->nua_nta, nua->nua_root, url->us_url, NH_PGET(nh, max_subscriptions), NULL, nh, TAG_NEXT(tags)))) status = 900, phrase = nua_internal_error; else if (!event && !(event = sip_event_make(home, event_s))) status = 900, phrase = "Could not create an event header"; else if (!(ev = nh_notifier_event(nh, home, event, tags))) status = 900, phrase = "Could not create an event view"; else if (nea_server_update(nh->nh_notifier, ev, TAG_NEXT(tags)) < 0) status = 900, phrase = "No content for event"; else if (nea_server_notify(nh->nh_notifier, ev) < 0) status = 900, phrase = "Error when notifying watchers"; else nua_stack_tevent(nua, nh, NULL, e, status = SIP_200_OK, SIPTAG_EVENT(event), SIPTAG_CONTENT_TYPE(ct), TAG_END()); if (status != 200) nua_stack_event(nua, nh, NULL, e, status, phrase, NULL); su_home_deinit(home); }
int nua_notify_server_report(nua_server_request_t *sr, tagi_t const *tags) { nua_handle_t *nh = sr->sr_owner; nua_dialog_usage_t *du = sr->sr_usage; struct event_usage *eu = nua_dialog_usage_private(du); sip_t const *sip = sr->sr_request.sip; enum nua_substate substate = nua_substate_terminated; sip_time_t delta = SIP_TIME_MAX; sip_event_t const *o = sip->sip_event; int retry = -1; int retval; if (eu) { sip_subscription_state_t *subs = sip->sip_subscription_state; substate = eu->eu_substate; if (substate == nua_substate_active || substate == nua_substate_pending) { if (subs && subs->ss_expires) { sip_time_t now = sip_now(); sip_time_t delta0 = strtoul(subs->ss_expires, NULL, 10); if (now + delta0 <= eu->eu_expires) delta = delta0; } } else if (substate == nua_substate_embryonic) { if (subs && subs->ss_reason) { if (su_casematch(subs->ss_reason, "deactivated")) { retry = 0; /* retry immediately */ } else if (su_casematch(subs->ss_reason, "probation")) { retry = 30; if (subs->ss_retry_after) retry = strtoul(subs->ss_retry_after, NULL, 10); if (retry > 3600) retry = 3600; } } } else if (substate == nua_substate_terminated) { sr->sr_terminating = 1; } } retval = nua_base_server_treport(sr, /* can destroy sr */ NUTAG_SUBSTATE(substate), SIPTAG_EVENT(o), TAG_NEXT(tags)); if (retval != 1 || du == NULL) return retval; if (eu->eu_unsolicited) { /* Xyzzy */; } else if (retry >= 0) { /* Try to subscribe again */ /* XXX - this needs through testing */ nua_dialog_remove(nh, nh->nh_ds, du); /* tear down */ nua_dialog_usage_set_refresh_range(du, retry, retry + 5); } else { if (delta < SIP_TIME_MAX) { nua_dialog_usage_set_refresh(du, delta); eu->eu_expires = du->du_refquested + delta; } } return retval; }