The possibility to set independent destination URIs for branches.
[sip-router] / dset.c
1 /*
2  * $Id$
3  *
4  * destination set
5  *
6  * Copyright (C) 2001-2004 FhG FOKUS
7  *
8  * This file is part of ser, a free SIP server.
9  *
10  * ser is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * For a license to use the ser software under conditions
16  * other than those described here, or to purchase support for this
17  * software, please contact iptel.org by e-mail at the following addresses:
18  *    info@iptel.org
19  *
20  * ser is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License 
26  * along with this program; if not, write to the Free Software 
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  */
29
30 #include <string.h>
31 #include "dprint.h"
32 #include "config.h"
33 #include "parser/parser_f.h"
34 #include "parser/msg_parser.h"
35 #include "ut.h"
36 #include "hash_func.h"
37 #include "error.h"
38 #include "dset.h"
39
40 #define CONTACT "Contact: "
41 #define CONTACT_LEN (sizeof(CONTACT) - 1)
42
43 #define CONTACT_DELIM ", "
44 #define CONTACT_DELIM_LEN (sizeof(CONTACT_DELIM) - 1)
45
46 #define Q_PARAM ">;q="
47 #define Q_PARAM_LEN (sizeof(Q_PARAM) - 1)
48
49 struct branch
50 {
51         char uri[MAX_URI_SIZE];
52         unsigned int len;
53
54              /* Real destination of the request */
55         char dst_uri[MAX_URI_SIZE];
56         unsigned int dst_uri_len;
57
58         int q; /* Preference of the contact among
59                 * contact within the array */
60 };
61
62
63 /* 
64  * Where we store URIs of additional transaction branches
65  * (-1 because of the default branch, #0)
66  */
67 static struct branch branches[MAX_BRANCHES - 1];
68
69 /* how many of them we have */
70 static unsigned int nr_branches = 0;
71
72 /* branch iterator */
73 static int branch_iterator = 0;
74
75 /* The q parameter of the Request-URI */
76 static qvalue_t ruri_q = Q_UNSPECIFIED; 
77
78
79 /*
80  * Initialize the branch iterator, the next
81  * call to next_branch will return the first
82  * contact from the dset array
83  */
84 void init_branch_iterator(void)
85 {
86         branch_iterator = 0;
87 }
88
89
90 /*
91  * Return the next branch from the dset
92  * array, 0 is returned if there are no
93  * more branches
94  */
95 char* next_branch(int* len, qvalue_t* q, char** dst_uri, int* dst_len)
96 {
97         unsigned int i;
98
99         i = branch_iterator;
100         if (i < nr_branches) {
101                 branch_iterator++;
102                 *len = branches[i].len;
103                 *q = branches[i].q;
104                 if (dst_uri && dst_len) {
105                         *dst_uri = branches[i].dst_uri;
106                         *dst_len = branches[i].dst_uri_len;
107                 }
108                 return branches[i].uri;
109         } else {
110                 *len = 0;
111                 *q = Q_UNSPECIFIED;
112                 if (dst_uri && dst_len) {
113                         *dst_uri = 0;
114                         *dst_len = 0;
115                 }
116                 return 0;
117         }
118 }
119
120
121 /*
122  * Empty the dset array
123  */
124 void clear_branches(void)
125 {
126         nr_branches = 0;
127         ruri_q = Q_UNSPECIFIED;
128 }
129
130
131 /* 
132  * Add a new branch to current transaction 
133  */
134 int append_branch(struct sip_msg* msg, char* uri, int uri_len, char* dst_uri, int dst_uri_len, qvalue_t q)
135 {
136              /* if we have already set up the maximum number
137               * of branches, don't try new ones 
138               */
139         if (nr_branches == MAX_BRANCHES - 1) {
140                 LOG(L_ERR, "ERROR: append_branch: max nr of branches exceeded\n");
141                 ser_error = E_TOO_MANY_BRANCHES;
142                 return -1;
143         }
144
145         if (uri_len > MAX_URI_SIZE - 1) {
146                 LOG(L_ERR, "ERROR: append_branch: too long uri: %.*s\n",
147                     uri_len, uri);
148                 return -1;
149         }
150
151              /* if not parameterized, take current uri */
152         if (uri == 0) {
153                 if (msg->new_uri.s) { 
154                         uri = msg->new_uri.s;
155                         uri_len = msg->new_uri.len;
156                 } else {
157                         uri = msg->first_line.u.request.uri.s;
158                         uri_len = msg->first_line.u.request.uri.len;
159                 }
160         }
161         
162         memcpy(branches[nr_branches].uri, uri, uri_len);
163              /* be safe -- add zero termination */
164         branches[nr_branches].uri[uri_len] = 0;
165         branches[nr_branches].len = uri_len;
166         branches[nr_branches].q = q;
167         
168         if (dst_uri) {
169                 memcpy(branches[nr_branches].dst_uri, dst_uri, dst_uri_len);
170                 branches[nr_branches].dst_uri[dst_uri_len] = 0;
171                 branches[nr_branches].dst_uri_len = dst_uri_len;
172         }
173
174         nr_branches++;
175         return 1;
176 }
177
178
179 /*
180  * Create a Contact header field from the dset
181  * array
182  */
183 char* print_dset(struct sip_msg* msg, int* len) 
184 {
185         int cnt, i, qlen;
186         qvalue_t q;
187         str uri;
188         char* p, *qbuf;
189         static char dset[MAX_REDIRECTION_LEN];
190
191         if (msg->new_uri.s) {
192                 cnt = 1;
193                 *len = msg->new_uri.len;
194                 if (ruri_q != Q_UNSPECIFIED) {
195                         *len += 1 + Q_PARAM_LEN + len_q(ruri_q);
196                 }
197         } else {
198                 cnt = 0;
199                 *len = 0;
200         }
201
202         init_branch_iterator();
203         while ((uri.s = next_branch(&uri.len, &q, 0, 0))) {
204                 cnt++;
205                 *len += uri.len;
206                 if (q != Q_UNSPECIFIED) {
207                         *len += 1 + Q_PARAM_LEN + len_q(q);
208                 }
209         }
210
211         if (cnt == 0) return 0; 
212
213         *len += CONTACT_LEN + CRLF_LEN + (cnt - 1) * CONTACT_DELIM_LEN;
214
215         if (*len + 1 > MAX_REDIRECTION_LEN) {
216                 LOG(L_ERR, "ERROR: redirection buffer length exceed\n");
217                 return 0;
218         }
219
220         memcpy(dset, CONTACT, CONTACT_LEN);
221         p = dset + CONTACT_LEN;
222         if (msg->new_uri.s) {
223                 if (ruri_q != Q_UNSPECIFIED) {
224                         *p++ = '<';
225                 }
226
227                 memcpy(p, msg->new_uri.s, msg->new_uri.len);
228                 p += msg->new_uri.len;
229
230                 if (ruri_q != Q_UNSPECIFIED) {
231                         memcpy(p, Q_PARAM, Q_PARAM_LEN);
232                         p += Q_PARAM_LEN;
233
234                         qbuf = q2str(ruri_q, &qlen);
235                         memcpy(p, qbuf, qlen);
236                         p += qlen;
237                 }
238                 i = 1;
239         } else {
240                 i = 0;
241         }
242
243         init_branch_iterator();
244         while ((uri.s = next_branch(&uri.len, &q, 0, 0))) {
245                 if (i) {
246                         memcpy(p, CONTACT_DELIM, CONTACT_DELIM_LEN);
247                         p += CONTACT_DELIM_LEN;
248                 }
249
250                 if (q != Q_UNSPECIFIED) {
251                         *p++ = '<';
252                 }
253
254                 memcpy(p, uri.s, uri.len);
255                 p += uri.len;
256                 if (q != Q_UNSPECIFIED) {
257                         memcpy(p, Q_PARAM, Q_PARAM_LEN);
258                         p += Q_PARAM_LEN;
259
260                         qbuf = q2str(q, &qlen);
261                         memcpy(p, qbuf, qlen);
262                         p += qlen;
263                 }
264                 i++;
265         }
266
267         memcpy(p, CRLF " ", CRLF_LEN + 1);
268         return dset;
269 }
270
271
272 /*
273  * Sets the q parameter of the Request-URI
274  */
275 void set_ruri_q(qvalue_t q)
276 {
277         ruri_q = q;
278 }
279
280
281 /*
282  * Return the q value of the Request-URI
283  */
284 qvalue_t get_ruri_q(void)
285 {
286         return ruri_q;
287 }