/** * Send a SIP request with formatted arguments * * @param reqp Pointer to allocated SIP request object * @param sip SIP Stack * @param stateful Stateful client transaction * @param met Null-terminated SIP Method string * @param uri Null-terminated Request URI string * @param route Next hop route URI (optional) * @param auth SIP authentication state * @param sendh Send handler * @param resph Response handler * @param arg Handler argument * @param fmt Formatted SIP headers * * @return 0 if success, otherwise errorcode */ int sip_requestf(struct sip_request **reqp, struct sip *sip, bool stateful, const char *met, const char *uri, const struct uri *route, struct sip_auth *auth, sip_send_h *sendh, sip_resp_h *resph, void *arg, const char *fmt, ...) { struct uri lroute; struct mbuf *mb; va_list ap; int err; if (!sip || !met || !uri || !fmt) return EINVAL; if (!route) { struct pl uripl; pl_set_str(&uripl, uri); err = uri_decode(&lroute, &uripl); if (err) return err; route = &lroute; } mb = mbuf_alloc(2048); if (!mb) return ENOMEM; err = mbuf_write_str(mb, "Max-Forwards: 70\r\n"); if (auth) err |= sip_auth_encode(mb, auth, met, uri); if (err) goto out; va_start(ap, fmt); err = mbuf_vprintf(mb, fmt, ap); va_end(ap); if (err) goto out; mb->pos = 0; err = sip_request(reqp, sip, stateful, met, -1, uri, -1, route, mb, sendh, resph, arg); if (err) goto out; out: mem_deref(mb); return err; }
/** * Send a SIP dialog request with formatted arguments * * @param reqp Pointer to allocated SIP request object * @param sip SIP Stack * @param stateful Stateful client transaction * @param met Null-terminated SIP Method string * @param dlg SIP Dialog state * @param cseq CSeq number * @param auth SIP authentication state * @param sendh Send handler * @param resph Response handler * @param arg Handler argument * @param fmt Formatted SIP headers * * @return 0 if success, otherwise errorcode */ int sip_drequestf(struct sip_request **reqp, struct sip *sip, bool stateful, const char *met, struct sip_dialog *dlg, uint32_t cseq, struct sip_auth *auth, sip_send_h *sendh, sip_resp_h *resph, void *arg, const char *fmt, ...) { struct mbuf *mb; va_list ap; int err; if (!sip || !met || !dlg || !fmt) return EINVAL; mb = mbuf_alloc(2048); if (!mb) return ENOMEM; err = mbuf_write_str(mb, "Max-Forwards: 70\r\n"); if (auth) err |= sip_auth_encode(mb, auth, met, sip_dialog_uri(dlg)); err |= sip_dialog_encode(mb, dlg, cseq, met); if (sip->software) err |= mbuf_printf(mb, "User-Agent: %s\r\n", sip->software); if (err) goto out; va_start(ap, fmt); err = mbuf_vprintf(mb, fmt, ap); va_end(ap); if (err) goto out; mb->pos = 0; err = sip_request(reqp, sip, stateful, met, -1, sip_dialog_uri(dlg), -1, sip_dialog_route(dlg), mb, sendh, resph, arg); if (err) goto out; out: mem_deref(mb); return err; }
int sipevent_notifyf(struct sipnot *not, struct mbuf **mbp, enum sipevent_subst state, enum sipevent_reason reason, uint32_t retry_after, const char *fmt, ...) { struct mbuf *mb; va_list ap; int err; if (!not || not->terminated || !fmt) return EINVAL; if (mbp && *mbp) return sipevent_notify(not, *mbp, state, reason, retry_after); mb = mbuf_alloc(1024); if (!mb) return ENOMEM; va_start(ap, fmt); err = mbuf_vprintf(mb, fmt, ap); va_end(ap); if (err) goto out; mb->pos = 0; err = sipevent_notify(not, mb, state, reason, retry_after); if (err) goto out; out: if (err || !mbp) mem_deref(mb); else *mbp = mb; return err; }
/** * Allocate a SIP Registration client * * @param regp Pointer to allocated SIP Registration client * @param sip SIP Stack instance * @param reg_uri SIP Request URI * @param to_uri SIP To-header URI * @param from_uri SIP From-header URI * @param expires Registration interval in [seconds] * @param cuser Contact username * @param routev Optional route vector * @param routec Number of routes * @param regid Register identification * @param authh Authentication handler * @param aarg Authentication handler argument * @param aref True to ref argument * @param resph Response handler * @param arg Response handler argument * @param params Optional Contact-header parameters * @param fmt Formatted strings with extra SIP Headers * * @return 0 if success, otherwise errorcode */ int sipreg_register(struct sipreg **regp, struct sip *sip, const char *reg_uri, const char *to_uri, const char *from_uri, uint32_t expires, const char *cuser, const char *routev[], uint32_t routec, int regid, sip_auth_h *authh, void *aarg, bool aref, sip_resp_h *resph, void *arg, const char *params, const char *fmt, ...) { struct sipreg *reg; int err; if (!regp || !sip || !reg_uri || !to_uri || !from_uri || !expires || !cuser) return EINVAL; reg = mem_zalloc(sizeof(*reg), destructor); if (!reg) return ENOMEM; err = sip_dialog_alloc(®->dlg, reg_uri, to_uri, NULL, from_uri, routev, routec); if (err) goto out; err = sip_auth_alloc(®->auth, authh, aarg, aref); if (err) goto out; err = str_dup(®->cuser, cuser); if (params) err |= str_dup(®->params, params); if (err) goto out; /* Custom SIP headers */ if (fmt) { va_list ap; reg->hdrs = mbuf_alloc(256); if (!reg->hdrs) { err = ENOMEM; goto out; } va_start(ap, fmt); err = mbuf_vprintf(reg->hdrs, fmt, ap); reg->hdrs->pos = 0; va_end(ap); if (err) goto out; } reg->sip = mem_ref(sip); reg->expires = expires; reg->resph = resph ? resph : dummy_handler; reg->arg = arg; reg->regid = regid; err = request(reg, true); if (err) goto out; out: if (err) mem_deref(reg); else *regp = reg; return err; }
/** * Connect to a remote SIP useragent * * @param sessp Pointer to allocated SIP Session * @param sock SIP Session socket * @param to_uri To SIP uri * @param from_name From display name * @param from_uri From SIP uri * @param cuser Contact username or URI * @param routev Outbound route vector * @param routec Outbound route vector count * @param ctype Session content-type * @param desc Content description (e.g. SDP) * @param authh SIP Authentication handler * @param aarg Authentication handler argument * @param aref True to mem_ref() aarg * @param offerh Session offer handler * @param answerh Session answer handler * @param progrh Session progress handler * @param estabh Session established handler * @param infoh Session info handler * @param referh Session refer handler * @param closeh Session close handler * @param arg Handler argument * @param fmt Formatted strings with extra SIP Headers * * @return 0 if success, otherwise errorcode */ int sipsess_connect(struct sipsess **sessp, struct sipsess_sock *sock, const char *to_uri, const char *from_name, const char *from_uri, const char *cuser, const char *routev[], uint32_t routec, const char *ctype, struct mbuf *desc, sip_auth_h *authh, void *aarg, bool aref, sipsess_offer_h *offerh, sipsess_answer_h *answerh, sipsess_progr_h *progrh, sipsess_estab_h *estabh, sipsess_info_h *infoh, sipsess_refer_h *referh, sipsess_close_h *closeh, void *arg, const char *fmt, ...) { struct sipsess *sess; int err; if (!sessp || !sock || !to_uri || !from_uri || !cuser || !ctype) return EINVAL; err = sipsess_alloc(&sess, sock, cuser, ctype, desc, authh, aarg, aref, offerh, answerh, progrh, estabh, infoh, referh, closeh, arg); if (err) return err; /* Custom SIP headers */ if (fmt) { va_list ap; sess->hdrs = mbuf_alloc(256); if (!sess->hdrs) { err = ENOMEM; goto out; } va_start(ap, fmt); err = mbuf_vprintf(sess->hdrs, fmt, ap); sess->hdrs->pos = 0; va_end(ap); if (err) goto out; } sess->owner = true; err = sip_dialog_alloc(&sess->dlg, to_uri, to_uri, from_name, from_uri, routev, routec); if (err) goto out; hash_append(sock->ht_sess, hash_joaat_str(sip_dialog_callid(sess->dlg)), &sess->he, sess); err = invite(sess); if (err) goto out; out: if (err) mem_deref(sess); else *sessp = sess; return err; }
/** * 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; }