int call_connect(struct call *call, const struct pl *paddr) { struct sip_addr addr; int err; if (!call || !paddr) return EINVAL; info("call: connecting to '%r'..\n", paddr); call->outgoing = true; /* if the peer-address is a full SIP address then we need * to parse it and extract the SIP uri part. */ if (0 == sip_addr_decode(&addr, paddr) && addr.dname.p) { err = pl_strdup(&call->peer_uri, &addr.auri); } else { err = pl_strdup(&call->peer_uri, paddr); } if (err) return err; set_state(call, STATE_OUTGOING); /* If we are using asyncronous medianat like STUN/TURN, then * wait until completed before sending the INVITE */ if (!call->acc->mnat) err = send_invite(call); return err; }
int sdp_media_radd(struct sdp_media **mp, struct sdp_session *sess, const struct pl *name, const struct pl *proto) { struct sdp_media *m; int err; if (!mp || !sess || !name || !proto) return EINVAL; err = media_alloc(&m, &sess->medial); if (err) return err; m->disabled = true; err = pl_strdup(&m->name, name); err |= pl_strdup(&m->proto, proto); if (err) mem_deref(m); else *mp = m; return err; }
void http_init(struct httpc *app, struct request **rpp, char *str_uri) { int ok; struct request *request; struct pl pl_uri; struct url url; *rpp = NULL; pl_uri.p = NULL; str_dup((char**)&pl_uri.p, str_uri); pl_uri.l = strlen(str_uri); ok = url_decode(&url, &pl_uri); if(ok!=0) goto err_uri; request = mem_zalloc(sizeof(*request), destructor); ok = hash_alloc(&request->hdrht, HDR_HASH_SIZE); request->err_h = dummy_err; request->done_h = http_done; request->post = NULL; request->form = 0; request->www_auth.p = NULL; request->www_auth.l = 0; request->auth = NULL; request->retry = 0; pl_strdup(&request->host, &url.host); pl_strdup(&request->path, &url.path); request->secure = !pl_strcmp(&url.scheme, "https"); memcpy(&request->meth, "GET", 4); request->meth[4] = 0; if(url.port) request->port = url.port; else request->port = request->secure ? 443 : 80; DEBUG_INFO("secure: %d port %d\n", request->secure, request->port); sa_init(&request->dest, AF_INET); ok = sa_set_str(&request->dest, request->host, request->port); request->state = ok ? START : RESOLVED; request->app = app; *rpp = request; err_uri: if(pl_uri.p) mem_deref((void*)pl_uri.p); return; }
int icem_rcand_add(struct icem *icem, enum cand_type type, uint8_t compid, uint32_t prio, const struct sa *addr, const struct sa *rel_addr, const struct pl *foundation) { struct cand *rcand; int err; if (!icem || !foundation) return EINVAL; rcand = mem_zalloc(sizeof(*rcand), cand_destructor); if (!rcand) return ENOMEM; list_append(&icem->rcandl, &rcand->le, rcand); rcand->type = type; rcand->compid = compid; rcand->prio = prio; sa_cpy(&rcand->addr, addr); sa_cpy(&rcand->rel, rel_addr); err = pl_strdup(&rcand->foundation, foundation); if (err) mem_deref(rcand); return err; }
int sdp_format_radd(struct sdp_media *m, const struct pl *id) { struct sdp_format *fmt; int err; if (!m || !id) return EINVAL; fmt = mem_zalloc(sizeof(*fmt), destructor); if (!fmt) return ENOMEM; list_append(&m->rfmtl, &fmt->le, fmt); err = pl_strdup(&fmt->id, id); if (err) goto out; fmt->pt = atoi(fmt->id); out: if (err) mem_deref(fmt); return err; }
static bool sdp_attr_handler(const char *name, const char *value, void *arg) { struct menc_st *st = arg; struct crypto c; (void)name; if (sdes_decode_crypto(&c, value)) return false; if (0 != pl_strcmp(&c.key_method, "inline")) return false; if (!cryptosuite_issupported(&c.suite)) return false; st->crypto_suite = mem_deref(st->crypto_suite); pl_strdup(&st->crypto_suite, &c.suite); if (start_crypto(st, &c.key_info)) return false; sdp_enc(st, st->sdpm, c.tag, st->crypto_suite); return true; }
/** * Send SIP instant MESSAGE to a peer * * @param ua User-Agent object * @param peer Peer SIP Address * @param msg Message to send * * @return 0 if success, otherwise errorcode */ int message_send(struct ua *ua, const char *peer, const char *msg) { struct sip_addr addr; struct pl pl; char *uri = NULL; int err = 0; if (!ua || !peer || !msg) return EINVAL; pl_set_str(&pl, peer); err = sip_addr_decode(&addr, &pl); if (err) return err; err = pl_strdup(&uri, &addr.auri); if (err) return err; err = sip_req_send(ua, "MESSAGE", uri, resp_handler, ua, "Accept: text/plain\r\n" "Content-Type: text/plain\r\n" "Content-Length: %zu\r\n" "\r\n%s", str_len(msg), msg); mem_deref(uri); return err; }
static int attr_decode_rtpmap(struct sdp_media *m, const struct pl *pl) { struct pl id, name, srate, ch; struct sdp_format *fmt; int err; if (!m) return 0; if (re_regex(pl->p, pl->l, "[^ ]+ [^/]+/[0-9]+[/]*[^]*", &id, &name, &srate, NULL, &ch)) return EBADMSG; fmt = sdp_format_find(&m->rfmtl, &id); if (!fmt) return 0; fmt->name = mem_deref(fmt->name); err = pl_strdup(&fmt->name, &name); if (err) return err; fmt->srate = pl_u32(&srate); fmt->ch = ch.l ? pl_u32(&ch) : 1; return 0; }
/** * Add a contact * * @param contactp Pointer to allocated contact (optional) * @param addr Contact in SIP address format * * @return 0 if success, otherwise errorcode */ int contact_add(struct contact **contactp, const struct pl *addr) { struct contact *c; struct pl pl; int err; 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; } c->status = PRESENCE_UNKNOWN; list_append(&cl, &c->le, c); out: if (err) mem_deref(c); else if (contactp) *contactp = c; return err; }
int cmd_process_long(struct commands *commands, const char *str, size_t len, struct re_printf *pf_resp, void *data) { struct cmd_arg arg; const struct cmd *cmd_long; char *name = NULL, *prm = NULL; struct pl pl_name, pl_prm; int err; if (!str || !len) return EINVAL; memset(&arg, 0, sizeof(arg)); err = re_regex(str, len, "[^ ]+[ ]*[~]*", &pl_name, NULL, &pl_prm); if (err) { return err; } err = pl_strdup(&name, &pl_name); if (pl_isset(&pl_prm)) err |= pl_strdup(&prm, &pl_prm); if (err) goto out; cmd_long = cmd_find_long(commands, name); if (cmd_long) { arg.key = LONG_PREFIX; arg.prm = prm; arg.complete = true; arg.data = data; if (cmd_long->h) err = cmd_long->h(pf_resp, &arg); } else { err = re_hprintf(pf_resp, "command not found (%s)\n", name); } out: mem_deref(name); mem_deref(prm); return err; }
/** * Set Public GRUU of a User-Agent (UA) * * @param ua User-Agent * @param pval Public GRUU */ void ua_pub_gruu_set(struct ua *ua, const struct pl *pval) { if (!ua) return; ua->pub_gruu = mem_deref(ua->pub_gruu); (void)pl_strdup(&ua->pub_gruu, pval); }
/** * 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; }
static int str_ldup(char **dst, const char *src, int len) { struct pl pl; pl.p = src; pl.l = len < 0 ? str_len(src) : (size_t)len; return pl_strdup(dst, &pl); }
int rst_alloc(struct rst **rstp, const char *dev) { struct pl host, port, path; struct rst *rst; int err; if (!rstp || !dev) return EINVAL; if (re_regex(dev, strlen(dev), "http://[^:/]+[:]*[0-9]*[^]+", &host, NULL, &port, &path)) { re_printf("rst: bad http url: %s\n", dev); return EBADMSG; } rst = mem_zalloc(sizeof(*rst), destructor); if (!rst) return ENOMEM; rst->id = "rst"; err = pl_strdup(&rst->host, &host); if (err) goto out; err = pl_strdup(&rst->path, &path); if (err) goto out; rst->port = pl_u32(&port); rst->port = rst->port ? rst->port : 80; err = rst_connect(rst); if (err) goto out; out: if (err) mem_deref(rst); else *rstp = rst; return err; }
void tcsipcall_send(struct tcsipcall*call) { struct mbuf *mb; int err; char *to_uri, *to_user; char *from_uri, *from_name; pl_strdup(&to_uri, &call->remote->auri); pl_strdup(&to_user, &call->remote->uri.user); pl_strdup(&from_uri, &call->local->auri); if(call->local->dname.l) pl_strdup(&from_name, &call->local->dname); else pl_strdup(&from_name, &call->local->uri.user); char date[100]; struct tm *tv; tv = gmtime(&call->tv.tv_sec); strftime(date, sizeof(date), "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", tv); tcmedia_get_offer(call->media, &mb); err = sipsess_connect(&call->sess, call->uac->sock, to_uri, from_name, from_uri, to_user, NULL, 0, "application/sdp", mb, NULL, call, false, offer_handler, answer_handler, progress_handler, establish_handler, NULL, NULL, close_handler, call, date); mem_deref(mb); /* free SDP buffer */ if(err) call->cstate |= CSTATE_ERR; else call->cstate |= CSTATE_OUT_RING; mem_deref(to_uri); mem_deref(to_user); mem_deref(from_uri); mem_deref(from_name); }
bool hdr_fetch(struct le *le, void *arg) { int err = 0; struct http_hdr *hdr = le->data; struct hdr_fetch *op = arg; if(pl_strcasecmp(&hdr->name, op->name) == 0) { err = pl_strdup(op->val, &hdr->val); return true; } return false; }
static void response_handler(int err, const struct sip_msg *msg, void *arg) { struct publisher *pub = arg; const struct sip_hdr *etag_hdr; if (err) return; if (msg->scode < 200) { return; } if (msg->scode < 300) { if (pub->expires == 0) return; etag_hdr = sip_msg_xhdr(msg, "SIP-ETag"); if (etag_hdr) { mem_deref(pub->etag); pl_strdup(&(pub->etag), &(etag_hdr->val)); pub->refresh = 1; tmr_start(&pub->tmr, pub->expires * 900, tmr_handler, pub); } else { warning("%s: publisher got 200 OK without etag\n", ua_aor(pub->ua)); } } else if (msg->scode == 412) { mem_deref(pub->etag); pub->etag = NULL; pub->refresh = 0; publish(pub); } else { warning("%s: publisher got error response %u %r\n", ua_aor(pub->ua), msg->scode, &msg->reason); } return; }
void tcsipcall_accept(struct tcsipcall*call) { int err; char *my_user; pl_strdup(&my_user, &call->local->uri.user); err = sipsess_accept(&call->sess, call->uac->sock, call->msg, 180, "Ringing", my_user, "application/sdp", NULL, NULL, call, false, offer_handler, answer_handler, establish_handler, NULL, NULL, close_handler, call, NULL); if(err) call->cstate |= CSTATE_ERR; mem_deref(my_user); }
static int attr_decode_fmtp(struct sdp_media *m, const struct pl *pl) { struct sdp_format *fmt; struct pl id, params; if (!m) return 0; if (re_regex(pl->p, pl->l, "[^ ]+ [^]*", &id, ¶ms)) return EBADMSG; fmt = sdp_format_find(&m->rfmtl, &id); if (!fmt) return 0; fmt->params = mem_deref(fmt->params); return pl_strdup(&fmt->params, ¶ms); }
/** * Update an existing SIP Dialog from a SIP Message * * @param dlg SIP Dialog to update * @param msg SIP Message * * @return 0 if success, otherwise errorcode */ int sip_dialog_update(struct sip_dialog *dlg, const struct sip_msg *msg) { const struct sip_hdr *contact; struct sip_addr addr; char *uri; int err; if (!dlg || !msg) return EINVAL; contact = sip_msg_hdr(msg, SIP_HDR_CONTACT); if (!contact) return EBADMSG; if (sip_addr_decode(&addr, &contact->val)) return EBADMSG; err = pl_strdup(&uri, &addr.auri); if (err) return err; if (dlg->route.scheme.p == dlg->uri) { struct uri tmp; struct pl pl; pl_set_str(&pl, uri); err = uri_decode(&tmp, &pl); if (err) goto out; dlg->route = tmp; } mem_deref(dlg->uri); dlg->uri = mem_ref(uri); out: mem_deref(uri); return err; }
int version_cmp(char *have, const struct pl *want_pl) { char *hdr = NULL, *want = NULL; unsigned int uhave, uwant; if(pl_strdup(&hdr, want_pl)) { return -1; } if(strncmp(hdr, "Version=", sizeof("Version=")-1)) { return -1; } want = hdr + sizeof("Version=")-1; uhave = str_ver(have); uwant = str_ver(want); out: mem_deref(hdr); return uhave - uwant; };
int call_accept(struct call *call, struct sipsess_sock *sess_sock, const struct sip_msg *msg) { bool got_offer; int err; if (!call || !msg) return EINVAL; call->outgoing = false; got_offer = (mbuf_get_left(msg->mb) > 0); err = pl_strdup(&call->peer_uri, &msg->from.auri); if (err) return err; if (pl_isset(&msg->from.dname)) { err = pl_strdup(&call->peer_name, &msg->from.dname); if (err) return err; } if (got_offer) { struct sdp_media *m; const struct sa *raddr; err = sdp_decode(call->sdp, msg->mb, true); if (err) return err; call->got_offer = true; /* * Each media description in the SDP answer MUST * use the same network type as the corresponding * media description in the offer. * * See RFC 6157 */ m = stream_sdpmedia(audio_strm(call->audio)); raddr = sdp_media_raddr(m); if (sa_af(raddr) != call->af) { info("call: incompatible address-family" " (local=%s, remote=%s)\n", net_af2name(call->af), net_af2name(sa_af(raddr))); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "Wrong address family"); return 0; } /* Check if we have any common audio codecs, after * the SDP offer has been parsed */ if (!have_common_audio_codecs(call)) { info("call: no common audio codecs - rejected\n"); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "No audio codecs"); return 0; } } err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing", ua_cuser(call->ua), "application/sdp", NULL, auth_handler, call->acc, true, sipsess_offer_handler, sipsess_answer_handler, sipsess_estab_handler, sipsess_info_handler, sipsess_refer_handler, sipsess_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: sipsess_accept: %m\n", err); return err; } set_state(call, STATE_INCOMING); /* New call */ tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call); if (!call->acc->mnat) call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri); 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 (sip_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 (!sip_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; }
int sipevent_accept(struct sipnot **notp, struct sipevent_sock *sock, const struct sip_msg *msg, struct sip_dialog *dlg, const struct sipevent_event *event, uint16_t scode, const char *reason, uint32_t expires_min, uint32_t expires_dfl, uint32_t expires_max, const char *cuser, const char *ctype, sip_auth_h *authh, void *aarg, bool aref, sipnot_close_h *closeh, void *arg, const char *fmt, ...) { struct sipnot *not; uint32_t expires; int err; if (!notp || !sock || !msg || !scode || !reason || !expires_dfl || !expires_max || !cuser || !ctype || expires_dfl < expires_min) return EINVAL; not = mem_zalloc(sizeof(*not), destructor); if (!not) return ENOMEM; if (!pl_strcmp(&msg->met, "REFER")) { err = str_dup(¬->event, "refer"); if (err) goto out; err = re_sdprintf(¬->id, "%u", msg->cseq.num); if (err) goto out; } else { if (!event) { err = EINVAL; goto out; } err = pl_strdup(¬->event, &event->event); if (err) goto out; if (pl_isset(&event->id)) { err = pl_strdup(¬->id, &event->id); if (err) goto out; } } if (dlg) { not->dlg = mem_ref(dlg); } else { err = sip_dialog_accept(¬->dlg, msg); if (err) goto out; } hash_append(sock->ht_not, hash_joaat_str(sip_dialog_callid(not->dlg)), ¬->he, not); err = sip_auth_alloc(¬->auth, authh, aarg, aref); if (err) goto out; err = str_dup(¬->cuser, cuser); if (err) goto out; err = str_dup(¬->ctype, ctype); if (err) goto out; if (fmt) { va_list ap; va_start(ap, fmt); err = re_vsdprintf(¬->hdrs, fmt, ap); va_end(ap); if (err) goto out; } not->expires_min = expires_min; not->expires_dfl = expires_dfl; not->expires_max = expires_max; not->substate = SIPEVENT_PENDING; not->sock = mem_ref(sock); not->sip = mem_ref(sock->sip); not->closeh = closeh ? closeh : internal_close_handler; not->arg = arg; if (pl_isset(&msg->expires)) expires = pl_u32(&msg->expires); else expires = not->expires_dfl; sipnot_refresh(not, expires); err = sipnot_reply(not, msg, scode, reason); if (err) goto out; not->subscribed = true; out: if (err) mem_deref(not); else *notp = not; return err; }
/** * Initialize a SIP Dialog from an incoming SIP Message * * @param dlg SIP Dialog to initialize * @param msg SIP Message * * @return 0 if success, otherwise errorcode */ int sip_dialog_create(struct sip_dialog *dlg, const struct sip_msg *msg) { char *uri = NULL, *rtag = NULL; const struct sip_hdr *contact; struct route_enc renc; struct sip_addr addr; struct pl pl; int err; if (!dlg || dlg->rtag || !dlg->cpos || !msg) return EINVAL; contact = sip_msg_hdr(msg, SIP_HDR_CONTACT); if (!contact) return EBADMSG; if (sip_addr_decode(&addr, &contact->val)) return EBADMSG; renc.mb = mbuf_alloc(512); if (!renc.mb) return ENOMEM; err = pl_strdup(&uri, &addr.auri); if (err) goto out; err = pl_strdup(&rtag, msg->req ? &msg->from.tag : &msg->to.tag); if (err) goto out; renc.end = 0; err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE, record_route_handler, &renc) ? ENOMEM : 0; err |= mbuf_printf(renc.mb, "To: %r\r\n", msg->req ? &msg->from.val : &msg->to.val); dlg->mb->pos = dlg->cpos; err |= mbuf_write_mem(renc.mb, mbuf_buf(dlg->mb), mbuf_get_left(dlg->mb)); dlg->mb->pos = 0; if (err) goto out; renc.mb->pos = 0; if (renc.end) { pl.p = (const char *)mbuf_buf(renc.mb) + ROUTE_OFFSET; pl.l = renc.end - ROUTE_OFFSET; err = sip_addr_decode(&addr, &pl); if (err) goto out; dlg->route = addr.uri; } else { struct uri tmp; pl_set_str(&pl, uri); err = uri_decode(&tmp, &pl); if (err) goto out; dlg->route = tmp; } mem_deref(dlg->mb); mem_deref(dlg->uri); dlg->mb = mem_ref(renc.mb); dlg->rtag = mem_ref(rtag); dlg->uri = mem_ref(uri); dlg->rseq = msg->req ? msg->cseq.num : 0; dlg->cpos = 0; out: mem_deref(renc.mb); mem_deref(rtag); mem_deref(uri); return err; }
/** * Fork a SIP Dialog from an incoming SIP Message * * @param dlgp Pointer to allocated SIP Dialog * @param odlg Original SIP Dialog * @param msg SIP Message * * @return 0 if success, otherwise errorcode */ int sip_dialog_fork(struct sip_dialog **dlgp, struct sip_dialog *odlg, const struct sip_msg *msg) { const struct sip_hdr *contact; struct sip_dialog *dlg; struct route_enc renc; struct sip_addr addr; struct pl pl; int err; if (!dlgp || !odlg || !odlg->cpos || !msg) return EINVAL; contact = sip_msg_hdr(msg, SIP_HDR_CONTACT); if (!contact || !msg->callid.p) return EBADMSG; if (sip_addr_decode(&addr, &contact->val)) return EBADMSG; dlg = mem_zalloc(sizeof(*dlg), destructor); if (!dlg) return ENOMEM; dlg->callid = mem_ref(odlg->callid); dlg->ltag = mem_ref(odlg->ltag); dlg->lseq = odlg->lseq; dlg->rseq = msg->req ? msg->cseq.num : 0; err = pl_strdup(&dlg->uri, &addr.auri); if (err) goto out; err = pl_strdup(&dlg->rtag, msg->req ? &msg->from.tag : &msg->to.tag); if (err) goto out; dlg->mb = mbuf_alloc(512); if (!dlg->mb) { err = ENOMEM; goto out; } renc.mb = dlg->mb; renc.end = 0; err |= sip_msg_hdr_apply(msg, msg->req, SIP_HDR_RECORD_ROUTE, record_route_handler, &renc) ? ENOMEM : 0; err |= mbuf_printf(dlg->mb, "To: %r\r\n", msg->req ? &msg->from.val : &msg->to.val); odlg->mb->pos = odlg->cpos; err |= mbuf_write_mem(dlg->mb, mbuf_buf(odlg->mb), mbuf_get_left(odlg->mb)); odlg->mb->pos = 0; if (err) goto out; dlg->mb->pos = 0; if (renc.end) { pl.p = (const char *)mbuf_buf(dlg->mb) + ROUTE_OFFSET; pl.l = renc.end - ROUTE_OFFSET; err = sip_addr_decode(&addr, &pl); dlg->route = addr.uri; } else { pl_set_str(&pl, dlg->uri); err = uri_decode(&dlg->route, &pl); } out: if (err) mem_deref(dlg); else *dlgp = dlg; 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; }
static void recv_handler(struct mbuf *mb, void *arg) { struct rst *rst = arg; size_t n; if (!rst->head_recv) { struct pl hdr, name, metaint, eoh; if (rst->mb) { size_t pos; int err; pos = rst->mb->pos; rst->mb->pos = rst->mb->end; err = mbuf_write_mem(rst->mb, mbuf_buf(mb), mbuf_get_left(mb)); if (err) { re_printf("rst: buffer write error: %m\n", err); rst->tc = mem_deref(rst->tc); tmr_start(&rst->tmr, RETRY_WAIT, reconnect, rst); return; } rst->mb->pos = pos; } else { rst->mb = mem_ref(mb); } if (re_regex((const char *)mbuf_buf(rst->mb), mbuf_get_left(rst->mb), "[^\r\n]1\r\n\r\n", &eoh)) return; rst->head_recv = true; hdr.p = (const char *)mbuf_buf(rst->mb); hdr.l = eoh.p + 5 - hdr.p; if (!re_regex(hdr.p, hdr.l, "icy-name:[ \t]*[^\r\n]+\r\n", NULL, &name)) (void)pl_strdup(&rst->name, &name); if (!re_regex(hdr.p, hdr.l, "icy-metaint:[ \t]*[0-9]+\r\n", NULL, &metaint)) rst->metaint = pl_u32(&metaint); if (rst->metaint == 0) { re_printf("rst: icy meta interval not available\n"); rst->tc = mem_deref(rst->tc); tmr_start(&rst->tmr, RETRY_WAIT, reconnect, rst); return; } rst_video_update(rst->vidsrc_st, rst->name, NULL); rst->mb->pos += hdr.l; re_printf("rst: name='%s' metaint=%zu\n", rst->name, rst->metaint); if (rst->mb->pos >= rst->mb->end) return; mb = rst->mb; } while (mb->pos < mb->end) { if (rst->metasz > 0) { n = min(mbuf_get_left(mb), rst->metasz - rst->bytec); if (rst->meta) mbuf_read_mem(mb, (uint8_t *)&rst->meta[rst->bytec], n); else mb->pos += n; rst->bytec += n; #if 0 re_printf("rst: metadata %zu bytes\n", n); #endif if (rst->bytec >= rst->metasz) { #if 0 re_printf("rst: metadata: [%s]\n", rst->meta); #endif rst->metasz = 0; rst->bytec = 0; rst_video_update(rst->vidsrc_st, rst->name, rst->meta); } } else if (rst->bytec < rst->metaint) { n = min(mbuf_get_left(mb), rst->metaint - rst->bytec); rst_audio_feed(rst->ausrc_st, mbuf_buf(mb), n); rst->bytec += n; mb->pos += n; #if 0 re_printf("rst: mp3data %zu bytes\n", n); #endif } else { rst->metasz = mbuf_read_u8(mb) * 16; rst->bytec = 0; rst->meta = mem_deref(rst->meta); rst->meta = mem_zalloc(rst->metasz + 1, NULL); #if 0 re_printf("rst: metalength %zu bytes\n", rst->metasz); #endif } } }
/** * Send an HTTP request * * @param reqp Pointer to allocated HTTP request object * @param cli HTTP Client * @param met Request method * @param uri Request URI * @param resph Response handler * @param datah Content handler (optional) * @param arg Handler argument * @param fmt Formatted HTTP headers and body (optional) * * @return 0 if success, otherwise errorcode */ int http_request(struct http_req **reqp, struct http_cli *cli, const char *met, const char *uri, http_resp_h *resph, http_data_h *datah, void *arg, const char *fmt, ...) { struct pl scheme, host, port, path; struct http_req *req; uint16_t defport; bool secure; va_list ap; int err; if (!reqp || !cli || !met || !uri) return EINVAL; if (re_regex(uri, strlen(uri), "[a-z]+://[^:/]+[:]*[0-9]*[^]+", &scheme, &host, NULL, &port, &path) || scheme.p != uri) return EINVAL; if (!pl_strcasecmp(&scheme, "http") || !pl_strcasecmp(&scheme, "ws")) { secure = false; defport = 80; } #ifdef USE_TLS else if (!pl_strcasecmp(&scheme, "https") || !pl_strcasecmp(&scheme, "wss")) { secure = true; defport = 443; } #endif else return ENOTSUP; req = mem_zalloc(sizeof(*req), req_destructor); if (!req) return ENOMEM; req->tls = mem_ref(cli->tls); req->secure = secure; req->port = pl_isset(&port) ? pl_u32(&port) : defport; req->resph = resph; req->datah = datah; req->arg = arg; err = pl_strdup(&req->host, &host); if (err) goto out; req->mbreq = mbuf_alloc(1024); if (!req->mbreq) { err = ENOMEM; goto out; } err = mbuf_printf(req->mbreq, "%s %r HTTP/1.1\r\n" "Host: %r\r\n", met, &path, &host); if (fmt) { va_start(ap, fmt); err |= mbuf_vprintf(req->mbreq, fmt, ap); va_end(ap); } else { err |= mbuf_write_str(req->mbreq, "\r\n"); } if (err) goto out; req->mbreq->pos = 0; if (!sa_set_str(&req->srvv[0], req->host, req->port)) { req->srvc = 1; err = req_connect(req); if (err) goto out; } else { err = dnsc_query(&req->dq, cli->dnsc, req->host, DNS_TYPE_A, DNS_CLASS_IN, true, query_handler, req); if (err) goto out; } out: if (err) mem_deref(req); else { req->reqp = reqp; *reqp = req; } return err; }
int call_accept(struct call *call, struct sipsess_sock *sess_sock, const struct sip_msg *msg) { bool got_offer; int err; if (!call || !msg) return EINVAL; got_offer = (mbuf_get_left(msg->mb) > 0); err = pl_strdup(&call->peer_uri, &msg->from.auri); if (err) return err; if (pl_isset(&msg->from.dname)) { err = pl_strdup(&call->peer_name, &msg->from.dname); if (err) return err; } if (got_offer) { err = sdp_decode(call->sdp, msg->mb, true); if (err) return err; call->got_offer = true; /* Check if we have any common audio codecs, after * the SDP offer has been parsed */ if (!have_common_audio_codecs(call)) { info("call: no common audio codecs - rejected\n"); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "No audio codecs"); return 0; } } err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing", ua_cuser(call->ua), "application/sdp", NULL, auth_handler, call->acc, true, sipsess_offer_handler, sipsess_answer_handler, sipsess_estab_handler, sipsess_info_handler, sipsess_refer_handler, sipsess_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: sipsess_accept: %m\n", err); return err; } set_state(call, STATE_INCOMING); /* New call */ tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call); if (!call->acc->mnat) call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri); return err; }