cpl_run.c

Go to the documentation of this file.
00001 /*
00002  * $Id: cpl_run.c 5600 2009-02-12 19:25:22Z miconda $
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 : created (bogdan)
00025  * 2003-09-11 : build_lump_rpl() merged into add_lump_rpl() (bogdan)
00026  * 2004-06-14 : all global variables merged into cpl_env and cpl_fct;
00027  *              append_branches param added to lookup node (bogdan)
00028  * 2004-06-14 : flag CPL_IS_STATEFUL is set now immediately after the 
00029  *              transaction is created (bogdan)
00030 */
00031 
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <time.h>
00035 #include <stdlib.h>
00036 
00037 #include "../../mem/mem.h"
00038 #include "../../mem/shm_mem.h"
00039 #include "../../str.h"
00040 #include "../../ut.h"
00041 #include "../../dprint.h"
00042 #include "../../parser/msg_parser.h"
00043 #include "../../data_lump_rpl.h"
00044 #include "../tm/tm_load.h"
00045 #include "../usrloc/usrloc.h"
00046 #include "CPL_tree.h"
00047 #include "loc_set.h"
00048 #include "cpl_utils.h"
00049 #include "cpl_nonsig.h"
00050 #include "cpl_sig.h"
00051 #include "cpl_env.h"
00052 #include "cpl_run.h"
00053 
00054 
00055 #define EO_SCRIPT            ((char*)0xffffffff)
00056 #define DEFAULT_ACTION       ((char*)0xfffffffe)
00057 #define CPL_SCRIPT_ERROR     ((char*)0xfffffffd)
00058 #define CPL_RUNTIME_ERROR    ((char*)0xfffffffc)
00059 #define CPL_TO_CONTINUE      ((char*)0xfffffffb)
00060 
00061 #define HDR_NOT_FOUND        ((char*)0xffffffff)
00062 #define UNDEF_CHAR           (0xff)
00063 
00064 
00065 static str cpl_301_reason = str_init("Moved permanently");
00066 static str cpl_302_reason = str_init("Moved temporarily");
00067 
00068 #define check_overflow_by_ptr(_ptr_,_intr_,_error_) \
00069    do {\
00070       if ( (char*)(_ptr_)>(_intr_)->script.len+(_intr_)->script.s ) {\
00071          LM_ERR("overflow detected ip=%p ptr=%p in "\
00072          "func. %s, line %d\n",(_intr_)->ip,_ptr_,__FILE__,__LINE__);\
00073          goto _error_; \
00074       } \
00075    }while(0)
00076 
00077 #define check_overflow_by_offset(_len_,_intr_,_error_) \
00078    do {\
00079       if ( (char*)((_intr_)->ip+(_len_)) > \
00080       (_intr_)->script.len+(_intr_)->script.s ) {\
00081          LM_ERR("overflow detected ip=%p offset=%d in "\
00082          "func. %s, line %d\n",(_intr_)->ip,_len_,__FILE__,__LINE__);\
00083          goto _error_; \
00084       } \
00085    }while(0)
00086 
00087 #define get_first_child(_node_) \
00088    ((NR_OF_KIDS(_node_)==0)?DEFAULT_ACTION:(_node_)+KID_OFFSET(_node_,0))
00089 
00090 #define get_basic_attr(_p_,_code_,_n_,_intr_,_error_) \
00091    do{\
00092       check_overflow_by_ptr( (_p_)+BASIC_ATTR_SIZE, _intr_, _error_);\
00093       _code_ = ntohs( *((unsigned short*)(_p_)) );\
00094       _n_ =  ntohs( *((unsigned short*)((_p_)+2)) );\
00095       (_p_) += 4;\
00096    }while(0)
00097 
00098 #define get_str_attr(_p_,_s_,_len_,_intr_,_error_,_FIXUP_) \
00099    do{\
00100       if ( ((int)(_len_))-(_FIXUP_)<=0 ) {\
00101          LM_ERR("%s:%d: attribute is an empty string\n",\
00102             __FILE__,__LINE__);\
00103          goto _error_; \
00104       } else {\
00105          check_overflow_by_ptr( (_p_)+(_len_), _intr_, _error_);\
00106          _s_ = _p_;\
00107          (_p_) += (_len_) + 1*(((_len_)&0x0001)==1);\
00108          (_len_) -= (_FIXUP_);\
00109       }\
00110    }while(0)
00111 
00112 
00113 
00114 struct cpl_interpreter* new_cpl_interpreter( struct sip_msg *msg, str *script)
00115 {
00116    struct cpl_interpreter *intr = 0;
00117 
00118    intr = (struct cpl_interpreter*)shm_malloc(sizeof(struct cpl_interpreter));
00119    if (!intr) {
00120       LM_ERR("no more shm free memory!\n");
00121       goto error;
00122    }
00123    memset( intr, 0, sizeof(struct cpl_interpreter));
00124 
00125    /* init the interpreter*/
00126    intr->script.s = script->s;
00127    intr->script.len = script->len;
00128    intr->recv_time = time(0);
00129    intr->ip = script->s;
00130    intr->msg = msg;
00131 
00132    /* check the beginning of the script */
00133    if ( NODE_TYPE(intr->ip)!=CPL_NODE ) {
00134       LM_ERR("first node is not CPL!!\n");
00135       goto error;
00136    }
00137 
00138    return intr;
00139 error:
00140    return 0;
00141 }
00142 
00143 
00144 
00145 void free_cpl_interpreter(struct cpl_interpreter *intr)
00146 {
00147    if (intr) {
00148       empty_location_set( &(intr->loc_set) );
00149       if (intr->script.s)
00150          shm_free( intr->script.s);
00151       if (intr->user.s)
00152          shm_free(intr->user.s);
00153       if (intr->flags&CPL_RURI_DUPLICATED)
00154          shm_free(intr->ruri);
00155       if (intr->flags&CPL_TO_DUPLICATED)
00156          shm_free(intr->to);
00157       if (intr->flags&CPL_FROM_DUPLICATED)
00158          shm_free(intr->from);
00159       if (intr->flags&CPL_SUBJECT_DUPLICATED)
00160          shm_free(intr->subject);
00161       if (intr->flags&CPL_ORGANIZATION_DUPLICATED)
00162          shm_free(intr->organization);
00163       if (intr->flags&CPL_USERAGENT_DUPLICATED)
00164          shm_free(intr->user_agent);
00165       if (intr->flags&CPL_ACCEPTLANG_DUPLICATED)
00166          shm_free(intr->accept_language);
00167       if (intr->flags&CPL_PRIORITY_DUPLICATED)
00168          shm_free(intr->priority);
00169       shm_free(intr);
00170    }
00171 }
00172 
00173 
00174 
00175 /* UPDATED + CHECKED
00176  */
00177 static inline char *run_cpl_node( struct cpl_interpreter *intr )
00178 {
00179    char *kid;
00180    unsigned char start;
00181    int i;
00182 
00183    start = (intr->flags&CPL_RUN_INCOMING)?INCOMING_NODE:OUTGOING_NODE;
00184    /* look for the starting node (incoming or outgoing) */
00185    for(i=0;i<NR_OF_KIDS(intr->ip);i++) {
00186       kid= intr->ip + KID_OFFSET(intr->ip,i);
00187       if ( NODE_TYPE(kid)==start ) {
00188          return get_first_child(kid);
00189       } else
00190       if (NODE_TYPE(kid)==SUBACTION_NODE ||
00191       NODE_TYPE(kid)==ANCILLARY_NODE ||
00192       NODE_TYPE(kid)==INCOMING_NODE  ||
00193       NODE_TYPE(kid)==OUTGOING_NODE ) {
00194          continue;
00195       } else {
00196          LM_ERR("unknown child type (%d) "
00197             "for CPL node!!\n",NODE_TYPE(kid));
00198          return CPL_SCRIPT_ERROR;
00199       }
00200    }
00201 
00202    LM_DBG("CPL node has no %d subnode -> default\n", start);
00203    return DEFAULT_ACTION;
00204 }
00205 
00206 
00207 
00208 /* UPDATED + CHECKED
00209  */
00210 static inline char *run_lookup( struct cpl_interpreter *intr )
00211 {
00212    unsigned short attr_name;
00213    unsigned short n;
00214    unsigned char  clear;
00215    char *p;
00216    char *kid;
00217    char *failure_kid = 0;
00218    char *success_kid = 0;
00219    char *notfound_kid = 0;
00220    int  i;
00221    time_t      tc;
00222    urecord_t*  r;
00223    ucontact_t* contact;
00224 
00225    clear = NO_VAL;
00226 
00227    /* check the params */
00228    for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
00229       get_basic_attr(p,attr_name,n,intr,script_error);
00230       switch (attr_name) {
00231          case CLEAR_ATTR:
00232             if (n!=YES_VAL && n!=NO_VAL)
00233                LM_WARN("invalid value (%u) found"
00234                   " for param. CLEAR in LOOKUP node -> using "
00235                   "default (%u)!\n",n,clear);
00236             else
00237                clear = n;
00238             break;
00239          default:
00240             LM_ERR("unknown attribute (%d) in LOOKUP node\n",attr_name);
00241             goto script_error;
00242       }
00243    }
00244 
00245    /* check the kids */
00246    for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) {
00247       kid = intr->ip + KID_OFFSET(intr->ip,i);
00248       check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error);
00249       switch ( NODE_TYPE(kid) ) {
00250          case SUCCESS_NODE :
00251             success_kid = kid;
00252             break;
00253          case NOTFOUND_NODE:
00254             notfound_kid = kid;
00255             break;
00256          case FAILURE_NODE:
00257             failure_kid = kid;
00258             break;
00259          default:
00260             LM_ERR("unknown output node type"
00261                " (%d) for LOOKUP node\n",NODE_TYPE(kid));
00262             goto script_error;
00263       }
00264    }
00265 
00266    kid = failure_kid;
00267 
00268    if (cpl_env.lu_domain) {
00269       /* fetch user's contacts via usrloc */
00270       tc = time(0);
00271       cpl_fct.ulb.lock_udomain( cpl_env.lu_domain, &intr->user );
00272       i = cpl_fct.ulb.get_urecord( cpl_env.lu_domain, &intr->user, &r);
00273       if (i < 0) {
00274          /* failure */
00275          LM_ERR("failed to query usrloc\n");
00276          cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain, &intr->user );
00277       } else if (i > 0) {
00278          /* not found */
00279          LM_DBG("'%.*s' Not found in usrloc\n",
00280             intr->user.len, intr->user.s);
00281          cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain, &intr->user );
00282          kid = notfound_kid;
00283       } else {
00284          contact = r->contacts;
00285          /* skip expired contacts */
00286          while ((contact) && (contact->expires <= tc))
00287             contact = contact->next;
00288          /* any contacts left? */
00289          if (contact) {
00290             /* clear loc set if requested */
00291             if (clear)
00292                empty_location_set( &(intr->loc_set) );
00293             /* start adding locations to set */
00294             do {
00295                LM_DBG("adding <%.*s>q=%d\n",
00296                   contact->c.len,contact->c.s,(int)(10*contact->q));
00297                if (add_location( &(intr->loc_set), &contact->c, 
00298                &contact->received, (int)(10*contact->q),
00299                CPL_LOC_DUPL|
00300                   ((contact->cflags&cpl_fct.ulb.nat_flag)?CPL_LOC_NATED:0)
00301                )==-1) {
00302                   LM_ERR("unable to add location to set :-(\n");
00303                   cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain, &intr->user );
00304                   goto runtime_error;
00305                }
00306                contact = contact->next;
00307             }while( contact && cpl_env.lu_append_branches);
00308             /* set the flag for modifying the location set */
00309             intr->flags |= CPL_LOC_SET_MODIFIED;
00310             /* we found a valid contact */
00311             kid = success_kid;
00312          } else {
00313             /* no valid contact found */
00314             kid = notfound_kid;
00315          }
00316          cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain, &intr->user );
00317       }
00318 
00319    }
00320 
00321    if (kid)
00322       return get_first_child(kid);
00323    return DEFAULT_ACTION;
00324 runtime_error:
00325    return CPL_RUNTIME_ERROR;
00326 script_error:
00327    return CPL_SCRIPT_ERROR;
00328 }
00329 
00330 
00331 
00332 /* UPDATED + CHECKED
00333  */
00334 static inline char *run_location( struct cpl_interpreter *intr )
00335 {
00336    unsigned short attr_name;
00337    unsigned short n;
00338    char  *p;
00339    unsigned char  prio;
00340    unsigned char  clear;
00341    str url;
00342    int i;
00343 
00344    clear = NO_VAL;
00345    prio = 10;
00346    url.s = (char*)UNDEF_CHAR;
00347    url.len = 0;
00348 
00349    /* sanity check */
00350    if (NR_OF_KIDS(intr->ip)>1) {
00351       LM_ERR("LOCATION node suppose to have max "
00352          "one child, not %d!\n",NR_OF_KIDS(intr->ip));
00353       goto script_error;
00354    }
00355 
00356    for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
00357       get_basic_attr(p,attr_name,n,intr,script_error);
00358       switch (attr_name) {
00359          case URL_ATTR:
00360             url.len = n;
00361             get_str_attr( p, url.s, url.len, intr, script_error,1);
00362             break;
00363          case PRIORITY_ATTR:
00364             if ( n>10)
00365                LM_WARN("invalid value (%u) found"
00366                   " for param. PRIORITY in LOCATION node -> using "
00367                   "default (%u)!\n",n,prio);
00368             else
00369                prio = n;
00370             break;
00371          case CLEAR_ATTR:
00372             if (n!=YES_VAL && n!=NO_VAL)
00373                LM_WARN("invalid value (%u) found"
00374                   " for param. CLEAR in LOCATION node -> using "
00375                   "default (%u)!\n",n,clear);
00376             else
00377                clear = n;
00378             break;
00379          default:
00380             LM_ERR("unknown attribute (%d) in "
00381                "LOCATION node\n",attr_name);
00382             goto script_error;
00383       }
00384    }
00385 
00386    if (url.s==(char*)UNDEF_CHAR) {
00387       LM_ERR("param. URL missing in LOCATION node\n");
00388       goto script_error;
00389    }
00390 
00391    if (clear)
00392       empty_location_set( &(intr->loc_set) );
00393    if (add_location( &(intr->loc_set), &url, 0, prio, 0/*no dup*/ )==-1) {
00394       LM_ERR("unable to add location to set :-(\n");
00395       goto runtime_error;
00396    }
00397    /* set the flag for modifying the location set */
00398    intr->flags |= CPL_LOC_SET_MODIFIED;
00399 
00400    return get_first_child(intr->ip);
00401 runtime_error:
00402    return CPL_RUNTIME_ERROR;
00403 script_error:
00404    return CPL_SCRIPT_ERROR;
00405 }
00406 
00407 
00408 
00409 /* UPDATED + CHECKED
00410  */
00411 static inline char *run_remove_location( struct cpl_interpreter *intr )
00412 {
00413    unsigned short attr_name;
00414    unsigned short n;
00415    char *p;
00416    str url;
00417    int i;
00418 
00419    url.s = (char*)UNDEF_CHAR;
00420 
00421    /* sanity check */
00422    if (NR_OF_KIDS(intr->ip)>1) {
00423       LM_ERR("REMOVE_LOCATION node suppose to have max one child, not %d!\n",
00424          NR_OF_KIDS(intr->ip));
00425       goto script_error;
00426    }
00427 
00428    /* dirty hack to speed things up in when loc set is already empty */
00429    if (intr->loc_set==0)
00430       goto done;
00431 
00432    for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
00433       get_basic_attr(p,attr_name,n,intr,script_error);
00434       switch (attr_name) {
00435          case LOCATION_ATTR:
00436             url.len = n;
00437             get_str_attr( p, url.s, url.len, intr, script_error,1);
00438             break;
00439          default:
00440             LM_ERR("unknown attribute "
00441                "(%d) in REMOVE_LOCATION node\n",attr_name);
00442             goto script_error;
00443       }
00444    }
00445 
00446    if (url.s==(char*)UNDEF_CHAR) {
00447       LM_DBG("remove all locs from loc_set\n");
00448       empty_location_set( &(intr->loc_set) );
00449    } else {
00450       remove_location( &(intr->loc_set), url.s, url.len );
00451    }
00452    /* set the flag for modifying the location set */
00453    intr->flags |= CPL_LOC_SET_MODIFIED;
00454 
00455 done:
00456    return get_first_child(intr->ip);
00457 script_error:
00458    return CPL_SCRIPT_ERROR;
00459 }
00460 
00461 
00462 
00463 /* UPDATED + CHECKED
00464  */
00465 static inline char *run_sub( struct cpl_interpreter *intr )
00466 {
00467    char  *p;
00468    unsigned short offset;
00469    unsigned short attr_name;
00470    int i;
00471 
00472    /* sanity check */
00473    if (NR_OF_KIDS(intr->ip)!=0) {
00474       LM_ERR("SUB node doesn't suppose to have any "
00475          "sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip));
00476       goto script_error;
00477    }
00478 
00479    /* check the number of attr */
00480    i = NR_OF_ATTR( intr->ip );
00481    if (i!=1) {
00482       LM_ERR("incorrect nr. of attr. %d (<>1) in SUB node\n",i);
00483       goto script_error;
00484    }
00485    /* get attr's name */
00486    p = ATTR_PTR(intr->ip);
00487    get_basic_attr( p, attr_name, offset, intr, script_error);
00488    if (attr_name!=REF_ATTR) {
00489       LM_ERR("invalid attr. %d (expected %d)in "
00490          "SUB node\n", attr_name, REF_ATTR);
00491       goto script_error;
00492    }
00493    /* make the jump */
00494    p = intr->ip - offset;
00495    /* check the destination pointer -> are we still inside the buffer ;-) */
00496    if (((char*)p)<intr->script.s) {
00497       LM_ERR("jump offset lower than the script "
00498          "beginning -> underflow!\n");
00499       goto script_error;
00500    }
00501    check_overflow_by_ptr( p+SIMPLE_NODE_SIZE(intr->ip), intr, script_error);
00502    /* check to see if we hit a subaction node */
00503    if ( NODE_TYPE(p)!=SUBACTION_NODE ) {
00504       LM_ERR("sub. jump hit a nonsubaction node!\n");
00505       goto script_error;
00506    }
00507    if ( NR_OF_ATTR(p)!=0 ) {
00508       LM_ERR("invalid subaction node reached "
00509          "(attrs=%d); expected (0)!\n",NR_OF_ATTR(p));
00510       goto script_error;
00511    }
00512 
00513    return get_first_child(p);
00514 script_error:
00515    return CPL_SCRIPT_ERROR;
00516 }
00517 
00518 
00519 
00520 /* UPDATED + CHECKED
00521  */
00522 static inline char *run_reject( struct cpl_interpreter *intr )
00523 {
00524    unsigned short attr_name;
00525    unsigned short status;
00526    unsigned short n;
00527    str reason;
00528    char *p;
00529    int i;
00530 
00531    reason.s = (char*)UNDEF_CHAR;
00532    status = UNDEF_CHAR;
00533 
00534    /* sanity check */
00535    if (NR_OF_KIDS(intr->ip)!=0) {
00536       LM_ERR("REJECT node doesn't suppose to have "
00537          "any sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip));
00538       goto script_error;
00539    }
00540 
00541    for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
00542       get_basic_attr( p, attr_name, n, intr, script_error);
00543       switch (attr_name) {
00544          case STATUS_ATTR:
00545             status = n;
00546             break;
00547          case REASON_ATTR:
00548             reason.len = n;
00549             get_str_attr( p, reason.s, reason.len, intr, script_error,1);
00550             break;
00551          default:
00552             LM_ERR("unknown attribute "
00553                "(%d) in REJECT node\n",attr_name);
00554             goto script_error;
00555       }
00556    }
00557 
00558    if (status==UNDEF_CHAR) {
00559       LM_ERR("mandatory attribute STATUS not found\n");
00560       goto script_error;
00561    }
00562    if (status<400 || status>=700) {
00563       LM_ERR("bad attribute STATUS (%d)\n",status);
00564       goto script_error;
00565    }
00566 
00567    if (reason.s==(char*)UNDEF_CHAR ) {
00568       switch (status) {
00569          case 486:
00570             reason.s = "Busy Here";
00571             reason.len = 9;
00572             break;
00573          case 404:
00574             reason.s = "Not Found";
00575             reason.len = 9;
00576             break;
00577          case 603:
00578             reason.s = "Decline";
00579             reason.len = 7;
00580             break;
00581          case 500:
00582             reason.s = "Internal Server Error";
00583             reason.len = 21;
00584             break;
00585          default:
00586             reason.s = "Generic Error";
00587             reason.len = 13;
00588       }
00589    }
00590 
00591    /* if still stateless and FORCE_STATEFUL set -> build the transaction */
00592    if ( !(intr->flags&CPL_IS_STATEFUL) && intr->flags&CPL_FORCE_STATEFUL) {
00593       i = cpl_fct.tmb.t_newtran( intr->msg );
00594       if (i<0) {
00595          LM_ERR("failed to build new transaction!\n");
00596          goto runtime_error;
00597       } else if (i==0) {
00598          LM_ERR(" processed INVITE is a retransmission!\n");
00599          /* instead of generating an error is better just to break the
00600           * script by returning EO_SCRIPT */
00601          return EO_SCRIPT;
00602       }
00603       intr->flags |= CPL_IS_STATEFUL;
00604    }
00605 
00606    /* send the reply */
00607    i = cpl_fct.slb.send_reply(intr->msg, (int)status, &reason );
00608 
00609    if ( i!=1 ) {
00610       LM_ERR("unable to send reject reply!\n");
00611       goto runtime_error;
00612    }
00613 
00614    return EO_SCRIPT;
00615 runtime_error:
00616    return CPL_RUNTIME_ERROR;
00617 script_error:
00618    return CPL_SCRIPT_ERROR;
00619 }
00620 
00621 
00622 
00623 /* UPDATED + CHECKED
00624  */
00625 static inline char *run_redirect( struct cpl_interpreter *intr )
00626 {
00627    struct location *loc;
00628    struct lump_rpl *lump;
00629    unsigned short attr_name;
00630    unsigned short permanent;
00631    unsigned short n;
00632    char *p;
00633    str lump_str;
00634    char *cp;
00635    int i;
00636 
00637    permanent = NO_VAL;
00638 
00639    /* sanity check */
00640    if (NR_OF_KIDS(intr->ip)!=0) {
00641       LM_ERR("REDIRECT node doesn't suppose "
00642          "to have any sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip));
00643       goto script_error;
00644    }
00645 
00646    /* read the attributes of the REDIRECT node*/
00647    for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
00648       get_basic_attr( p, attr_name, n, intr, script_error);
00649       switch (attr_name) {
00650          case PERMANENT_ATTR:
00651             if (n!=YES_VAL && n!=NO_VAL) {
00652                LM_ERR("unsupported value (%d)"
00653                   " in attribute PERMANENT for REDIRECT node",n);
00654                goto script_error;
00655             }
00656             permanent = n;
00657             break;
00658          default:
00659             LM_ERR("unknown attribute "
00660                "(%d) in REDIRECT node\n",attr_name);
00661             goto script_error;
00662       }
00663    }
00664 
00665    /* build the lump for Contact header */
00666    lump_str.len = 9 /*"Contact: "*/;
00667    for(loc=intr->loc_set;loc;loc=loc->next)
00668       lump_str.len += 1/*"<"*/ + loc->addr.uri.len + 7/*">;q=x.x"*/ +
00669          2*(loc->next!=0)/*" ,"*/;
00670    lump_str.len += CRLF_LEN;
00671 
00672    lump_str.s = pkg_malloc( lump_str.len );
00673    if(!lump_str.s) {
00674       LM_ERR("out of pkg memory!\n");
00675       goto runtime_error;
00676    }
00677    cp = lump_str.s;
00678    memcpy( cp , "Contact: " , 9);
00679    cp += 9;
00680    for(loc=intr->loc_set;loc;loc=loc->next) {
00681       *(cp++) = '<';
00682       memcpy(cp,loc->addr.uri.s,loc->addr.uri.len);
00683       cp += loc->addr.uri.len;
00684       memcpy(cp,">;q=",4);
00685       cp += 4;
00686       *(cp++) = (loc->addr.priority!=10)?'0':'1';
00687       *(cp++) = '.';
00688       *(cp++) = '0'+(loc->addr.priority%10);
00689       if (loc->next) {
00690          *(cp++) = ' ';
00691          *(cp++) = ',';
00692       }
00693    }
00694    memcpy(cp,CRLF,CRLF_LEN);
00695 
00696    /* if still stateless and FORCE_STATEFUL set -> build the transaction */
00697    if ( !(intr->flags&CPL_IS_STATEFUL) && intr->flags&CPL_FORCE_STATEFUL) {
00698       i = cpl_fct.tmb.t_newtran( intr->msg );
00699       if (i<0) {
00700          LM_ERR("failed to build new transaction!\n");
00701          pkg_free( lump_str.s );
00702          goto runtime_error;
00703       } else if (i==0) {
00704          LM_ERR("processed INVITE is a retransmission!\n");
00705          /* instead of generating an error is better just to break the
00706           * script by returning EO_SCRIPT */
00707          pkg_free( lump_str.s );
00708          return EO_SCRIPT;
00709       }
00710       intr->flags |= CPL_IS_STATEFUL;
00711    }
00712 
00713    /* add the lump to the reply */
00714    lump = add_lump_rpl( intr->msg, lump_str.s , lump_str.len , LUMP_RPL_HDR);
00715    if(!lump) {
00716       LM_ERR("unable to add lump_rpl! \n");
00717       pkg_free( lump_str.s );
00718       goto runtime_error;
00719    }
00720 
00721    /* send the reply */
00722    if (permanent)
00723       i = cpl_fct.slb.send_reply( intr->msg,301,&cpl_301_reason);
00724    else
00725       i = cpl_fct.slb.send_reply( intr->msg,302,&cpl_302_reason);
00726 
00727    /* msg which I'm working on can be in private memory or is a clone into
00728     * shared memory (if I'm after a failed proxy); So, it's better to removed
00729     * by myself the lump that I added previously */
00730    unlink_lump_rpl( intr->msg, lump);
00731    free_lump_rpl( lump );
00732 
00733    if (i!=1) {
00734       LM_ERR("unable to send redirect reply!\n");
00735       goto runtime_error;
00736    }
00737 
00738    return EO_SCRIPT;
00739 runtime_error:
00740    return CPL_RUNTIME_ERROR;
00741 script_error:
00742    return CPL_SCRIPT_ERROR;
00743 }
00744 
00745 
00746 
00747 /* UPDATED + CHECKED
00748  */
00749 static inline char *run_log( struct cpl_interpreter *intr )
00750 {
00751    char  *p;
00752    unsigned short attr_name;
00753    unsigned short n;
00754    str name    = {0,0};
00755    str comment = {0,0};
00756    str user;
00757    int i;
00758 
00759    /* sanity check */
00760    if (NR_OF_KIDS(intr->ip)>1) {
00761       LM_ERR("LOG node suppose to have max one child"
00762          ", not %d!\n",NR_OF_KIDS(intr->ip));
00763       goto script_error;
00764    }
00765 
00766    /* is logging enabled? */
00767    if ( cpl_env.log_dir==0 )
00768       goto done;
00769 
00770    /* read the attributes of the LOG node*/
00771    p = ATTR_PTR(intr->ip);
00772    for( i=NR_OF_ATTR(intr->ip); i>0 ; i-- ) {
00773       get_basic_attr( p, attr_name, n, intr, script_error);
00774       switch (attr_name) {
00775          case NAME_ATTR:
00776             get_str_attr( p, name.s, n, intr, script_error,1);
00777             name.len = n;
00778             break;
00779          case COMMENT_ATTR:
00780             get_str_attr( p, comment.s, n, intr, script_error,1);
00781             comment.len = n;
00782             break;
00783          default:
00784             LM_ERR("unknown attribute "
00785                "(%d) in LOG node\n",attr_name);
00786             goto script_error;
00787       }
00788    }
00789 
00790    if (comment.len==0) {
00791       LM_NOTICE("LOG node has no comment attr -> skipping\n");
00792       goto done;
00793    }
00794 
00795    user.len = intr->user.len + name.len + comment.len;
00796    /* duplicate the attrs in shm memory */
00797    user.s = p = (char*)shm_malloc( user.len );
00798    if (!user.s) {
00799       LM_ERR("no more shm memory!\n");
00800       goto runtime_error;
00801    }
00802    /* copy the user name */
00803    memcpy( p, intr->user.s, intr->user.len);
00804    user.len = intr->user.len;
00805    p += intr->user.len;
00806    /* copy the log name */
00807    if (name.len) {
00808       memcpy( p, name.s, name.len );
00809       name.s = p;
00810       p += name.len;
00811    }
00812    /* copy the comment */
00813    memcpy( p, comment.s, comment.len);
00814    comment.s = p;
00815 
00816    /* send the command */
00817    write_cpl_cmd( CPL_LOG_CMD, &user, &name, &comment );
00818 
00819 done:
00820    return get_first_child(intr->ip);
00821 runtime_error:
00822    return CPL_RUNTIME_ERROR;
00823 script_error:
00824    return CPL_SCRIPT_ERROR;
00825 }
00826 
00827 
00828 
00829 /* UPDATED + CHECKED
00830  */
00831 static inline char *run_mail( struct cpl_interpreter *intr )
00832 {
00833    unsigned short attr_name;
00834    unsigned short n;
00835    char  *p;
00836    str subject = {0,0};
00837    str body    = {0,0};
00838    str to      = {0,0};
00839    int i;
00840 
00841    /* sanity check */
00842    if (NR_OF_KIDS(intr->ip)>1) {
00843       LM_ERR("MAIL node suppose to have max one"
00844          " child, not %d!\n",NR_OF_KIDS(intr->ip));
00845       goto script_error;
00846    }
00847 
00848    /* read the attributes of the MAIL node*/
00849    for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) {
00850       get_basic_attr(p, attr_name, n, intr, script_error);
00851       switch (attr_name) {
00852          case TO_ATTR:
00853             get_str_attr(p, to.s, n, intr, script_error,0);
00854             to.len = n;
00855             break;
00856          case SUBJECT_ATTR:
00857             get_str_attr(p, subject.s, n, intr, script_error,0);
00858             subject.len = n;
00859             break;
00860          case BODY_ATTR:
00861             get_str_attr(p, body.s, n, intr, script_error,0);
00862             body.len = n;
00863             break;
00864          default:
00865             LM_ERR("unknown attribute (%d) in MAIL node\n",attr_name);
00866             goto script_error;
00867       }
00868    }
00869 
00870    if (to.len==0) {
00871       LM_ERR("email has an empty TO hdr!\n");
00872       goto script_error;
00873    }
00874    if (body.len==0 && subject.len==0) {
00875       LM_WARN("I refuse to send email with no "
00876          "body and no subject -> skipping...\n");
00877       goto done;
00878    }
00879 
00880    /* duplicate the attrs in shm memory */
00881    p = (char*)shm_malloc( to.len + subject.len + body.len );
00882    if (!p) {
00883       LM_ERR("no more shm memory!\n");
00884       goto runtime_error;
00885    }
00886    /* copy the TO */
00887    memcpy( p, to.s, to.len );
00888    to.s = p;
00889    p += to.len;
00890    /* copy the subject */
00891    if (subject.len) {
00892       memcpy( p, subject.s, subject.len );
00893       subject.s = p;
00894       p += subject.len;
00895    }
00896    /* copy the body */
00897    if (body.len) {
00898       memcpy( p, body.s, body.len );
00899       body.s = p;
00900       p += body.len;
00901    }
00902 
00903    /* send the command */
00904    write_cpl_cmd( CPL_MAIL_CMD, &to, &subject, &body);
00905 
00906 done:
00907    return get_first_child(intr->ip);
00908 runtime_error:
00909    return CPL_RUNTIME_ERROR;
00910 script_error:
00911    return CPL_SCRIPT_ERROR;
00912 }
00913 
00914 
00915 
00916 static inline int run_default( struct cpl_interpreter *intr )
00917 {
00918    if (!(intr->flags&CPL_PROXY_DONE)) {
00919       /* no signaling operations */
00920       if ( !(intr->flags&CPL_LOC_SET_MODIFIED) ) {
00921          /*  no location modifications */
00922          if (intr->loc_set==0 ) {
00923             /* case 1 : no location modifications or signaling operations
00924              * performed, location set empty ->
00925              * Look up the user's location through whatever mechanism the
00926              * server would use if no CPL script were in effect */
00927             return SCRIPT_DEFAULT;
00928          } else {
00929             /* case 2 : no location modifications or signaling operations
00930              * performed, location set non-empty: (This can only happen 
00931              * for outgoing calls.) ->
00932              * Proxy the call to the address in the location set.
00933              * With other words, let ser to continue processing the
00934              * request as nothing happened */
00935             return SCRIPT_DEFAULT;
00936          }
00937       } else {
00938          /* case 3 : location modifications performed, no signaling 
00939           * operations ->
00940           * Proxy the call to the addresses in the location set */
00941          if (!cpl_proxy_to_loc_set(intr->msg,&(intr->loc_set),intr->flags))
00942             return SCRIPT_END;
00943          return SCRIPT_RUN_ERROR;
00944       }
00945    } else {
00946       /* case 4 : proxy operation previously taken -> return whatever the 
00947        * "best" response is of all accumulated responses to the call to this
00948        * point, according to the rules of the underlying signaling
00949        * protocol. */
00950       /* we will let ser to choose and forward one of the replies -> for this
00951        * nothing must be done */
00952       return SCRIPT_END;
00953    }
00954    /*return SCRIPT_RUN_ERROR;*/
00955 }
00956 
00957 
00958 
00959 /* include all inline functions for processing the switches */
00960 #include "cpl_switches.h"
00961 /* include inline function for running proxy node */
00962 #include "cpl_proxy.h"
00963 
00964 
00965 
00966 int cpl_run_script( struct cpl_interpreter *intr )
00967 {
00968    char *new_ip;
00969 
00970    do {
00971       check_overflow_by_offset( SIMPLE_NODE_SIZE(intr->ip), intr, error);
00972       switch ( NODE_TYPE(intr->ip) ) {
00973          case CPL_NODE:
00974             LM_DBG("processing CPL node \n");
00975             new_ip = run_cpl_node( intr ); /*UPDATED&TESTED*/
00976             break;
00977          case ADDRESS_SWITCH_NODE:
00978             LM_DBG("processing address-switch node\n");
00979             new_ip = run_address_switch( intr ); /*UPDATED&TESTED*/
00980             break;
00981          case STRING_SWITCH_NODE:
00982             LM_DBG("processing string-switch node\n");
00983             new_ip = run_string_switch( intr ); /*UPDATED&TESTED*/
00984             break;
00985          case PRIORITY_SWITCH_NODE:
00986             LM_DBG("processing priority-switch node\n");
00987             new_ip = run_priority_switch( intr ); /*UPDATED&TESTED*/
00988             break;
00989          case TIME_SWITCH_NODE:
00990             LM_DBG("processing time-switch node\n");
00991             new_ip = run_time_switch( intr ); /*UPDATED&TESTED*/
00992             break;
00993          case LANGUAGE_SWITCH_NODE:
00994             LM_DBG("processing language-switch node\n");
00995             new_ip = run_language_switch( intr ); /*UPDATED&TESTED*/
00996             break;
00997          case LOOKUP_NODE:
00998             LM_DBG("processing lookup node\n");
00999             new_ip = run_lookup( intr ); /*UPDATED&TESTED*/
01000             break;
01001          case LOCATION_NODE:
01002             LM_DBG("processing location node\n");
01003             new_ip = run_location( intr ); /*UPDATED&TESTED*/
01004             break;
01005          case REMOVE_LOCATION_NODE:
01006             LM_DBG("processing remove_location node\n");
01007             new_ip = run_remove_location( intr ); /*UPDATED&TESTED*/
01008             break;
01009          case PROXY_NODE:
01010             LM_DBG("processing proxy node\n");
01011             new_ip = run_proxy( intr );/*UPDATED&TESTED*/
01012             break;
01013          case REJECT_NODE:
01014             LM_DBG("processing reject node\n");
01015             new_ip = run_reject( intr ); /*UPDATED&TESTED*/
01016             break;
01017          case REDIRECT_NODE:
01018             LM_DBG("processing redirect node\n");
01019             new_ip = run_redirect( intr ); /*UPDATED&TESTED*/
01020             break;
01021          case LOG_NODE:
01022             LM_DBG("processing log node\n");
01023             new_ip = run_log( intr ); /*UPDATED&TESTED*/
01024             break;
01025          case MAIL_NODE:
01026             LM_DBG("processing mail node\n");
01027             new_ip = run_mail( intr ); /*UPDATED&TESTED*/
01028             break;
01029          case SUB_NODE:
01030             LM_DBG("processing sub node\n");
01031             new_ip = run_sub( intr ); /*UPDATED&TESTED*/
01032             break;
01033          default:
01034             LM_ERR("unknown type node (%d)\n",
01035                NODE_TYPE(intr->ip));
01036             goto error;
01037       }
01038 
01039       if (new_ip==CPL_RUNTIME_ERROR) {
01040          LM_ERR("runtime error\n");
01041          return SCRIPT_RUN_ERROR;
01042       } else if (new_ip==CPL_SCRIPT_ERROR) {
01043          LM_ERR("script error\n");
01044          return SCRIPT_FORMAT_ERROR;
01045       } else if (new_ip==DEFAULT_ACTION) {
01046          LM_DBG("running default action\n");
01047          return run_default(intr);
01048       } else if (new_ip==EO_SCRIPT) {
01049          LM_DBG("script interpretation done!\n");
01050          return SCRIPT_END;
01051       } else if (new_ip==CPL_TO_CONTINUE) {
01052          LM_DBG("done for the moment; waiting after signaling!\n");
01053          return SCRIPT_TO_BE_CONTINUED;
01054       }
01055       /* move to the new instruction */
01056       intr->ip = new_ip;
01057    }while(1);
01058 
01059 error:
01060    return SCRIPT_FORMAT_ERROR;
01061 }

Generated on Mon May 21 18:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6