1 /**
2 * @file sip/sipsrv.c Mock SIP server
3 *
4 * Copyright (C) 2010 - 2015 Creytiv.com
5 */
6 #include <string.h>
7 #include <time.h>
8 #include <re.h>
9 #include <baresip.h>
10 #include "../test.h"
11 #include "sipsrv.h"
12
13
14 #define DEBUG_MODULE "mock/sipsrv"
15 #define DEBUG_LEVEL 5
16 #include <re_dbg.h>
17
18
19 #define LOCAL_PORT 0
20 #define LOCAL_SECURE_PORT 0
21 #define EXPIRES_MIN 60
22 #define EXPIRES_MAX 3600
23
24
print_contact(struct re_printf * pf,const struct aor * aor)25 static int print_contact(struct re_printf *pf, const struct aor *aor)
26 {
27 const uint64_t now = (uint64_t)time(NULL);
28 struct le *le;
29 int err = 0;
30
31 for (le=aor->locl.head; le; le=le->next) {
32
33 const struct location *loc = le->data;
34
35 if (loc->expires < now)
36 continue;
37
38 err |= re_hprintf(pf, "Contact: <%s>;expires=%lli\r\n",
39 loc->uri, loc->expires - now);
40 }
41
42 return err;
43 }
44
45
handle_register(struct sip_server * srv,const struct sip_msg * msg)46 static bool handle_register(struct sip_server *srv, const struct sip_msg *msg)
47 {
48 struct auth auth = { srv, "", false };
49 struct sip *sip = srv->sip;
50 struct list *lst;
51 struct aor *aor;
52 struct le *le;
53 int err;
54
55 /* Request URI */
56 err = domain_find(srv, &msg->uri);
57 if (err) {
58 if (err == ENOENT) {
59 warning("domain not found\n");
60 return false;
61 }
62
63 sip_reply(sip, msg, 500, strerror(err));
64 warning("domain find error: %s\n", strerror(err));
65 return true;
66 }
67
68 /* Authorize */
69 if (srv->auth_enabled)
70 err = domain_auth(srv, &msg->to.uri, true,
71 msg, SIP_HDR_AUTHORIZATION, &auth);
72 else
73 err = domain_find(srv, &msg->to.uri);
74
75 if (err && err != EAUTH) {
76 DEBUG_NOTICE("domain auth/find error: %m\n", err);
77 }
78
79 switch (err) {
80
81 case 0:
82 break;
83
84 case EAUTH:
85 sip_replyf(sip, msg, 401, "Unauthorized",
86 "WWW-Authenticate: %H\r\n"
87 "Content-Length: 0\r\n\r\n",
88 auth_print, &auth);
89 return true;
90
91 case EPERM:
92 sip_reply(sip, msg, 403, "Forbidden");
93 return true;
94
95 case ENOENT:
96 sip_reply(sip, msg, 404, "Not Found");
97 return true;
98
99 default:
100 sip_reply(sip, msg, 500, strerror(err));
101 warning("domain error: %s\n", strerror(err));
102 return true;
103 }
104
105 /* Find AoR */
106 err = aor_find(srv, &aor, &msg->to.uri);
107 if (err) {
108 if (err != ENOENT) {
109 sip_reply(sip, msg, 500, strerror(err));
110 warning("aor find error: %s\n", strerror(err));
111 return true;
112 }
113
114 err = aor_create(srv, &aor, &msg->to.uri);
115 if (err) {
116 sip_reply(sip, msg, 500, strerror(err));
117 warning("aor create error: %s\n", strerror(err));
118 return true;
119 }
120 }
121
122 /* Process Contacts */
123 lst = hash_list(msg->hdrht, SIP_HDR_CONTACT);
124
125 for (le=list_head(lst); le; le=le->next) {
126
127 const struct sip_hdr *hdr = le->data;
128 struct sip_addr contact;
129 uint32_t expires;
130 struct pl pl;
131
132 if (hdr->id != SIP_HDR_CONTACT)
133 continue;
134
135 err = sip_addr_decode(&contact, &hdr->val);
136 if (err) {
137 sip_reply(sip, msg, 400, "Bad Contact");
138 goto fail;
139 }
140
141 if (!msg_param_decode(&contact.params, "expires", &pl))
142 expires = pl_u32(&pl);
143 else if (pl_isset(&msg->expires))
144 expires = pl_u32(&msg->expires);
145 else
146 expires = 3600;
147
148 if (expires > 0 && expires < EXPIRES_MIN) {
149 sip_replyf(sip, msg, 423, "Interval Too Brief",
150 "Min-Expires: %u\r\n"
151 "Content-Length: 0\r\n\r\n",
152 EXPIRES_MIN);
153 goto fail;
154 }
155
156 expires = min(expires, EXPIRES_MAX);
157
158 err = location_update(&aor->locl, msg, &contact, expires);
159 if (err) {
160 sip_reply(sip, msg, 500, strerror(err));
161 if (err != EPROTO)
162 warning("location update error: %s\n",
163 strerror(err));
164 goto fail;
165 }
166 }
167
168 location_commit(&aor->locl);
169
170 sip_treplyf(NULL, NULL, sip, msg, false, 200, "OK",
171 "%H"
172 "Date: %H\r\n"
173 "Content-Length: 0\r\n\r\n",
174 print_contact, aor,
175 fmt_gmtime, NULL);
176
177 return true;
178
179 fail:
180 location_rollback(&aor->locl);
181
182 return true;
183 }
184
185
sip_msg_handler(const struct sip_msg * msg,void * arg)186 static bool sip_msg_handler(const struct sip_msg *msg, void *arg)
187 {
188 struct sip_server *srv = arg;
189 int err = 0;
190
191 #if 0
192 DEBUG_NOTICE("[%u] recv %r via %s\n", srv->instance,
193 &msg->met, sip_transp_name(msg->tp));
194 #endif
195
196 srv->tp_last = msg->tp;
197
198 if (0 == pl_strcmp(&msg->met, "REGISTER")) {
199 ++srv->n_register_req;
200 if (handle_register(srv, msg))
201 goto out;
202
203 sip_reply(srv->sip, msg, 503, "Server Error");
204 }
205 else {
206 DEBUG_NOTICE("method not handled (%r)\n", &msg->met);
207 return false;
208 }
209
210 if (srv->terminate)
211 err = sip_reply(srv->sip, msg, 503, "Server Error");
212
213 if (err) {
214 DEBUG_WARNING("could not reply: %m\n", err);
215 }
216
217 out:
218 if (srv->terminate)
219 re_cancel(); /* XXX: avoid this */
220
221 return true;
222 }
223
224
destructor(void * arg)225 static void destructor(void *arg)
226 {
227 struct sip_server *srv = arg;
228
229 srv->terminate = true;
230
231 sip_close(srv->sip, false);
232 mem_deref(srv->sip);
233
234 hash_flush(srv->ht_aor);
235 mem_deref(srv->ht_aor);
236
237 hash_flush(srv->ht_dom);
238 mem_deref(srv->ht_dom);
239 }
240
241
sip_server_alloc(struct sip_server ** srvp)242 int sip_server_alloc(struct sip_server **srvp)
243 {
244 struct sip_server *srv;
245 struct sa laddr, laddrs;
246 struct tls *tls = NULL;
247 int err;
248
249 if (!srvp)
250 return EINVAL;
251
252 srv = mem_zalloc(sizeof *srv, destructor);
253 if (!srv)
254 return ENOMEM;
255
256 err = sa_set_str(&laddr, "127.0.0.1", LOCAL_PORT);
257 err |= sa_set_str(&laddrs, "127.0.0.1", LOCAL_SECURE_PORT);
258 if (err)
259 goto out;
260
261 err = sip_alloc(&srv->sip, NULL, 16, 16, 16,
262 "mock SIP server", NULL, NULL);
263 if (err)
264 goto out;
265
266 err |= sip_transp_add(srv->sip, SIP_TRANSP_UDP, &laddr);
267 err |= sip_transp_add(srv->sip, SIP_TRANSP_TCP, &laddr);
268 if (err)
269 goto out;
270
271 #ifdef USE_TLS
272 err = tls_alloc(&tls, TLS_METHOD_SSLV23, NULL, NULL);
273 if (err)
274 goto out;
275
276 err = tls_set_certificate(tls, test_certificate,
277 strlen(test_certificate));
278 if (err)
279 goto out;
280
281 err |= sip_transp_add(srv->sip, SIP_TRANSP_TLS, &laddrs, tls);
282 #endif
283 if (err)
284 goto out;
285
286 err = sip_listen(&srv->lsnr, srv->sip, true, sip_msg_handler, srv);
287 if (err)
288 goto out;
289
290 srv->secret = rand_u64();
291
292 err = hash_alloc(&srv->ht_dom, 32);
293 if (err)
294 goto out;
295
296 err = hash_alloc(&srv->ht_aor, 32);
297 if (err)
298 goto out;
299
300 out:
301 mem_deref(tls);
302 if (err)
303 mem_deref(srv);
304 else
305 *srvp = srv;
306
307 return err;
308 }
309
310
sip_server_uri(struct sip_server * srv,char * uri,size_t sz,enum sip_transp tp)311 int sip_server_uri(struct sip_server *srv, char *uri, size_t sz,
312 enum sip_transp tp)
313 {
314 struct sa laddr;
315 int err;
316
317 if (!srv || !uri || !sz)
318 return EINVAL;
319
320 err = sip_transp_laddr(srv->sip, &laddr, tp, NULL);
321 if (err)
322 return err;
323
324 /* NOTE: angel brackets needed to parse ;transport parameter */
325 if (re_snprintf(uri, sz, "<sip:x@%J%s>",
326 &laddr, sip_transp_param(tp)) < 0)
327 return ENOMEM;
328
329 return 0;
330 }
331