/src/opensips/parser/contact/contact.c
Line | Count | Source |
1 | | /* |
2 | | * Parses one Contact in Contact HF body |
3 | | * |
4 | | * Copyright (C) 2001-2003 FhG Fokus |
5 | | * |
6 | | * This file is part of opensips, a free SIP server. |
7 | | * |
8 | | * opensips is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 2 of the License, or |
11 | | * (at your option) any later version |
12 | | * |
13 | | * opensips is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | * |
22 | | * History: |
23 | | * ------- |
24 | | * 2003-03-25 Adapted to use new parameter parser (janakj) |
25 | | */ |
26 | | |
27 | | #include <string.h> /* memset */ |
28 | | #include "../../mem/mem.h" /* pkg_malloc, pkg_free */ |
29 | | #include "../../dprint.h" |
30 | | #include "../../trim.h" /* trim_leading, trim_trailing */ |
31 | | #include "contact.h" |
32 | | |
33 | | |
34 | 114k | #define ST1 1 /* Basic state */ |
35 | 3.19k | #define ST2 2 /* Quoted */ |
36 | 4.73k | #define ST3 3 /* Angle quoted */ |
37 | 4.98k | #define ST4 4 /* Angle quoted and quoted */ |
38 | 1.79k | #define ST5 5 /* Escape in quoted */ |
39 | 2.83k | #define ST6 6 /* Escape in angle quoted and quoted */ |
40 | | |
41 | | |
42 | | /* |
43 | | * Skip URI, stops when , (next contact) |
44 | | * or ; (parameter) is found |
45 | | */ |
46 | | static inline int skip_uri(str* _s) |
47 | 30.8k | { |
48 | 30.8k | register int st = ST1; |
49 | | |
50 | 2.94M | while(_s->len) { |
51 | 2.94M | switch(*(_s->s)) { |
52 | 53.4k | case ',': |
53 | 79.2k | case ';': |
54 | 79.2k | if (st == ST1) return 0; |
55 | 48.6k | break; |
56 | | |
57 | 48.6k | case '\"': |
58 | 4.13k | switch(st) { |
59 | 715 | case ST1: st = ST2; break; |
60 | 683 | case ST2: st = ST1; break; |
61 | 1.09k | case ST3: st = ST4; break; |
62 | 1.06k | case ST4: st = ST3; break; |
63 | 256 | case ST5: st = ST2; break; |
64 | 330 | case ST6: st = ST4; break; |
65 | 4.13k | } |
66 | 4.13k | break; |
67 | | |
68 | 4.13k | case '<': |
69 | 2.35k | switch(st) { |
70 | 1.32k | case ST1: st = ST3; break; |
71 | 12 | case ST3: |
72 | 12 | LM_ERR("second < found\n"); |
73 | 12 | return -1; |
74 | 196 | case ST5: st = ST2; break; |
75 | 203 | case ST6: st = ST4; break; |
76 | 2.35k | } |
77 | 2.34k | break; |
78 | | |
79 | 2.36k | case '>': |
80 | 2.36k | switch(st) { |
81 | 6 | case ST1: |
82 | 6 | LM_ERR("> is first\n"); |
83 | 6 | return -2; |
84 | | |
85 | 1.24k | case ST3: st = ST1; break; |
86 | 196 | case ST5: st = ST2; break; |
87 | 198 | case ST6: st = ST4; break; |
88 | 2.36k | } |
89 | 2.35k | break; |
90 | | |
91 | 4.39k | case '\\': |
92 | 4.39k | switch(st) { |
93 | 898 | case ST2: st = ST5; break; |
94 | 1.42k | case ST4: st = ST6; break; |
95 | 247 | case ST5: st = ST2; break; |
96 | 683 | case ST6: st = ST4; break; |
97 | 4.39k | } |
98 | 4.39k | break; |
99 | | |
100 | 2.85M | default: break; |
101 | | |
102 | 2.94M | } |
103 | | |
104 | 2.91M | _s->s++; |
105 | 2.91M | _s->len--; |
106 | 2.91M | } |
107 | | |
108 | 240 | if (st != ST1) { |
109 | 97 | LM_ERR("< or \" not closed\n"); |
110 | 97 | return -3; |
111 | 97 | } |
112 | | |
113 | 143 | return 0; |
114 | 240 | } |
115 | | |
116 | | |
117 | | /* |
118 | | * Skip name part |
119 | | * |
120 | | * _s will be adjusted to point at the beginning |
121 | | * of URI |
122 | | */ |
123 | | static inline int skip_name(str* _s) |
124 | 30.9k | { |
125 | 30.9k | char* last_wsp, *p; |
126 | 30.9k | int i, quoted = 0; |
127 | | |
128 | | |
129 | 30.9k | if (!_s) { |
130 | 0 | LM_ERR("invalid parameter value\n"); |
131 | 0 | return -1; |
132 | 0 | } |
133 | | |
134 | 30.9k | p = _s->s; |
135 | | |
136 | 30.9k | last_wsp = 0; |
137 | | |
138 | 1.38M | for(i = 0; i < _s->len; i++) { |
139 | 1.38M | if (!quoted) { |
140 | 768k | if ((*p == ' ') || (*p == '\t')) { |
141 | 20.3k | last_wsp = p; |
142 | 748k | } else { |
143 | 748k | if (*p == '<') { |
144 | 1.16k | _s->s = p; |
145 | 1.16k | _s->len -= i; |
146 | 1.16k | return 0; |
147 | 1.16k | } |
148 | | |
149 | 747k | if (*p == ':') { |
150 | 29.6k | if (last_wsp) { |
151 | 12.4k | _s->len -= last_wsp - _s->s + 1; |
152 | 12.4k | _s->s = last_wsp; |
153 | 12.4k | } |
154 | 29.6k | return 0; |
155 | 29.6k | } |
156 | | |
157 | 717k | if (*p == '\"') { |
158 | 4.03k | quoted = 1; |
159 | 4.03k | } |
160 | 717k | } |
161 | 768k | } else { |
162 | 611k | if ((*p == '\"') && (*(p-1) != '\\')) quoted = 0; |
163 | 611k | } |
164 | 1.34M | p++; |
165 | 1.34M | } |
166 | | |
167 | 110 | if (quoted) { |
168 | 14 | LM_ERR("closing quote missing in name part of Contact\n"); |
169 | 96 | } else { |
170 | 96 | LM_ERR("error in contact, scheme separator not found\n"); |
171 | 96 | } |
172 | | |
173 | 110 | return -1; |
174 | 30.9k | } |
175 | | |
176 | | |
177 | | /* |
178 | | * Parse contacts in a Contact HF |
179 | | */ |
180 | | int parse_contacts(str* _s, contact_t** _c) |
181 | 1.07k | { |
182 | 1.07k | contact_t* c; |
183 | 1.07k | contact_t* last; |
184 | 1.07k | param_hooks_t hooks; |
185 | | |
186 | 1.07k | last = NULL; |
187 | | |
188 | 30.9k | while(1) { |
189 | | /* Allocate and clear contact structure */ |
190 | 30.9k | c = (contact_t*)pkg_malloc(sizeof(contact_t)); |
191 | 30.9k | if (c == 0) { |
192 | 0 | LM_ERR("no pkg memory left\n"); |
193 | 0 | goto error; |
194 | 0 | } |
195 | 30.9k | memset(c, 0, sizeof(contact_t)); |
196 | | |
197 | 30.9k | c->name.s = _s->s; |
198 | | |
199 | 30.9k | if (skip_name(_s) < 0) { |
200 | 110 | LM_ERR("failed to skip name part\n"); |
201 | 110 | goto error; |
202 | 110 | } |
203 | | |
204 | 30.8k | c->uri.s = _s->s; |
205 | 30.8k | c->name.len = _s->s - c->name.s; |
206 | 30.8k | trim_trailing(&c->name); |
207 | | |
208 | | /* Find the end of the URI */ |
209 | 30.8k | if (skip_uri(_s) < 0) { |
210 | 115 | LM_ERR("failed to skip URI\n"); |
211 | 115 | goto error; |
212 | 115 | } |
213 | | |
214 | 30.7k | c->uri.len = _s->s - c->uri.s; /* Calculate URI length */ |
215 | 30.7k | trim_trailing(&(c->uri)); /* Remove any trailing spaces from URI */ |
216 | | |
217 | | /* Remove <> if any */ |
218 | 30.7k | if ((c->uri.len >= 2) && (c->uri.s[0] == '<') && |
219 | 1.09k | (c->uri.s[c->uri.len - 1] == '>')) { |
220 | 668 | c->uri.s++; |
221 | 668 | c->uri.len -= 2; |
222 | 668 | } |
223 | | |
224 | 30.7k | trim(&c->uri); |
225 | | |
226 | | /* RFC3261 grammar enforces the existence of an URI */ |
227 | 30.7k | if (c->uri.len==0) { |
228 | 31 | LM_ERR("Empty URI found in contact body\n"); |
229 | 31 | goto error; |
230 | 31 | } |
231 | | |
232 | 30.7k | if (_s->len == 0) goto ok; |
233 | | |
234 | 30.5k | if (_s->s[0] == ';') { /* Contact parameter found */ |
235 | 7.22k | _s->s++; |
236 | 7.22k | _s->len--; |
237 | 7.22k | trim_leading(_s); |
238 | | |
239 | 7.22k | if (_s->len == 0) { |
240 | 11 | LM_ERR("failed to parse params\n"); |
241 | 11 | goto error; |
242 | 11 | } |
243 | | |
244 | 7.21k | if (parse_params(_s, CLASS_CONTACT, &hooks, &c->params) < 0) { |
245 | 220 | LM_ERR("failed to parse contact parameters\n"); |
246 | 220 | goto error; |
247 | 220 | } |
248 | | |
249 | 6.99k | c->q = hooks.contact.q; |
250 | 6.99k | c->expires = hooks.contact.expires; |
251 | 6.99k | c->received = hooks.contact.received; |
252 | 6.99k | c->methods = hooks.contact.methods; |
253 | 6.99k | c->instance = hooks.contact.instance; |
254 | | |
255 | 6.99k | if (_s->len == 0) goto ok; |
256 | 6.99k | } |
257 | | |
258 | | /* Next character is comma */ |
259 | 29.9k | c->len = _s->s - c->name.s; |
260 | 29.9k | _s->s++; |
261 | 29.9k | _s->len--; |
262 | 29.9k | trim_leading(_s); |
263 | | |
264 | 29.9k | if (_s->len == 0) { |
265 | 26 | LM_ERR("text after comma missing\n"); |
266 | 26 | goto error; |
267 | 26 | } |
268 | | |
269 | 29.8k | if (last) {last->next=c;} else {*_c = c;} |
270 | 29.8k | last = c; |
271 | 29.8k | } |
272 | | |
273 | 513 | error: |
274 | 513 | if (c) free_contacts(&c); |
275 | 513 | free_contacts(_c); /* Free any contacts created so far */ |
276 | 513 | return -1; |
277 | | |
278 | 559 | ok: |
279 | 559 | c->len = _s->s - c->name.s; |
280 | 559 | if (last) {last->next=c;} else {*_c = c;} |
281 | 559 | return 0; |
282 | 1.07k | } |
283 | | |
284 | | |
285 | | /* |
286 | | * Free list of contacts |
287 | | * _c is head of the list |
288 | | */ |
289 | | void free_contacts(contact_t** _c) |
290 | 1.58k | { |
291 | 1.58k | contact_t* ptr; |
292 | | |
293 | 32.5k | while(*_c) { |
294 | 30.9k | ptr = *_c; |
295 | 30.9k | *_c = (*_c)->next; |
296 | 30.9k | if (ptr->params) { |
297 | 6.99k | free_params(ptr->params); |
298 | 6.99k | } |
299 | 30.9k | pkg_free(ptr); |
300 | 30.9k | } |
301 | 1.58k | } |
302 | | |
303 | | |
304 | | /* |
305 | | * Print list of contacts, just for debugging |
306 | | */ |
307 | | void log_contacts(contact_t* _c) |
308 | 0 | { |
309 | 0 | contact_t* ptr; |
310 | |
|
311 | 0 | ptr = _c; |
312 | |
|
313 | 0 | while(ptr) { |
314 | 0 | LM_DBG("---Contact---\n"); |
315 | 0 | LM_DBG("name : '%.*s'\n", ptr->name.len, ptr->name.s); |
316 | 0 | LM_DBG("URI : '%.*s'\n", ptr->uri.len, ptr->uri.s); |
317 | 0 | LM_DBG("instance: %p\n", ptr->instance); |
318 | 0 | LM_DBG("q : %p\n", ptr->q); |
319 | 0 | LM_DBG("expires : %p\n", ptr->expires); |
320 | 0 | LM_DBG("received: %p\n", ptr->received); |
321 | 0 | LM_DBG("method : %p\n", ptr->methods); |
322 | 0 | LM_DBG("len : %d\n", ptr->len); |
323 | 0 | if (ptr->params) { |
324 | 0 | print_params(ptr->params); |
325 | 0 | } |
326 | 0 | LM_DBG("---/Contact---\n"); |
327 | 0 | ptr = ptr->next; |
328 | 0 | } |
329 | 0 | } |