int sipevent_substate_decode(struct sipevent_substate *ss, const struct pl *pl) { struct pl state, param; int err; if (!ss || !pl) return EINVAL; err = re_regex(pl->p, pl->l, "[a-z]+[ \t\r\n]*[^]*", &state, NULL, &ss->params); if (err) return EBADMSG; if (!pl_strcasecmp(&state, "active")) ss->state = SIPEVENT_ACTIVE; else if (!pl_strcasecmp(&state, "pending")) ss->state = SIPEVENT_PENDING; else if (!pl_strcasecmp(&state, "terminated")) ss->state = SIPEVENT_TERMINATED; else ss->state = -1; if (!msg_param_decode(&ss->params, "reason", ¶m)) { if (!pl_strcasecmp(¶m, "deactivated")) ss->reason = SIPEVENT_DEACTIVATED; else if (!pl_strcasecmp(¶m, "probation")) ss->reason = SIPEVENT_PROBATION; else if (!pl_strcasecmp(¶m, "rejected")) ss->reason = SIPEVENT_REJECTED; else if (!pl_strcasecmp(¶m, "timeout")) ss->reason = SIPEVENT_TIMEOUT; else if (!pl_strcasecmp(¶m, "giveup")) ss->reason = SIPEVENT_GIVEUP; else if (!pl_strcasecmp(¶m, "noresource")) ss->reason = SIPEVENT_NORESOURCE; else ss->reason = -1; } else { ss->reason = -1; } if (!msg_param_decode(&ss->params, "expires", ¶m)) ss->expires = param; else ss->expires = pl_null; if (!msg_param_decode(&ss->params, "retry-after", ¶m)) ss->retry_after = param; else ss->retry_after = pl_null; return 0; }
/** * Find a User-Agent (UA) which has certain address parameter and/or value * * @param name SIP Address parameter name * @param value SIP Address parameter value (optional) * * @return User-Agent (UA) if found, otherwise NULL */ struct ua *uag_find_param(const char *name, const char *value) { struct le *le; for (le = uag.ual.head; le; le = le->next) { struct ua *ua = le->data; struct sip_addr *laddr = account_laddr(ua->acc); struct pl val; if (value) { if (0 == msg_param_decode(&laddr->params, name, &val) && 0 == pl_strcasecmp(&val, value)) { return ua; } } else { if (0 == msg_param_exists(&laddr->params, name, &val)) return ua; } } return NULL; }
/** * Add a contact * * @param contacts Contacts container * @param contactp Pointer to allocated contact (optional) * @param addr Contact in SIP address format * * @return 0 if success, otherwise errorcode */ int contact_add(struct contacts *contacts, struct contact **contactp, const struct pl *addr) { struct contact *c; struct pl pl; int err; if (!contacts) return EINVAL; c = mem_zalloc(sizeof(*c), destructor); if (!c) return ENOMEM; err = pl_strdup(&c->buf, addr); if (err) goto out; pl_set_str(&pl, c->buf); err = sip_addr_decode(&c->addr, &pl); if (err) { warning("contact: decode error '%r'\n", addr); goto out; } if (0 == msg_param_decode(&c->addr.params, "access", &pl)) { if (0 == pl_strcasecmp(&pl, "block")) { c->access = ACCESS_BLOCK; } else if (0 == pl_strcasecmp(&pl, "allow")) { c->access = ACCESS_ALLOW; } else { warning("contact: unknown 'access=%r' for '%r'\n", &pl, addr); err = EINVAL; goto out; } } else c->access = ACCESS_UNKNOWN; c->status = PRESENCE_UNKNOWN; list_append(&contacts->cl, &c->le, c); hash_append(contacts->cht, hash_joaat_pl(&c->addr.auri), &c->he, c); out: if (err) mem_deref(c); else if (contactp) *contactp = c; return err; }
int sipevent_event_decode(struct sipevent_event *se, const struct pl *pl) { struct pl param; int err; if (!se || !pl) return EINVAL; err = re_regex(pl->p, pl->l, "[^; \t\r\n]+[ \t\r\n]*[^]*", &se->event, NULL, &se->params); if (err) return EBADMSG; if (!msg_param_decode(&se->params, "id", ¶m)) se->id = param; else se->id = pl_null; return 0; }
/** * Decode a pointer-length string into a SIP Via header * * @param via SIP Via header * @param pl Pointer-length string * * @return 0 for success, otherwise errorcode */ int sip_via_decode(struct sip_via *via, const struct pl *pl) { struct pl transp, host, port; int err; if (!via || !pl) return EINVAL; err = re_regex(pl->p, pl->l, "SIP[ \t\r\n]*/[ \t\r\n]*2.0[ \t\r\n]*/[ \t\r\n]*" "[A-Z]+[ \t\r\n]*[^; \t\r\n]+[ \t\r\n]*[^]*", NULL, NULL, NULL, NULL, &transp, NULL, &via->sentby, NULL, &via->params); if (err) return err; if (!pl_strcmp(&transp, "TCP")) via->tp = SIP_TRANSP_TCP; else if (!pl_strcmp(&transp, "TLS")) via->tp = SIP_TRANSP_TLS; else if (!pl_strcmp(&transp, "UDP")) via->tp = SIP_TRANSP_UDP; else via->tp = SIP_TRANSP_NONE; err = decode_hostport(&via->sentby, &host, &port); if (err) return err; sa_init(&via->addr, AF_INET); (void)sa_set(&via->addr, &host, 0); if (pl_isset(&port)) sa_set_port(&via->addr, pl_u32(&port)); via->val = *pl; return msg_param_decode(&via->params, "branch", &via->branch); }
int subscriber_init(void) { struct le *le; int err = 0; for (le = list_head(contact_list()); le; le = le->next) { struct contact *c = le->data; struct sip_addr *addr = contact_addr(c); struct pl val; if (0 == msg_param_decode(&addr->params, "presence", &val) && 0 == pl_strcasecmp(&val, "p2p")) { err |= presence_alloc(le->data); } } info("Subscribing to %u contacts\n", list_count(&presencel)); return err; }
/** * Send a SIP request * * @param reqp Pointer to allocated SIP request object * @param sip SIP Stack * @param stateful Stateful client transaction * @param met SIP Method string * @param metl Length of SIP Method string * @param uri Request URI * @param uril Length of Request URI string * @param route Next hop route URI * @param mb Buffer containing SIP request * @param sendh Send handler * @param resph Response handler * @param arg Handler argument * * @return 0 if success, otherwise errorcode */ int sip_request(struct sip_request **reqp, struct sip *sip, bool stateful, const char *met, int metl, const char *uri, int uril, const struct uri *route, struct mbuf *mb, sip_send_h *sendh, sip_resp_h *resph, void *arg) { struct sip_request *req; struct sa dst; struct pl pl; int err; if (!sip || !met || !uri || !route || !mb) return EINVAL; if (pl_strcasecmp(&route->scheme, "sip")) return ENOSYS; req = mem_zalloc(sizeof(*req), destructor); if (!req) return ENOMEM; list_append(&sip->reql, &req->le, req); err = str_ldup(&req->met, met, metl); if (err) goto out; err = str_ldup(&req->uri, uri, uril); if (err) goto out; if (msg_param_decode(&route->params, "maddr", &pl)) pl = route->host; err = pl_strdup(&req->host, &pl); if (err) goto out; req->stateful = stateful; req->mb = mem_ref(mb); req->sip = sip; req->sendh = sendh; req->resph = resph; req->arg = arg; if (!msg_param_decode(&route->params, "transport", &pl)) { if (!pl_strcasecmp(&pl, "udp")) req->tp = SIP_TRANSP_UDP; else if (!pl_strcasecmp(&pl, "tcp")) req->tp = SIP_TRANSP_TCP; else if (!pl_strcasecmp(&pl, "tls")) req->tp = SIP_TRANSP_TLS; else { err = EPROTONOSUPPORT; goto out; } if (!sip_transp_supported(sip, req->tp, AF_UNSPEC)) { err = EPROTONOSUPPORT; goto out; } req->tp_selected = true; } else { req->tp = SIP_TRANSP_NONE; if (!transp_next(sip, &req->tp)) { err = EPROTONOSUPPORT; goto out; } req->tp_selected = false; } if (!sa_set_str(&dst, req->host, sip_transp_port(req->tp, route->port))) { err = request(req, req->tp, &dst); if (!req->stateful) { mem_deref(req); return err; } } else if (route->port) { req->port = sip_transp_port(req->tp, route->port); err = addr_lookup(req, req->host); } else if (req->tp_selected) { err = srv_lookup(req, req->host); } else { err = dnsc_query(&req->dnsq, sip->dnsc, req->host, DNS_TYPE_NAPTR, DNS_CLASS_IN, true, naptr_handler, req); } out: if (err) mem_deref(req); else if (reqp) { req->reqp = reqp; *reqp = req; } return err; }
static inline int hdr_add(struct sip_msg *msg, const struct pl *name, enum sip_hdrid id, const char *p, ssize_t l, bool atomic, bool line) { struct sip_hdr *hdr; int err = 0; hdr = mem_zalloc(sizeof(*hdr), hdr_destructor); if (!hdr) return ENOMEM; hdr->name = *name; hdr->val.p = p; hdr->val.l = MAX(l, 0); hdr->id = id; switch (id) { case SIP_HDR_VIA: case SIP_HDR_ROUTE: if (!atomic) break; hash_append(msg->hdrht, id, &hdr->he, mem_ref(hdr)); list_append(&msg->hdrl, &hdr->le, mem_ref(hdr)); break; default: if (atomic) hash_append(msg->hdrht, id, &hdr->he, mem_ref(hdr)); if (line) list_append(&msg->hdrl, &hdr->le, mem_ref(hdr)); break; } /* parse common headers */ switch (id) { case SIP_HDR_VIA: if (!atomic || pl_isset(&msg->via.sentby)) break; err = sip_via_decode(&msg->via, &hdr->val); break; case SIP_HDR_TO: err = sip_addr_decode((struct sip_addr *)&msg->to, &hdr->val); if (err) break; (void)msg_param_decode(&msg->to.params, "tag", &msg->to.tag); msg->to.val = hdr->val; break; case SIP_HDR_FROM: err = sip_addr_decode((struct sip_addr *)&msg->from, &hdr->val); if (err) break; (void)msg_param_decode(&msg->from.params, "tag", &msg->from.tag); msg->from.val = hdr->val; break; case SIP_HDR_CALL_ID: msg->callid = hdr->val; break; case SIP_HDR_CSEQ: err = sip_cseq_decode(&msg->cseq, &hdr->val); break; case SIP_HDR_MAX_FORWARDS: msg->maxfwd = hdr->val; break; case SIP_HDR_CONTENT_TYPE: err = msg_ctype_decode(&msg->ctyp, &hdr->val); break; case SIP_HDR_CONTENT_LENGTH: msg->clen = hdr->val; break; case SIP_HDR_EXPIRES: msg->expires = hdr->val; break; default: /* re_printf("%r = %u\n", &hdr->name, id); */ break; } mem_deref(hdr); return err; }
int location_update(struct list *locl, const struct sip_msg *msg, const struct sip_addr *contact, uint32_t expires) { struct location *loc, *loc_new = NULL; struct loctmp *tmp; struct pl pl; int err; if (!locl || !msg || !contact) return EINVAL; loc = list_ledata(list_apply(locl, true, cmp_handler, (void *)&contact->uri)); if (!loc) { if (expires == 0) return 0; loc = loc_new = mem_zalloc(sizeof(*loc), destructor_location); if (!loc) return ENOMEM; list_append(locl, &loc->le, loc); } else { if (!pl_strcmp(&msg->callid, loc->callid) && msg->cseq.num <= loc->cseq) return EPROTO; if (expires == 0) { loc->rm = true; return 0; } } tmp = mem_zalloc(sizeof(*tmp), destructor_loctmp); if (!tmp) { err = ENOMEM; goto out; } err = pl_strdup(&tmp->uri, &contact->auri); if (err) goto out; pl_set_str(&pl, tmp->uri); if (uri_decode(&tmp->duri, &pl)) { err = EBADMSG; goto out; } err = pl_strdup(&tmp->callid, &msg->callid); if (err) goto out; if (!msg_param_decode(&contact->params, "q", &pl)) tmp->q = pl_float(&pl); else tmp->q = 1; tmp->cseq = msg->cseq.num; tmp->expires = expires; tmp->src = msg->src; out: if (err) { mem_deref(loc_new); mem_deref(tmp); } else { mem_deref(loc->tmp); loc->tmp = tmp; } return err; }