1 /**
2 * @file reg.c SIP Registration
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #include <re_types.h>
7 #include <re_mem.h>
8 #include <re_mbuf.h>
9 #include <re_sa.h>
10 #include <re_list.h>
11 #include <re_hash.h>
12 #include <re_fmt.h>
13 #include <re_uri.h>
14 #include <re_sys.h>
15 #include <re_tmr.h>
16 #include <re_msg.h>
17 #include <re_sip.h>
18 #include <re_sipreg.h>
19
20
21 enum {
22 DEFAULT_EXPIRES = 3600,
23 };
24
25
26 /** Defines a SIP Registration client */
27 struct sipreg {
28 struct sip_loopstate ls;
29 struct sa laddr;
30 struct tmr tmr;
31 struct sip *sip;
32 struct sip_keepalive *ka;
33 struct sip_request *req;
34 struct sip_dialog *dlg;
35 struct sip_auth *auth;
36 struct mbuf *hdrs;
37 char *cuser;
38 sip_resp_h *resph;
39 void *arg;
40 uint32_t expires;
41 uint32_t failc;
42 uint32_t wait;
43 enum sip_transp tp;
44 bool registered;
45 bool terminated;
46 char *params;
47 int regid;
48 };
49
50
51 static int request(struct sipreg *reg, bool reset_ls);
52
53
dummy_handler(int err,const struct sip_msg * msg,void * arg)54 static void dummy_handler(int err, const struct sip_msg *msg, void *arg)
55 {
56 (void)err;
57 (void)msg;
58 (void)arg;
59 }
60
61
destructor(void * arg)62 static void destructor(void *arg)
63 {
64 struct sipreg *reg = arg;
65
66 tmr_cancel(®->tmr);
67
68 if (!reg->terminated) {
69
70 reg->resph = dummy_handler;
71 reg->terminated = true;
72
73 if (reg->req) {
74 mem_ref(reg);
75 return;
76 }
77
78 if (reg->registered && !request(reg, true)) {
79 mem_ref(reg);
80 return;
81 }
82 }
83
84 mem_deref(reg->ka);
85 mem_deref(reg->dlg);
86 mem_deref(reg->auth);
87 mem_deref(reg->cuser);
88 mem_deref(reg->sip);
89 mem_deref(reg->hdrs);
90 mem_deref(reg->params);
91 }
92
93
failwait(uint32_t failc)94 static uint32_t failwait(uint32_t failc)
95 {
96 return min(1800, (30 * (1<<min(failc, 6)))) * (500 + rand_u16() % 501);
97 }
98
99
tmr_handler(void * arg)100 static void tmr_handler(void *arg)
101 {
102 struct sipreg *reg = arg;
103 int err;
104
105 err = request(reg, true);
106 if (err) {
107 tmr_start(®->tmr, failwait(++reg->failc), tmr_handler, reg);
108 reg->resph(err, NULL, reg->arg);
109 }
110 }
111
112
keepalive_handler(int err,void * arg)113 static void keepalive_handler(int err, void *arg)
114 {
115 struct sipreg *reg = arg;
116
117 /* failure will be handled in response handler */
118 if (reg->req || reg->terminated)
119 return;
120
121 tmr_start(®->tmr, failwait(++reg->failc), tmr_handler, reg);
122 reg->resph(err, NULL, reg->arg);
123 }
124
125
start_outbound(struct sipreg * reg,const struct sip_msg * msg)126 static void start_outbound(struct sipreg *reg, const struct sip_msg *msg)
127 {
128 const struct sip_hdr *flowtimer;
129
130 if (!sip_msg_hdr_has_value(msg, SIP_HDR_REQUIRE, "outbound"))
131 return;
132
133 flowtimer = sip_msg_hdr(msg, SIP_HDR_FLOW_TIMER);
134
135 (void)sip_keepalive_start(®->ka, reg->sip, msg,
136 flowtimer ? pl_u32(&flowtimer->val) : 0,
137 keepalive_handler, reg);
138 }
139
140
contact_handler(const struct sip_hdr * hdr,const struct sip_msg * msg,void * arg)141 static bool contact_handler(const struct sip_hdr *hdr,
142 const struct sip_msg *msg, void *arg)
143 {
144 struct sipreg *reg = arg;
145 struct sip_addr c;
146 struct pl pval;
147 char uri[256];
148
149 if (sip_addr_decode(&c, &hdr->val))
150 return false;
151
152 if (re_snprintf(uri, sizeof(uri), "sip:%s@%J%s", reg->cuser,
153 ®->laddr, sip_transp_param(reg->tp)) < 0)
154 return false;
155
156 if (pl_strcmp(&c.auri, uri))
157 return false;
158
159 if (!msg_param_decode(&c.params, "expires", &pval)) {
160 reg->wait = pl_u32(&pval);
161 }
162 else if (pl_isset(&msg->expires))
163 reg->wait = pl_u32(&msg->expires);
164 else
165 reg->wait = DEFAULT_EXPIRES;
166
167 return true;
168 }
169
170
response_handler(int err,const struct sip_msg * msg,void * arg)171 static void response_handler(int err, const struct sip_msg *msg, void *arg)
172 {
173 const struct sip_hdr *minexp;
174 struct sipreg *reg = arg;
175
176 reg->wait = failwait(reg->failc + 1);
177
178 if (err || sip_request_loops(®->ls, msg->scode)) {
179 reg->failc++;
180 goto out;
181 }
182
183 if (msg->scode < 200) {
184 return;
185 }
186 else if (msg->scode < 300) {
187 reg->registered = true;
188 reg->wait = reg->expires;
189 sip_msg_hdr_apply(msg, true, SIP_HDR_CONTACT, contact_handler,
190 reg);
191 reg->wait *= 900;
192 reg->failc = 0;
193
194 if (reg->regid > 0 && !reg->terminated && !reg->ka)
195 start_outbound(reg, msg);
196 }
197 else {
198 if (reg->terminated && !reg->registered)
199 goto out;
200
201 switch (msg->scode) {
202
203 case 401:
204 case 407:
205 err = sip_auth_authenticate(reg->auth, msg);
206 if (err) {
207 err = (err == EAUTH) ? 0 : err;
208 break;
209 }
210
211 err = request(reg, false);
212 if (err)
213 break;
214
215 return;
216
217 case 403:
218 sip_auth_reset(reg->auth);
219 break;
220
221 case 423:
222 minexp = sip_msg_hdr(msg, SIP_HDR_MIN_EXPIRES);
223 if (!minexp || !pl_u32(&minexp->val) || !reg->expires)
224 break;
225
226 reg->expires = pl_u32(&minexp->val);
227
228 err = request(reg, false);
229 if (err)
230 break;
231
232 return;
233 }
234
235 ++reg->failc;
236 }
237
238 out:
239 if (!reg->expires) {
240 mem_deref(reg);
241 }
242 else if (reg->terminated) {
243 if (!reg->registered || request(reg, true))
244 mem_deref(reg);
245 }
246 else {
247 tmr_start(®->tmr, reg->wait, tmr_handler, reg);
248 reg->resph(err, msg, reg->arg);
249 }
250 }
251
252
send_handler(enum sip_transp tp,const struct sa * src,const struct sa * dst,struct mbuf * mb,void * arg)253 static int send_handler(enum sip_transp tp, const struct sa *src,
254 const struct sa *dst, struct mbuf *mb, void *arg)
255 {
256 struct sipreg *reg = arg;
257 int err;
258
259 (void)dst;
260
261 if (reg->expires > 0) {
262 reg->laddr = *src;
263 reg->tp = tp;
264 }
265
266 err = mbuf_printf(mb, "Contact: <sip:%s@%J%s>;expires=%u%s%s",
267 reg->cuser, ®->laddr, sip_transp_param(reg->tp),
268 reg->expires,
269 reg->params ? ";" : "",
270 reg->params ? reg->params : "");
271
272 if (reg->regid > 0)
273 err |= mbuf_printf(mb, ";reg-id=%d", reg->regid);
274
275 err |= mbuf_printf(mb, "\r\n");
276
277 return err;
278 }
279
280
request(struct sipreg * reg,bool reset_ls)281 static int request(struct sipreg *reg, bool reset_ls)
282 {
283 if (reg->terminated)
284 reg->expires = 0;
285
286 if (reset_ls)
287 sip_loopstate_reset(®->ls);
288
289 return sip_drequestf(®->req, reg->sip, true, "REGISTER", reg->dlg,
290 0, reg->auth, send_handler, response_handler, reg,
291 "%s"
292 "%b"
293 "Content-Length: 0\r\n"
294 "\r\n",
295 reg->regid > 0
296 ? "Supported: gruu, outbound, path\r\n" : "",
297 reg->hdrs ? mbuf_buf(reg->hdrs) : NULL,
298 reg->hdrs ? mbuf_get_left(reg->hdrs) : (size_t)0);
299 }
300
301
302 /**
303 * Allocate a SIP Registration client
304 *
305 * @param regp Pointer to allocated SIP Registration client
306 * @param sip SIP Stack instance
307 * @param reg_uri SIP Request URI
308 * @param to_uri SIP To-header URI
309 * @param from_name SIP From-header display name (optional)
310 * @param from_uri SIP From-header URI
311 * @param expires Registration interval in [seconds]
312 * @param cuser Contact username
313 * @param routev Optional route vector
314 * @param routec Number of routes
315 * @param regid Register identification
316 * @param authh Authentication handler
317 * @param aarg Authentication handler argument
318 * @param aref True to ref argument
319 * @param resph Response handler
320 * @param arg Response handler argument
321 * @param params Optional Contact-header parameters
322 * @param fmt Formatted strings with extra SIP Headers
323 *
324 * @return 0 if success, otherwise errorcode
325 */
sipreg_register(struct sipreg ** regp,struct sip * sip,const char * reg_uri,const char * to_uri,const char * from_name,const char * from_uri,uint32_t expires,const char * cuser,const char * routev[],uint32_t routec,int regid,sip_auth_h * authh,void * aarg,bool aref,sip_resp_h * resph,void * arg,const char * params,const char * fmt,...)326 int sipreg_register(struct sipreg **regp, struct sip *sip, const char *reg_uri,
327 const char *to_uri, const char *from_name,
328 const char *from_uri, uint32_t expires,
329 const char *cuser, const char *routev[], uint32_t routec,
330 int regid, sip_auth_h *authh, void *aarg, bool aref,
331 sip_resp_h *resph, void *arg,
332 const char *params, const char *fmt, ...)
333 {
334 struct sipreg *reg;
335 int err;
336
337 if (!regp || !sip || !reg_uri || !to_uri || !from_uri ||
338 !expires || !cuser)
339 return EINVAL;
340
341 reg = mem_zalloc(sizeof(*reg), destructor);
342 if (!reg)
343 return ENOMEM;
344
345 err = sip_dialog_alloc(®->dlg, reg_uri, to_uri, from_name, from_uri,
346 routev, routec);
347 if (err)
348 goto out;
349
350 err = sip_auth_alloc(®->auth, authh, aarg, aref);
351 if (err)
352 goto out;
353
354 err = str_dup(®->cuser, cuser);
355 if (params)
356 err |= str_dup(®->params, params);
357 if (err)
358 goto out;
359
360 /* Custom SIP headers */
361 if (fmt) {
362 va_list ap;
363
364 reg->hdrs = mbuf_alloc(256);
365 if (!reg->hdrs) {
366 err = ENOMEM;
367 goto out;
368 }
369
370 va_start(ap, fmt);
371 err = mbuf_vprintf(reg->hdrs, fmt, ap);
372 reg->hdrs->pos = 0;
373 va_end(ap);
374
375 if (err)
376 goto out;
377 }
378
379 reg->sip = mem_ref(sip);
380 reg->expires = expires;
381 reg->resph = resph ? resph : dummy_handler;
382 reg->arg = arg;
383 reg->regid = regid;
384
385 err = request(reg, true);
386 if (err)
387 goto out;
388
389 out:
390 if (err)
391 mem_deref(reg);
392 else
393 *regp = reg;
394
395 return err;
396 }
397
398
399 /**
400 * Get the local socket address for a SIP Registration client
401 *
402 * @param reg SIP Registration client
403 *
404 * @return Local socket address
405 */
sipreg_laddr(const struct sipreg * reg)406 const struct sa *sipreg_laddr(const struct sipreg *reg)
407 {
408 return reg ? ®->laddr : NULL;
409 }
410