tm/uac.c

Go to the documentation of this file.
00001 /*
00002  * $Id: uac.c 5376 2008-12-17 19:07:14Z osas $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * --------
00024  *  2003-01-23  t_uac_dlg now uses get_out_socket (jiri)
00025  *  2003-01-27  fifo:t_uac_dlg completed (jiri)
00026  *  2003-01-29  scratchpad removed (jiri)
00027  *  2003-02-13  t_uac, t _uac_dlg, gethfblock, uri2proxy changed to use 
00028  *               proto & rb->dst (andrei)
00029  *  2003-02-27  FIFO/UAC now dumps reply -- good for CTD (jiri)
00030  *  2003-02-28  scratchpad compatibility abandoned (jiri)
00031  *  2003-03-01  kr set through a function now (jiri)
00032  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
00033  *  2003-04-02  port_no_str does not contain a leading ':' anymore (andrei)
00034  *  2003-07-08  appropriate log messages in check_params(...), 
00035  *               call calculate_hooks if next_hop==NULL in t_uac (dcm) 
00036  *  2003-10-24  updated to the new socket_info lists (andrei)
00037  *  2003-12-03  completion filed removed from transaction and uac callbacks
00038  *              merged in transaction callbacks as LOCAL_COMPLETED (bogdan)
00039  *  2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
00040  *  2004-02-13  t->is_invite, t->local, t->noisy_ctimer replaced (bogdan)
00041  *  2004-08-23  avp support in t_uac (bogdan)
00042  *
00043  */
00044 
00045 /*! \file
00046  * \brief TM :: Simple user agent support
00047  *
00048  * \ingroup tm
00049  * - Module: \ref tm
00050  *
00051  * Simple UAC for things such as SUBSCRIBE or SMS gateway;
00052  * no authentication and other UAC features -- just send
00053  * a message, retransmit and await a reply; forking is not
00054  * supported during client generation, in all other places
00055  * it is -- adding it should be simple
00056  */
00057 
00058 #include <string.h>
00059 #include "../../mem/shm_mem.h"
00060 #include "../../dprint.h"
00061 #include "../../md5.h"
00062 #include "../../socket_info.h"
00063 
00064 #ifdef USE_LOCAL_ROUTE
00065 #include "../../receive.h"
00066 #include "../../route.h"
00067 #include "../../action.h"
00068 #include "../../dset.h"
00069 #endif
00070 
00071 #include "ut.h"
00072 #include "h_table.h"
00073 #include "t_hooks.h"
00074 #include "t_funcs.h"
00075 #include "t_msgbuilder.h"
00076 #include "callid.h"
00077 #include "uac.h"
00078 
00079 /*! from tag length, MD5 + '-' + CRC16 */
00080 #define FROM_TAG_LEN (MD5_LEN + 1 /* - */ + CRC16_LEN)
00081 
00082 /*! from tag */
00083 static char from_tag[FROM_TAG_LEN + 1];
00084 
00085 /*! Enable/disable passing of provisional replies to FIFO applications */
00086 int pass_provisional_replies = 0;
00087 
00088 
00089 /*!
00090  * \brief Initialize UAC
00091  */
00092 int uac_init(void) 
00093 {
00094    str src[3];
00095    struct socket_info *si;
00096 
00097    if (RAND_MAX < TM_TABLE_ENTRIES) {
00098       LM_WARN("uac does not spread across the whole hash table\n");
00099    }
00100    /* on tcp/tls bind_address is 0 so try to get the first address we listen
00101     * on no matter the protocol */
00102    si=bind_address?bind_address:get_first_socket();
00103    if (si==0){
00104       LM_CRIT("null socket list\n");
00105       return -1;
00106    }
00107 
00108    /* calculate the initial From tag */
00109    src[0].s = "Long live SER server";
00110    src[0].len = strlen(src[0].s);
00111    src[1].s = si->address_str.s;
00112    src[1].len = strlen(src[1].s);
00113    src[2].s = si->port_no_str.s;
00114    src[2].len = strlen(src[2].s);
00115 
00116    MD5StringArray(from_tag, src, 3);
00117    from_tag[MD5_LEN] = '-';
00118    return 1;
00119 }
00120 
00121 
00122 /*!
00123  * \brief Generate a From tag from the callid
00124  * \note update the global from tag value
00125  * \param tag tag generated tag
00126  * \param callid source callid
00127  */
00128 void generate_fromtag(str* tag, str* callid)
00129 {
00130    /* calculate from tag from callid */
00131    crcitt_string_array(&from_tag[MD5_LEN + 1], callid, 1);
00132    tag->s = from_tag;
00133    tag->len = FROM_TAG_LEN;
00134 }
00135 
00136 
00137 /*!
00138  * \brief Check value of parameters
00139  * \param method SIP method
00140  * \param to To URI
00141  * \param from From URI
00142  * \param dialog dialog state
00143  * \return 0 if parameter are ok, negative on error
00144  */
00145 static inline int check_params(str* method, str* to, str* from, dlg_t** dialog)
00146 {
00147    if (!method || !to || !from || !dialog) {
00148       LM_ERR("invalid parameter value\n");
00149       return -1;
00150    }
00151 
00152    if (!method->s || !method->len) {
00153       LM_ERR("invalid request method\n");
00154       return -2;
00155    }
00156 
00157    if (!to->s || !to->len) {
00158       LM_ERR("invalid To URI\n");
00159       return -4;
00160    }
00161 
00162    if (!from->s || !from->len) {
00163       LM_ERR("invalid From URI\n");
00164       return -5;
00165    }
00166    return 0;
00167 }
00168 
00169 
00170 /*!
00171  * \brief Generate a hash from a dialog state
00172  * \param dlg dialog state
00173  * \return generated hash
00174  */
00175 static inline unsigned int dlg2hash( dlg_t* dlg )
00176 {
00177    str cseq_nr;
00178    unsigned int hashid;
00179 
00180    cseq_nr.s=int2str(dlg->loc_seq.value, &cseq_nr.len);
00181    hashid = tm_hash(dlg->id.call_id, cseq_nr);
00182    LM_DBG("%d\n", hashid);
00183    return hashid;
00184 }
00185 
00186 
00187 #ifdef USE_LOCAL_ROUTE
00188 static inline struct sip_msg* buf_to_sip_msg(char *buf, unsigned int len,  
00189                                                 dlg_t *dialog)
00190 {
00191    static struct sip_msg req;
00192 
00193    memset( &req, 0, sizeof(req) );
00194    req.id = get_next_msg_no();
00195    req.buf = buf;
00196    req.len = len;
00197    if (parse_msg(buf, len, &req)!=0) {
00198       LM_CRIT("BUG - buffer parsing failed!");
00199       return NULL;
00200    }
00201    /* populate some special fields in sip_msg */
00202       req.set_global_address=default_global_address;
00203       req.set_global_port=default_global_port;
00204    req.force_send_socket = dialog->send_sock; 
00205    if (set_dst_uri(&req, dialog->hooks.next_hop)) {
00206       LM_ERR("failed to set dst_uri");
00207       free_sip_msg(&req);
00208       return NULL;
00209    }
00210    req.rcv.proto = dialog->send_sock->proto;
00211    req.rcv.src_ip = dialog->send_sock->address;
00212    req.rcv.src_port = dialog->send_sock->port_no;
00213 
00214    return &req;
00215 }
00216 #endif
00217 
00218 
00219 /*!
00220  * \brief Send a request using data from the dialog structure
00221  * \param method SIP method
00222  * \param headers SIP header
00223  * \param body 
00224  * \param dialog dialog state
00225  * \param cb transaction callback
00226  * \param cbp transaction callback parameter
00227  * \return 1 on success, negative on error
00228  */
00229 int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
00230                                     transaction_cb cb, void* cbp)
00231 {
00232    union sockaddr_union to_su;
00233    struct cell *new_cell;
00234    struct retr_buf *request;
00235 #ifndef USE_LOCAL_ROUTE
00236    char* buf;
00237    int buf_len, ret, flags;
00238 #else
00239    static struct sip_msg *req;
00240    struct usr_avp **backup;
00241    char *buf, *buf1;
00242    int buf_len, buf_len1;
00243    int ret, flags, sflag_bk;
00244    int backup_route_type;
00245 #endif
00246    unsigned int hi;
00247 
00248    ret=-1;
00249    
00250    /*** added by dcm 
00251     * - needed by external ua to send a request within a dlg
00252     */
00253    if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0)
00254       goto error2;
00255 
00256    LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len,
00257          dialog->hooks.next_hop->s);
00258    /* it's a new message, so we will take the default socket */
00259    if (dialog->send_sock) {
00260       if (uri2su( dialog->hooks.next_hop, &to_su,
00261       dialog->send_sock->proto)==-1) {
00262          goto error2;
00263       }
00264    } else {
00265       dialog->send_sock = uri2sock(0, dialog->hooks.next_hop, &to_su,
00266          PROTO_NONE);
00267       if (dialog->send_sock==0) {
00268          ret=ser_error;
00269          LM_ERR("no socket found\n");
00270          goto error2;
00271       }
00272    }
00273 
00274    new_cell = build_cell(0); 
00275    if (!new_cell) {
00276       ret=E_OUT_OF_MEM;
00277       LM_ERR("short of cell shmem\n");
00278       goto error2;
00279    }
00280 
00281    /* pass the transaction flags from dialog to transaction */
00282    new_cell->flags |= dialog->T_flags;
00283 
00284    /* add the callback the transaction for LOCAL_COMPLETED event */
00285    flags = TMCB_LOCAL_COMPLETED;
00286    /* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */
00287    if (pass_provisional_replies || pass_provisional(new_cell))
00288       flags |= TMCB_LOCAL_RESPONSE_OUT;
00289    if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,0)!=1){
00290       ret=E_OUT_OF_MEM;
00291       LM_ERR("short of tmcb shmem\n");
00292       goto error2;
00293    }
00294 
00295    if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0)
00296       new_cell->flags |= T_IS_INVITE_FLAG;
00297    new_cell->flags |= T_IS_LOCAL_FLAG;
00298 
00299    request = &new_cell->uac[0].request;
00300    request->dst.to = to_su;
00301    request->dst.send_sock = dialog->send_sock;
00302    request->dst.proto = dialog->send_sock->proto;
00303    request->dst.proto_reserved1 = 0;
00304 
00305    hi=dlg2hash(dialog);
00306    LOCK_HASH(hi);
00307    insert_into_hash_table_unsafe(new_cell, hi);
00308    UNLOCK_HASH(hi);
00309 
00310    buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len);
00311    if (!buf) {
00312       LM_ERR("failed to build message\n");
00313       ret=E_OUT_OF_MEM;
00314       goto error1;
00315    }
00316 
00317 #ifdef USE_LOCAL_ROUTE
00318    if (local_rlist) {
00319       LM_DBG("building sip_msg from buffer\n");
00320       req = buf_to_sip_msg(buf, buf_len, dialog);
00321       if (req==NULL) {
00322          LM_ERR("failed to build sip_msg from buffer");
00323       } else {
00324          /* set transaction AVP list */
00325          backup = set_avp_list( &new_cell->user_avps );
00326          /* backup script flags */
00327          sflag_bk = getsflags();
00328          /* disable parallel forking */
00329          set_dset_state( 0 /*disable*/);
00330 
00331          /* run the route */
00332          swap_route_type( backup_route_type, LOCAL_ROUTE);
00333          run_top_route( local_rlist, req);
00334          set_route_type( backup_route_type );
00335 
00336          set_dset_state( 1 /*enable*/);
00337          setsflagsval(sflag_bk);
00338          set_avp_list( backup );
00339 
00340          /* check for changes - if none, do not regenerate the buffer 
00341           * we ignore any change on RURI and DSTURI and they should not
00342           * be changed  -bogdan */
00343          if (req->new_uri.s)
00344             { pkg_free(req->new_uri.s); req->new_uri.s=0; req->new_uri.len=0; }
00345          if (req->dst_uri.s)
00346             { pkg_free(req->dst_uri.s); req->dst_uri.s=0; req->dst_uri.len=0; }
00347 
00348          if (req->add_rm || req->body_lumps) {
00349             LM_DBG("re-building the buffer (sip_msg changed) - lumps are"
00350                "%p %p\n",req->add_rm, req->body_lumps);
00351             /* build the shm buffer now */
00352             buf1 = build_req_buf_from_sip_req(req,(unsigned int*)&buf_len1,
00353                dialog->send_sock, dialog->send_sock->proto,
00354                MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG );
00355             if (!buf1) {
00356                LM_ERR("no more shm mem\n"); 
00357                free_sip_msg(req);
00358                /* keep original buffer */
00359             } else {
00360                shm_free(buf);
00361                buf = buf1;
00362                buf_len = buf_len1;
00363                /* use new buffer */
00364             }
00365          }
00366       }
00367    }
00368 #endif
00369 
00370    new_cell->method.s = buf;
00371    new_cell->method.len = method->len;
00372 
00373    request->buffer.s = buf;
00374    request->buffer.len = buf_len;
00375    new_cell->nr_of_outgoings++;
00376    
00377    if (SEND_BUFFER(request) == -1) {
00378       LM_ERR("attempt to send to '%.*s' failed\n", 
00379          dialog->hooks.next_hop->len,
00380          dialog->hooks.next_hop->s);
00381    }
00382    
00383    start_retr(request);
00384    return 1;
00385 
00386 error1:
00387    LOCK_HASH(hi);
00388    remove_from_hash_table_unsafe(new_cell);
00389    UNLOCK_HASH(hi);
00390    free_cell(new_cell);
00391 error2:
00392    return ret;
00393 }
00394 
00395 
00396 /*!
00397  * \brief Send a message within a dialog
00398  * \param method SIP method
00399  * \param headers SIP header
00400  * \param body SIP body
00401  * \param dialog dialog state
00402  * \param completion_cb transaction callback
00403  * \param cbp transaction callback parameter
00404  * \return 1 on success, negative on error
00405  */
00406 int req_within(str* method, str* headers, str* body, dlg_t* dialog,
00407                            transaction_cb completion_cb, void* cbp)
00408 {
00409    if (!method || !dialog) {
00410       LM_ERR("invalid parameter value\n");
00411       goto err;
00412    }
00413 
00414    if (dialog->state != DLG_CONFIRMED) {
00415       LM_ERR("dialog is not confirmed yet\n");
00416       goto err;
00417    }
00418 
00419    if ( !( ((method->len == 3) && !memcmp("ACK", method->s, 3)) ||
00420            ((method->len == 6) && !memcmp("CANCEL", method->s, 6)) ) )  {
00421       dialog->loc_seq.value++; /* Increment CSeq */
00422    }
00423 
00424    return t_uac(method, headers, body, dialog, completion_cb, cbp);
00425 err:
00426    return -1;
00427 }
00428 
00429 
00430 /*!
00431  * \brief Send an initial request that will start a dialog
00432  * \param method SIP method
00433  * \param to To URI
00434  * \param from From URI
00435  * \param headers SIP headers
00436  * \param body SIP body
00437  * \param dialog dialog state
00438  * \param cb transaction callback
00439  * \param cbp transaction callback parameter
00440  * \return 1 on success, negative on error 
00441  */
00442 int req_outside(str* method, str* to, str* from, str* headers, str* body,
00443                         dlg_t** dialog, transaction_cb cb, void* cbp)
00444 {
00445    str callid, fromtag;
00446 
00447    if (check_params(method, to, from, dialog) < 0) goto err;
00448    
00449    generate_callid(&callid);
00450    generate_fromtag(&fromtag, &callid);
00451 
00452    if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, dialog) < 0) {
00453       LM_ERR("failed to create new dialog\n");
00454       goto err;
00455    }
00456 
00457    return t_uac(method, headers, body, *dialog, cb, cbp);
00458 err:
00459    return -1;
00460 }
00461 
00462 
00463 /*!
00464  * \brief Send a transactional request, no dialogs involved
00465  * \param m SIP method
00466  * \param ruri Request URI
00467  * \param to To URI
00468  * \param from From URI
00469  * \param h SIP headers
00470  * \param b SIP body
00471  * \param oburi outbound URI
00472  * \param cb transaction callback
00473  * \param cbp transaction callback parameter
00474  * \return 1 on success, negative on error 
00475  */
00476 int request(str* m, str* ruri, str* to, str* from, str* h, str* b, str *oburi,
00477                                  transaction_cb cb, void* cbp)
00478 {
00479    str callid, fromtag;
00480    dlg_t* dialog;
00481    int res;
00482 
00483    if (check_params(m, to, from, &dialog) < 0) goto err;
00484 
00485    generate_callid(&callid);
00486    generate_fromtag(&fromtag, &callid);
00487 
00488    if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, &dialog) < 0) {
00489       LM_ERR("failed to create temporary dialog\n");
00490       goto err;
00491    }
00492 
00493    if (ruri) {
00494       dialog->rem_target.s = ruri->s;
00495       dialog->rem_target.len = ruri->len;
00496       dialog->hooks.request_uri = &dialog->rem_target;
00497    }
00498    
00499    if (oburi && oburi->s) dialog->hooks.next_hop = oburi;
00500 
00501    w_calculate_hooks(dialog);
00502 
00503    res = t_uac(m, h, b, dialog, cb, cbp);
00504    dialog->rem_target.s = 0;
00505    free_dlg(dialog);
00506    return res;
00507 
00508 err:
00509    return -1;
00510 }

Generated on Thu May 24 20:00:33 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6