modules/tm/mi.c

Go to the documentation of this file.
00001 /*
00002  * $Id: mi.c 5299 2008-12-04 18:12:33Z henningw $
00003  *
00004  * Header file for TM MI functions
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  * Copyright (C) 2006 Voice Sistem SRL
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License 
00022  * along with this program; if not, write to the Free Software 
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  * History:
00026  * --------
00027  *  2006-12-04  created (bogdan)
00028  */
00029 
00030 /*! \file
00031  * \brief TM :: MI functions
00032  *
00033  * \ingroup tm
00034  * - Module: \ref tm
00035  */
00036 
00037 #include <stdlib.h>
00038 #include "../../parser/parse_from.h"
00039 #include "mi.h"
00040 #include "h_table.h"
00041 #include "t_lookup.h"
00042 #include "t_reply.h"
00043 #include "t_cancel.h"
00044 #include "dlg.h"
00045 #include "callid.h"
00046 #include "uac.h"
00047 
00048 /*! simple string list */
00049 struct str_list {
00050    str s;
00051    struct str_list *next;
00052 };
00053 
00054 /*! Which header fields should be skipped */
00055 #define skip_hf(_hf) \
00056    (((_hf)->type == HDR_FROM_T)  || \
00057    ((_hf)->type == HDR_TO_T)     || \
00058    ((_hf)->type == HDR_CALLID_T) || \
00059    ((_hf)->type == HDR_CSEQ_T))
00060 
00061 
00062 /************** Helper functions (from previous FIFO impl) *****************/
00063 
00064 /*!
00065  * \brief Check if the request pushed via MI is correctly formed
00066  *
00067  * Check if the request pushed via MI is correctly formed. Test if
00068  * necessary SIP header fileds are included, could be parsed and the
00069  * CSEQ is correct.
00070  * \param msg SIP message
00071  * \param method SIP method
00072  * \param body SIP body
00073  * \param cseq SIP CSEQ value
00074  * \param callid SIP callid, optional
00075  * \return zero on success, or a mi_root with an error message included otherwise
00076  */
00077 static inline struct mi_root* mi_check_msg(struct sip_msg* msg, str* method,
00078                               str* body, int* cseq, str* callid)
00079 {
00080    struct cseq_body *parsed_cseq;
00081 
00082    if (body && body->len && !msg->content_type)
00083       return init_mi_tree( 400, "Content-Type missing", 19);
00084 
00085    if (body && body->len && msg->content_length)
00086       return init_mi_tree( 400, "Content-Length disallowed", 24);
00087 
00088    if (!msg->to)
00089       return init_mi_tree( 400, "To missing", 10);
00090 
00091    if (!msg->from)
00092       return init_mi_tree( 400, "From missing", 12);
00093 
00094    /* we also need to know if there is from-tag and add it otherwise */
00095    if (parse_from_header(msg) < 0)
00096       return init_mi_tree( 400, "Error in From", 13);
00097 
00098    if (msg->cseq && (parsed_cseq = get_cseq(msg))) {
00099       if (str2int( &parsed_cseq->number, (unsigned int*)cseq)!=0)
00100          return init_mi_tree( 400, "Bad CSeq number", 15);
00101 
00102       if (parsed_cseq->method.len != method->len
00103       || memcmp(parsed_cseq->method.s, method->s, method->len) !=0 )
00104          return init_mi_tree( 400, "CSeq method mismatch", 20);
00105    } else {
00106       *cseq = -1;
00107    }
00108 
00109    if (msg->callid) {
00110       callid->s = msg->callid->body.s;
00111       callid->len = msg->callid->body.len;
00112    } else {
00113       callid->s = 0;
00114       callid->len = 0;
00115    }
00116 
00117    return 0;
00118 }
00119 
00120 /*!
00121  * \brief Allocate a new str on a str list
00122  *
00123  * Allocate a new str in pkg_mem and attach it to a str list. Update
00124  * the total number of list elements.
00125  * \param s char array
00126  * \param len length of the char array
00127  * \param last last list element
00128  * \param total total number of list elements
00129  * \return pointer to the new list element
00130  */
00131 static inline struct str_list *new_str(char *s, int len, struct str_list **last, int *total)
00132 {
00133    struct str_list *new;
00134    new=pkg_malloc(sizeof(struct str_list));
00135    if (!new) {
00136       LM_ERR("no more pkg mem\n");
00137       return 0;
00138    }
00139    new->s.s=s;
00140    new->s.len=len;
00141    new->next=0;
00142 
00143    (*last)->next=new;
00144    *last=new;
00145    *total+=len;
00146 
00147    return new;
00148 }
00149 
00150 /*!
00151  * \brief Convert a header field block to char array
00152  *
00153  * Convert a header field block to char array, allocated in
00154  * pkg_mem.
00155  * \param uri SIP URI
00156  * \param hf header field
00157  * \param l
00158  * \param send_sock socket information
00159  * \return new allocated char array on success, zero otherwise
00160  */
00161 static inline char *get_hfblock( str *uri, struct hdr_field *hf, int *l, struct socket_info** send_sock)
00162 {
00163    struct str_list sl, *last, *new, *i, *foo;
00164    int hf_avail, frag_len, total_len;
00165    char *begin, *needle, *dst, *ret, *d;
00166    str *sock_name, *portname;
00167    union sockaddr_union to_su;
00168 
00169    ret=0; /* pessimist: assume failure */
00170    total_len=0;
00171    last=&sl;
00172    last->next=0;
00173    portname=sock_name=0;
00174 
00175    for (; hf; hf=hf->next) {
00176       if (skip_hf(hf)) continue;
00177 
00178       begin=needle=hf->name.s; 
00179       hf_avail=hf->len;
00180 
00181       /* substitution loop */
00182       while(hf_avail) {
00183          d=memchr(needle, SUBST_CHAR, hf_avail);
00184          if (!d || d+1>=needle+hf_avail) { /* nothing to substitute */
00185             new=new_str(begin, hf_avail, &last, &total_len); 
00186             if (!new) goto error;
00187             break;
00188          } else {
00189             frag_len=d-begin;
00190             d++; /* d not at the second substitution char */
00191             switch(*d) {
00192                case SUBST_CHAR:  /* double SUBST_CHAR: IP */
00193                   /* string before substitute */
00194                   new=new_str(begin, frag_len, &last, &total_len); 
00195                   if (!new) goto error;
00196                   /* substitute */
00197                   if (!sock_name) {
00198                      if (*send_sock==0){
00199                         *send_sock=uri2sock(0, uri, &to_su,PROTO_NONE);
00200                         if (!*send_sock) {
00201                            LM_ERR("send_sock failed\n");
00202                            goto error;
00203                         }
00204                      }
00205                      sock_name=&(*send_sock)->address_str;
00206                      portname=&(*send_sock)->port_no_str;
00207                   }
00208                   new=new_str(sock_name->s, sock_name->len,
00209                         &last, &total_len );
00210                   if (!new) goto error;
00211                   /* inefficient - FIXME --andrei*/
00212                   new=new_str(":", 1, &last, &total_len);
00213                   if (!new) goto error;
00214                   new=new_str(portname->s, portname->len,
00215                         &last, &total_len );
00216                   if (!new) goto error;
00217                   /* keep going ... */
00218                   begin=needle=d+1;hf_avail-=frag_len+2;
00219                   continue;
00220                default:
00221                   /* no valid substitution char -- keep going */
00222                   hf_avail-=frag_len+1;
00223                   needle=d;
00224             }
00225          } /* possible substitute */
00226       } /* substitution loop */
00227       /* proceed to next header */
00228       /* new=new_str(CRLF, CRLF_LEN, &last, &total_len );
00229       if (!new) goto error; */
00230       LM_DBG("one more hf processed\n");
00231    } /* header loop */
00232 
00233 
00234    /* construct a single header block now */
00235    ret=pkg_malloc(total_len);
00236    if (!ret) {
00237       LM_ERR("no pkg mem for hf block\n");
00238       goto error;
00239    }
00240    i=sl.next;
00241    dst=ret;
00242    while(i) {
00243       foo=i;
00244       i=i->next;
00245       memcpy(dst, foo->s.s, foo->s.len);
00246       dst+=foo->s.len;
00247       pkg_free(foo);
00248    }
00249    *l=total_len;
00250    return ret;
00251 
00252 error:
00253    i=sl.next;
00254    while(i) {
00255       foo=i;
00256       i=i->next;
00257       pkg_free(foo);
00258    }
00259    *l=0;
00260    return 0;
00261 }
00262 
00263 
00264 /*!
00265  * \brief Print routes
00266  *
00267  * Print route to MI node, allocate temporary memory in pkg_mem.
00268  * \param node MI node
00269  * \param dlg route set
00270  */
00271 static inline void mi_print_routes( struct mi_node *node, dlg_t* dlg)
00272 {
00273 #define MI_ROUTE_PREFIX_S       "Route: "
00274 #define MI_ROUTE_PREFIX_LEN     (sizeof(MI_ROUTE_PREFIX_S)-1)
00275 #define MI_ROUTE_SEPARATOR_S    ", "
00276 #define MI_ROUTE_SEPARATOR_LEN  (sizeof(MI_ROUTE_SEPARATOR_S)-1)
00277    rr_t* ptr;
00278    int len;
00279    char *p, *s;
00280 
00281    ptr = dlg->hooks.first_route;
00282 
00283    if (ptr==NULL) {
00284       add_mi_node_child( node, 0, 0, 0, ".",1);
00285       return;
00286    }
00287 
00288    len = MI_ROUTE_PREFIX_LEN;
00289    for( ; ptr ; ptr=ptr->next)
00290       len += ptr->len + MI_ROUTE_SEPARATOR_LEN*(ptr->next!=NULL);
00291    if (dlg->hooks.last_route)
00292       len += dlg->hooks.last_route->len + 2;
00293 
00294 
00295    s = pkg_malloc( len );
00296    if (s==0) {
00297       LM_ERR("no more pkg mem\n");
00298       return;
00299    }
00300 
00301 
00302    p = s;
00303    memcpy( p, MI_ROUTE_PREFIX_S, MI_ROUTE_PREFIX_LEN);
00304    p += MI_ROUTE_PREFIX_LEN;
00305 
00306    for( ptr = dlg->hooks.first_route ; ptr ; ptr=ptr->next) {
00307       memcpy( p, ptr->nameaddr.name.s, ptr->len);
00308       p += ptr->len;
00309       if (ptr->next) {
00310          memcpy( p, MI_ROUTE_SEPARATOR_S, MI_ROUTE_SEPARATOR_LEN);
00311          p += MI_ROUTE_SEPARATOR_LEN;
00312       }
00313    }
00314 
00315    if (dlg->hooks.last_route) {
00316       *(p++) = '<';
00317       memcpy( p, dlg->hooks.last_route->s, dlg->hooks.last_route->len);
00318       p += dlg->hooks.last_route->len;
00319       *(p++) = '>';
00320    }
00321 
00322    add_mi_node_child( node, MI_DUP_VALUE, 0, 0, s, len);
00323    pkg_free(s);
00324 }
00325 
00326 
00327 /*!
00328  * \brief Print URIs
00329  *
00330  * Print URIs to MI node, allocate temporary memory in shm_mem.
00331  * \param node MI node
00332  * \param reply SIP reply
00333  * \return zero on success, -1 on errors
00334  */
00335 static inline int mi_print_uris( struct mi_node *node, struct sip_msg* reply)
00336 {
00337    dlg_t* dlg;
00338 
00339    if (reply==0)
00340       goto empty;
00341 
00342    dlg = (dlg_t*)shm_malloc(sizeof(dlg_t));
00343    if (!dlg) {
00344       LM_ERR("no shm memory left\n");
00345       return -1;
00346    }
00347 
00348    memset(dlg, 0, sizeof(dlg_t));
00349    if (dlg_response_uac(dlg, reply) < 0) {
00350       LM_ERR("failed to create dialog\n");
00351       free_dlg(dlg);
00352       return -1;
00353    }
00354 
00355    if (dlg->state != DLG_CONFIRMED) {
00356       free_dlg(dlg);
00357       goto empty;
00358    }
00359 
00360    if (dlg->hooks.request_uri->s) {
00361       add_mi_node_child( node, MI_DUP_VALUE, 0, 0,
00362          dlg->hooks.request_uri->s, dlg->hooks.request_uri->len);
00363    } else {
00364       add_mi_node_child( node, 0, 0, 0, ".",1);
00365    }
00366    if (dlg->hooks.next_hop->s) {
00367       add_mi_node_child( node, MI_DUP_VALUE, 0, 0,
00368          dlg->hooks.next_hop->s, dlg->hooks.next_hop->len);
00369    } else {
00370       add_mi_node_child( node, 0, 0, 0, ".",1);
00371    }
00372 
00373    mi_print_routes( node, dlg);
00374 
00375    free_dlg(dlg);
00376    return 0;
00377 empty:
00378    add_mi_node_child( node, 0, 0, 0, ".",1);
00379    add_mi_node_child( node, 0, 0, 0, ".",1);
00380    add_mi_node_child( node, 0, 0, 0, ".",1);
00381    return 0;
00382 }
00383 
00384 
00385 static void mi_uac_dlg_hdl( struct cell *t, int type, struct tmcb_params *ps )
00386 {
00387    struct mi_handler *mi_hdl;
00388    struct mi_root *rpl_tree;
00389    str text;
00390 
00391    LM_DBG("MI UAC generated status %d\n", ps->code);
00392    if (!*ps->param)
00393       return;
00394 
00395    mi_hdl = (struct mi_handler *)(*ps->param);
00396 
00397    rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00398    if (rpl_tree==0)
00399       goto done;
00400 
00401    if (ps->rpl==FAKED_REPLY) {
00402       get_reply_status( &text, ps->rpl, ps->code);
00403       if (text.s==0) {
00404          LM_ERR("get_reply_status failed\n");
00405          rpl_tree = 0;
00406          goto done;
00407       }
00408       add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, 0, 0,
00409          text.s, text.len);
00410       pkg_free(text.s);
00411       mi_print_uris( &rpl_tree->node, 0 );
00412       add_mi_node_child( &rpl_tree->node, 0, 0, 0, ".",1);
00413    } else { 
00414       addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%d %.*s",
00415          ps->rpl->first_line.u.reply.statuscode,
00416          ps->rpl->first_line.u.reply.reason.len,
00417          ps->rpl->first_line.u.reply.reason.s);
00418       mi_print_uris( &rpl_tree->node, ps->rpl);
00419       add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, 0, 0,
00420          ps->rpl->headers->name.s,
00421          ps->rpl->len-(ps->rpl->headers->name.s - ps->rpl->buf));
00422    }
00423 
00424    LM_DBG("mi_callback successfully completed\n");
00425 done:
00426    if (ps->code >= 200) {
00427       mi_hdl->handler_f( rpl_tree, mi_hdl, 1 /*done*/ );
00428       *ps->param = 0;
00429    } else {
00430       mi_hdl->handler_f( rpl_tree, mi_hdl, 0 );
00431    }
00432 }
00433 
00434 
00435 
00436 /**************************** MI functions ********************************/
00437 
00438 
00439 /*
00440   Syntax of "t_uac_dlg" :
00441     method
00442     RURI
00443     NEXT_HOP
00444     socket
00445     headers
00446     [Body]
00447 */
00448 struct mi_root*  mi_tm_uac_dlg(struct mi_root* cmd_tree, void* param)
00449 {
00450    static char err_buf[MAX_REASON_LEN];
00451    static struct sip_msg tmp_msg;
00452    static dlg_t dlg;
00453    struct mi_root *rpl_tree;
00454    struct mi_node *node;
00455    struct sip_uri pruri;
00456    struct sip_uri pnexthop;
00457    struct socket_info* sock;
00458    str *method;
00459    str *ruri;
00460    str *nexthop;
00461    str *socket;
00462    str *hdrs;
00463    str *body;
00464    str s;
00465    str callid = {0,0};
00466    int sip_error;
00467    int proto;
00468    int port;
00469    int cseq;
00470    int n;
00471 
00472    for( n=0,node = cmd_tree->node.kids; n<6 && node ; n++,node=node->next );
00473    if ( !(n==5 || n==6) || node!=0)
00474       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00475 
00476    /* method name (param 1) */
00477    node = cmd_tree->node.kids;
00478    method = &node->value;
00479 
00480    /* RURI (param 2) */
00481    node = node->next;
00482    ruri = &node->value;
00483    if (parse_uri( ruri->s, ruri->len, &pruri) < 0 )
00484       return init_mi_tree( 400, "Invalid RURI", 12);
00485 
00486    /* nexthop RURI (param 3) */
00487    node = node->next;
00488    nexthop = &node->value;
00489    if (nexthop->len==1 && nexthop->s[0]=='.') {
00490       nexthop = 0;
00491    } else {
00492       if (parse_uri( nexthop->s, nexthop->len, &pnexthop) < 0 )
00493          return init_mi_tree( 400, "Invalid NEXTHOP", 15);
00494    }
00495 
00496    /* socket (param 4) */
00497    node = node->next;
00498    socket = &node->value;
00499    if (socket->len==1 && socket->s[0]=='.' ) {
00500       sock = 0;
00501    } else {
00502       if (parse_phostport( socket->s, socket->len, &s.s, &s.len,
00503       &port,&proto)!=0)
00504          return init_mi_tree( 404, "Invalid local socket", 20);
00505       sock = grep_sock_info( &s, (unsigned short)port, proto);
00506       if (sock==0)
00507          return init_mi_tree( 404, "Local socket not found", 22);
00508    }
00509 
00510    /* new headers (param 5) */
00511    node = node->next;
00512    if (node->value.len==1 && node->value.s[0]=='.')
00513       hdrs = 0;
00514    else {
00515       hdrs = &node->value;
00516       /* use SIP parser to look at what is in the FIFO request */
00517       memset( &tmp_msg, 0, sizeof(struct sip_msg));
00518       tmp_msg.len = hdrs->len; 
00519       tmp_msg.buf = tmp_msg.unparsed = hdrs->s;
00520       if (parse_headers( &tmp_msg, HDR_EOH_F, 0) == -1 )
00521          return init_mi_tree( 400, "Bad headers", 11);
00522    }
00523 
00524    /* body (param 5 - optional) */
00525    node = node->next;
00526    if (node)
00527       body = &node->value;
00528    else
00529       body = 0;
00530 
00531    /* at this moment, we collected all the things we got, let's
00532     * verify user has not forgotten something */
00533    rpl_tree = mi_check_msg( &tmp_msg, method, body, &cseq, &callid);
00534    if (rpl_tree) {
00535       if (tmp_msg.headers) free_hdr_field_lst(tmp_msg.headers);
00536       return rpl_tree;
00537    }
00538 
00539    s.s = get_hfblock( nexthop ? nexthop : ruri,
00540          tmp_msg.headers, &s.len, &sock);
00541    if (s.s==0) {
00542       if (tmp_msg.headers) free_hdr_field_lst(tmp_msg.headers);
00543       return 0;
00544    }
00545 
00546    memset( &dlg, 0, sizeof(dlg_t));
00547    /* Fill in Call-ID, use given Call-ID if
00548     * present and generate it if not present */
00549    if (callid.s && callid.len)
00550       dlg.id.call_id = callid;
00551    else
00552       generate_callid(&dlg.id.call_id);
00553 
00554    /* We will not fill in dlg->id.rem_tag because
00555     * if present it will be printed within To HF */
00556 
00557    /* Generate fromtag if not present */
00558    if (!(get_from(&tmp_msg)->tag_value.len&&get_from(&tmp_msg)->tag_value.s))
00559       generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);
00560 
00561    /* Fill in CSeq */
00562    if (cseq!=-1)
00563       dlg.loc_seq.value = cseq;
00564    else
00565       dlg.loc_seq.value = DEFAULT_CSEQ;
00566    dlg.loc_seq.is_set = 1;
00567 
00568    dlg.loc_uri = tmp_msg.from->body;
00569    dlg.rem_uri = tmp_msg.to->body;
00570    dlg.hooks.request_uri = ruri;
00571    dlg.hooks.next_hop = (nexthop ? nexthop : ruri);
00572    dlg.send_sock = sock;
00573 
00574    if (cmd_tree->async_hdl==NULL)
00575       n = t_uac( method, &s, body, &dlg, 0, 0);
00576    else
00577       n = t_uac( method, &s, body, &dlg, mi_uac_dlg_hdl,
00578             (void*)cmd_tree->async_hdl);
00579 
00580    pkg_free(s.s);
00581    if (tmp_msg.headers) free_hdr_field_lst(tmp_msg.headers);
00582 
00583    if (n<=0) {
00584       /* error */
00585       rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00586       if (rpl_tree==0)
00587          return 0;
00588 
00589       n = err2reason_phrase( n, &sip_error, err_buf, sizeof(err_buf),
00590          "MI/UAC") ;
00591       if (n > 0 )
00592          addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%d %.*s",
00593             sip_error, n, err_buf);
00594       else
00595          add_mi_node_child( &rpl_tree->node, 0, 0, 0,
00596             "500 MI/UAC failed", 17);
00597 
00598       return rpl_tree;
00599    } else {
00600       if (cmd_tree->async_hdl==NULL)
00601          return init_mi_tree( 202, "Accepted", 8);
00602       else
00603          return MI_ROOT_ASYNC_RPL;
00604    }
00605 }
00606 
00607 
00608 /*
00609   Syntax of "t_uac_cancel" :
00610     callid
00611     cseq
00612 */
00613 struct mi_root* mi_tm_cancel(struct mi_root* cmd_tree, void* param)
00614 {
00615    struct mi_node *node;
00616    struct cell *trans;
00617 
00618    node =  cmd_tree->node.kids;
00619    if ( !node || !node->next || node->next->next)
00620       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00621 
00622    if( t_lookup_callid( &trans, node->value, node->next->value) < 0 )
00623       return init_mi_tree( 481, "No such transaction", 19);
00624 
00625    /* cancel the call */
00626    LM_DBG("cancelling transaction %p\n",trans);
00627 
00628    cancel_uacs( trans, ~0/*all branches*/);
00629 
00630    UNREF(trans);
00631 
00632    return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00633 }
00634 
00635 
00636 /*
00637   Syntax of "t_hash" :
00638     no nodes
00639 */
00640 struct mi_root* mi_tm_hash(struct mi_root* cmd_tree, void* param)
00641 {
00642    struct mi_root* rpl_tree= NULL;
00643    struct mi_node* rpl;
00644    struct mi_node* node;
00645    struct mi_attr* attr;
00646    struct s_table* tm_t;
00647    char *p;
00648    int i;
00649    int len;
00650 
00651    rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00652    if (rpl_tree==0)
00653       return 0;
00654    rpl = &rpl_tree->node;
00655    tm_t = get_tm_table();
00656 
00657    for (i=0; i<TM_TABLE_ENTRIES; i++) {
00658       p = int2str((unsigned long)i, &len );
00659       node = add_mi_node_child(rpl, MI_DUP_VALUE , 0, 0, p, len);
00660       if(node == NULL)
00661          goto error;
00662 
00663       p = int2str((unsigned long)tm_t->entrys[i].cur_entries, &len );
00664       attr = add_mi_attr(node, MI_DUP_VALUE, "Current", 7, p, len );
00665       if(attr == NULL)
00666          goto error;
00667 
00668       p = int2str((unsigned long)tm_t->entrys[i].acc_entries, &len );
00669       attr = add_mi_attr(node, MI_DUP_VALUE, "Total", 5, p, len );
00670       if(attr == NULL)
00671          goto error;
00672    }
00673 
00674    return rpl_tree;
00675 error:
00676    free_mi_tree(rpl_tree);
00677    return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
00678 }
00679 
00680 
00681 /*
00682   Syntax of "t_reply" :
00683   code
00684   reason
00685   trans_id
00686   to_tag
00687   new headers
00688   [Body]
00689 */
00690 struct mi_root* mi_tm_reply(struct mi_root* cmd_tree, void* param)
00691 {
00692    struct mi_node* node;
00693    unsigned int hash_index;
00694    unsigned int hash_label;
00695    unsigned int rpl_code;
00696    struct cell *trans;
00697    str *reason;
00698    str *totag;
00699    str *new_hdrs;
00700    str *body;
00701    str tmp;
00702    char *p;
00703    int n;
00704 
00705    for( n=0,node = cmd_tree->node.kids; n<6 && node ; n++,node=node->next );
00706    if ( !(n==5 || n==6) || node!=0)
00707       return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00708 
00709    /* get all info from the command */
00710 
00711    /* reply code (param 1) */
00712    node = cmd_tree->node.kids;
00713    if (str2int( &node->value, &rpl_code)!=0 || rpl_code>=700)
00714       return init_mi_tree( 400, "Invalid reply code", 18);
00715 
00716    /* reason text (param 2) */
00717    node = node->next;
00718    reason = &node->value;
00719 
00720    /* trans_id (param 3) */
00721    node = node->next;
00722    tmp = node->value;
00723    p = memchr( tmp.s, ':', tmp.len);
00724    if ( p==NULL)
00725       return init_mi_tree( 400, "Invalid trans_id", 16);
00726 
00727    tmp.len = p-tmp.s;
00728    if( str2int( &tmp, &hash_index)!=0 )
00729       return init_mi_tree( 400, "Invalid index in trans_id", 25);
00730 
00731    tmp.s = p+1;
00732    tmp.len = (node->value.s+node->value.len) - tmp.s;
00733    if( str2int( &tmp, &hash_label)!=0 )
00734       return init_mi_tree( 400, "Invalid label in trans_id", 25);
00735 
00736    if( t_lookup_ident( &trans, hash_index, hash_label)<0 )
00737       return init_mi_tree( 404, "Transaction not found", 21);
00738 
00739    /* to_tag (param 4) */
00740    node = node->next;
00741    totag = &node->value;
00742 
00743    /* new headers (param 5) */
00744    node = node->next;
00745    if (node->value.len==1 && node->value.s[0]=='.')
00746       new_hdrs = 0;
00747    else 
00748       new_hdrs = &node->value;
00749 
00750    /* body (param 5 - optional) */
00751    node = node->next;
00752    if (node)
00753       body = &node->value;
00754    else
00755       body = 0;
00756 
00757    /* it's refcounted now, t_reply_with body unrefs for me -- I can 
00758     * continue but may not use T anymore  */
00759    n = t_reply_with_body( trans, rpl_code, reason, body, new_hdrs, totag);
00760 
00761    if (n<0)
00762       return init_mi_tree( 500, "Reply failed", 12);
00763 
00764    return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00765 }
00766 

Generated on Wed May 23 20:00:27 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6