- Spelling checked
[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         int q; /* Preference of the contact among
54                 * contact within the array */
55 };
56
57
58 /* 
59  * Where we store URIs of additional transaction branches
60  * (-1 because of the default branch, #0)
61  */
62 static struct branch branches[MAX_BRANCHES - 1];
63
64 /* how many of them we have */
65 static unsigned int nr_branches = 0;
66
67 /* branch iterator */
68 static int branch_iterator = 0;
69
70 /* The q parameter of the Request-URI */
71 static qvalue_t ruri_q = Q_UNSPECIFIED; 
72
73
74 /*
75  * Initialize the branch iterator, the next
76  * call to next_branch will return the first
77  * contact from the dset array
78  */
79 void init_branch_iterator(void)
80 {
81         branch_iterator = 0;
82 }
83
84
85 /*
86  * Return the next branch from the dset
87  * array, 0 is returned if there are no
88  * more branches
89  */
90 char* next_branch(int* len, qvalue_t* q)
91 {
92         unsigned int i;
93
94         i = branch_iterator;
95         if (i < nr_branches) {
96                 branch_iterator++;
97                 *len = branches[i].len;
98                 *q = branches[i].q;
99                 return branches[i].uri;
100         } else {
101                 *len = 0;
102                 *q = Q_UNSPECIFIED;
103                 return 0;
104         }
105 }
106
107
108 /*
109  * Empty the dset array
110  */
111 void clear_branches(void)
112 {
113         nr_branches = 0;
114         ruri_q = Q_UNSPECIFIED;
115 }
116
117
118 /* 
119  * Add a new branch to current transaction 
120  */
121 int append_branch(struct sip_msg* msg, char* uri, int uri_len, qvalue_t q)
122 {
123              /* if we have already set up the maximum number
124               * of branches, don't try new ones 
125               */
126         if (nr_branches == MAX_BRANCHES - 1) {
127                 LOG(L_ERR, "ERROR: append_branch: max nr of branches exceeded\n");
128                 ser_error = E_TOO_MANY_BRANCHES;
129                 return -1;
130         }
131
132         if (uri_len > MAX_URI_SIZE - 1) {
133                 LOG(L_ERR, "ERROR: append_branch: too long uri: %.*s\n",
134                     uri_len, uri);
135                 return -1;
136         }
137
138              /* if not parameterized, take current uri */
139         if (uri == 0) {
140                 if (msg->new_uri.s) { 
141                         uri = msg->new_uri.s;
142                         uri_len = msg->new_uri.len;
143                 } else {
144                         uri = msg->first_line.u.request.uri.s;
145                         uri_len = msg->first_line.u.request.uri.len;
146                 }
147         }
148         
149         memcpy(branches[nr_branches].uri, uri, uri_len);
150              /* be safe -- add zero termination */
151         branches[nr_branches].uri[uri_len] = 0;
152         branches[nr_branches].len = uri_len;
153         branches[nr_branches].q = q;
154         
155         nr_branches++;
156         return 1;
157 }
158
159
160 /*
161  * Create a Contact header field from the dset
162  * array
163  */
164 char* print_dset(struct sip_msg* msg, int* len) 
165 {
166         int cnt, i, qlen;
167         qvalue_t q;
168         str uri;
169         char* p, *qbuf;
170         static char dset[MAX_REDIRECTION_LEN];
171
172         if (msg->new_uri.s) {
173                 cnt = 1;
174                 *len = msg->new_uri.len;
175                 if (ruri_q != Q_UNSPECIFIED) {
176                         *len += 1 + Q_PARAM_LEN + len_q(ruri_q);
177                 }
178         } else {
179                 cnt = 0;
180                 *len = 0;
181         }
182
183         init_branch_iterator();
184         while ((uri.s = next_branch(&uri.len, &q))) {
185                 cnt++;
186                 *len += uri.len;
187                 if (q != Q_UNSPECIFIED) {
188                         *len += 1 + Q_PARAM_LEN + len_q(q);
189                 }
190         }
191
192         if (cnt == 0) return 0; 
193
194         *len += CONTACT_LEN + CRLF_LEN + (cnt - 1) * CONTACT_DELIM_LEN;
195
196         if (*len + 1 > MAX_REDIRECTION_LEN) {
197                 LOG(L_ERR, "ERROR: redirection buffer length exceed\n");
198                 return 0;
199         }
200
201         memcpy(dset, CONTACT, CONTACT_LEN);
202         p = dset + CONTACT_LEN;
203         if (msg->new_uri.s) {
204                 if (ruri_q != Q_UNSPECIFIED) {
205                         *p++ = '<';
206                 }
207
208                 memcpy(p, msg->new_uri.s, msg->new_uri.len);
209                 p += msg->new_uri.len;
210
211                 if (ruri_q != Q_UNSPECIFIED) {
212                         memcpy(p, Q_PARAM, Q_PARAM_LEN);
213                         p += Q_PARAM_LEN;
214
215                         qbuf = q2str(ruri_q, &qlen);
216                         memcpy(p, qbuf, qlen);
217                         p += qlen;
218                 }
219                 i = 1;
220         } else {
221                 i = 0;
222         }
223
224         init_branch_iterator();
225         while ((uri.s = next_branch(&uri.len, &q))) {
226                 if (i) {
227                         memcpy(p, CONTACT_DELIM, CONTACT_DELIM_LEN);
228                         p += CONTACT_DELIM_LEN;
229                 }
230
231                 if (q != Q_UNSPECIFIED) {
232                         *p++ = '<';
233                 }
234
235                 memcpy(p, uri.s, uri.len);
236                 p += uri.len;
237                 if (q != Q_UNSPECIFIED) {
238                         memcpy(p, Q_PARAM, Q_PARAM_LEN);
239                         p += Q_PARAM_LEN;
240
241                         qbuf = q2str(q, &qlen);
242                         memcpy(p, qbuf, qlen);
243                         p += qlen;
244                 }
245                 i++;
246         }
247
248         memcpy(p, CRLF " ", CRLF_LEN + 1);
249         return dset;
250 }
251
252
253 /*
254  * Sets the q parameter of the Request-URI
255  */
256 void set_ruri_q(qvalue_t q)
257 {
258         ruri_q = q;
259 }
260
261
262 /*
263  * Return the q value of the Request-URI
264  */
265 qvalue_t get_ruri_q(void)
266 {
267         return ruri_q;
268 }