path/path.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Path handling for intermediate proxies.
00005  *
00006  * Copyright (C) 2006 Inode GmbH (Andreas Granig <andreas.granig@inode.info>)
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  */
00025 
00033 #include <string.h>
00034 #include <stdio.h>
00035 
00036 #include "../../mem/mem.h"
00037 #include "../../data_lump.h"
00038 #include "../../parser/parse_param.h"
00039 #include "../../dset.h"
00040 
00041 #include "path.h"
00042 #include "path_mod.h"
00043 
00044 #define PATH_PREFIX             "Path: <sip:"
00045 #define PATH_PREFIX_LEN         (sizeof(PATH_PREFIX)-1)
00046 
00047 #define PATH_LR_PARAM           ";lr"
00048 #define PATH_LR_PARAM_LEN       (sizeof(PATH_LR_PARAM)-1)
00049 
00050 #define PATH_RC_PARAM           ";received="
00051 #define PATH_RC_PARAM_LEN       (sizeof(PATH_RC_PARAM)-1)
00052 
00053 #define PATH_CRLF               ">\r\n"
00054 #define PATH_CRLF_LEN           (sizeof(PATH_CRLF)-1)
00055 
00056 static int prepend_path(struct sip_msg* _m, str *user, int recv)
00057 {
00058         struct lump *l;
00059         char *prefix, *suffix, *crlf;
00060         int prefix_len, suffix_len;
00061         struct hdr_field *hf;
00062         str rcv_addr = {0, 0};
00063         char *src_ip;
00064                 
00065         prefix = suffix = crlf = 0;
00066 
00067         prefix_len = PATH_PREFIX_LEN + (user->len ? (user->len+1) : 0);
00068         prefix = pkg_malloc(prefix_len);
00069         if (!prefix) {
00070                 LM_ERR("no pkg memory left for prefix\n");
00071                 goto out1;
00072         }
00073         memcpy(prefix, PATH_PREFIX, PATH_PREFIX_LEN);
00074         if (user->len) {
00075                 memcpy(prefix + PATH_PREFIX_LEN, user->s, user->len);
00076                 memcpy(prefix + prefix_len - 1, "@", 1);
00077         }
00078 
00079         suffix_len = PATH_LR_PARAM_LEN + (recv ? PATH_RC_PARAM_LEN : 0);
00080         suffix = pkg_malloc(suffix_len);
00081         if (!suffix) {
00082                 LM_ERR("no pkg memory left for suffix\n");
00083                 goto out1;
00084         }
00085         memcpy(suffix, PATH_LR_PARAM, PATH_LR_PARAM_LEN);
00086         if(recv)
00087                 memcpy(suffix+PATH_LR_PARAM_LEN, PATH_RC_PARAM, PATH_RC_PARAM_LEN);
00088 
00089         crlf = pkg_malloc(PATH_CRLF_LEN);
00090         if (!crlf) {
00091                 LM_ERR("no pkg memory left for crlf\n");
00092                 goto out1;
00093         }
00094         memcpy(crlf, PATH_CRLF, PATH_CRLF_LEN);
00095 
00096         if (parse_headers(_m, HDR_PATH_F, 0) < 0) {
00097                 LM_ERR("failed to parse message for Path header\n");
00098                 goto out1;
00099         }
00100         for (hf = _m->headers; hf; hf = hf->next) {
00101                 if (hf->type == HDR_PATH_T) {
00102                         break;
00103                 } 
00104         }
00105         if (hf)
00106                 /* path found, add ours in front of that */
00107                 l = anchor_lump(_m, hf->name.s - _m->buf, 0, 0);
00108         else
00109                 /* no path, append to message */
00110                 l = anchor_lump(_m, _m->unparsed - _m->buf, 0, 0);
00111         if (!l) {
00112                 LM_ERR("failed to get anchor\n");
00113                 goto out1;
00114         }
00115 
00116         l = insert_new_lump_before(l, prefix, prefix_len, 0);
00117         if (!l) goto out1;
00118         l = insert_subst_lump_before(l, SUBST_SND_ALL, 0);
00119         if (!l) goto out2;
00120         l = insert_new_lump_before(l, suffix, suffix_len, 0);
00121         if (!l) goto out2;
00122         if (recv) {
00123                 /* TODO: agranig: optimize this one! */
00124                 src_ip = ip_addr2a(&_m->rcv.src_ip);
00125                 rcv_addr.s = pkg_malloc(6 + IP_ADDR_MAX_STR_SIZE + 22); /* "sip:<ip>:<port>;transport=sctp"\0 */
00126                 if(!rcv_addr.s) {
00127                         LM_ERR("no pkg memory left for receive-address\n");
00128                         goto out3;
00129                 }
00130                 switch (_m->rcv.proto) {
00131                         case PROTO_UDP:
00132                                 rcv_addr.len = snprintf(rcv_addr.s, 6 + IP_ADDR_MAX_STR_SIZE + 6, "\"sip:%s:%u\"", src_ip, _m->rcv.src_port);
00133                                 break;
00134                         case PROTO_TCP:
00135                                 rcv_addr.len = snprintf(rcv_addr.s, 6 + IP_ADDR_MAX_STR_SIZE + 20, "\"sip:%s:%u;transport=tcp\"", src_ip, _m->rcv.src_port);
00136                                 break;
00137                         case PROTO_TLS:
00138                                 rcv_addr.len = snprintf(rcv_addr.s, 6 + IP_ADDR_MAX_STR_SIZE + 20, "\"sip:%s:%u;transport=tls\"", src_ip, _m->rcv.src_port);
00139                                 break;
00140                         case PROTO_SCTP:
00141                                 rcv_addr.len = snprintf(rcv_addr.s, 6 + IP_ADDR_MAX_STR_SIZE + 21, "\"sip:%s:%u;transport=sctp\"", src_ip, _m->rcv.src_port);
00142                                 break;
00143             }
00144 
00145                 l = insert_new_lump_before(l, rcv_addr.s, rcv_addr.len, 0);
00146                 if (!l) goto out3;
00147         }
00148         l = insert_new_lump_before(l, crlf, CRLF_LEN+1, 0);
00149         if (!l) goto out4;
00150         
00151         return 1;
00152         
00153 out1:
00154         if (prefix) pkg_free(prefix);
00155 out2:
00156         if (suffix) pkg_free(suffix);
00157 out3:
00158         if (rcv_addr.s) pkg_free(rcv_addr.s);
00159 out4:
00160         if (crlf) pkg_free(crlf);
00161 
00162         LM_ERR("failed to insert prefix lump\n");
00163 
00164         return -1;
00165 }
00166 
00170 int add_path(struct sip_msg* _msg, char* _a, char* _b)
00171 {
00172         str user = {0,0};
00173         return prepend_path(_msg, &user, 0);
00174 }
00175 
00180 int add_path_usr(struct sip_msg* _msg, char* _usr, char* _b)
00181 {
00182         return prepend_path(_msg, (str*)_usr, 0);
00183 }
00184 
00189 int add_path_received(struct sip_msg* _msg, char* _a, char* _b)
00190 {
00191         str user = {0,0};
00192         return prepend_path(_msg, &user, 1);
00193 }
00194 
00199 int add_path_received_usr(struct sip_msg* _msg, char* _usr, char* _b)
00200 {
00201         return prepend_path(_msg, (str*)_usr, 1);
00202 }
00203 
00207 void path_rr_callback(struct sip_msg *_m, str *r_param, void *cb_param)
00208 {
00209         param_hooks_t hooks;
00210         param_t *params;
00211                         
00212         if (parse_params(r_param, CLASS_CONTACT, &hooks, &params) != 0) {
00213                 LM_ERR("failed to parse route parameters\n");
00214                 return;
00215         }
00216 
00217         if (hooks.contact.received) {
00218                 if (set_dst_uri(_m, &hooks.contact.received->body) != 0) {
00219                         LM_ERR("failed to set dst-uri\n");
00220                         free_params(params);
00221                         return;
00222                 }
00223                 /* dst_uri changed, so it makes sense to re-use the current uri for
00224                         forking */
00225                 ruri_mark_new(); /* re-use uri for serial forking */
00226         }
00227         free_params(params);
00228 }