1 /**
2  * @file sipevent/listen.c  SIP Event Listen
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_tmr.h>
15 #include <re_msg.h>
16 #include <re_sip.h>
17 #include <re_sipevent.h>
18 #include "sipevent.h"
19 
20 
21 struct subcmp {
22 	const struct sipevent_event *evt;
23 	const struct sip_msg *msg;
24 };
25 
26 
27 static void destructor(void *arg)
28 {
29 	struct sipevent_sock *sock = arg;
30 
31 	mem_deref(sock->lsnr);
32 	hash_flush(sock->ht_not);
33 	hash_flush(sock->ht_sub);
34 	mem_deref(sock->ht_not);
35 	mem_deref(sock->ht_sub);
36 }
37 
38 
39 static bool event_cmp(const struct sipevent_event *evt,
40 		      const char *event, const char *id,
41 		      int32_t refer_cseq)
42 {
43 	if (pl_strcmp(&evt->event, event))
44 		return false;
45 
46 	if (!pl_isset(&evt->id) && !id)
47 		return true;
48 
49 	if (!pl_isset(&evt->id))
50 		return false;
51 
52 	if (!id) {
53 		if (refer_cseq >= 0 && (int32_t)pl_u32(&evt->id) == refer_cseq)
54 			return true;
55 
56 		return false;
57 	}
58 
59 	if (pl_strcmp(&evt->id, id))
60 		return false;
61 
62 	return true;
63 }
64 
65 
66 static bool not_cmp_handler(struct le *le, void *arg)
67 {
68 	const struct subcmp *cmp = arg;
69 	struct sipnot *not = le->data;
70 
71 	return sip_dialog_cmp(not->dlg, cmp->msg) &&
72 		event_cmp(cmp->evt, not->event, not->id, -1);
73 }
74 
75 
76 static bool sub_cmp_handler(struct le *le, void *arg)
77 {
78 	const struct subcmp *cmp = arg;
79 	struct sipsub *sub = le->data;
80 
81 	return sip_dialog_cmp(sub->dlg, cmp->msg) &&
82 		(!cmp->evt || event_cmp(cmp->evt, sub->event, sub->id,
83 					sub->refer_cseq));
84 }
85 
86 
87 static bool sub_cmp_half_handler(struct le *le, void *arg)
88 {
89 	const struct subcmp *cmp = arg;
90 	struct sipsub *sub = le->data;
91 
92 	return sip_dialog_cmp_half(sub->dlg, cmp->msg) &&
93 		!sip_dialog_established(sub->dlg) &&
94 		(!cmp->evt || event_cmp(cmp->evt, sub->event, sub->id,
95 					sub->refer_cseq));
96 }
97 
98 
99 static struct sipnot *sipnot_find(struct sipevent_sock *sock,
100 				  const struct sip_msg *msg,
101 				  const struct sipevent_event *evt)
102 {
103 	struct subcmp cmp;
104 
105 	cmp.msg = msg;
106 	cmp.evt = evt;
107 
108 	return list_ledata(hash_lookup(sock->ht_not,
109 				       hash_joaat_pl(&msg->callid),
110 				       not_cmp_handler, &cmp));
111 }
112 
113 
114 struct sipsub *sipsub_find(struct sipevent_sock *sock,
115 			   const struct sip_msg *msg,
116 			   const struct sipevent_event *evt, bool full)
117 {
118 	struct subcmp cmp;
119 
120 	cmp.msg = msg;
121 	cmp.evt = evt;
122 
123 	return list_ledata(hash_lookup(sock->ht_sub,
124 				       hash_joaat_pl(&msg->callid), full ?
125 				       sub_cmp_handler : sub_cmp_half_handler,
126 				       &cmp));
127 }
128 
129 
130 static void notify_handler(struct sipevent_sock *sock,
131 			   const struct sip_msg *msg)
132 {
133 	struct sipevent_substate state;
134 	struct sipevent_event event;
135 	struct sip *sip = sock->sip;
136 	const struct sip_hdr *hdr;
137 	struct sipsub *sub;
138 	uint32_t nrefs;
139 	char m[256];
140 	int err;
141 
142 	hdr = sip_msg_hdr(msg, SIP_HDR_EVENT);
143 	if (!hdr || sipevent_event_decode(&event, &hdr->val)) {
144 		(void)sip_reply(sip, msg, 489, "Bad Event");
145 		return;
146 	}
147 
148 	hdr = sip_msg_hdr(msg, SIP_HDR_SUBSCRIPTION_STATE);
149 	if (!hdr || sipevent_substate_decode(&state, &hdr->val)) {
150 		(void)sip_reply(sip, msg, 400,"Bad Subscription-State Header");
151 		return;
152 	}
153 
154 	sub = sipsub_find(sock, msg, &event, true);
155 	if (!sub) {
156 		sub = sipsub_find(sock, msg, &event, false);
157 		if (!sub) {
158 			(void)sip_reply(sip, msg,
159 					481, "Subscription Does Not Exist");
160 			return;
161 		}
162 
163 		if (sub->forkh) {
164 
165 			struct sipsub *fsub;
166 
167 			err = sub->forkh(&fsub, sub, msg, sub->arg);
168 			if (err) {
169 				(void)sip_reply(sip, msg, 500,
170 						str_error(err, m, sizeof(m)));
171 				return;
172 			}
173 
174 			sub = fsub;
175 		}
176 		else {
177 			err = sip_dialog_create(sub->dlg, msg);
178 			if (err) {
179 				(void)sip_reply(sip, msg, 500,
180 						str_error(err, m, sizeof(m)));
181 				return;
182 			}
183 		}
184 	}
185 	else {
186 		if (!sip_dialog_rseq_valid(sub->dlg, msg)) {
187 			(void)sip_reply(sip, msg, 500, "Bad Sequence");
188 			return;
189 		}
190 
191 		(void)sip_dialog_update(sub->dlg, msg);
192 	}
193 
194 	if (sub->refer_cseq >= 0 && !sub->id && pl_isset(&event.id)) {
195 
196 		err = pl_strdup(&sub->id, &event.id);
197 		if (err) {
198 			(void)sip_treply(NULL, sip, msg, 500,
199 					 str_error(err, m, sizeof(m)));
200 			return;
201 		}
202 	}
203 
204 	switch (state.state) {
205 
206 	case SIPEVENT_ACTIVE:
207 	case SIPEVENT_PENDING:
208 		if (!sub->termconf)
209 			sub->subscribed = true;
210 
211 		if (!sub->terminated && !sub->termwait &&
212 		    pl_isset(&state.expires))
213 			sipsub_reschedule(sub, pl_u32(&state.expires) * 900);
214 		break;
215 
216 	case SIPEVENT_TERMINATED:
217 		sub->subscribed = false;
218 		sub->termconf = true;
219 		break;
220 	}
221 
222 	mem_ref(sub);
223 	sub->notifyh(sip, msg, sub->arg);
224 	nrefs = mem_nrefs(sub);
225 	mem_deref(sub);
226 
227 	/* check if subscription was deref'd from notify handler */
228 	if (nrefs == 1)
229 		return;
230 
231 	if (state.state == SIPEVENT_TERMINATED) {
232 
233 		if (!sub->terminated) {
234 			sub->termwait = false;
235 			sipsub_terminate(sub, 0, msg, &state);
236 		}
237 		else if (sub->termwait) {
238 			sub->termwait = false;
239 			tmr_cancel(&sub->tmr);
240 			mem_deref(sub);
241 		}
242 	}
243 }
244 
245 
246 static void subscribe_handler(struct sipevent_sock *sock,
247 			      const struct sip_msg *msg)
248 {
249 	struct sipevent_event event;
250 	struct sip *sip = sock->sip;
251 	const struct sip_hdr *hdr;
252 	struct sipnot *not;
253 	uint32_t expires;
254 
255 	hdr = sip_msg_hdr(msg, SIP_HDR_EVENT);
256 	if (!hdr || sipevent_event_decode(&event, &hdr->val)) {
257 		(void)sip_reply(sip, msg, 400, "Bad Event Header");
258 		return;
259 	}
260 
261 	not = sipnot_find(sock, msg, &event);
262 	if (!not || not->terminated) {
263 		(void)sip_reply(sip, msg, 481, "Subscription Does Not Exist");
264 		return;
265 	}
266 
267 	if (pl_isset(&msg->expires))
268 		expires = pl_u32(&msg->expires);
269 	else
270 		expires = not->expires_dfl;
271 
272 	if (expires > 0 && expires < not->expires_min) {
273 		(void)sip_replyf(sip, msg, 423, "Interval Too Brief",
274 				 "Min-Expires: %u\r\n"
275 				 "Content-Length: 0\r\n"
276 				 "\r\n",
277 				 not->expires_min);
278 		return;
279 	}
280 
281 	if (!sip_dialog_rseq_valid(not->dlg, msg)) {
282 		(void)sip_reply(sip, msg, 500, "Bad Sequence");
283 		return;
284 	}
285 
286 	(void)sip_dialog_update(not->dlg, msg);
287 
288 	sipnot_refresh(not, expires);
289 
290 	(void)sipnot_reply(not, msg, 200, "OK");
291 
292 	(void)sipnot_notify(not);
293 }
294 
295 
296 static bool request_handler(const struct sip_msg *msg, void *arg)
297 {
298 	struct sipevent_sock *sock = arg;
299 
300 	if (!pl_strcmp(&msg->met, "SUBSCRIBE")) {
301 
302 		if (pl_isset(&msg->to.tag)) {
303 			subscribe_handler(sock, msg);
304 			return true;
305 		}
306 
307 		return sock->subh ? sock->subh(msg, sock->arg) : false;
308 	}
309 	else if (!pl_strcmp(&msg->met, "NOTIFY")) {
310 
311 		notify_handler(sock, msg);
312 		return true;
313 	}
314 	else {
315 		return false;
316 	}
317 }
318 
319 
320 int sipevent_listen(struct sipevent_sock **sockp, struct sip *sip,
321 		    uint32_t htsize_not, uint32_t htsize_sub,
322 		    sip_msg_h *subh, void *arg)
323 {
324 	struct sipevent_sock *sock;
325 	int err;
326 
327 	if (!sockp || !sip || !htsize_not || !htsize_sub)
328 		return EINVAL;
329 
330 	sock = mem_zalloc(sizeof(*sock), destructor);
331 	if (!sock)
332 		return ENOMEM;
333 
334 	err = sip_listen(&sock->lsnr, sip, true, request_handler, sock);
335 	if (err)
336 		goto out;
337 
338 	err = hash_alloc(&sock->ht_not, htsize_not);
339 	if (err)
340 		goto out;
341 
342 	err = hash_alloc(&sock->ht_sub, htsize_sub);
343 	if (err)
344 		goto out;
345 
346 	sock->sip  = sip;
347 	sock->subh = subh;
348 	sock->arg  = arg;
349 
350  out:
351 	if (err)
352 		mem_deref(sock);
353 	else
354 		*sockp = sock;
355 
356 	return err;
357 }
358