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