/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * */ /**@CFILE nta_compat.c * @brief Compatibility functions for Nokia SIP Transaction API * * These functions are deprecated and should not be used anymore. * * @author Pekka Pessi * * @date Created: Tue Jul 24 22:28:34 2001 ppessi */ #include "config.h" #include #include #include #include #include "sofia-sip/nta.h" #include "nta_compat.h" #include "nta_internal.h" #include #include /** Set UAS flag value. * * The function nta_agent_set_uas() is used to set or clear User Agent * Server flag. * * Currently, the flag determines how the agent handles 2XX replies to an * incoming INVITE request. If flag is set, the agent resends the 2XX final * responses to an INVITE. * * @deprecated Use nta_agent_set_params() and NTATAG_UA() instead. */ int nta_agent_set_uas(nta_agent_t *agent, int value) { int retval = 1; nta_agent_set_params(agent, NTATAG_UA(value != 0), TAG_END()); nta_agent_get_params(agent, NTATAG_UA_REF(retval), TAG_END()); return retval; } /** Set branch key. * * @deprecated Use nta_agent_set_params() and NTATAG_BRANCH_KEY() instead. */ msg_param_t nta_agent_set_branch(nta_agent_t *agent, msg_param_t branch) { msg_param_t retval = ""; nta_agent_set_params(agent, NTATAG_BRANCH_KEY(branch), TAG_END()); nta_agent_get_params(agent, NTATAG_BRANCH_KEY_REF(retval), TAG_END()); return retval; } /** Set default proxy. * * @deprecated Use nta_agent_set_params() and NTATAG_DEFAULT_PROXY() instead. */ int nta_agent_set_proxy(nta_agent_t *agent, url_string_t const *u) { if (agent) nta_agent_set_params(agent, NTATAG_DEFAULT_PROXY(u), TAG_END()); return 0; } /**Return default @b Tag. * * The function nta_agent_tag() returns the default @To @b tag * which is used by NTA agent. * * @param agent NTA agent object * * @return The default tag used by NTA agent. * * @deprecated Use nta_agent_newtag() to generate a new, unique tag value. * * @sa NTATAG_TAG_3261(). */ msg_param_t nta_agent_tag(nta_agent_t const *agent) { return (agent && agent->sa_2543_tag) ? agent->sa_2543_tag + strlen("tag=") : NULL; } /** Reply to the request message. */ int nta_msg_reply(nta_agent_t *agent, msg_t *msg, int status, char const *phrase, void *extra, ...) { int retval; va_list(headers); va_start(headers, extra); retval = nta_msg_vreply(agent, msg, status, phrase, extra, headers); va_end(headers); return retval; } /** Reply to the request message (stdarg version of nta_msg_reply()). */ int nta_msg_vreply(nta_agent_t *agent, msg_t *req_msg, int status, char const *phrase, void *extra, va_list headers) { msg_t *reply = nta_msg_create(agent, 0); sip_t *sip = sip_object(reply); if (sip_add_headers(reply, sip, extra, headers) < 0) sip = NULL; return nta_msg_mreply(agent, reply, sip, status, phrase, req_msg, TAG_END()); } /** Send the message (stdarg version of nta_msg_send()). */ int nta_msg_vsend(nta_agent_t *agent, msg_t *msg, url_string_t const *u, void *extra, va_list headers) { sip_t *sip = sip_object(msg); if (extra && sip_add_headers(msg, sip, extra, headers) < 0) { msg_destroy(msg); return -1; } return nta_msg_tsend(agent, msg, u, TAG_END()); } /** Send the message. */ int nta_msg_send(nta_agent_t *agent, msg_t *msg, url_string_t const *u, void *extra, ...) { int retval; va_list headers; va_start(headers, extra); retval = nta_msg_vsend(agent, msg, u, extra, headers); va_end(headers); return retval; } /** * Create a new leg object for incoming request message. * * @param agent agent object * @param callback function which is called for each * incoming request belonging to this leg * @param magic call leg context * @param msg a request message * * @note The ownership of @a msg will pass back to NTA upon successful call * to the function nta_msg_leg(). In other words, if the call to @a * nta_msg_leg() is successful, the application may not do anything with @a * msg anymore. Instead of that, NTA will create of a new incoming request * object for the @a msg and eventually return the request to application by * calling the @a callback function. * * @deprecated Use nta_leg_stateful() instead. */ nta_leg_t *nta_msg_leg(nta_agent_t *agent, msg_t *msg, nta_request_f *callback, nta_leg_magic_t *magic, ...) { nta_leg_t *leg; sip_t *sip = sip_object(msg); SU_DEBUG_9(("\tnta_msg_leg(): called\n")); assert(msg && sip && sip->sip_request); if (!msg || !sip || !sip->sip_request || !callback) return NULL; leg = nta_leg_tcreate(agent, callback, magic, SIPTAG_CALL_ID(sip->sip_call_id), SIPTAG_FROM(sip->sip_to), /* local address */ SIPTAG_TO(sip->sip_from), /* remote address */ TAG_END()); if (!leg) /* xyzzy */; else if (nta_leg_server_route(leg, sip->sip_record_route, sip->sip_contact) < 0) nta_leg_destroy(leg), leg = NULL; else if (nta_leg_stateful(leg, msg) < 0) nta_leg_destroy(leg), leg = NULL; SU_DEBUG_9(("\tnta_msg_leg(): returns %p\n", leg)); return leg; } static void sm_leg_recv(su_root_magic_t *rm, su_msg_r msg, union sm_arg_u *u); /** Process msg statefully using the leg. */ int nta_leg_stateful(nta_leg_t *leg, msg_t *msg) { su_msg_r su_msg = SU_MSG_RINITIALIZER; nta_agent_t *agent = leg->leg_agent; su_root_t *root = agent->sa_root; struct leg_recv_s *a; /* Create a su message that is passed to NTA network thread */ if (su_msg_create(su_msg, su_root_task(root), su_root_task(root), sm_leg_recv, /* Function to call */ sizeof(struct leg_recv_s)) == SU_FAILURE) return -1; agent->sa_stats->as_trless_to_tr++; a = su_msg_data(su_msg)->a_leg_recv; a->leg = leg; a->msg = msg; a->tport = tport_incref(tport_delivered_by(agent->sa_tports, msg)); return su_msg_send(su_msg); } /** @internal Delayed leg_recv(). */ static void sm_leg_recv(su_root_magic_t *rm, su_msg_r msg, union sm_arg_u *u) { struct leg_recv_s *a = u->a_leg_recv; leg_recv(a->leg, a->msg, sip_object(a->msg), a->tport); tport_decref(&a->tport); } /**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 headers, terminated with a @c NULL * * @deprecated Use nta_leg_tcreate() instead. */ nta_leg_t *nta_leg_create(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, ...) { nta_leg_t *leg; va_list headers; va_start(headers, extra); leg = nta_leg_vcreate(agent, callback, magic, i, from, to, extra, headers); va_end(headers); return leg; } /** * 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()); } /**Mark leg as branchable. * * This function does currently absolutely nothing. * * @param leg leg to be marked branchable. * * @note Currently, all legs @b are branchable. * * @deprecated Do not use. */ int nta_leg_branch(nta_leg_t *leg) { return 0; } /** Add route from final response * * @deprecated Use nta_leg_client_route(). */ int nta_leg_route(nta_leg_t *leg, sip_record_route_t const *route, sip_contact_t const *contact, url_string_t const *url) { return nta_leg_client_route(leg, route, contact); } #if 0 /**Get response message. * * The function nta_incoming_getresponse() retrieves a copy of the latest * outgoing response message. The response message is copied; the original * copy is kept by the transaction. * * @param irq incoming (server) transaction handle * * @retval * A pointer to the copy of the response message is returned, or NULL if an * error occurred. */ msg_t *nta_incoming_getresponse(nta_incoming_t *irq) { if (irq && irq->irq_response) { msg_t *msg = nta_msg_create(irq->irq_agent, 0); sip_t *sip = sip_object(msg); msg_clone(msg, irq->irq_response); /* Copy the SIP headers from the old message */ if (msg_copy_all(msg, sip, sip_object(irq->irq_response)) >= 0) return msg; msg_destroy(msg); } return NULL; } /**Get request message. * * The function nta_outgoing_getrequest() retrieves the request message sent * to the network. The request message is copied; the original copy is kept * by the transaction. * * @param orq outgoing transaction handle * * @retval * A pointer to the copy of the request message is returned, or NULL if an * error occurred. */ msg_t *nta_outgoing_getrequest(nta_outgoing_t *orq) { if (orq && orq->orq_request) { msg_t *msg = nta_msg_create(orq->orq_agent, 0); sip_t *sip = sip_object(msg); msg_clone(msg, orq->orq_request); /* Copy the SIP headers from the old message */ if (sip_copy_all(msg, sip, sip_object(orq->orq_request)) >= 0) return msg; msg_destroy(msg); } return NULL; } /**Get latest response message. * * The function nta_outgoing_getresponse() retrieves the latest incoming * response message to the outgoing transaction. Note that the message is * not copied, but removed from the transaction. * * @param orq outgoing transaction handle * * @retval * A pointer to response message is returned, or NULL if no response message * has been received or the response message has already been retrieved. */ msg_t *nta_outgoing_getresponse(nta_outgoing_t *orq) { msg_t *msg = NULL; if (orq && orq->orq_response) msg = orq->orq_response, orq->orq_response = NULL; return msg; } #endif /** Create an outgoing request belonging to the leg. * * The function nta_outgoing_create() creates an outgoing transaction and * sends the request. The request is sent to the @a route_url (if * non-NULL), default proxy (as specified by nta_agent_set_proxy()), or to * the address specified by @a request_uri. In the latest case, all the * tranport parameters are stripped from the request_uri. If no @a * request_uri is specified, it is taken from the @To header. * * When NTA receives response to the request, it invokes the @c callback * function. * * @param leg call leg object * @param callback callback function (may be @c NULL) * @param magic application context pointer * @param route_url URL used to route transaction requests * @param method method type * @param name method name * @param request_uri Request-URI * @param extra, ... list of extra headers * * @return * The function nta_outgoing_create() returns a pointer to newly created * outgoing transaction object if successful, and NULL otherwise. * * @deprecated * Use nta_outgoing_tcreate() or nta_outgoing_mcreate() instead. */ nta_outgoing_t *nta_outgoing_create(nta_leg_t *leg, nta_response_f *callback, nta_outgoing_magic_t *magic, url_string_t const *route_url, sip_method_t method, char const *name, url_string_t const *request_uri, void const *extra, ...) { nta_outgoing_t *orq; va_list headers; va_start(headers, extra); orq = nta_outgoing_vcreate(leg, callback, magic, route_url, method, name, request_uri, extra, headers); va_end(headers); return orq; } /**Create a request belonging to the leg * (stdarg version of nta_outgoing_create()). * * @deprecated * Use nta_outgoing_tcreate() or nta_outgoing_mcreate() instead. */ nta_outgoing_t *nta_outgoing_vcreate(nta_leg_t *leg, nta_response_f *callback, nta_outgoing_magic_t *magic, url_string_t const *route_url, sip_method_t method, char const *name, url_string_t const *request_uri, void const *extra, va_list headers) { nta_agent_t *agent = leg->leg_agent; msg_t *msg = nta_msg_create(agent, 0); sip_t *sip = sip_object(msg); nta_outgoing_t *orq; if (extra && sip_add_headers(msg, sip, extra, headers) < 0) orq = NULL; else if (route_url && leg->leg_route && !sip->sip_route && sip_add_dup(msg, sip, (sip_header_t *)leg->leg_route) < 0) orq = NULL; else if (nta_msg_request_complete(msg, leg, method, name, request_uri) < 0) orq = NULL; else orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg); if (!orq) msg_destroy(msg); return orq; } /**Forward a request. * * @deprecated * Use nta_outgoing_mcreate() instead. */ nta_outgoing_t *nta_outgoing_tclone(nta_agent_t *agent, nta_response_f *callback, nta_outgoing_magic_t *magic, url_string_t const *route_url, msg_t *parent, tag_type_t tag, tag_value_t value, ...) { ta_list ta; msg_t *msg; nta_outgoing_t *orq = NULL; if (parent == NULL) return NULL; if ((msg = nta_msg_create(agent, 0)) == NULL) return NULL; ta_start(ta, tag, value); msg_clone(msg, parent); if (parent && sip_copy_all(msg, sip_object(msg), sip_object(parent)) < 0) ; else if (sip_add_tl(msg, sip_object(msg), ta_tags(ta)) < 0) ; else orq = nta_outgoing_mcreate(agent, callback, magic, route_url, msg); ta_end(ta); if (!orq) msg_destroy(msg); return orq; } /** Forward a request belonging to the leg. * * The function nta_outgoing_forward() will create an outgoing transaction * based on the incoming transaction. The forwarded message is specified by * @a isip parameter. The caller rewrite the URL by giving non-NULL @a * request_url. * * The request is sent to the server specified by @a route_url if it is * non-NULL. * * @deprecated * Use nta_outgoing_mcreate() instead. */ nta_outgoing_t *nta_outgoing_forward(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 *ireq, sip_t const *isip, void const *extra, ...) { nta_outgoing_t *orq; va_list headers; va_start(headers, extra); orq = nta_outgoing_vforward(leg, callback, magic, route_url, request_uri, ireq, isip, extra, headers); va_end(headers); return orq; } /**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; } /** Fork an outgoing request toward another destination. * * @deprecated * Use nta_outgoing_mcreate() instead. */ nta_outgoing_t *nta_outgoing_fork(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, ...) { nta_outgoing_t *orq; va_list headers; va_start(headers, extra); orq = nta_outgoing_vfork(old_orq, callback, magic, route_url, request_uri, extra, headers); va_end(headers); return orq; } /** 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; } /** * Reply to an incoming transaction request. * * This function creates and sends a response message to an incoming request. * It is possible to send several non-final (1xx) responses, but only one * final response. * * @param irq incoming request * @param status status code * @param phrase status phrase (may be NULL if status code is well-known) * @param extra, ... optional additional headers terminated by NULL * * @deprecated * Use nta_incoming_treply() instead. */ int nta_incoming_reply(nta_incoming_t *irq, int status, char const *phrase, void const *extra, ...) { int retval; va_list headers; va_start(headers, extra); retval = nta_incoming_vreply(irq, status, phrase, extra, headers); va_end(headers); return retval; } /**Reply to an incoming transaction request (stdarg version). * * @deprecated * Use nta_incoming_treply() instead. */ int nta_incoming_vreply(nta_incoming_t *irq, int status, char const *phrase, void const *extra, va_list headers) { if (irq->irq_status < 200 || status < 200 || (irq->irq_method == sip_method_invite && status < 300)) { msg_t *msg = nta_msg_create(irq->irq_agent, 0); sip_t *sip = sip_object(msg); if (!msg) return -1; else if (nta_msg_response_complete(msg, irq, status, phrase) < 0) msg_destroy(msg); else if (sip_add_headers(msg, sip, extra, headers) < 0 ) msg_destroy(msg); else if (sip_message_complete(msg) < 0) msg_destroy(msg); else if (nta_incoming_mreply(irq, msg) < 0) msg_destroy(msg); else return 0; } return -1; } /** * Forward a response to incoming transaction. * * This function forwards a response message from outgoing request to an * incoming request. It copies the message save the first via field, and * send the response message to the address specified in the second via. * * It is possible to send several non-final (1xx) responses, but only one * final response. * * @param irq incoming request * @param orq * @param sip message structure for outgoing transaction * @param extra, ... list of optional additional headers terminated by NULL * * @bug Adding extra headers is unimplemented. * * @deprecated Use nta_incoming_mreply() instead. */ int nta_incoming_forward(nta_incoming_t *irq, nta_outgoing_t *orq, sip_t const *sip, void const *extra, ...) { msg_t *msg = nta_outgoing_response(orq); int status; if (irq == NULL || sip == NULL || msg == NULL || sip != sip_object(msg)) return -1; status = sip->sip_status->st_status; sip_via_remove(msg, (sip_t *)sip); /* Remove topmost via */ if (sip_message_complete(msg) < 0) msg_destroy(msg); if (nta_incoming_mreply(irq, msg) < 0) msg_destroy(msg); else return 0; return -1; } /** 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); }