core: dset minor cleanups
[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 #include "mem/mem.h"
40 #include "ip_addr.h"
41
42 #define CONTACT "Contact: "
43 #define CONTACT_LEN (sizeof(CONTACT) - 1)
44
45 #define CONTACT_DELIM ", "
46 #define CONTACT_DELIM_LEN (sizeof(CONTACT_DELIM) - 1)
47
48 #define Q_PARAM ">;q="
49 #define Q_PARAM_LEN (sizeof(Q_PARAM) - 1)
50
51 struct branch
52 {
53         char uri[MAX_URI_SIZE];
54         unsigned int len;
55
56              /* Real destination of the request */
57         char dst_uri[MAX_URI_SIZE];
58         unsigned int dst_uri_len;
59
60         /* Path set */
61         char path[MAX_PATH_SIZE];
62         unsigned int path_len;
63
64         int q; /* Preference of the contact among
65                 * contact within the array */
66         struct socket_info* force_send_socket;
67
68         /* Branch flags */
69         flag_t flags;
70 };
71
72
73 /* 
74  * Where we store URIs of additional transaction branches
75  * (-1 because of the default branch, #0)
76  */
77 static struct branch branches[MAX_BRANCHES - 1];
78
79 /* how many of them we have */
80 unsigned int nr_branches = 0;
81
82 /* branch iterator */
83 static int branch_iterator = 0;
84
85 /* The q parameter of the Request-URI */
86 static qvalue_t ruri_q = Q_UNSPECIFIED;
87
88 /* Branch flags of the Request-URI */
89 static flag_t ruri_bflags;
90
91
92 static inline flag_t* get_bflags_ptr(unsigned int branch)
93 {
94         if (branch == 0) return &ruri_bflags;
95         if (branch - 1 < nr_branches) return &branches[branch - 1].flags;
96         return NULL;
97 }
98
99
100 int setbflag(unsigned int branch, flag_t flag)
101 {
102         flag_t* flags;
103
104         if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
105         (*flags) |= 1 << flag;
106         return 1;
107 }
108
109
110 int isbflagset(unsigned int branch, flag_t flag)
111 {
112         flag_t* flags;
113
114         if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
115         return ((*flags) & (1 << flag)) ? 1 : -1;
116 }
117
118
119 int resetbflag(unsigned int branch, flag_t flag)
120 {
121         flag_t* flags;
122
123         if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
124         (*flags) &= ~ (1 << flag);
125         return 1;
126 }
127
128
129 int getbflagsval(unsigned int branch, flag_t* res)
130 {
131         flag_t* flags;
132         if (res == NULL) return -1;
133         if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
134         *res = *flags;
135         return 1;
136 }
137
138
139 int setbflagsval(unsigned int branch, flag_t val)
140 {
141         flag_t* flags;
142         if ((flags = get_bflags_ptr(branch)) == NULL) return -1;
143         *flags = val;
144         return 1;
145 }
146
147
148 /*
149  * Initialize the branch iterator, the next
150  * call to next_branch will return the first
151  * contact from the dset array
152  */
153 void init_branch_iterator(void)
154 {
155         branch_iterator = 0;
156 }
157
158 int get_branch_iterator(void)
159 {
160         return branch_iterator;
161 }
162
163
164
165 /** \brief Get a branch from the destination set
166  * \return Return the 'i' branch from the dset
167  * array, 0 is returned if there are no
168  * more branches
169  */
170 char* get_branch(unsigned int i, int* len, qvalue_t* q, str* dst_uri,
171                                  str* path, unsigned int *flags,
172                                  struct socket_info** force_socket)
173 {
174         if (i < nr_branches) {
175                 *len = branches[i].len;
176                 *q = branches[i].q;
177                 if (dst_uri) {
178                         dst_uri->len = branches[i].dst_uri_len;
179                         dst_uri->s = (dst_uri->len)?branches[i].dst_uri:0;
180                 }
181                 if (path) {
182                         path->len = branches[i].path_len;
183                         path->s = (path->len)?branches[i].path:0;
184                 }
185                 if (force_socket)
186                         *force_socket = branches[i].force_send_socket;
187                 if (flags)
188                         *flags = branches[i].flags;
189                 return branches[i].uri;
190         } else {
191                 *len = 0;
192                 *q = Q_UNSPECIFIED;
193                 if (dst_uri) {
194                         dst_uri->s = 0;
195                         dst_uri->len = 0;
196                 }
197                 if (path) {
198                         path->s = 0;
199                         path->len = 0;
200                 }
201                 if (force_socket)
202                         *force_socket = 0;
203                 if (flags)
204                         *flags = 0;
205                 return 0;
206         }
207 }
208
209
210
211 /** Return the next branch from the dset array.
212  * 0 is returned if there are no more branches
213  */
214 char* next_branch(int* len, qvalue_t* q, str* dst_uri, str* path,
215                                         unsigned int* flags, struct socket_info** force_socket)
216 {
217         char* ret;
218         
219         ret=get_branch(branch_iterator, len, q, dst_uri, path, flags,
220                                         force_socket);
221         if (likely(ret))
222                 branch_iterator++;
223         return ret;
224 }
225
226
227 /*
228  * Empty the dset array
229  */
230 void clear_branches(void)
231 {
232         nr_branches = 0;
233         ruri_q = Q_UNSPECIFIED;
234         ruri_bflags = 0;
235 }
236
237
238
239 /**  Add a new branch to the current transaction.
240  * @param msg - sip message, used for getting the uri if not specified (0).
241  * @param uri - uri, can be 0 (in which case the uri is taken from msg)
242  * @param dst_uri - destination uri, can be 0.
243  * @param path - path vector (passed in a string), can be 0.
244  * @param q  - q value.
245  * @param flags - per branch flags.
246  * @param force_socket - socket that should be used when sending.
247  *
248  * @return  <0 (-1) on failure, 1 on success (script convention).
249  */
250 int append_branch(struct sip_msg* msg, str* uri, str* dst_uri, str* path,
251                 qvalue_t q, unsigned int flags, struct socket_info* force_socket)
252 {
253         str luri;
254
255 #ifdef USE_LOCAL_ROUTE
256         if (unlikely(dset_state==0))
257                 return -1;
258 #endif
259
260         /* if we have already set up the maximum number
261          * of branches, don't try new ones 
262          */
263         if (unlikely(nr_branches == MAX_BRANCHES - 1)) {
264                 LOG(L_ERR, "max nr of branches exceeded\n");
265                 ser_error = E_TOO_MANY_BRANCHES;
266                 return -1;
267         }
268
269         /* if not parameterized, take current uri */
270         if (uri==0 || uri->len==0 || uri->s==0) {
271                 if (msg->new_uri.s)
272                         luri = msg->new_uri;
273                 else
274                         luri = msg->first_line.u.request.uri;
275         } else {
276                 luri = *uri;
277         }
278
279         if (unlikely(luri.len > MAX_URI_SIZE - 1)) {
280                 LOG(L_ERR, "too long uri: %.*s\n", luri.len, luri.s);
281                 return -1;
282         }
283
284         /* copy the dst_uri */
285         if (dst_uri && dst_uri->len && dst_uri->s) {
286                 if (unlikely(dst_uri->len > MAX_URI_SIZE - 1)) {
287                         LOG(L_ERR, "too long dst_uri: %.*s\n", dst_uri->len, dst_uri->s);
288                         return -1;
289                 }
290                 memcpy(branches[nr_branches].dst_uri, dst_uri->s, dst_uri->len);
291                 branches[nr_branches].dst_uri[dst_uri->len] = 0;
292                 branches[nr_branches].dst_uri_len = dst_uri->len;
293         } else {
294                 branches[nr_branches].dst_uri[0] = '\0';
295                 branches[nr_branches].dst_uri_len = 0;
296         }
297
298         /* copy the path string */
299         if (unlikely(path && path->len && path->s)) {
300                 if (unlikely(path->len > MAX_PATH_SIZE - 1)) {
301                         LOG(L_ERR, "too long path: %.*s\n", path->len, path->s);
302                         return -1;
303                 }
304                 memcpy(branches[nr_branches].path, path->s, path->len);
305                 branches[nr_branches].path[path->len] = 0;
306                 branches[nr_branches].path_len = path->len;
307         } else {
308                 branches[nr_branches].path[0] = '\0';
309                 branches[nr_branches].path_len = 0;
310         }
311
312         /* copy the ruri */
313         memcpy(branches[nr_branches].uri, luri.s, luri.len);
314         branches[nr_branches].uri[luri.len] = 0;
315         branches[nr_branches].len = luri.len;
316         branches[nr_branches].q = q;
317
318         branches[nr_branches].force_send_socket = force_socket;
319         branches[nr_branches].flags = flags;
320
321         nr_branches++;
322         return 1;
323 }
324
325
326 /*
327  * Create a Contact header field from the dset
328  * array
329  */
330 char* print_dset(struct sip_msg* msg, int* len) 
331 {
332         int cnt, i;
333         unsigned int qlen;
334         qvalue_t q;
335         str uri;
336         char* p, *qbuf;
337         static char dset[MAX_REDIRECTION_LEN];
338
339         if (msg->new_uri.s) {
340                 cnt = 1;
341                 *len = msg->new_uri.len;
342                 if (ruri_q != Q_UNSPECIFIED) {
343                         *len += 1 + Q_PARAM_LEN + len_q(ruri_q);
344                 }
345         } else {
346                 cnt = 0;
347                 *len = 0;
348         }
349
350         init_branch_iterator();
351         while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0))) {
352                 cnt++;
353                 *len += uri.len;
354                 if (q != Q_UNSPECIFIED) {
355                         *len += 1 + Q_PARAM_LEN + len_q(q);
356                 }
357         }
358
359         if (cnt == 0) return 0; 
360
361         *len += CONTACT_LEN + CRLF_LEN + (cnt - 1) * CONTACT_DELIM_LEN;
362
363         if (*len + 1 > MAX_REDIRECTION_LEN) {
364                 LOG(L_ERR, "ERROR: redirection buffer length exceed\n");
365                 return 0;
366         }
367
368         memcpy(dset, CONTACT, CONTACT_LEN);
369         p = dset + CONTACT_LEN;
370         if (msg->new_uri.s) {
371                 if (ruri_q != Q_UNSPECIFIED) {
372                         *p++ = '<';
373                 }
374
375                 memcpy(p, msg->new_uri.s, msg->new_uri.len);
376                 p += msg->new_uri.len;
377
378                 if (ruri_q != Q_UNSPECIFIED) {
379                         memcpy(p, Q_PARAM, Q_PARAM_LEN);
380                         p += Q_PARAM_LEN;
381
382                         qbuf = q2str(ruri_q, &qlen);
383                         memcpy(p, qbuf, qlen);
384                         p += qlen;
385                 }
386                 i = 1;
387         } else {
388                 i = 0;
389         }
390
391         init_branch_iterator();
392         while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0))) {
393                 if (i) {
394                         memcpy(p, CONTACT_DELIM, CONTACT_DELIM_LEN);
395                         p += CONTACT_DELIM_LEN;
396                 }
397
398                 if (q != Q_UNSPECIFIED) {
399                         *p++ = '<';
400                 }
401
402                 memcpy(p, uri.s, uri.len);
403                 p += uri.len;
404                 if (q != Q_UNSPECIFIED) {
405                         memcpy(p, Q_PARAM, Q_PARAM_LEN);
406                         p += Q_PARAM_LEN;
407
408                         qbuf = q2str(q, &qlen);
409                         memcpy(p, qbuf, qlen);
410                         p += qlen;
411                 }
412                 i++;
413         }
414
415         memcpy(p, CRLF " ", CRLF_LEN + 1);
416         return dset;
417 }
418
419
420 /*
421  * Sets the q parameter of the Request-URI
422  */
423 void set_ruri_q(qvalue_t q)
424 {
425         ruri_q = q;
426 }
427
428
429 /*
430  * Return the q value of the Request-URI
431  */
432 qvalue_t get_ruri_q(void)
433 {
434         return ruri_q;
435 }
436
437
438
439 /*
440  * Rewrite Request-URI
441  */
442 int rewrite_uri(struct sip_msg* _m, str* _s)
443 {
444         char* buf;
445
446         buf = (char*)pkg_malloc(_s->len + 1);
447         if (!buf) {
448                 LOG(L_ERR, "ERROR: rewrite_uri: No memory left\n");
449                 return -1;
450         }
451
452         memcpy(buf, _s->s, _s->len);
453         buf[_s->len] = '\0';
454
455         _m->parsed_uri_ok = 0;
456         if (_m->new_uri.s) {
457                 pkg_free(_m->new_uri.s);
458         }
459
460         _m->new_uri.s = buf;
461         _m->new_uri.len = _s->len;
462
463         return 1;
464 }
465