static int send_handler(enum sip_transp tp, const struct sa *src, const struct sa *dst, struct mbuf *mb, void *arg) { struct sipreg *reg = arg; int err; (void)dst; if (reg->expires > 0) { reg->laddr = *src; reg->tp = tp; } err = mbuf_printf(mb, "Contact: <sip:%s@%J%s>;expires=%u%s%s", reg->cuser, ®->laddr, sip_transp_param(reg->tp), reg->expires, reg->params ? ";" : "", reg->params ? reg->params : ""); if (reg->regid > 0) err |= mbuf_printf(mb, ";reg-id=%d", reg->regid); err |= mbuf_printf(mb, "\r\n"); return err; }
static void stats_handler(struct mbuf *mb) { (void)mbuf_printf(mb, "allocs_cur %u\n", turnd.allocc_cur); (void)mbuf_printf(mb, "allocs_tot %llu\n", turnd.allocc_tot); (void)mbuf_printf(mb, "bytes_tx %llu\n", turnd.bytec_tx); (void)mbuf_printf(mb, "bytes_rx %llu\n", turnd.bytec_rx); (void)mbuf_printf(mb, "bytes_tot %llu\n", turnd.bytec_tx + turnd.bytec_rx); }
void chan_status(const struct chanlist *cl, struct mbuf *mb) { if (!cl || !mb) return; (void)mbuf_printf(mb, " channels: "); (void)hash_apply(cl->ht_numb, status_handler, mb); (void)mbuf_printf(mb, "\n"); }
static void tcp_estab_handler(void *arg) { DEBUG_INFO("connection established\n"); int ok; struct request * request = arg; struct mbuf *mb; char CN[256]; if(request->secure) { ok = tls_verify_cert(request->ssl, CN, sizeof(CN)); if(ok!=0) goto fail; DEBUG_INFO("https CN %s\n", CN); ok = strcmp(request->host, CN); if(ok!=0) goto fail; } mb = mbuf_alloc(1024); mbuf_printf(mb, "%s %s HTTP/1.1\r\n", request->meth, request->path); mbuf_printf(mb, "Host: %s\r\n", request->host); write_auth(request, mb); mbuf_write_str(mb, "Connection: close\r\n"); hash_apply(request->hdrht, hdr_write, mb); hash_flush(request->hdrht); if(request->post) { request->post->pos = 0; mbuf_printf(mb, "Content-Length: %d\r\n", mbuf_get_left(request->post)); if(request->form) mbuf_printf(mb, "Content-Type: " "application/x-www-form-urlencoded\r\n"); mbuf_printf(mb, "\r\n"); mbuf_write_mem(mb, mbuf_buf(request->post), mbuf_get_left(request->post)); } else { mbuf_write_str(mb, "\r\n"); } mb->pos = 0; tcp_send(request->tcp, mb); mem_deref(mb); return; fail: DEBUG_WARNING("ssl fail %p %d\n", request->app->tls, ok); }
/** * Connect an outgoing call to a given SIP uri * * @param ua User-Agent * @param callp Optional pointer to allocated call object * @param from_uri Optional From uri, or NULL for default AOR * @param uri SIP uri to connect to * @param params Optional URI parameters * @param vmode Video mode * * @return 0 if success, otherwise errorcode */ int ua_connect(struct ua *ua, struct call **callp, const char *from_uri, const char *uri, const char *params, enum vidmode vmode) { struct call *call = NULL; struct mbuf *dialbuf; struct pl pl; int err = 0; if (!ua || !str_isset(uri)) return EINVAL; dialbuf = mbuf_alloc(64); if (!dialbuf) return ENOMEM; if (params) err |= mbuf_printf(dialbuf, "<"); err |= uri_complete(ua, dialbuf, uri); if (params) { err |= mbuf_printf(dialbuf, ";%s", params); } /* Append any optional URI parameters */ err |= mbuf_write_pl(dialbuf, &ua->acc->luri.params); if (params) err |= mbuf_printf(dialbuf, ">"); if (err) goto out; err = ua_call_alloc(&call, ua, vmode, NULL, NULL, from_uri); if (err) goto out; pl.p = (char *)dialbuf->buf; pl.l = dialbuf->end; err = call_connect(call, &pl); if (err) mem_deref(call); else if (callp) *callp = call; out: mem_deref(dialbuf); return err; }
void write_auth(struct request *req, struct mbuf *mb) { int err; struct realm *realm; uint8_t digest[MD5_SIZE]; uint64_t cnonce; if(!req->auth) return; realm = req->auth; cnonce = rand_u64(); err = mkdigest(digest, realm, req->meth, req->path, cnonce); err |= mbuf_write_str(mb, "Authorization: "); err |= mbuf_printf(mb, "Digest username=\"%s\"", realm->user); err |= mbuf_printf(mb, ", realm=\"%s\"", realm->realm); err |= mbuf_printf(mb, ", nonce=\"%s\"", realm->nonce); err |= mbuf_printf(mb, ", uri=\"%s\"", req->path); err |= mbuf_printf(mb, ", response=\"%w\"", digest, sizeof(digest)); if (realm->opaque) err |= mbuf_printf(mb, ", opaque=\"%s\"", realm->opaque); if (realm->qop) { err |= mbuf_printf(mb, ", cnonce=\"%016llx\"", cnonce); err |= mbuf_write_str(mb, ", qop=auth"); err |= mbuf_printf(mb, ", nc=%08x", realm->nc); } ++realm->nc; err |= mbuf_write_str(mb, "\r\n"); }
int sip_auth_encode(struct mbuf *mb, struct sip_auth *auth, const char *met, const char *uri) { struct le *le; int err = 0; if (!mb || !auth || !met || !uri) return EINVAL; for (le = auth->realml.head; le; le = le->next) { const uint64_t cnonce = rand_u64(); struct realm *realm = le->data; uint8_t digest[MD5_SIZE]; err = mkdigest(digest, realm, met, uri, cnonce); if (err) break; switch (realm->hdr) { case SIP_HDR_WWW_AUTHENTICATE: err = mbuf_write_str(mb, "Authorization: "); break; case SIP_HDR_PROXY_AUTHENTICATE: err = mbuf_write_str(mb, "Proxy-Authorization: "); break; default: continue; } err |= mbuf_printf(mb, "Digest username=\"%s\"", realm->user); err |= mbuf_printf(mb, ", realm=\"%s\"", realm->realm); err |= mbuf_printf(mb, ", nonce=\"%s\"", realm->nonce); err |= mbuf_printf(mb, ", uri=\"%s\"", uri); err |= mbuf_printf(mb, ", response=\"%w\"", digest, sizeof(digest)); if (realm->opaque) err |= mbuf_printf(mb, ", opaque=\"%s\"", realm->opaque); if (realm->qop) { err |= mbuf_printf(mb, ", cnonce=\"%016llx\"", cnonce); err |= mbuf_write_str(mb, ", qop=auth"); err |= mbuf_printf(mb, ", nc=%08x", realm->nc); } ++realm->nc; err |= mbuf_write_str(mb, "\r\n"); if (err) break; } return err; }
int sip_dialog_encode(struct mbuf *mb, struct sip_dialog *dlg, uint32_t cseq, const char *met) { int err = 0; if (!mb || !dlg || !met) return EINVAL; err |= mbuf_write_mem(mb, mbuf_buf(dlg->mb), mbuf_get_left(dlg->mb)); err |= mbuf_printf(mb, "Call-ID: %s\r\n", dlg->callid); err |= mbuf_printf(mb, "CSeq: %u %s\r\n", strcmp(met, "ACK") ? dlg->lseq++ : cseq, met); return err; }
static void status_handler(struct mbuf *mb) { (void)mbuf_printf(mb, "TURN relay=%j relay6=%j (err %llu/%llu)\n", &turnd.rel_addr, &turnd.rel_addr6, turnd.errc_tx, turnd.errc_rx); (void)hash_apply(turnd.ht_alloc, allocation_status, mb); }
static void httpd_handler(const struct pl *uri, struct mbuf *mb) { struct pl cmd, params, r; uint32_t refresh = 0; if (re_regex(uri->p, uri->l, "/[^?]*[^]*", &cmd, ¶ms)) return; if (!re_regex(params.p, params.l, "[?&]1r=[0-9]+", NULL, &r)) refresh = pl_u32(&r); mbuf_write_str(mb, "<html>\n<head>\n"); mbuf_write_str(mb, " <title>Restund Server Status</title>\n"); if (refresh) mbuf_printf(mb, " <meta http-equiv=\"refresh\" content=\"%u\">\n", refresh); mbuf_write_str(mb, "</head>\n<body>\n"); mbuf_write_str(mb, "<h2>Restund Server Status</h2>\n"); server_info(mb); mbuf_write_str(mb, "<hr size=\"1\"/>\n<pre>\n"); restund_cmd(&cmd, mb); mbuf_write_str(mb, "</pre>\n</body>\n</html>\n"); }
int call_notify_sipfrag(struct call *call, uint16_t scode, const char *reason, ...) { struct mbuf *mb; va_list ap; int err; if (!call) return EINVAL; mb = mbuf_alloc(512); if (!mb) return ENOMEM; va_start(ap, reason); (void)mbuf_printf(mb, "SIP/2.0 %u %v\n", scode, reason, &ap); va_end(ap); mb->pos = 0; if (scode >= 200) { err = sipevent_notify(call->not, mb, SIPEVENT_TERMINATED, SIPEVENT_NORESOURCE, 0); call->not = mem_deref(call->not); } else { err = sipevent_notify(call->not, mb, SIPEVENT_ACTIVE, SIPEVENT_NORESOURCE, 0); } mem_deref(mb); return err; }
static void estab_handler(void *arg) { struct rst *rst = arg; struct mbuf *mb; int err; re_printf("rst: connection established\n"); mb = mbuf_alloc(512); if (!mb) { err = ENOMEM; goto out; } err = mbuf_printf(mb, "GET %s HTTP/1.0\r\n" "Icy-MetaData: 1\r\n" "\r\n", rst->path); if (err) goto out; mb->pos = 0; err = tcp_send(rst->tc, mb); if (err) goto out; out: if (err) { re_printf("rst: error sending HTTP request: %m\n", err); } mem_deref(mb); }
void http_post(struct request *request, char* key, char* val) { struct mbuf* mb; char *cur; int sz; memcpy(&request->meth, "POST", 5); if(request->post) { mb = request->post; mbuf_printf(mb, "&"); } else { mb = mbuf_alloc(1024); } if(key) { mbuf_printf(mb, "%s=", key); sz = 0; cur = val; while(*val) { switch(*val) { case '+': case '&': mbuf_write_mem(mb, (const uint8_t *)cur, sz); sz = 0; mbuf_printf(mb, "%%%02X", *val); val ++; cur = val; break; default: sz++; val++; } } if(cur != val) { mbuf_write_mem(mb, (const uint8_t *)cur, sz); } request->form = 1; } else { mbuf_printf(mb, "%s", val); } request->post = mb; }
static int request(struct sip_request *req, enum sip_transp tp, const struct sa *dst) { struct mbuf *mb = NULL; char *branch = NULL; int err = ENOMEM; struct sa laddr; req->provrecv = false; branch = mem_alloc(24, NULL); mb = mbuf_alloc(1024); if (!branch || !mb) goto out; (void)re_snprintf(branch, 24, "z9hG4bK%016llx", rand_u64()); err = sip_transp_laddr(req->sip, &laddr, tp, dst); if (err) goto out; err = mbuf_printf(mb, "%s %s SIP/2.0\r\n", req->met, req->uri); err |= mbuf_printf(mb, "Via: SIP/2.0/%s %J;branch=%s;rport\r\n", sip_transp_name(tp), &laddr, branch); err |= req->sendh ? req->sendh(tp, &laddr, dst, mb, req->arg) : 0; err |= mbuf_write_mem(mb, mbuf_buf(req->mb), mbuf_get_left(req->mb)); if (err) goto out; mb->pos = 0; if (!req->stateful) err = sip_send(req->sip, NULL, tp, dst, mb); else err = sip_ctrans_request(&req->ct, req->sip, tp, dst, req->met, branch, mb, response_handler, req); if (err) goto out; out: mem_deref(branch); mem_deref(mb); return err; }
bool hdr_write(struct le *le, void *arg) { struct http_hdr *hdr = le->data; struct mbuf *mb = arg; mbuf_printf(mb, "%r: %r\r\n", &hdr->name, &hdr->val); return false; }
static bool status_handler(struct le *le, void *arg) { struct chan *chan = le->data; struct mbuf *mb = arg; (void)mbuf_printf(mb, " (0x%x %J %is)", chan->numb, &chan->peer, chan->expires - time(NULL)); return false; }
static int uri_complete(struct ua *ua, struct mbuf *buf, const char *uri) { size_t len; int err = 0; /* Skip initial whitespace */ while (isspace(*uri)) ++uri; len = str_len(uri); /* Append sip: scheme if missing */ if (0 != re_regex(uri, len, "sip:")) err |= mbuf_printf(buf, "sip:"); err |= mbuf_write_str(buf, uri); /* Append domain if missing */ if (0 != re_regex(uri, len, "[^@]+@[^]+", NULL, NULL)) { #if HAVE_INET6 if (AF_INET6 == ua->acc->luri.af) err |= mbuf_printf(buf, "@[%r]", &ua->acc->luri.host); else #endif err |= mbuf_printf(buf, "@%r", &ua->acc->luri.host); /* Also append port if specified and not 5060 */ switch (ua->acc->luri.port) { case 0: case SIP_PORT: break; default: err |= mbuf_printf(buf, ":%u", ua->acc->luri.port); break; } } return err; }
static int h263_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, bool offer, void *arg) { (void)offer; (void)arg; if (!mb || !fmt) return 0; return mbuf_printf(mb, "a=fmtp:%s CIF=1;CIF4=1\r\n", fmt->id); }
static int mpg4_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, bool offer, void *arg) { (void)offer; (void)arg; if (!mb || !fmt) return 0; return mbuf_printf(mb, "a=fmtp:%s profile-level-id=3\r\n", fmt->id); }
static int send_handler(enum sip_transp tp, const struct sa *src, const struct sa *dst, struct mbuf *mb, void *arg) { struct sip_contact contact; struct sipsess *sess = arg; (void)dst; sip_contact_set(&contact, sess->cuser, src, tp); return mbuf_printf(mb, "%H", sip_contact_print, &contact); }
int vie_rtx_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, bool offer, void *data) { const struct vidcodec *vc = (const struct vidcodec *)data; int err = 0; (void)vc; err |= mbuf_printf(mb, "a=fmtp:%s apt=100\r\n", fmt->id); return err; }
int vp8_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, bool offer, void *arg) { const struct vp8_vidcodec *vp8 = arg; (void)offer; if (!mb || !fmt || !vp8 || !vp8->max_fs) return 0; return mbuf_printf(mb, "a=fmtp:%s max-fs=%u\r\n", fmt->id, vp8->max_fs); }
int amr_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, bool offer, void *arg) { const struct aucodec *ac = arg; (void)offer; if (!mb || !fmt || !ac) return 0; return mbuf_printf(mb, "a=fmtp:%s octet-align=1\r\n", fmt->id); }
int vie_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, bool offer, void *data) { const struct vidcodec *vc = (const struct vidcodec *)data; int err = 0; (void)vc; err |= mbuf_printf(mb, "a=rtcp-fb:%s ccm fir\r\n", fmt->id); err |= mbuf_printf(mb, "a=rtcp-fb:%s nack\r\n", fmt->id); err |= mbuf_printf(mb, "a=rtcp-fb:%s nack pli\r\n", fmt->id); #if USE_REMB /* NOTE: REMB is not necessary */ err |= mbuf_printf(mb, "a=rtcp-fb:%s goog-remb\r\n", fmt->id); #endif err |= mbuf_printf(mb, "a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n"); #if USE_RTP_ROTATION err |= mbuf_printf(mb, "a=extmap:4 urn:3gpp:video-orientation\r\n"); #endif return err; }
static void server_info(struct mbuf *mb) { const uint32_t uptime = (uint32_t)(time(NULL) - stg.start); mbuf_write_str(mb, "<table>\n"); mbuf_write_str(mb, " <tr><td>Version:</td><td>" VERSION "</td></tr>\n"); mbuf_write_str(mb, " <tr><td>Built:</td><td>" __DATE__ " " __TIME__ "</td></tr>\n"); mbuf_printf(mb, " <tr><td>Uptime:</td><td>%H</td></tr>\n", fmt_human_time, &uptime); mbuf_write_str(mb, "</table>\n"); }
static bool record_route_handler(const struct sip_hdr *hdr, const struct sip_msg *msg, void *arg) { struct route_enc *renc = arg; (void)msg; if (mbuf_printf(renc->mb, "Route: %r\r\n", &hdr->val)) return true; if (!renc->end) renc->end = renc->mb->pos - 2; return false; }
/** * 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; }
static int opus_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, bool offer, void *arg) { bool mirror; (void)arg; (void)offer; if (!mb || !fmt) return 0; mirror = !offer && str_isset(fmtp_mirror); return mbuf_printf(mb, "a=fmtp:%s %s\r\n", fmt->id, mirror ? fmtp_mirror : fmtp); }
static int h264_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, bool offer, void *arg) { struct vidcodec *vc = arg; const uint8_t profile_idc = 0x42; /* baseline profile */ const uint8_t profile_iop = 0x80; (void)offer; if (!mb || !fmt || !vc) return 0; return mbuf_printf(mb, "a=fmtp:%s" " packetization-mode=0" ";profile-level-id=%02x%02x%02x" "\r\n", fmt->id, profile_idc, profile_iop, h264_level_idc); }
static bool allocation_status(struct le *le, void *arg) { const uint32_t bsize = hash_bsize(turnd.ht_alloc); struct allocation *al = le->data; struct mbuf *mb = arg; (void)mbuf_printf(mb, "- %04u %s/%J/%J - %J \"%s\" %us (drop %llu/%llu)\n", sa_hash(&al->cli_addr, SA_ALL) & (bsize - 1), net_proto2name(al->proto), &al->cli_addr, &al->srv_addr, &al->rel_addr, al->username, (uint32_t)tmr_get_expire(&al->tmr) / 1000, al->dropc_tx, al->dropc_rx); perm_status(al->perms, mb); chan_status(al->chans, mb); return false; }