seas_action.c

Go to the documentation of this file.
00001 /* $Id: seas_action.c 5376 2008-12-17 19:07:14Z osas $
00002  *
00003  * Copyright (C) 2006-2007 VozTelecom Sistemas S.L
00004  *
00005  * This file is part of Kamailio, a free SIP server.
00006  *
00007  * Kamailio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version
00011  *
00012  * Kamailio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License 
00018  * along with this program; if not, write to the Free Software 
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  * History:
00022  * -------
00023  * 2008-04-04 added support for local and remote dispaly name in TM dialogs
00024  *            (by Andrei Pisau <andrei at voice-system dot ro> )
00025  *
00026  */
00027 
00028 #include <unistd.h>
00029 #include <string.h>
00030 #include <arpa/inet.h>
00031 #include <sys/types.h>
00032 #include <signal.h>
00033 #include <poll.h>
00034 #include <assert.h>/*assert*/
00035 
00036 #include "../../mem/mem.h"
00037 #include "../../dprint.h"
00038 #include "../../str.h"
00039 #include "../../pt.h"/*process_count*/
00040 #include "../../ip_addr.h"
00041 #include "../../tags.h"
00042 #include "../../error.h"
00043 #include "../../ut.h"
00044 #include "../../parser/hf.h"
00045 #include "../../parser/parse_fline.h"
00046 #include "../../parser/parser_f.h"/*find_not_quoted*/
00047 #include "../../parser/parse_to.h"
00048 #include "../../parser/parse_from.h"
00049 #include "../../parser/parse_cseq.h"
00050 #include "../../parser/parse_content.h"
00051 #include "../../parser/parse_rr.h"/*parse_rr*/
00052 #include "../../parser/parse_via.h"/*parse_via*/
00053 #include "../../parser/parse_param.h"/*parse_params*/
00054 #include "../../parser/parse_uri.h" /*parse_uri*/
00055 #include "../../parser/msg_parser.h"
00056 #include "encode_msg.h"
00057 #include "../tm/t_lookup.h"
00058 #include "../tm/h_table.h"
00059 #include "../tm/dlg.h"
00060 #include "seas.h"
00061 #include "statistics.h"
00062 #include "seas_action.h"
00063 #include "seas_error.h"
00064 #include "ha.h"
00065 
00066 #define MAX_HEADER 1024
00067 
00068 #define SPIRAL_HDR "X-WeSIP-SPIRAL: true"
00069 #define SPIRAL_HDR_LEN (sizeof(SPIRAL_HDR)-1)
00070 
00071 #define RECORD_ROUTE "Record-Route: "
00072 #define RECORD_ROUTE_LEN (sizeof(RECORD_ROUTE)-1)
00073 
00074 #define VIA "Via: "
00075 #define VIA_LEN (sizeof(VIA)-1)
00076 
00077 extern char *seas_tag_suffix;
00078 extern char seas_tags[];
00079 pid_t my_parent;
00080 extern int fifo_pid;
00081 
00082 static inline struct sip_msg *parse_ac_msg(hdr_flags_t flags,char *start,int len);
00083 static inline void free_sip_msg_lite(struct sip_msg *my_msg);
00084 static inline int calculate_hooks(dlg_t* _d);
00085 
00086 static inline int process_input(int fd);
00087 static inline int process_pings(struct ha *the_table);
00088 static inline int ac_jain_pong(as_p the_as,char *action,int len);
00089 int process_pong(struct ha *the_table,unsigned int seqno);
00090 int print_local_uri(as_p as,char processor_id,char *where,int len);
00091 
00092 
00093 int dispatch_actions(void)
00094 {
00095    int fd,n,ret,timeout,elapsed_ms;
00096    static int ktimeout;
00097    struct pollfd fds[1];
00098    struct timeval last,now;
00099 
00100    /* now the process_no is set, I delete the pt (process_table) global var,
00101    * because it confuses LM_*() */
00102    pt=0;
00103    fd=my_as->u.as.action_fd;
00104    fds[0].fd=fd;
00105    fds[0].events=POLLIN|POLLHUP;
00106    fds[0].revents=0;
00107    my_parent=getppid();
00108    snprintf(whoami,MAX_WHOAMI_LEN,"[%.*s] Action dispatcher",my_as->name.len,my_as->name.s);
00109    if(jain_ping_timeout && servlet_ping_timeout)
00110       ktimeout=jain_ping_timeout<servlet_ping_timeout?jain_ping_timeout:servlet_ping_timeout;
00111    else if(jain_ping_timeout)
00112       ktimeout=jain_ping_timeout;
00113    else if(servlet_ping_timeout)
00114       ktimeout=servlet_ping_timeout;
00115    /*ac_buffer is pkg_malloc because only this process (action dispatcher) will use it*/
00116    if((my_as->u.as.ac_buffer.s = pkg_malloc(AS_BUF_SIZE))==0){
00117       LM_ERR("no more pkg mem\n");
00118       return -1;
00119    }
00120    my_as->u.as.ac_buffer.len=0;
00121    if(use_ha){
00122       timeout=ktimeout;
00123       while(1){
00124     gettimeofday(&last,NULL);
00125     print_pingtable(&my_as->u.as.jain_pings,-1,1);
00126     if(0>(n=poll(fds,1,timeout))){
00127        if(errno==EINTR){
00128           gettimeofday(&last,NULL);
00129           continue;
00130        }else if(errno==EBADF){
00131           LM_ERR("EBADF !!\n");
00132        }else{
00133           LM_ERR("on poll\n");
00134        }
00135     }else if(n==0){/*timeout*/
00136        if (0>(ret=process_pings(&my_as->u.as.jain_pings))) {
00137           return ret;
00138        }
00139        timeout=ktimeout;
00140     }else{ /*events*/
00141        if (0>(ret=process_input(fd))) {
00142           return ret;
00143        }
00144        gettimeofday(&now,NULL);
00145        elapsed_ms=((now.tv_sec-last.tv_sec)*1000)+((now.tv_usec-last.tv_usec)/1000);
00146        if(elapsed_ms<timeout){
00147           timeout-=elapsed_ms;
00148        }else{
00149           if(0>(ret=process_pings(&my_as->u.as.jain_pings))){
00150         return ret;
00151           }
00152           timeout=ktimeout;
00153        }
00154     }
00155     fds[0].events=POLLIN|POLLHUP;
00156     fds[0].revents=0;
00157       }
00158    }else{
00159       do{
00160     ret=process_input(fd);
00161       }while(ret>=0);
00162    }
00163 
00164    return 0;
00165 }
00166 
00167 static inline int process_input(int fd)
00168 {
00169    int j,k;
00170 
00171    k=AS_BUF_SIZE-(my_as->u.as.ac_buffer.len);
00172 again:
00173    if(0>(j=read(fd,my_as->u.as.ac_buffer.s+my_as->u.as.ac_buffer.len,k))){
00174       if(errno==EINTR)
00175     goto again;
00176       LM_ERR("reading data for as %.*s (%s)\n",my_as->name.len,my_as->name.s,strerror(errno));
00177       return -1;
00178    }else if(j==0){
00179       pkg_free(my_as->u.as.ac_buffer.s);
00180       close(fd);
00181       LM_ERR("read 0 bytes from AS:%.*s\n",my_as->name.len,my_as->name.s);
00182       /** we return, so we will exit, so our parent (Event Dispatcher) will receive a sigchld and know
00183        * it should tear down the corresponding AS
00184        * what still is not clear is what will happen to events that were put in the pipe...
00185        */
00186       return -2;
00187    }
00188    (my_as->u.as.ac_buffer.len)+=j;
00189    LM_DBG("read %d bytes from AS action socket (total = %d)\n",j,my_as->u.as.ac_buffer.len);
00190    if(use_stats)
00191       receivedplus();
00192    if(my_as->u.as.ac_buffer.len>5){
00193       process_action(&my_as->u.as);
00194       LM_DBG("(Action dispatched,buffer.len=%d)\n",my_as->u.as.ac_buffer.len);
00195    }
00196    return 0;
00197 }
00198 
00199 /**
00200  * The ha structure (high availability) uses a circular (ring) buffer. A linked
00201  * list could be used, but it would involve a lot of shm_malloc/free, and this
00202  * would involve a lot of shm-lock_get/release, which would interfere a lot
00203  * with all the SER processes. With a this ring buffer, the lock_get/release only
00204  * involve the SEAS processes.
00205  * This function scans the ping structures in the buffer, computing the elapsed time
00206  * from when the ping was sent, so if the ping has timed out, it increases the 
00207  * timed_out_pings counter. All the timed-out pings are removed from the buffer (the
00208  * begin index is incremented). Because the pings are added always at the end
00209  * of the buffer, they will always be ordered in increasing time, so when we find one ping
00210  * that has not timed out, the following pings will neither be.
00211  *
00212  */
00213 static inline int process_pings(struct ha *the_table)
00214 {
00215    int i,k,elapsed;
00216    struct ping *tmp;
00217    struct timeval now;
00218 
00219    tmp=NULL;
00220    gettimeofday(&now,NULL);
00221    if(the_table->count==0)
00222       return 0;
00223    lock_get(the_table->mutex);
00224    {
00225       print_pingtable(the_table,-1,0);
00226       for(i=0;i<the_table->count;i++){
00227     k=(the_table->begin+i)%the_table->size;
00228     tmp=the_table->pings+k;
00229     elapsed=(now.tv_sec-tmp->sent.tv_sec)*1000+(now.tv_usec-tmp->sent.tv_usec)/1000;
00230     if(elapsed>the_table->timeout){
00231        LM_DBG("ping timed out %d\n",tmp->id);
00232        the_table->timed_out_pings++;
00233     }else{
00234        the_table->begin=k;
00235        the_table->count-=i;
00236        break;
00237     }
00238       }
00239    }
00240    lock_release(the_table->mutex);
00241    return 0;
00242 }
00243 
00244 /* Because TransactionModule organizes statistics based on process_no, 
00245  * and process_no are only assigned to SER processes (not to Action dispatchers like us ;)
00246  * we have to simulate we are the FIFO process, so TM thinks that the transactions WE put
00247  * are put by the fifo process...
00248 static inline void set_process_no()
00249 {
00250    int pcnt,i;
00251 
00252    pcnt=process_count();
00253    for(i=0;i<pcnt;i++){
00254       if(pt[i].pid==fifo_pid){
00255     process_no=i;
00256     LM_DBG("Setting fake process_no to %d (fifo pid=%d)\n",i,fifo_pid);
00257     return;
00258       }
00259    }
00260    for(i=0;i<pcnt;i++){
00261       if(!memcmp(pt[i].desc,"unix domain socket server",26)){
00262     process_no=i;
00263     LM_DBG("Setting fake process_no to %d\n",i);
00264     return;
00265       }
00266    }
00267    LM_ERR("unable to fake process_no\n");
00268 }
00269 */
00270 
00271 /**Processes the actions received from the socket.
00272  * returns
00273  *    -1 on error
00274  *    0 on success
00275  */
00276 int process_action(as_p the_as)
00277 {
00278    unsigned int ac_len;
00279    ac_len=(the_as->ac_buffer.s[0]<<24)|(the_as->ac_buffer.s[1]<<16)|(the_as->ac_buffer.s[2]<<8)|((the_as->ac_buffer.s[3])&0xFF);
00280    /*yeah, it comes in network byte order*/
00281    /*if ac_len > BUF_SIZE then a flag should be put on the AS so that the whole length
00282     * of the action is skipped, until a mechanism for handling big packets is implemented*/
00283    if(use_stats)
00284       stats_reply();
00285    if(ac_len>AS_BUF_SIZE){
00286       LM_WARN("action too big (%d)!!! should be skipped and"
00287            " an error returned!\n",ac_len);
00288       return -1;
00289    }
00290    while (the_as->ac_buffer.len>=ac_len) {
00291       LM_DBG("Processing action %d bytes long\n",ac_len);
00292       switch(the_as->ac_buffer.s[4]){
00293     case REPLY_PROV:
00294     case REPLY_FIN:
00295        LM_DBG("Processing a REPLY action from AS (length=%d): %.*s\n",
00296             ac_len,the_as->name.len,the_as->name.s);
00297        ac_reply(the_as,the_as->ac_buffer.s+5,ac_len-5);
00298        break;
00299     case UAC_REQ:
00300        LM_DBG("Processing an UAC REQUEST action from AS (length=%d): %.*s\n",
00301             ac_len,the_as->name.len,the_as->name.s);
00302        ac_uac_req(the_as,the_as->ac_buffer.s+5,ac_len-5);
00303        break;
00304     case AC_CANCEL:
00305        LM_DBG("Processing a CANCEL REQUEST action from AS (length=%d): %.*s\n",
00306             ac_len,the_as->name.len,the_as->name.s);
00307        ac_cancel(the_as,the_as->ac_buffer.s+5,ac_len-5);
00308        break;
00309     case SL_MSG:
00310        LM_DBG("Processing a STATELESS MESSAGE action from AS (length=%d): %.*s\n",
00311             ac_len,the_as->name.len,the_as->name.s);
00312        ac_sl_msg(the_as,the_as->ac_buffer.s+5,ac_len-5);
00313        break;
00314     case JAIN_PONG:
00315        LM_DBG("Processing a PONG\n");
00316        ac_jain_pong(the_as,the_as->ac_buffer.s+5,ac_len-5);
00317        break;
00318     default:
00319        LM_DBG("Processing a UNKNOWN TYPE action from AS (length=%d): %.*s\n",
00320             ac_len,the_as->name.len,the_as->name.s);
00321        break;
00322       }
00323       memmove(the_as->ac_buffer.s,the_as->ac_buffer.s+ac_len,(the_as->ac_buffer.len)-ac_len);
00324       (the_as->ac_buffer.len)-=ac_len;
00325       if(the_as->ac_buffer.len>5){
00326     ac_len=(the_as->ac_buffer.s[0]<<24)|(the_as->ac_buffer.s[1]<<16)|(the_as->ac_buffer.s[2]<<8)|((the_as->ac_buffer.s[3])&0xFF);
00327       }else{
00328     return 0;
00329       }
00330    }
00331    return 0;
00332 }
00333 
00334 static inline int ac_jain_pong(as_p the_as,char *action,int len)
00335 {
00336    unsigned int seqno,flags;
00337    int k;
00338    k=0;
00339    net2hostL(flags,action,k);
00340    net2hostL(seqno,action,k);
00341    process_pong(&the_as->jain_pings,seqno);
00342    return 0;
00343 }
00344 
00345 int process_pong(struct ha *the_table,unsigned int seqno)
00346 {
00347    int i,k,elapsed;
00348    struct ping *tmp;
00349    struct timeval now;
00350 
00351    gettimeofday(&now,NULL);
00352    tmp=NULL;
00353    if(the_table->count==0)
00354       return 0;
00355    lock_get(the_table->mutex);
00356    print_pingtable(the_table,-1,0);
00357    for(i=0;i<the_table->count;i++){
00358       k=(the_table->begin+i)%the_table->size;
00359       tmp=the_table->pings+k;
00360       if(tmp->id == seqno){
00361     elapsed=(now.tv_sec-tmp->sent.tv_sec)*1000+(now.tv_usec-tmp->sent.tv_usec)/1000;
00362     LM_DBG("Ping-Pong delay: %d (timeout was:%d)\n",elapsed,the_table->timeout);
00363     if(elapsed>the_table->timeout){
00364        /*if this ping has timed out, all the more-ancient pings will also be
00365         * timed out*/
00366        the_table->timed_out_pings+=i;
00367     }/*anyway, when we find a ping in the table, we remove all the pings that are more
00368        ancient (if there are any..)*/
00369     the_table->count-=(i+1);
00370     the_table->begin=(k+1)%the_table->size;
00371     break;
00372       }
00373    }
00374    lock_release(the_table->mutex);
00375    return 0;
00376 }
00377 
00378 
00379 /**
00380  * ac_cancel:
00381  * @param the_as Application Server structure which sent this action
00382  * @param action action payload
00383  * @param len the length of the payload
00384  * 
00385  * This function cancels a previously initiated UAC Transaction.
00386  * it receives the HashIndex and Label of the cell being cancelled
00387  * and invokes t_cancel_uac from the transactionModule API which 
00388  * cancels the transaction.
00389  *
00390  * Returns: 
00391  * */
00392 
00393 int ac_cancel(as_p the_as,char *action,int len)
00394 {
00395    unsigned int flags,ret,cancelled_hashIdx,cancelled_label,i;
00396    char processor_id;
00397    struct sip_msg *my_msg;
00398    struct as_uac_param *the_param;
00399    struct cell* t_invite;
00400    int k,retval,uac_id;
00401    str headers,body;
00402 
00403    body.s=headers.s=NULL;
00404    my_msg=NULL;
00405    the_param=NULL;
00406    i=k=0;
00407 
00408    net2hostL(flags,action,k);
00409    net2hostL(uac_id,action,k);
00410 
00411    processor_id=action[k++];
00412 
00413    net2hostL(cancelled_hashIdx,action,k);
00414    net2hostL(cancelled_label,action,k);
00415 
00416    if(!(headers.s=pkg_malloc(MAX_HEADER))){
00417       LM_ERR("Out of Memory!!");
00418       goto error;
00419    }
00420    headers.len=0;
00421    if(!(my_msg=pkg_malloc(sizeof(struct sip_msg)))){
00422       LM_ERR("out of memory!\n");
00423       goto error;
00424    }
00425    memset(my_msg,0,sizeof(struct sip_msg));
00426    my_msg->buf=action+k;
00427    my_msg->len=len-k;
00428    LM_DBG("Action UAC Message: uac_id:%d processor_id=%d, message:[%.*s]\n",
00429          uac_id,processor_id,len-4,&action[4]);
00430    if(parse_msg(action+k,len-k,my_msg)<0){
00431       LM_ERR("parsing sip_msg");
00432       goto error;
00433    }
00434    if(my_msg->first_line.type==SIP_REPLY){
00435       LM_ERR("trying to create a UAC with a SIP response!!\n");
00436       goto error;
00437    }
00438    if(parse_headers(my_msg,HDR_EOH_F,0)==-1){
00439       LM_ERR("parsing headers\n");
00440       goto error;
00441    }
00442    if(0>(headers.len=extract_allowed_headers(my_msg,1,-1,HDR_CONTENTLENGTH_F|HDR_ROUTE_F|HDR_TO_F|HDR_FROM_F|HDR_CALLID_F|HDR_CSEQ_F,headers.s,MAX_HEADER))) {
00443       LM_ERR("Unable to extract allowed headers!!\n");
00444       goto error;
00445    }
00446    if(flags & SPIRAL_FLAG){
00447       memcpy(headers.s+headers.len,SPIRAL_HDR CRLF,SPIRAL_HDR_LEN + CRLF_LEN);
00448       headers.len+=SPIRAL_HDR_LEN+CRLF_LEN;
00449       /*headers.s[headers.len]=0;
00450       fake_uri.s=pkg_malloc(200);
00451       fake_uri.len=print_local_uri(the_as,processor_id,fake_uri.s,200);
00452 
00453       if(fake_uri.len<0){
00454     SLM_ERR("printing local uri\n");
00455     goto error;
00456       }
00457       my_dlg->hooks.next_hop=&fake_uri;*/
00458    }
00459 
00460    headers.s[headers.len]=0;
00461 
00462    /*let's get the body*/
00463    i=(unsigned int)get_content_length(my_msg);
00464    if(i!=0){
00465       if(!(body.s=pkg_malloc(i))){
00466     LM_ERR("Out of Memory!");
00467     goto error;
00468       }
00469       memcpy(body.s,get_body(my_msg),i);
00470       body.len=i;
00471       LM_DBG("Trying to construct a Sip Request with: body:%d[%s]"
00472            " headers:%d[%s]\n", body.len,body.s,headers.len,headers.s);
00473    }else{
00474       body.s=NULL;
00475       body.len=0;
00476    }
00477 
00478    if(!(the_param=shm_malloc(sizeof(struct as_uac_param)))){
00479       LM_ERR("no more share memory\n");
00480       goto error;
00481    }
00482 
00483    if(seas_f.tmb.t_lookup_ident(&t_invite,cancelled_hashIdx,cancelled_label)<0){
00484       LM_ERR("failed to t_lookup_ident hash_idx=%d,"
00485          "label=%d\n", cancelled_hashIdx,cancelled_label);
00486       goto error;
00487    }
00488    seas_f.tmb.unref_cell(t_invite);
00489 
00490    the_param->who=my_as;
00491    the_param->uac_id=uac_id;
00492    the_param->processor_id=processor_id;
00493    the_param->destroy_cb_set=0;
00494    
00495    ret=seas_f.tmb.t_cancel_uac(&headers,&body,cancelled_hashIdx,cancelled_label,uac_cb,(void*)the_param);
00496    if (ret == 0) {
00497       LM_ERR( "t_cancel_uac failed\n");
00498       as_action_fail_resp(uac_id,SE_CANCEL,SE_CANCEL_MSG,SE_CANCEL_MSG_LEN);
00499       goto error;
00500    }else{
00501       the_param->label=ret;
00502    }
00503 
00504    seas_f.tmb.unref_cell(t_invite);
00505    retval=0;
00506    goto exit;
00507 error:
00508    retval = -1;
00509    if(the_param)
00510       shm_free(the_param);
00511 exit:
00512    if(headers.s)
00513       pkg_free(headers.s);
00514    if(body.s)
00515       pkg_free(headers.s);
00516    if(my_msg){
00517       if(my_msg->headers)
00518     free_hdr_field_lst(my_msg->headers);
00519       pkg_free(my_msg);
00520    }
00521    return retval;
00522 }
00523 
00524 int recordroute_diff(struct sip_msg *req,struct sip_msg *resp)
00525 {
00526    struct hdr_field *hf;
00527    rr_t *rr1;
00528    int i,j,k;
00529    i=j=k=0;
00530    /* count how many record-route bodies come in the response*/
00531    /* this does not work, I think because of siblings
00532    for(hf=resp->record_route;hf;hf=hf->sibling,j=0){
00533    */
00534    for(hf=resp->headers;hf;hf=hf->next,j=0){
00535       if(hf->type != HDR_RECORDROUTE_T)
00536     continue;
00537       if(!hf->parsed){
00538     if(0>parse_rr(hf))
00539        goto error;
00540     j=1;
00541       }
00542       for(rr1=hf->parsed;rr1;rr1=rr1->next){
00543     i++;
00544       }
00545       if(j){
00546     free_rr((rr_t**)(void*)&hf->parsed);
00547     hf->parsed=NULL;
00548       }
00549    }
00550    /*
00551    for(hf=req->record_route;hf;hf=hf->sibling,j=0){
00552       */
00553    for(hf=req->headers;hf;hf=hf->next,j=0){
00554       if(hf->type != HDR_RECORDROUTE_T)
00555     continue;
00556       if(!hf->parsed){
00557     if(0>parse_rr(hf))
00558        goto error;
00559     j=1;
00560       }
00561       for(rr1=hf->parsed;rr1;rr1=rr1->next){
00562     k++;
00563       }
00564       if(j){
00565     free_rr((rr_t**)(void*)&hf->parsed);
00566     hf->parsed=NULL;
00567       }
00568    }
00569    return i-k;
00570 error:
00571    return -1;
00572 }
00573 
00574 int via_diff(struct sip_msg *req,struct sip_msg *resp)
00575 {
00576    struct hdr_field *hf;
00577    struct via_body *vb;
00578    int i,j,k;
00579 
00580    i=j=k=0;
00581    /* count how many via bodies come in the response*/
00582    for(hf=resp->h_via1;hf;hf=hf->sibling){
00583       if(!hf->parsed){
00584     if((vb=pkg_malloc(sizeof(struct via_body)))==0){
00585        LM_ERR("Out of mem in via_diff!!\n");
00586        return -1;
00587     }
00588     memset(vb,0,sizeof(struct via_body));
00589     if(parse_via(hf->body.s,hf->body.s+hf->body.len+1,vb)==0){
00590        LM_ERR("Unable to parse via in via_diff!\n");
00591        pkg_free(vb);
00592        return -1;
00593     }
00594     hf->parsed=vb;
00595     j=1;
00596       }
00597       for(vb=hf->parsed;vb;vb=vb->next){
00598     i++;
00599       }
00600       if(j){
00601     free_via_list((struct via_body*)hf->parsed);
00602     hf->parsed=NULL;
00603     j=0;
00604       }
00605    }
00606    j=0;
00607    /* count how many via bodies were in the orig. request*/
00608    for(hf=req->h_via1;hf;hf=hf->sibling){
00609       if(!hf->parsed){
00610     if((vb=pkg_malloc(sizeof(struct via_body)))==0){
00611        goto error;
00612     }
00613     memset(vb,0,sizeof(struct via_body));
00614     if(parse_via(hf->body.s,hf->body.s+hf->body.len+1,vb)==0){
00615        goto error;
00616     }
00617     hf->parsed=vb;
00618     j=1;
00619       }
00620       for(vb=hf->parsed;vb;vb=vb->next){
00621     k++;
00622       }
00623       if(j){
00624     free_via_list((struct via_body*)hf->parsed);
00625     hf->parsed=NULL;
00626     j=0;
00627       }
00628    }
00629    return i-k;
00630 error:
00631    return -1;
00632 }
00633 
00634 /**
00635  * ac_reply: UAS transaction Reply action. It replies to an incoming request with a response.
00636  * @param the_as The App Server that sent this action.
00637  * @param action action
00638  * @param len length
00639  *
00640  * function description
00641  *
00642  * Returns: what
00643  */
00644 int ac_reply(as_p the_as,char *action,int len)
00645 {
00646    unsigned int flags,hash_index,label,contentlength;
00647    struct cell *c;
00648    struct sip_msg *my_msg;
00649    struct to_body *tb;
00650    str new_header,body,totag;
00651    char *ttag;
00652    int i,k,retval;
00653    static char headers[MAX_HEADER];
00654 
00655    contentlength=0;
00656    ttag=NULL;
00657    my_msg=NULL;
00658    i=k=0;
00659 
00660    net2hostL(flags,action,k);
00661    net2hostL(hash_index,action,k);
00662    net2hostL(label,action,k);
00663 
00664    if(seas_f.tmb.t_lookup_ident(&c,hash_index,label)<0){
00665       LM_ERR("Failed to t_lookup_ident hash_idx=%d,label=%d\n",hash_index,label);
00666       goto error;
00667    }
00668    if(use_stats)
00669       action_stat(c);
00670    if(c->uas.status>=200){
00671       LM_ERR("ac_reply: trying to reply to a \"%.*s\" transaction"
00672        "that is already in completed state\n",REQ_LINE(c->uas.request).method.len,REQ_LINE(c->uas.request).method.s);
00673       goto error;
00674    }
00675    if (!(my_msg=parse_ac_msg(HDR_EOH_F,action+k,len-k))) {
00676       LM_ERR("Failed to parse_ac_msg hash_idx=%d,label=%d\n",hash_index,label);
00677       goto error;
00678    }
00679    tb=(struct to_body*)my_msg->to->parsed;
00680    if(tb->tag_value.s && tb->tag_value.len){
00681       totag=tb->tag_value;
00682    }else{
00683       totag.s=NULL;
00684       totag.len=0;
00685       /*if(!(ttag=pkg_malloc(TOTAG_VALUE_LEN))){
00686     LM_ERR("Out of memory !!!\n");
00687     goto error;
00688       }
00689       totag.s=ttag;
00690       calc_crc_suffix(c->uas.request,seas_tag_suffix);
00691       LM_DBG("seas_tags = %.*s\n",TOTAG_VALUE_LEN,seas_tags);
00692       memcpy(totag.s,seas_tags,TOTAG_VALUE_LEN);
00693       totag.len=TOTAG_VALUE_LEN;*/
00694    }
00695    LM_DBG("Using totag=[%.*s]\n",totag.len,totag.s);
00696    if(my_msg->content_length)
00697       contentlength=(unsigned int)(long)my_msg->content_length->parsed;
00698    if(0>(i=recordroute_diff(c->uas.request,my_msg))){/*not likely..*/
00699       LM_DBG("Seems that request had more RecordRoutes than response...\n");
00700       goto error;
00701    }else
00702       LM_DBG("Recordroute Diff = %d\n",i);
00703 
00704    if(0>(i=extract_allowed_headers(my_msg,0,i,HDR_VIA_F|HDR_TO_F|HDR_FROM_F|HDR_CSEQ_F|HDR_CALLID_F|HDR_CONTENTLENGTH_F,headers,MAX_HEADER))){
00705       LM_ERR("ac_reply() filtering headers !\n");
00706       goto error;
00707    }
00708    headers[i]=0;
00709    new_header.s=headers;
00710    new_header.len=i;
00711 
00712    /* If it is INVITE and response is success (>=200 && <300), we mark it as local so that
00713     * SER does NOT retransmit the final response (by default, SER retransmit local UAS final
00714     * responses...*/
00715    if(is_invite(c) && my_msg->first_line.u.reply.statuscode>=200 && my_msg->first_line.u.reply.statuscode<300)
00716       c->flags |= T_IS_LOCAL_FLAG;
00717    /*WARNING casting unsigned int to int*/
00718    body.len=contentlength;
00719    body.s=get_body(my_msg);
00720 
00721    LM_DBG("Trying to construct a SipReply with: ReasonPhrase:[%.*s] body:[%.*s] headers:[%.*s] totag:[%.*s]\n",\
00722     my_msg->first_line.u.reply.reason.len,my_msg->first_line.u.reply.reason.s,\
00723     body.len,body.s,new_header.len,new_header.s,totag.len,totag.s);
00724    /* t_reply_with_body un-ref-counts the transaction, so dont use it anymore*/
00725    if(seas_f.tmb.t_reply_with_body(c,my_msg->first_line.u.reply.statuscode,&(my_msg->first_line.u.reply.reason),&body,&new_header,&totag)<0){
00726       LM_ERR("Failed to t_reply\n");
00727       goto error;
00728    }
00729    retval=0;
00730    goto exit;
00731 error:
00732    retval = -1;
00733    seas_f.tmb.unref_cell(c);
00734 exit:
00735    if(ttag)
00736       pkg_free(ttag);
00737    if(my_msg){
00738       free_sip_msg_lite(my_msg);
00739       pkg_free(my_msg);
00740    }
00741    return retval;
00742 }
00743 
00744 static inline struct sip_msg *parse_ac_msg(hdr_flags_t flags,char *start,int len)
00745 {
00746    struct sip_msg *my_msg;
00747    my_msg=NULL;
00748    if(!(my_msg=pkg_malloc(sizeof(struct sip_msg)))){
00749       LM_ERR("ac_reply: out of memory!\n");
00750       goto error;
00751    }
00752    memset(my_msg,0,sizeof(struct sip_msg));
00753    my_msg->buf=start;
00754    my_msg->len=len;
00755    LM_DBG("Action Message:[%.*s]\n",len,start);
00756    if(0>parse_msg(start,len,my_msg)){
00757       LM_ERR("parse_ac_msg: parsing sip_msg");
00758       goto error;
00759    }
00760    if(0>parse_headers(my_msg,flags,0)){
00761       LM_ERR("parse_ac_msg: parsing headers\n");
00762       goto error;
00763    }
00764    return my_msg;
00765 error:
00766    if(my_msg){
00767       free_sip_msg_lite(my_msg);
00768       pkg_free(my_msg);
00769    }
00770    return NULL;
00771 }
00772 
00773 /* Actions are composed as follows:
00774  * (the action length and type as always= 5 bytes)
00775  *
00776  * TODO performance speedup: instead of using
00777  * dynamically allocated memory for headers,body,totag,reason and my_msg
00778  * use static buffers.
00779  *
00780  */
00781 int ac_sl_msg(as_p the_as,char *action,int len)
00782 {
00783    char processor_id;
00784    struct sip_msg *my_msg;
00785    str *uri;
00786    struct proxy_l *proxy;
00787    rr_t *my_route;
00788    int i,k,retval;
00789    unsigned int flags;
00790    enum sip_protos proto;
00791 
00792    my_msg=NULL;
00793    i=k=0;
00794 
00795    net2hostL(flags,action,k);
00796    processor_id=action[k++];
00797    proxy=0;
00798 
00799    if(!(my_msg = parse_ac_msg(HDR_EOH_F,action+k,len-k))){
00800       LM_ERR("out of memory!\n");
00801       goto error;
00802    }
00803    if(my_msg->first_line.type == SIP_REQUEST)
00804       LM_DBG("forwarding request:\"%.*s\" statelessly \n",my_msg->first_line.u.request.method.len+1+\
00805        my_msg->first_line.u.request.uri.len,my_msg->first_line.u.request.method.s);
00806    else
00807       LM_DBG("forwarding reply:\"%.*s\" statelessly \n",my_msg->first_line.u.reply.status.len+1+\
00808        my_msg->first_line.u.reply.reason.len,my_msg->first_line.u.reply.status.s);
00809 
00810    if (my_msg->route) {
00811       if (parse_rr(my_msg->route) < 0) {
00812     LM_ERR( "Error while parsing Route body\n");
00813     goto error;
00814       }
00815       my_route = (rr_t*)my_msg->route->parsed;
00816       uri=&(my_route->nameaddr.uri);
00817    }else{
00818       uri = GET_RURI(my_msg);
00819    }
00820    my_msg->force_send_socket=grep_sock_info(&my_msg->via1->host,my_msg->via1->port,my_msg->via1->proto);
00821    /* or also could be:
00822       my_msg->force_send_socket=the_as->binds[processor_id].bind_address;
00823       not sure which is better...
00824       */
00825    proxy=uri2proxy(uri,PROTO_NONE);
00826    if (proxy==0) {
00827       LM_ERR("unable to create proxy from URI \n");
00828       goto error;
00829    }
00830    proto=proxy->proto; /* uri2proxy set it correctly */
00831    //TODO my_msg->recvd
00832    if(0>forward_sl_request(my_msg,proxy,proto))
00833       goto error;
00834    retval=0;
00835    goto exit;
00836 error:
00837    retval = -1;
00838 exit:
00839    if(proxy){
00840       free_proxy(proxy);
00841       pkg_free(proxy);
00842    }
00843    if(my_msg){
00844       free_sip_msg_lite(my_msg);
00845       pkg_free(my_msg);
00846    }
00847    return retval;
00848 }
00849 
00850 static inline void free_sip_msg_lite(struct sip_msg *my_msg)
00851 {
00852    if(my_msg){
00853       /**should do the same as in free_sip_msg() but w/o freeing my_msg->buf*/
00854       if (my_msg->new_uri.s) { pkg_free(my_msg->new_uri.s); my_msg->new_uri.len=0; }
00855       if (my_msg->dst_uri.s) { pkg_free(my_msg->dst_uri.s); my_msg->dst_uri.len=0; }
00856       if (my_msg->path_vec.s) { pkg_free(my_msg->path_vec.s);my_msg->path_vec.len=0; }
00857       if (my_msg->headers)     free_hdr_field_lst(my_msg->headers);
00858       if (my_msg->add_rm)      free_lump_list(my_msg->add_rm);
00859       if (my_msg->body_lumps)  free_lump_list(my_msg->body_lumps);
00860       /* this is not in lump_struct.h, and anyhow it's not supposed to be any lumps
00861        * in our messages... or is it?
00862       if (my_msg->reply_lump)   free_reply_lump(my_msg->reply_lump);
00863       */
00864    }
00865 }
00866 
00867 int forward_sl_request(struct sip_msg *msg,struct proxy_l *proxy,int proto)
00868 {
00869    union sockaddr_union *to;
00870    struct socket_info *send_sock;
00871    int ret;
00872 
00873    to = (union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union));
00874    ret = -1;
00875 
00876    hostent2su(to, &proxy->host, proxy->addr_idx,
00877       (proxy->port)?proxy->port:SIP_PORT);
00878 
00879    do {
00880       send_sock=get_send_socket(msg, to, proto);
00881       if (send_sock==0){
00882          LM_ERR( "cannot forward to af %d, "
00883             "proto %d no corresponding listening socket\n",
00884             to->s.sa_family, proto);
00885          continue;
00886       }
00887       LM_DBG("Sending:\n%.*s.\n", (int)msg->len,msg->buf);
00888       if (msg_send(send_sock, proto, to, 0, msg->buf,msg->len)<0){
00889          LM_ERR("Error sending message !!\n");
00890          continue;
00891       }
00892       ret = 0;
00893       break;
00894    }while( get_next_su( proxy, to, 0)==0 );
00895 
00896    pkg_free(to);
00897    return ret;
00898 }
00899 
00900 
00901 
00902 /*Actions are composed as follows:
00903  * (the action length and type as always= 5 bytes)
00904  * 4:uac_id
00905  *
00906  * int request(str* method, str* req_uri, str* to, str* from, str* headers, str* body, transaction_cb c, void* cp)
00907  * TODO performance speedup: instead of using
00908  * dynamically allocated memory for headers,body,totag,reason and my_msg
00909  * use static buffers.
00910  *
00911  */
00912 int ac_uac_req(as_p the_as,char *action,int len)
00913 {
00914    unsigned int flags,cseq;
00915    char err_buf[MAX_REASON_LEN],processor_id;
00916    struct sip_msg *my_msg;
00917    struct to_body *fb,*tb;
00918    struct cseq_body *cseqb;
00919    struct as_uac_param *the_param;
00920    dlg_t *my_dlg;
00921    int i,k,retval,uac_id,sip_error,ret,err_ret;
00922    long clen;
00923    str headers,body,fake_uri;
00924 
00925    headers.s=body.s=fake_uri.s=NULL;
00926    my_dlg=NULL;
00927    my_msg=NULL;
00928    the_param=NULL;
00929    i=k=clen=0;
00930 
00931    net2hostL(flags,action,k);
00932    net2hostL(uac_id,action,k);
00933 
00934    processor_id=action[k++];
00935 
00936    if(!(headers.s=pkg_malloc(MAX_HEADER))){
00937       LM_ERR("Out of Memory!!");
00938       goto error;
00939    }
00940    headers.len=0;
00941    LM_DBG("Action UAC Message: uac_id:%d processor_id=%d\n",uac_id,processor_id);
00942    if (!(my_msg = parse_ac_msg(HDR_EOH_F,action+k,len-k))) {
00943       LM_ERR("out of memory!\n");
00944       goto error;
00945    }
00946    if(my_msg->first_line.type==SIP_REPLY){
00947       LM_ERR("trying to create a UAC with a SIP response!!\n");
00948       goto error;
00949    }
00950    if(parse_headers(my_msg,HDR_EOH_F,0)==-1){
00951       LM_ERR("parsing headers\n");
00952       goto error;
00953    }
00954    if(parse_from_header(my_msg)<0){
00955       LM_ERR("parsing from header ! \n");
00956       goto error;
00957    }
00958    if(check_transaction_quadruple(my_msg)==0){
00959       as_action_fail_resp(uac_id,SE_UAC,"Headers missing (to,from,call-id,cseq)?",0);
00960       LM_ERR("Headers missing (to,from,call-id,cseq)?");
00961       goto error;
00962    }
00963    if(!(get_from(my_msg)) || !(get_from(my_msg)->tag_value.s) || 
00964     !(get_from(my_msg)->tag_value.len)){
00965       as_action_fail_resp(uac_id,SE_UAC,"From tag missing",0);
00966       LM_ERR("From tag missing");
00967       goto error;
00968    }
00969    fb=my_msg->from->parsed;
00970    tb=my_msg->to->parsed;
00971    cseqb=my_msg->cseq->parsed;
00972    if(0!=(str2int(&cseqb->number,&cseq))){
00973       LM_DBG("unable to parse CSeq\n");
00974       goto error;
00975    }
00976    if(my_msg->first_line.u.request.method_value != METHOD_ACK &&
00977     my_msg->first_line.u.request.method_value != METHOD_CANCEL) {
00978       /** we trick req_within */
00979       cseq--;
00980    }
00981    if(seas_f.tmb.new_dlg_uac(&(my_msg->callid->body),&(fb->tag_value),cseq,\
00982        &(fb->uri),&(tb->uri),&my_dlg) < 0) {
00983       as_action_fail_resp(uac_id,SE_UAC,"Error creating new dialog",0);
00984       LM_ERR("Error while creating new dialog\n");
00985       goto error;
00986    }
00987    if(seas_f.tmb.dlg_add_extra(my_dlg,&(fb->display),&(tb->display)) < 0 ) {
00988       as_action_fail_resp(uac_id,SE_UAC,
00989          "Error adding the display names to the new dialog",0);
00990       LM_ERR("failed to add display names to the new dialog\n");
00991       goto error;
00992    }
00993 
00994    if(tb->tag_value.s && tb->tag_value.len)
00995       shm_str_dup(&my_dlg->id.rem_tag,&tb->tag_value);
00996    /**Awful hack: to be able to set our own CSeq, from_tag and call-ID we have
00997     * to use req_within instead of req_outside (it sets it's own CSeq,Call-ID
00998     * and ftag), so we have to simulate that the dialog is already in completed
00999     * state so...
01000     */
01001    server_signature=0;
01002    my_dlg->state = DLG_CONFIRMED;
01003    if(0>(headers.len=extract_allowed_headers(my_msg,1,-1,HDR_CONTENTLENGTH_F|HDR_ROUTE_F|HDR_TO_F|HDR_FROM_F|HDR_CALLID_F|HDR_CSEQ_F,headers.s,MAX_HEADER))) {
01004       LM_ERR("Unable to extract allowed headers!!\n");
01005       goto error;
01006    }
01007    headers.s[headers.len]=0;
01008    /*let's get the body*/
01009    if(my_msg->content_length)
01010       clen=(long)get_content_length(my_msg);
01011    if(clen!=0){
01012       if(!(body.s=pkg_malloc(clen))){
01013     LM_ERR("Out of Memory!");
01014     goto error;
01015       }
01016       memcpy(body.s,get_body(my_msg),clen);
01017       body.len=clen;
01018       body.s[clen]=0;
01019       LM_DBG("Trying to construct a Sip Request with: body:%d[%.*s] headers:%d[%.*s]\n",\
01020        body.len,body.len,body.s,headers.len,headers.len,headers.s);
01021       /*t_reply_with_body un-ref-counts the transaction, so dont use it anymore*/
01022    }else{
01023       body.s=NULL;
01024       body.len=0;
01025    }
01026    /*Now... create the UAC !!
01027     * it would be great to know the hash_index and the label that have been assigned
01028     * to our newly created cell, but t_uac does not leave any way for us to know...
01029     * only that when that transaction transitions its state (ie. a response is received,
01030     * a timeout is reached, etc...) the callback will be called with the given parameter.
01031     *
01032     * So the only way we have to know who we are, is passing as a parameter a structure with
01033     * 2 pointers: one to the app_server and the other, the identifier of the UAC (uac_id).
01034     *
01035     */
01036    if(!(the_param=shm_malloc(sizeof(struct as_uac_param)))){
01037       LM_ERR("out of shared memory\n");
01038       goto error;
01039    }
01040    the_param->who=my_as;
01041    the_param->uac_id=uac_id;
01042    the_param->processor_id=processor_id;
01043    the_param->destroy_cb_set=0;
01044 
01045    shm_str_dup(&my_dlg->rem_target,&my_msg->first_line.u.request.uri);
01046 
01047    if (my_msg->route) {
01048       if (parse_rr(my_msg->route) < 0) {
01049     LM_ERR( "Error while parsing Route body\n");
01050     goto error;
01051       }
01052       /* TODO route_set should be a shm copy of my_msg->route->parsed */
01053       my_dlg->route_set=(rr_t*)my_msg->route->parsed;
01054       /** this SHOULD be:
01055        shm_duplicate_rr(&my_dlg->route_set,my_msg->route->parsed);
01056        * but it will last more...
01057        */
01058    }
01059    calculate_hooks(my_dlg);
01060    if(flags & SPIRAL_FLAG){
01061       memcpy(headers.s+headers.len,SPIRAL_HDR CRLF,SPIRAL_HDR_LEN + CRLF_LEN);
01062       headers.len+=SPIRAL_HDR_LEN+CRLF_LEN;
01063       headers.s[headers.len]=0;
01064       fake_uri.s=pkg_malloc(200);
01065       fake_uri.len=print_local_uri(the_as,processor_id,fake_uri.s,200);
01066 
01067       if(fake_uri.len<0){
01068     LM_ERR("printing local uri\n");
01069     goto error;
01070       }
01071       my_dlg->hooks.next_hop=&fake_uri;
01072    }
01073    my_dlg->T_flags=T_NO_AUTOACK_FLAG|T_PASS_PROVISIONAL_FLAG ;
01074    ret=seas_f.tmb.t_request_within(&(my_msg->first_line.u.request.method),&headers,&body,my_dlg,uac_cb,(void *)the_param);
01075    /** now undo all the fakes we have put in my_dlg*/
01076    /*because my_dlg->route_set should be shm but we fake it (its pkg_mem)*/
01077    my_dlg->route_set=(rr_t *)0;
01078    if (ret <= 0) {
01079       err_ret = err2reason_phrase(ret,&sip_error,err_buf, sizeof(err_buf), "SEAS/UAC");
01080       LM_ERR("Error on request_within %s\n",err_buf );
01081       if(err_ret > 0) {
01082     as_action_fail_resp(uac_id,ret,err_buf,0);
01083       }else{
01084     as_action_fail_resp(uac_id,E_UNSPEC,"500 SEAS/UAC error",0);
01085       }
01086       goto error;
01087    }
01088    retval=0;
01089    goto exit;
01090 error:
01091    retval = -1;
01092    if(the_param)
01093       shm_free(the_param);
01094 exit:
01095    seas_f.tmb.free_dlg(my_dlg);
01096    if(headers.s)
01097       pkg_free(headers.s);
01098    if(body.s)
01099       pkg_free(body.s);
01100    if(fake_uri.s)
01101       pkg_free(fake_uri.s);
01102    if(my_msg){
01103       if(my_msg->headers)
01104     free_hdr_field_lst(my_msg->headers);
01105       pkg_free(my_msg);
01106    }
01107    return retval;
01108 }
01109 
01110 /**
01111  * len MUST be >0
01112  */
01113 int print_local_uri(as_p as,char processor_id,char *where,int len)
01114 {
01115    int i;
01116    struct socket_info *si;
01117    str proto;
01118    proto.s=NULL;
01119    proto.len=0;
01120    for(i=0;i<MAX_BINDS;i++){
01121       if(as->bound_processor[i]==processor_id)
01122     break;
01123    }
01124    if(i==MAX_BINDS){
01125       LM_DBG("processor ID not found\n");
01126       return -1;
01127    }
01128    si=as->binds[i];
01129    switch(si->proto){
01130       case PROTO_UDP:
01131     proto.s="";
01132     proto.len=0;
01133     break;
01134       case PROTO_TCP:
01135     proto.s=TRANSPORT_PARAM "TCP";
01136     proto.len=TRANSPORT_PARAM_LEN + 3;
01137     break;
01138       case PROTO_TLS:
01139     proto.s=TRANSPORT_PARAM "TLS";
01140     proto.len=TRANSPORT_PARAM_LEN + 3;
01141     break;
01142       case PROTO_SCTP:
01143     proto.s=TRANSPORT_PARAM "SCTP";
01144     proto.len=TRANSPORT_PARAM_LEN + 4;
01145     break;
01146    }
01147    switch(si->address.af){
01148       case AF_INET:
01149     i=snprintf(where,len,"sip:%d.%d.%d.%d:%u%.*s",si->address.u.addr[0],si->address.u.addr[1],\
01150           si->address.u.addr[2],si->address.u.addr[3],si->port_no,proto.len,proto.s);
01151     break;
01152       case AF_INET6:
01153     i=snprintf(where,len,"sip:[%x:%x:%x:%x:%x:%x:%x:%x]:%u%.*s", htons(si->address.u.addr16[0]), htons(si->address.u.addr16[1]),\
01154           htons(si->address.u.addr16[2]), htons(si->address.u.addr16[3]), htons(si->address.u.addr16[4]), htons(si->address.u.addr16[5]),\
01155           htons(si->address.u.addr16[6]), htons(si->address.u.addr16[7]),si->port_no,proto.len,proto.s);
01156     break;
01157       default:
01158     LM_ERR("address family unknown\n");
01159     return -1;
01160    }
01161    if(i>len){
01162       LM_ERR("Output was truncated!!\n");
01163       return -1;
01164    }else if(i<0){
01165       LM_ERR("Error on snprintf\n");
01166       return i;
01167    }
01168    return i;
01169 }
01170 
01171 /* !!! COPIED FROM MODULES/TM  !!
01172  * This function skips name part
01173  * uri parsed by parse_contact must be used
01174  * (the uri must not contain any leading or
01175  *  trailing part and if angle bracket were
01176  *  used, right angle bracket must be the
01177  *  last character in the string)
01178  *
01179  * _s will be modified so it should be a tmp
01180  * copy
01181  */
01182 void get_raw_uri(str* _s)
01183 {
01184         char* aq;
01185 
01186         if (_s->s[_s->len - 1] == '>') {
01187                 aq = find_not_quoted(_s, '<');
01188                 _s->len -= aq - _s->s + 2;
01189                 _s->s = aq + 1;
01190         }
01191 }
01192 /* !!! COPIED FROM MODULES/TM  !!
01193  * Calculate dialog hooks
01194  *
01195  * This is copied from modules/tm/dlg.c
01196  *
01197  * Maybe a reference to the original function in TM
01198  * could be reached via handlers or whatever...
01199  */
01200 static inline int calculate_hooks(dlg_t* _d)
01201 {
01202    str* uri;
01203    struct sip_uri puri;
01204 
01205    if (_d->route_set) {
01206       uri = &_d->route_set->nameaddr.uri;
01207       if (parse_uri(uri->s, uri->len, &puri) < 0) {
01208          LM_ERR( "Error while parsing URI\n");
01209          return -1;
01210       }
01211 
01212       if (puri.lr.s) {
01213          if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target;
01214          else _d->hooks.request_uri = &_d->rem_uri;
01215     _d->hooks.next_hop = &_d->route_set->nameaddr.uri;
01216     _d->hooks.first_route = _d->route_set;
01217       } else {
01218          _d->hooks.request_uri = &_d->route_set->nameaddr.uri;
01219          _d->hooks.next_hop = _d->hooks.request_uri;
01220          _d->hooks.first_route = _d->route_set->next;
01221          _d->hooks.last_route = &_d->rem_target;
01222       }
01223    } else {
01224       if (_d->rem_target.s) _d->hooks.request_uri = &_d->rem_target;
01225       else _d->hooks.request_uri = &_d->rem_uri;
01226       _d->hooks.next_hop = _d->hooks.request_uri;
01227    }
01228 
01229    if ((_d->hooks.request_uri) && (_d->hooks.request_uri->s) && (_d->hooks.request_uri->len)) {
01230       _d->hooks.ru.s = _d->hooks.request_uri->s;
01231       _d->hooks.ru.len = _d->hooks.request_uri->len;
01232       _d->hooks.request_uri = &_d->hooks.ru;
01233       get_raw_uri(_d->hooks.request_uri);
01234    }
01235    if ((_d->hooks.next_hop) && (_d->hooks.next_hop->s) && (_d->hooks.next_hop->len)) {
01236       _d->hooks.nh.s = _d->hooks.next_hop->s;
01237       _d->hooks.nh.len = _d->hooks.next_hop->len;
01238       _d->hooks.next_hop = &_d->hooks.nh;
01239       get_raw_uri(_d->hooks.next_hop);
01240    }
01241 
01242    return 0;
01243 }
01244 
01245 /**
01246  * Strips the "<strip_top_vias>" topmost via headers.
01247  * Leaves only the topmost "<allow_top_routes>" Record-Route headers.
01248  *
01249  */
01250 int extract_allowed_headers(struct sip_msg *my_msg,int strip_top_vias,int allow_top_Rroutes,hdr_flags_t forbidden_hdrs,char *headers,int headers_len)
01251 {
01252    struct hdr_field *hf;
01253    rr_t *rb;
01254    struct via_body *vb;
01255    int len,k,rtcnt,i;
01256 
01257    len=0;
01258    rtcnt=allow_top_Rroutes;
01259    rb=NULL;
01260    vb=NULL;
01261 
01262    for(hf=my_msg->headers;hf;hf=hf->next){
01263       if(forbidden_hdrs & HDR_T2F(hf->type)){
01264     LM_DBG("Skipping header (%.*s)\n",hf->name.len,hf->name.s);
01265     continue;
01266       }else if(hf->type==HDR_VIA_T && strip_top_vias > 0){
01267     /** All vias MUST be parsed !!*/
01268     for(i=0,vb=hf->parsed;vb;vb=vb->next,i++);
01269     if(i<=strip_top_vias){
01270        LM_DBG("Stripping vias [%.*s]\n",hf->len,hf->name.s);
01271        /** skip this via header*/
01272        strip_top_vias-=i;
01273     }else{
01274        assert(i>1);
01275        vb=hf->parsed;
01276        while(strip_top_vias--)
01277           vb=vb->next;
01278        k= (hf->name.s + hf->len) - vb->name.s;
01279        LM_DBG("Stripping vias [%.*s]\n",(int)(vb->name.s-hf->name.s),
01280         hf->name.s);
01281        if(k+VIA_LEN<headers_len){
01282           memcpy(headers+len,VIA,VIA_LEN);
01283           len+=VIA_LEN;
01284           memcpy(headers+len,vb->name.s,k);
01285           len+=k;
01286        }else{
01287           LM_ERR("Out Of Space !!\n");
01288           goto error;
01289        }
01290     }
01291       }else if(hf->type==HDR_RECORDROUTE_T && rtcnt>=0){
01292     if(rtcnt==0)
01293        continue;
01294     if(!hf->parsed && 0>parse_rr(hf)){
01295        LM_ERR("parsing Record-Route:\"%.*s\"\n",hf->body.len,hf->body.s);
01296        goto error;
01297     }
01298     for(i=0,rb=hf->parsed;rb;rb=rb->next,i++);
01299     if(i<=rtcnt){
01300        if((len+hf->len)<headers_len){
01301           LM_DBG("Allowing RecordRoute [%.*s]\n",hf->len,hf->name.s);
01302           memcpy(headers+len,hf->name.s,hf->len);
01303           len+=hf->len;
01304        }else{
01305           LM_ERR("Unable to keep recordroute (not enough space left in headers) Discarding \"%.*s\" \n",hf->name.len,hf->name.s);
01306           goto error;
01307        }
01308        /** is this dangerous ? because the rtcnt is the control variable for this conditional 'if'
01309         * so if I change rtcnt value in one of the statements... what then ??? */
01310        rtcnt-=i;
01311     }else{
01312        assert(rtcnt>0);
01313        rb=hf->parsed;
01314        while(--rtcnt)
01315           rb=rb->next;
01316        k= (((rb->nameaddr.name.s) + rb->len)-hf->name.s) ;
01317        if(len+k+CRLF_LEN<headers_len){
01318           memcpy(headers+len,hf->name.s,k);
01319           LM_DBG("Allowing RecordRoute [%.*s\r\n]\n",k,hf->name.s);
01320           len+=k;
01321           memcpy(headers+len,CRLF,CRLF_LEN);
01322           len+=CRLF_LEN;
01323        }else{
01324           LM_ERR("Out Of Space !!\n");
01325           goto error;
01326        }
01327     }
01328     if(hf->parsed){
01329        free_rr((rr_t **)(void*)(&hf->parsed));
01330        hf->parsed=NULL;
01331     }
01332       }else{
01333     if((len+hf->len)<headers_len){
01334        memcpy(headers+len,hf->name.s,hf->len);
01335        len+=hf->len;
01336     }else{
01337        LM_WARN("Too many headers. Discarding \"%.*s\" \n",
01338             hf->name.len,hf->name.s);
01339     }
01340       }
01341    }/*for*/
01342    return len;
01343 error:
01344    return -1;
01345 }
01346 
01347 
01348 /**
01349  * ERROR action responses are composed of:
01350  * 4: the length of the event
01351  * 1: the event type (AC_RES_FAIL)
01352  * 4: NBO of the uac-action-request identification (uac_id)
01353  * 4: the sip_error code in NBO.
01354  * 1: (unsigned) the length of the string.
01355  * N: the string
01356  *
01357  */
01358 int as_action_fail_resp(int uac_id,int sip_error,char *err_buf,int i)
01359 {
01360    char msg[14+MAX_REASON_LEN];
01361    int k, ev_len;
01362    k=4;
01363    if(i==0)
01364       i=strlen(err_buf);
01365    if(i>MAX_REASON_LEN){
01366       LM_ERR("Error Reason bigger than MAX_REASON_LEN\n");
01367       return -1;
01368    }
01369    msg[k++]=AC_RES_FAIL;
01370    uac_id=htonl(uac_id);
01371    memcpy(msg+k,&uac_id,4);
01372    k+=4;
01373    sip_error=htonl(sip_error);
01374    memcpy(msg+k,&sip_error,4);
01375    k+=4;
01376    msg[k++]=(char)(unsigned char)i;
01377    memcpy(msg+k,err_buf,i);
01378    k+=i;
01379    ev_len=htonl(k);
01380    memcpy(msg,&ev_len,4);
01381    write(my_as->u.as.action_fd,msg,k);
01382    return 0;
01383 }
01384 
01385 /*
01386  * This callback function should be used in order to free the parameters passed to uac_cb.
01387  * This callback is called when the transaction is detroyed.
01388  */
01389 void uac_cleanup_cb(struct cell* t, int type, struct tmcb_params *rcvd_params)
01390 {
01391    struct as_uac_param *ev_info;
01392 
01393    ev_info=(struct as_uac_param*)*rcvd_params->param;
01394 
01395    if(ev_info) {  
01396       shm_free(ev_info);
01397       *rcvd_params->param=NULL;
01398    }
01399 }
01400 
01401 /**
01402  * This function will be called from a SER process when a reply is received for
01403  * the transaction. The SER processes only have acces to the EventDispatcher 
01404  * fifo (not to the ActionDispatcher) so EventDispatcher will be the one who 
01405  * will send the event to the AppServer.
01406  * TODO WARNING !!! there's a clear MEMORY LEAK here, see exit: at the bottom of
01407  * the function... it should free ev_info !!!!!!!!
01408  * I have disabled the free() because It may be that we receive a retransmitted 200 OK
01409  * if the ACK gets lost, that 200 OK will make SER invoke this callback a second,third, etc time...
01410  *
01411  */
01412 void uac_cb(struct cell* t, int type,struct tmcb_params *rcvd_params)
01413 {
01414    as_msg_p my_as_ev=0;
01415    int mylen,code,i;
01416    struct as_uac_param *ev_info;
01417    struct sip_msg *msg;
01418    char *buffer;
01419 
01420    ev_info=(struct as_uac_param*)*rcvd_params->param;
01421    msg=rcvd_params->rpl;
01422    code=rcvd_params->code;
01423    buffer=0;
01424    if(!ev_info || !ev_info->who){
01425       return;
01426    }
01427 
01428    if(type == TMCB_LOCAL_COMPLETED && !ev_info->destroy_cb_set) {
01429       if(seas_f.tmb.register_tmcb(NULL, t, TMCB_TRANS_DELETED, uac_cleanup_cb, (void*)ev_info, NULL) <= 0) {
01430          LM_ERR( "register_tmcb for destroy callback failed\n");
01431          goto error;
01432       }
01433       ev_info->destroy_cb_set = 1;
01434    }
01435 
01436    LM_DBG("reply to UAC Transaction for AS:%.*s code: %d\n",
01437          ev_info->who->name.len,ev_info->who->name.s,code);
01438    LM_DBG("transaction %p Nr_of_outgoings:%d is_Local:%c\n",
01439          t,t->nr_of_outgoings,is_local(t)?'y':'n');
01440    for(i=0;i<t->nr_of_outgoings;i++)
01441       LM_DBG("UAC[%d].last_received=%d\n",i,t->uac[i].last_received);
01442    if(!(my_as_ev=shm_malloc(sizeof(as_msg_t)))){
01443       LM_ERR("no more shared mem\n");
01444       goto error;
01445    }
01446    if(!(buffer=create_as_action_reply(t,rcvd_params,ev_info->uac_id,ev_info->processor_id,&mylen))){
01447       LM_ERR("failed to encode message\n");
01448       goto error;
01449    }
01450    my_as_ev->as = ev_info->who;
01451    my_as_ev->msg = buffer;
01452    my_as_ev->len = mylen;
01453    my_as_ev->type = RES_IN;
01454    my_as_ev->transaction = t;
01455    if(write(write_pipe,&my_as_ev,sizeof(as_msg_p))<=0){
01456       goto error;
01457    }
01458    goto exit;
01459 error:
01460    if(my_as_ev){
01461       shm_free(my_as_ev);
01462    }
01463    if(buffer)
01464       shm_free(buffer);
01465 exit:
01466    return ;
01467 }
01468 
01469 char* create_as_action_reply(struct cell *c,struct tmcb_params *params,int uac_id,char processor_id,int *evt_len)
01470 {
01471    int i;
01472    unsigned int code,flags;
01473    unsigned short int port;
01474    unsigned int k,len;
01475    char *buffer;
01476    struct sip_msg *msg;
01477    if(!(buffer=shm_malloc(ENCODED_MSG_SIZE))){
01478       LM_ERR("create_as_action_reply Out Of Memory !!\n");
01479       return 0;
01480    }
01481    msg=0;
01482    *evt_len=0;
01483    flags=0;
01484    if(params->rpl==FAKED_REPLY)
01485       flags=FAKED_REPLY_FLAG;
01486    /*length*/
01487    k=4;
01488    /*type*/
01489    buffer[k++]=(unsigned char)RES_IN;
01490    /*processor id*/
01491    buffer[k++]=processor_id;
01492    /*flags (by now, not used)*/
01493    flags=htonl(flags);
01494    memcpy(buffer+k,&flags,4);
01495    k+=4;
01496    /*recv info*/
01497    if(!(params->rpl == FAKED_REPLY)) {
01498       msg=params->rpl;
01499       /*protocol should be UDP,TCP,TLS or whatever*/
01500       buffer[k++]=(unsigned char)msg->rcv.proto;
01501       /*src ip len + src ip*/
01502       len=msg->rcv.src_ip.len;
01503       buffer[k++]=(unsigned char)len;
01504       memcpy(buffer+k,&(msg->rcv.src_ip.u),len);
01505       k+=len;
01506       /*dst ip len + dst ip*/
01507       len=msg->rcv.dst_ip.len;
01508       buffer[k++]=(unsigned char)len;
01509       memcpy(buffer+k,&(msg->rcv.dst_ip.u),len);
01510       k+=len;
01511       /*src port */
01512       port=htons(msg->rcv.src_port);
01513       memcpy(buffer+k,&port,2);
01514       k+=2;
01515       /*dst port */
01516       port=htons(msg->rcv.dst_port);
01517       memcpy(buffer+k,&port,2);
01518       k+=2;
01519    }else{
01520       /*protocol*/
01521       buffer[k++]=0;
01522       /*src ip len*/
01523       buffer[k++]=0;
01524       /*dst ip len*/
01525       buffer[k++]=0;
01526       /*skip src port and dst port*/
01527       buffer[k++]=0;
01528       buffer[k++]=0;
01529       buffer[k++]=0;
01530       buffer[k++]=0;
01531    }
01532    /*hash_index*/
01533    i=htonl(c->hash_index);
01534    memcpy(buffer+k,&i,4);
01535    k+=4;
01536    /*label*/
01537    i=(!strncmp(c->method.s,"CANCEL",6)) ? \
01538      htonl(((struct as_uac_param*)*params->param)->label) : \
01539    htonl(c->label);
01540    memcpy(buffer+k,&i,4);
01541    k+=4;
01542    /*uac_id*/
01543    uac_id=htonl(uac_id);
01544    memcpy(buffer+k,&uac_id,4);
01545    k+=4;
01546    /*code*/
01547    code=htonl(params->code);
01548    memcpy(buffer+k,&code,4);
01549    k+=4;
01550    /*length of event (hdr+payload-4), copied at the beginning*/
01551    if(params->rpl != FAKED_REPLY) {
01552       if((i=encode_msg(msg,buffer+k,ENCODED_MSG_SIZE-k))<0){
01553     LM_ERR("failed to encode msg\n");
01554     goto error;
01555       }
01556       k+=i;
01557    }
01558    *evt_len=k;
01559    k=htonl(k);
01560    memcpy(buffer,&k,4);
01561    return buffer;
01562 error:
01563    return 0;
01564 }
01565 
01566 

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