/** Add a Content-Length and separator to a message */ int http_message_complete(msg_t *msg, http_t *http) { #if 1 if (!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) return -1; l = http_content_length_create(msg_home(msg), (uint32_t)len); if (msg_header_insert(msg, http, (http_header_t *)l) < 0) return -1; } #endif if (!http->http_separator) { http_separator_t *sep = http_separator_create(msg_home(msg)); if (msg_header_insert(msg, http, (http_header_t *)sep) < 0) return -1; } return 0; }
/** Complete a HTTP request. */ int http_request_complete(msg_t *msg) { size_t len = 0; http_t *http = http_object(msg); http_payload_t const *pl; su_home_t *home = msg_home(msg); if (!http) return -1; if (!http->http_request) return -1; if (!http->http_host) return -1; for (pl = http->http_payload; pl; pl = pl->pl_next) len += pl->pl_len; if (len > UINT32_MAX) return -1; if (!http->http_content_length) { http->http_content_length = http_content_length_create(home, (uint32_t)len); } else { if (http->http_content_length->l_length != len) { http->http_content_length->l_length = (uint32_t)len; msg_fragment_clear(http->http_content_length->l_common); } } if (!http->http_separator) http->http_separator = http_separator_create(home); return 0; }
/** Copy a complete message, not keeping the header chain structure. * * @retval 0 when successful * @retval -1 upon an error */ static int msg_dup_or_copy_all(msg_t *msg, msg_t const *original, msg_header_t *(*copy_one)(su_home_t *h, msg_header_t const *)) { su_home_t *home = msg_home(msg); msg_pub_t *dst = msg->m_object; msg_pub_t const *src = original->m_object; msg_header_t * const *ssh; msg_header_t * const *end; msg_header_t const *sh; msg_header_t **hh; msg_header_t *h; assert(copy_one); end = (msg_header_t**)((char *)src + src->msg_size); for (ssh = &src->msg_request; ssh < end; ssh++) { sh = *ssh; if (!sh) continue; hh = msg_hclass_offset(msg->m_class, dst, sh->sh_class); if (hh == NULL) return -1; for (; sh; sh = sh->sh_next) { h = copy_one(home, sh); if (h == NULL) return -1; if (*hh) { /* If there is multiple instances of single headers, put the extra headers into the list of erroneous headers */ if (msg_is_single(h)) { msg_error_t **e; for (e = &dst->msg_error; *e; e = &(*e)->er_next) ; *e = (msg_error_t *)h; continue; } while (*hh) hh = &(*hh)->sh_next; } *hh = h; if (msg_is_list(sh)) /* Copy only first list entry */ break; } } return 0; }
/** Add a duplicate of header object to a HTTP message. */ int http_add_dup(msg_t *msg, http_t *http, http_header_t const *o) { if (o == HTTP_NONE) return 0; if (msg == NULL || o == NULL) return -1; return msg_header_insert(msg, http, msg_header_dup(msg_home(msg), o)); }
int http_add_make(msg_t *msg, http_t *http, msg_hclass_t *hc, char const *s) { if (s == NULL) return 0; if (msg == NULL) return -1; return msg_header_insert(msg, http, msg_header_make(msg_home(msg), hc, s)); }
/** Fork an outgoing request (stdarg version of nta_outgoing_fork()). * * @deprecated * Use nta_outgoing_mcreate() instead. */ nta_outgoing_t *nta_outgoing_vfork(nta_outgoing_t *old_orq, nta_response_f *callback, nta_outgoing_magic_t *magic, url_string_t const *route_url, url_string_t const *request_uri, void const *extra, va_list headers) { nta_outgoing_t * orq; msg_t *msg, *imsg; sip_t *sip, *isip; nta_agent_t *agent; su_home_t *home; if (!old_orq || !old_orq->orq_request || !request_uri) return NULL; agent = old_orq->orq_agent; imsg = old_orq->orq_request; if (!(msg = nta_msg_create(agent, 0))) return NULL; msg_clone(msg, imsg); sip = sip_object(msg); isip = sip_object(imsg); home = msg_home(msg); /* Copy the SIP headers from the imsg message */ if (sip_copy_all(msg, sip, isip) < 0) orq = NULL; else if (sip_via_remove(msg, sip) == NULL) orq = NULL; else if (sip_add_dup(msg, sip_object(msg), (sip_header_t const *) sip_request_create(home, sip->sip_request->rq_method, sip->sip_request->rq_method_name, request_uri, NULL)) < 0) orq = NULL; else if (sip_add_headers(msg, sip, extra, headers) < 0) orq = NULL; else orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg); if (!orq) msg_destroy(msg); return orq; }
/** Add headers from the request to the response message. */ int http_complete_response(msg_t *msg, int status, char const *phrase, http_t const *request) { su_home_t *home = msg_home(msg); http_t *http = msg_object(msg); if (!http || !request || !request->http_request) return -1; if (!http->http_status) http->http_status = http_status_create(home, status, phrase, NULL); if (!http->http_status) return -1; if (!http->http_separator) { http_separator_t *sep = http_separator_create(msg_home(msg)); if (msg_header_insert(msg, http, (http_header_t *)sep) < 0) return -1; } return 0; }
/**@ingroup sip_route * * Get first route header and rewrite the RequestURI. */ sip_route_t *sip_route_follow(msg_t *msg, sip_t *sip) { if (sip->sip_route) { /* XXX - in case of outbound proxy, route may contain our address */ sip_route_t *r = sip_route_remove(msg, sip); sip_request_t *rq = sip->sip_request; rq = sip_request_create(msg_home(msg), rq->rq_method, rq->rq_method_name, (url_string_t const *)r->r_url, rq->rq_version); url_strip_transport(rq->rq_url); msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t *)rq); return r; } return NULL; }
/** Send a BYE to an INVITE. * * @deprecated * This function should used only if application requires * RFC2543 compatibility. */ nta_outgoing_t *nta_outgoing_tbye(nta_outgoing_t *orq, nta_response_f *callback, nta_outgoing_magic_t *magic, url_string_t const *route_url, tag_type_t tag, tag_value_t value, ...) { msg_t *msg; sip_t *sip, *inv; sip_cseq_t *cs; sip_request_t *rq; su_home_t *home; url_string_t *url; if (orq == NULL || orq->orq_method != sip_method_invite) return NULL; inv = sip_object(orq->orq_request); msg = nta_msg_create(orq->orq_agent, 0); home = msg_home(msg); sip = sip_object(msg); if (inv == NULL || sip == NULL) { msg_destroy(msg); return NULL; } sip_add_tl(msg, sip, SIPTAG_TO(inv->sip_to), SIPTAG_FROM(inv->sip_from), SIPTAG_CALL_ID(inv->sip_call_id), SIPTAG_ROUTE(inv->sip_route), TAG_END()); url = (url_string_t *)inv->sip_request->rq_url; rq = sip_request_create(home, SIP_METHOD_BYE, url, NULL); sip_header_insert(msg, sip, (sip_header_t*)rq); cs = sip_cseq_create(home, inv->sip_cseq->cs_seq + 1, SIP_METHOD_BYE); sip_header_insert(msg, sip, (sip_header_t*)cs); return nta_outgoing_mcreate(orq->orq_agent, callback, magic, route_url, msg); }
/* Return Via that looks very natted */ static sip_via_t *natted_via(struct message *m, const char *receive_natted) { su_home_t *h; sip_via_t *via; h = msg_home(m->msg); via = sip_via_dup(h, m->sip->sip_via); msg_header_replace_param(h, via->v_common, receive_natted); if (via->v_protocol == sip_transport_udp) msg_header_replace_param(h, via->v_common, "rport=9"); if (via->v_protocol == sip_transport_tcp && via->v_rport) { tp_name_t const *tpn = tport_name(m->tport); char *rport = su_sprintf(h, "rport=%s", tpn->tpn_port); msg_header_replace_param(h, via->v_common, rport); } return via; }
int http_add_format(msg_t *msg, http_t *http, msg_hclass_t *hc, char const *fmt, ...) { http_header_t *h; va_list ap; if (fmt == NULL) return 0; if (msg == NULL) return -1; va_start(ap, fmt); h = http_header_vformat(msg_home(msg), hc, fmt, ap); va_end(ap); return msg_header_insert(msg, http, h); }
/** Copy header chain. * * @retval 0 when successful * @retval -1 upon an error */ static int msg_copy_chain(msg_t *msg, msg_t const *original) { su_home_t *home = msg_home(msg); msg_pub_t *dst = msg->m_object; msg_header_t **tail; msg_header_t *dh; msg_header_t const *sh; msg_header_t **hh; tail = msg->m_tail; for (sh = original->m_chain; sh; sh = (msg_header_t const *)sh->sh_succ) { hh = msg_hclass_offset(msg->m_class, dst, sh->sh_class); if (!hh) break; while (*hh) hh = &(*hh)->sh_next; dh = msg_header_copy_one(home, sh); if (!dh) break; dh->sh_prev = tail, *tail = dh, tail = &dh->sh_succ; *hh = dh; } msg->m_tail = tail; if (sh) return -1; return 0; }
/** 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 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; }
static int nua_notify_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; struct notifier_usage *nu = nua_dialog_usage_private(du); su_home_t *home = msg_home(msg); sip_time_t now = sip_now(); sip_subscription_state_t *ss = sip->sip_subscription_state; char const *expires; if (du == NULL) /* Subscription has been terminated */ return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg); assert(du && nu); if (du && nua_client_bind(cr, du) < 0) return -1; if (nu->nu_requested) nu->nu_expires = nu->nu_requested; nu->nu_requested = 0; if (nu->nu_expires <= now || du->du_shutdown) { nu->nu_substate = nua_substate_terminated; expires = "expires=0"; } else { expires = su_sprintf(home, "expires=%lu", nu->nu_expires - now); } if (ss == NULL || nua_substate_make(ss->ss_substate) != nu->nu_substate) { if (nu->nu_substate == nua_substate_terminated) expires = nu->nu_expires > now ? "reason=noresource" : "reason=timeout"; ss = sip_subscription_state_format(home, "%s;%s", nua_substate_name(nu->nu_substate), expires); msg_header_insert(msg, (void *)sip, (void *)ss); } else if (nu->nu_substate != nua_substate_terminated) { msg_header_replace_param(home, ss->ss_common, expires); } #if SU_HAVE_EXPERIMENTAL if (nu->nu_tag && !sip->sip_etag) msg_header_add_make(msg, (void *)sip, sip_etag_class, nu->nu_tag); if (nu->nu_no_body) { nu->nu_no_body = 0; msg_header_remove(msg, (void *)sip, (void *)sip->sip_payload); msg_header_remove(msg, (void *)sip, (void *)sip->sip_content_length); } #endif if (nu->nu_substate == nua_substate_terminated) nua_client_set_terminating(cr, 1); if (cr->cr_terminating) { nua_server_request_t *sr; for (sr = du->du_dialog->ds_sr; sr; sr = sr->sr_next) { if (sr->sr_usage == du) { /* If subscribe has not been responded, don't terminate usage by NOTIFY */ sr->sr_terminating = 1; nua_client_set_terminating(cr, 0); break; } } } if (du->du_event && !sip->sip_event) sip_add_dup(cr->cr_msg, sip, (sip_header_t *)du->du_event); return nua_base_client_request(cr, msg, sip, tags); }
/**Forward a request belonging to the leg * (stdarg version of nta_outgoing_forward()). * * @deprecated * Use nta_outgoing_mcreate() instead. */ nta_outgoing_t *nta_outgoing_vforward(nta_leg_t *leg, nta_response_f *callback, nta_outgoing_magic_t *magic, url_string_t const *route_url, url_string_t const *request_uri, nta_incoming_t const *ireq, sip_t const *isip, void const *extra, va_list headers) { nta_agent_t *agent = leg->leg_agent; nta_outgoing_t *orq = NULL; msg_t *msg, *imsg; sip_t *sip; su_home_t *home; assert(leg); assert(ireq); if (isip == NULL) imsg = ireq->irq_request, isip = sip_object(ireq->irq_request); else if (isip == sip_object(ireq->irq_request)) imsg = ireq->irq_request; else if (isip == sip_object(ireq->irq_request2)) imsg = ireq->irq_request2; else { SU_DEBUG_3(("nta_outgoing_forward: invalid arguments\n")); return NULL; } assert(isip); assert(isip->sip_request); if (!route_url) route_url = (url_string_t *)agent->sa_default_proxy; if (!(msg = nta_msg_create(agent, 0))) return NULL; msg_clone(msg, imsg); sip = sip_object(msg); home = msg_home(msg); /* Copy the SIP headers from the @c imsg message */ do { if (sip_copy_all(msg, sip, isip) < 0) break; if (sip_add_headers(msg, sip, extra, headers) < 0) break; if (!route_url && sip->sip_route) { request_uri = (url_string_t *)sip->sip_route->r_url; if (!sip_route_remove(msg, sip)) break; } if (request_uri) { sip_request_t *rq; rq = sip_request_create(home, sip->sip_request->rq_method, sip->sip_request->rq_method_name, request_uri, NULL); if (!rq || sip_header_insert(msg, sip, (sip_header_t *)rq) < 0) break; } if ((orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg))) return orq; } while (0); msg_destroy(msg); return NULL; }
/** @internal Send an event to the application. */ int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg, nua_event_t event, int status, char const *phrase, tagi_t const *tags) { su_msg_r sumsg = SU_MSG_R_INIT; size_t e_len, len, xtra, p_len; if (event == nua_r_ack || event == nua_i_none) return event; if (nh == nua->nua_dhandle) nh = NULL; if (nua_log->log_level >= 5) { char const *name = nua_event_name(event) + 4; char const *p = phrase ? phrase : ""; if (status == 0) SU_DEBUG_5(("nua(%p): event %s %s\n", (void *)nh, name, p)); else SU_DEBUG_5(("nua(%p): event %s %u %s\n", (void *)nh, name, status, p)); } if (event == nua_r_destroy) { if (msg) msg_destroy(msg); if (status >= 200) { nh_destroy(nua, nh); } return event; } if ((event > nua_r_authenticate && event <= nua_r_ack) || event < nua_i_error || (nh && !nh->nh_valid) || (nua->nua_shutdown && event != nua_r_shutdown && !nua->nua_prefs->ngp_shutdown_events)) { if (msg) msg_destroy(msg); return event; } if (tags) { e_len = offsetof(nua_ee_data_t, ee_data[0].e_tags); len = tl_len(tags); xtra = tl_xtra(tags, len); } else { e_len = sizeof(nua_ee_data_t), len = 0, xtra = 0; } p_len = phrase ? strlen(phrase) + 1 : 1; if (su_msg_new(sumsg, e_len + len + xtra + p_len) == 0) { nua_ee_data_t *ee = su_msg_data(sumsg); nua_event_data_t *e = ee->ee_data; void *p; if (tags) { tagi_t *t = e->e_tags, *t_end = (tagi_t *)((char *)t + len); void *b = t_end, *end = (char *)b + xtra; t = tl_dup(t, tags, &b); p = b; assert(t == t_end); assert(b == end); (void)end; } else p = e + 1; ee->ee_nua = nua_stack_ref(nua); e->e_event = event; e->e_nh = nh ? nua_handle_ref(nh) : NULL; e->e_status = status; e->e_phrase = strcpy(p, phrase ? phrase : ""); if (msg) e->e_msg = msg, su_home_threadsafe(msg_home(msg)); su_msg_deinitializer(sumsg, nua_event_deinit); su_msg_send_to(sumsg, nua->nua_client, nua_application_event); } return event; }
/** @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; }
/**Send a request message. * * @retval 0 if request is pending * @retval >=1 if error event has been sent * @retval < 0 if no error event has been sent */ static int nua_client_request_sendmsg(nua_client_request_t *cr) { nua_handle_t *nh = cr->cr_owner; nua_dialog_state_t *ds = nh->nh_ds; sip_method_t method = cr->cr_method; char const *name = cr->cr_method_name; url_string_t const *url = (url_string_t *)cr->cr_target; nta_leg_t *leg; msg_t *msg; sip_t *sip; int error; assert(cr->cr_orq == NULL); cr->cr_offer_sent = cr->cr_answer_recv = 0; cr->cr_offer_recv = cr->cr_answer_sent = 0; if (!ds->ds_leg && cr->cr_dialog) { ds->ds_leg = nta_leg_tcreate(nh->nh_nua->nua_nta, nua_stack_process_request, nh, SIPTAG_CALL_ID(cr->cr_sip->sip_call_id), SIPTAG_FROM(cr->cr_sip->sip_from), SIPTAG_TO(cr->cr_sip->sip_to), SIPTAG_CSEQ(cr->cr_sip->sip_cseq), TAG_END()); if (!ds->ds_leg) return -1; } if (cr->cr_sip->sip_from && ds->ds_leg) { if (cr->cr_sip->sip_from->a_tag == NULL) { if (sip_from_tag(msg_home(cr->cr_msg), cr->cr_sip->sip_from, nta_leg_tag(ds->ds_leg, NULL)) < 0) { return -1; } } } cr->cr_retry_count++; if (ds->ds_leg) leg = ds->ds_leg; else leg = nh->nh_nua->nua_dhandle->nh_ds->ds_leg; /* Default leg */ msg = msg_copy(cr->cr_msg), sip = sip_object(msg); if (msg == NULL) return -1; if (nua_dialog_is_established(ds)) { while (sip->sip_route) sip_route_remove(msg, sip); } else if (!ds->ds_route) { sip_route_t *initial_route = NH_PGET(nh, initial_route); if (initial_route) { initial_route = sip_route_dup(msg_home(msg), initial_route); if (!initial_route) return -1; msg_header_prepend(msg, (msg_pub_t*)sip, /* This should be (msg_header_t **)&sip->sip_route * but directly casting pointer &sip->sip_route gives * spurious type-punning warning */ (msg_header_t **)((char *)sip + offsetof(sip_t, sip_route)), (msg_header_t *)initial_route); } } /** * For in-dialog requests, the request URI is taken from the @Contact * header received from the remote party during dialog establishment, * and the NUTAG_URL() is ignored. * * Also, the @CallID and @CSeq headers and @From and @To tags are * generated based on the dialog information and added to the request. * If the dialog has a route, it is added to the request, too. */ if (nta_msg_request_complete(msg, leg, method, name, url) < 0) { msg_destroy(msg); return -1; } /**@MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is * also added now, if it does not exist. */ if (!ds->ds_remote) ds->ds_remote = sip_to_dup(nh->nh_home, sip->sip_to); if (!ds->ds_local) ds->ds_local = sip_from_dup(nh->nh_home, sip->sip_from); /** * Next, values previously set with nua_set_params() or nua_set_hparams() * are used: @Allow, @Supported, @Organization, @UserAgent and * @AllowEvents headers are added to the request if they are not already * set. */ if (!sip->sip_allow) sip_add_dup(msg, sip, (sip_header_t*)NH_PGET(nh, allow)); if (!sip->sip_supported && NH_PGET(nh, supported)) sip_add_dup(msg, sip, (sip_header_t *)NH_PGET(nh, supported)); if (method == sip_method_register && NH_PGET(nh, path_enable) && !sip_has_feature(sip->sip_supported, "path") && !sip_has_feature(sip->sip_require, "path")) sip_add_make(msg, sip, sip_supported_class, "path"); if (!sip->sip_organization && NH_PGET(nh, organization)) sip_add_make(msg, sip, sip_organization_class, NH_PGET(nh, organization)); if (!sip->sip_user_agent && NH_PGET(nh, user_agent)) sip_add_make(msg, sip, sip_user_agent_class, NH_PGET(nh, user_agent)); /** Any node implementing one or more event packages SHOULD include an * appropriate @AllowEvents header indicating all supported events in * all methods which initiate dialogs and their responses (such as * INVITE) and OPTIONS responses. */ if (!sip->sip_allow_events && NH_PGET(nh, allow_events) && (method == sip_method_notify || /* Always in NOTIFY */ (!ds->ds_remote_tag && /* And in initial requests */ (method == sip_method_subscribe || method == sip_method_refer || method == sip_method_options || method == sip_method_invite)))) sip_add_dup(msg, sip, (void *)NH_PGET(nh, allow_events)); /** * Next, the stack generates a @Contact header for the request (unless * the application already gave a @Contact header or it does not want to * use @Contact and indicates that by including SIPTAG_CONTACT(NULL) or * SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the * application has registered the URI in @From header, the @Contact * header used with registration is used. Otherwise, the @Contact header * is generated from the local IP address and port number. */ /**For the initial requests, @ServiceRoute set that was received from the * registrar is also added to the request message. */ if (cr->cr_method != sip_method_register) { if (cr->cr_contactize && cr->cr_has_contact) { sip_contact_t *ltarget = sip_contact_dup(nh->nh_home, sip->sip_contact); if (ds->ds_ltarget) msg_header_free(nh->nh_home, (msg_header_t *)ds->ds_ltarget); ds->ds_ltarget = ltarget; } if (ds->ds_ltarget && !cr->cr_has_contact) sip_add_dup(msg, sip, (sip_header_t *)ds->ds_ltarget); if (nua_registration_add_contact_to_request(nh, msg, sip, cr->cr_contactize && !cr->cr_has_contact && !ds->ds_ltarget, !ds->ds_route) < 0) { msg_destroy(msg); return -1; } } cr->cr_wait_for_cred = 0; if (cr->cr_methods->crm_send) error = cr->cr_methods->crm_send(cr, msg, sip, NULL); else error = nua_base_client_request(cr, msg, sip, NULL); if (error == -1) msg_destroy(msg); return error; }
/**Add message separator, then test if message is complete. * * Add sip_content_length and sip_separator if they are missing. * The test that all necessary message components ( @From, @To, * @CSeq, @CallID, @ContentLength and message separator are present. * * @retval 0 when successful * @retval -1 upon an error: headers are missing and they could not be added */ int sip_complete_message(msg_t *msg) { sip_t *sip = sip_object(msg); su_home_t *home = msg_home(msg); size_t len = 0; ssize_t mplen; if (sip == NULL) return -1; if (!sip->sip_separator) sip->sip_separator = sip_separator_create(msg_home(msg)); if (sip->sip_multipart) { sip_content_type_t *c = sip->sip_content_type; msg_multipart_t *mp = sip->sip_multipart; sip_common_t *head; if (!c || msg_multipart_complete(msg_home(msg), c, mp) < 0) return -1; if (sip->sip_payload) head = sip->sip_payload->pl_common; else head = sip->sip_separator->sep_common; if (!head || !msg_multipart_serialize(&head->h_succ, mp)) return -1; mplen = msg_multipart_prepare(msg, mp, sip->sip_flags); if (mplen == -1) return -1; len = (size_t)mplen; } if (sip->sip_payload) len += sip->sip_payload->pl_len; if (len > UINT32_MAX) return -1; if (!sip->sip_content_length) { msg_header_insert(msg, (msg_pub_t *)sip, (msg_header_t*) sip_content_length_create(home, (uint32_t)len)); } else { if (sip->sip_content_length->l_length != len) { sip->sip_content_length->l_length = (uint32_t)len; sip_fragment_clear(sip->sip_content_length->l_common); } } if (!sip->sip_cseq || !sip->sip_call_id || !sip->sip_to || !sip->sip_from || !sip->sip_separator || !sip->sip_content_length) return -1; return 0; }
static tport_t *tport_http_connect(tport_primary_t *pri, su_addrinfo_t *ai, tp_name_t const *tpn) { tport_http_connect_t *thc = (tport_http_connect_t *)pri; tport_http_connect_instance_t *thci; tport_master_t *mr = pri->pri_master; msg_t *msg, *response; char hostport[TPORT_HOSTPORTSIZE]; tport_t *tport; http_request_t *rq; msg = msg_create(http_default_mclass(), 0); if (!msg) return NULL; tport_hostport(hostport, sizeof hostport, (void *)ai->ai_addr, 1); rq = http_request_format(msg_home(msg), "CONNECT %s HTTP/1.1", hostport); if (msg_header_insert(msg, NULL, (void *)rq) < 0 || msg_header_add_str(msg, NULL, "User-Agent: Sofia-SIP/" VERSION "\n") < 0 || msg_header_add_str(msg, NULL, "Proxy-Connection: keepalive\n") < 0 || msg_header_add_make(msg, NULL, http_host_class, hostport) < 0 || msg_header_add_make(msg, NULL, http_separator_class, "\r\n") < 0 || msg_serialize(msg, NULL) < 0 || msg_prepare(msg) < 0) return (void)msg_destroy(msg), NULL; /* * Create a response message that ignores the body * if there is no Content-Length */ response = msg_create(http_default_mclass(), mr->mr_log | MSG_FLG_MAILBOX); tport = tport_base_connect(pri, thc->thc_proxy, ai, tpn); if (!tport) { msg_destroy(msg); msg_destroy(response); return tport; } thci = (tport_http_connect_instance_t*)tport; thci->thci_response = response; tport->tp_msg = response; msg_set_next(response, thci->thci_stackmsg = tport_msg_alloc(tport, 512)); if (tport_send_msg(tport, msg, tpn, NULL) < 0) { SU_DEBUG_9(("tport_send_msg failed in tpot_http_connect\n" VA_NONE)); msg_destroy(msg); tport_zap_secondary(tport); return NULL; } tport_set_secondary_timer(tport); return tport; }