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