static void sipsess_info_handler(struct sip *sip, const struct sip_msg *msg, void *arg) { struct call *call = arg; if (msg_ctype_cmp(&msg->ctyp, "application", "dtmf-relay")) { struct pl body, sig, dur; int err; pl_set_mbuf(&body, msg->mb); err = re_regex(body.p, body.l, "Signal=[0-9]+", &sig); err |= re_regex(body.p, body.l, "Duration=[0-9]+", &dur); if (err) { (void)sip_reply(sip, msg, 400, "Bad Request"); } else { char s = pl_u32(&sig); uint32_t duration = pl_u32(&dur); if (s == 10) s = '*'; else if (s == 11) s = '#'; else s += '0'; info("received DTMF: '%c' (duration=%r)\n", s, &dur); (void)sip_reply(sip, msg, 200, "OK"); if (call->dtmfh) { tmr_start(&call->tmr_dtmf, duration, dtmfend_handler, call); call->dtmfh(call, s, call->arg); } } } #ifdef USE_VIDEO else if (msg_ctype_cmp(&msg->ctyp, "application", "media_control+xml")) { call_handle_info_req(call, msg); (void)sip_reply(sip, msg, 200, "OK"); } #endif else { (void)sip_reply(sip, msg, 488, "Not Acceptable Here"); } }
static inline int hdr_add(struct http_msg *msg, const struct pl *name, enum http_hdrid id, const char *p, ssize_t l) { struct http_hdr *hdr; 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; list_append(&msg->hdrl, &hdr->le, hdr); /* parse common headers */ switch (id) { case HTTP_HDR_CONTENT_TYPE: msg->ctype = hdr->val; break; case HTTP_HDR_CONTENT_LENGTH: msg->clen = pl_u32(&hdr->val); break; default: break; } return 0; }
static int decode_sdpparam_h263(struct videnc_state *st, const struct pl *name, const struct pl *val) { enum h263_fmt fmt = h263_fmt(name); const int mpi = pl_u32(val); if (fmt == H263_FMT_OTHER) { info("h263: unknown param '%r'\n", name); return 0; } if (mpi < 1 || mpi > 32) { info("h263: %r: MPI out of range %d\n", name, mpi); return 0; } if (st->u.h263.picszn >= ARRAY_SIZE(st->u.h263.picszv)) { info("h263: picszv overflow: %r\n", name); return 0; } st->u.h263.picszv[st->u.h263.picszn].fmt = fmt; st->u.h263.picszv[st->u.h263.picszn].mpi = mpi; ++st->u.h263.picszn; return 0; }
static uint32_t wait_term(const struct sipevent_substate *substate) { uint32_t wait; switch (substate->reason) { case SIPEVENT_DEACTIVATED: case SIPEVENT_TIMEOUT: wait = 5; break; case SIPEVENT_REJECTED: case SIPEVENT_NORESOURCE: wait = 3600; break; case SIPEVENT_PROBATION: case SIPEVENT_GIVEUP: default: wait = 300; if (pl_isset(&substate->retry_after)) wait = max(wait, pl_u32(&substate->retry_after)); break; } return wait; }
static void sipsub_notify_handler(struct sip *sip, const struct sip_msg *msg, void *arg) { struct call *call = arg; struct pl scode, reason; uint32_t sc; if (re_regex((char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb), "SIP/2.0 [0-9]+ [^\r\n]+", &scode, &reason)) { (void)sip_reply(sip, msg, 400, "Bad sipfrag"); return; } (void)sip_reply(sip, msg, 200, "OK"); sc = pl_u32(&scode); if (sc >= 300) { warning("call: transfer failed: %u %r\n", sc, &reason); call_event_handler(call, CALL_EVENT_TRANSFER_FAILED, "%u %r", sc, &reason); } else if (sc >= 200) { call_event_handler(call, CALL_EVENT_CLOSED, "Call transfered"); } }
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"); }
static void decode_param(const struct pl *name, const struct pl *val, void *arg) { struct aucodec_st *st = arg; int err; if (0 == pl_strcasecmp(name, "bitrate")) { st->bitrate = pl_u32(val) * 1000; } else if (0 == pl_strcasecmp(name, "frame-size")) { st->frame_size = pl_u32(val); if (st->frame_size & 0x1) { DEBUG_WARNING("frame-size is NOT even: %u\n", st->frame_size); } } else if (0 == pl_strcasecmp(name, "low-overhead")) { struct pl fs, bpfv; uint32_t i; st->low_overhead = true; err = re_regex(val->p, val->l, "[0-9]+/[0-9,]+", &fs, &bpfv); if (err) return; st->frame_size = pl_u32(&fs); for (i=0; i<ARRAY_SIZE(st->bpfv) && bpfv.l > 0; i++) { struct pl bpf, co; co.l = 0; if (re_regex(bpfv.p, bpfv.l, "[0-9]+[,]*", &bpf, &co)) break; pl_advance(&bpfv, bpf.l + co.l); st->bpfv[i] = pl_u32(&bpf); } st->bpfn = i; } else { DEBUG_NOTICE("unknown param: %r = %r\n", name, val); } }
static void tcp_recv_handler(struct mbuf *mb, void *arg) { struct request *request = arg; int ok; struct pl ver; struct pl code; struct pl phrase; struct pl headers; struct pl body; DEBUG_INFO("recv data[%d]\n", mbuf_get_left(mb)); if(request->state == STREAM) { request->stream_h(request, HTTP_STREAM_DATA, mb, request->arg); return; } if(request->body) { ok = mbuf_write_mem(request->body, mbuf_buf(mb), mbuf_get_left(mb)); goto clen; } ok = re_regex((const char*)mbuf_buf(mb), mbuf_get_left(mb), "HTTP/[^ \t\r\n]+ [0-9]+ [^\t\r\n]+\r\n[^]1", &ver, &code, &phrase, &headers); // XXX: check ok // XXX: check headers.l request->status = pl_u32(&code); headers.l = mbuf_get_left(mb) - (headers.p - (const char*)mbuf_buf(mb)); body.l = 0; parse_headers(request, (char*)headers.p, headers.l, &body); if(body.l) { request->body = mbuf_alloc(body.l); mbuf_write_mem(request->body, (const unsigned char*)body.p, body.l); } request->response = mem_ref(mb); clen: if(request->body && request->clen > request->body->end) return; if(request->status >= 200 || request->stream_h == NULL) { request->done_h(request, request->status, request->arg); request->state = END; mem_deref(request); return; } request->state = STREAM; request->stream_h(request, HTTP_STREAM_EST, mb, request->arg); }
static int attr_decode_rtcp(struct sdp_media *m, const struct pl *pl) { struct pl port, addr; int err = 0; if (!m) return 0; if (!re_regex(pl->p, pl->l, "[0-9]+ IN IP[46]1 [^ ]+", &port, NULL, &addr)) { (void)sa_set(&m->raddr_rtcp, &addr, pl_u32(&port)); } else if (!re_regex(pl->p, pl->l, "[0-9]+", &port)) { sa_set_port(&m->raddr_rtcp, pl_u32(&port)); } else err = EBADMSG; return err; }
static void decoder_fmtp_decode(struct audec_state *st, const char *fmtp) { struct pl mode; if (!fmtp) return; if (re_regex(fmtp, strlen(fmtp), "mode=[0-9]+", &mode)) return; set_decoder_mode(st, pl_u32(&mode)); }
static int media_decode(struct sdp_media **mp, struct sdp_session *sess, bool offer, const struct pl *pl) { struct pl name, port, proto, fmtv, fmt; struct sdp_media *m; int err; if (re_regex(pl->p, pl->l, "[a-z]+ [^ ]+ [^ ]+[^]*", &name, &port, &proto, &fmtv)) return EBADMSG; m = list_ledata(*mp ? (*mp)->le.next : sess->medial.head); if (!m) { if (!offer) return EPROTO; m = sdp_media_find(sess, &name, &proto); if (!m) { err = sdp_media_radd(&m, sess, &name, &proto); if (err) return err; } else { list_unlink(&m->le); list_append(&sess->medial, &m->le, m); } } else { if (pl_strcmp(&name, m->name)) return offer ? ENOTSUP : EPROTO; if (pl_strcmp(&proto, m->proto)) return ENOTSUP; } while (!re_regex(fmtv.p, fmtv.l, " [^ ]+", &fmt)) { pl_advance(&fmtv, fmt.p + fmt.l - fmtv.p); err = sdp_format_radd(m, &fmt); if (err) return err; } m->raddr = sess->raddr; sa_set_port(&m->raddr, pl_u32(&port)); m->rdir = sess->rdir; *mp = m; return 0; }
static void start_outbound(struct sipreg *reg, const struct sip_msg *msg) { const struct sip_hdr *flowtimer; if (!sip_msg_hdr_has_value(msg, SIP_HDR_REQUIRE, "outbound")) return; flowtimer = sip_msg_hdr(msg, SIP_HDR_FLOW_TIMER); (void)sip_keepalive_start(®->ka, reg->sip, msg, flowtimer ? pl_u32(&flowtimer->val) : 0, keepalive_handler, reg); }
uint32_t vp8_max_fs(const char *fmtp) { struct pl pl, max_fs; if (!fmtp) return 0; pl_set_str(&pl, fmtp); if (fmt_param_get(&pl, "max-fs", &max_fs)) return pl_u32(&max_fs); return 0; }
static uint32_t packetization_mode(const char *fmtp) { struct pl pl, mode; if (!fmtp) return 0; pl_set_str(&pl, fmtp); if (fmt_param_get(&pl, "packetization-mode", &mode)) return pl_u32(&mode); return 0; }
int conf_get_range(const struct conf *conf, const char *name, struct range *rng) { struct pl r, min, max; uint32_t v; int err; err = conf_get(conf, name, &r); if (err) return err; err = re_regex(r.p, r.l, "[0-9]+-[0-9]+", &min, &max); if (err) { /* fallback to non-range numeric value */ err = conf_get_u32(conf, name, &v); if (err) { warning("conf: %s: could not parse range: (%r)\n", name, &r); return err; } rng->min = rng->max = v; return err; } rng->min = pl_u32(&min); rng->max = pl_u32(&max); if (rng->min > rng->max) { warning("conf: %s: invalid range (%u - %u)\n", name, rng->min, rng->max); return EINVAL; } return 0; }
static int bandwidth_decode(int32_t *bwv, const struct pl *pl) { struct pl type, bw; if (re_regex(pl->p, pl->l, "[^:]+:[0-9]+", &type, &bw)) return EBADMSG; if (!pl_strcmp(&type, "CT")) bwv[SDP_BANDWIDTH_CT] = pl_u32(&bw); else if (!pl_strcmp(&type, "AS")) bwv[SDP_BANDWIDTH_AS] = pl_u32(&bw); else if (!pl_strcmp(&type, "RS")) bwv[SDP_BANDWIDTH_RS] = pl_u32(&bw); else if (!pl_strcmp(&type, "RR")) bwv[SDP_BANDWIDTH_RR] = pl_u32(&bw); else if (!pl_strcmp(&type, "TIAS")) bwv[SDP_BANDWIDTH_TIAS] = pl_u32(&bw); return 0; }
static unsigned int str_ver(char *version) { int shift = 24; unsigned int ret = 0; struct pl ver; char *part = version; while(*version) { if(*version == '.') { ver.p = part; ver.l = version - part; ret |= pl_u32(&ver) << shift; shift -= 8; part = version+1; } version ++; } ver.p = part; ver.l = version - part; ret |= pl_u32(&ver) << shift; part = version+1; return ret; };
/* decode sdpparameter for h264 */ static void param_handler(const struct pl *name, const struct pl *val, void *arg) { struct videnc_state *st = arg; if (0 == pl_strcasecmp(name, "packetization-mode")) { st->h264.packetization_mode = pl_u32(val); if (st->h264.packetization_mode != 0) { warning("gst_video: illegal packetization-mode %u\n", st->h264.packetization_mode); return; } } else if (0 == pl_strcasecmp(name, "profile-level-id")) { struct pl prof = *val; if (prof.l != 6) { warning("gst_video: invalid profile-level-id (%r)\n", val); return; } prof.l = 2; st->h264.profile_idc = pl_x32(&prof); prof.p += 2; st->h264.profile_iop = pl_x32(&prof); prof.p += 2; st->h264.level_idc = pl_x32(&prof); } else if (0 == pl_strcasecmp(name, "max-fs")) { st->h264.max_fs = pl_u32(val); } else if (0 == pl_strcasecmp(name, "max-smbps")) { st->h264.max_smbps = pl_u32(val); } return; }
/** * Get the numeric value of a configuration item * * @param conf Configuration object * @param name Name of config item key * @param num Returned numeric value of config item, if present * * @return 0 if success, otherwise errorcode */ int conf_get_u32(const struct conf *conf, const char *name, uint32_t *num) { struct pl pl; int err; if (!conf || !name || !num) return EINVAL; err = conf_get(conf, name, &pl); if (err) return err; *num = pl_u32(&pl); return 0; }
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; }
/** * 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); }
void hdr_add(struct request *req, enum http_hdr_id id, struct pl *name, struct pl *val) { struct http_hdr *hdr; switch(id) { case HTTP_CONTENT_LENGTH: req->clen = pl_u32(val); break; case HTTP_WWW_AUTH: req->www_auth.l = val->l; req->www_auth.p = val->p; break; default: ;; } hdr = mem_zalloc(sizeof(struct http_hdr), hdr_destruct); hdr->name.l = name->l; hdr->name.p = name->p; hdr->val.l = val->l; hdr->val.p = val->p; hash_append(req->hdrht, id, &hdr->he, hdr); }
int ice_cand_attr_decode(struct ice_cand_attr *cand, const char *val) { struct pl pl_fnd, pl_compid, pl_transp, pl_prio, pl_addr, pl_port; struct pl pl_type, pl_raddr, pl_rport, pl_opt = PL_INIT; size_t len; char type[8]; int err; if (!cand || !val) return EINVAL; memset(cand, 0, sizeof(*cand)); len = str_len(val); err = re_regex(val, len, "[^ ]+ [0-9]+ [a-z]+ [0-9]+ [^ ]+ [0-9]+ typ [a-z]+" "[^]*", &pl_fnd, &pl_compid, &pl_transp, &pl_prio, &pl_addr, &pl_port, &pl_type, &pl_opt); if (err) return err; (void)pl_strcpy(&pl_fnd, cand->foundation, sizeof(cand->foundation)); if (0 == pl_strcasecmp(&pl_transp, "UDP")) cand->proto = IPPROTO_UDP; else if (0 == pl_strcasecmp(&pl_transp, "TCP")) cand->proto = IPPROTO_TCP; else cand->proto = 0; err = sa_set(&cand->addr, &pl_addr, pl_u32(&pl_port)); if (err) return err; cand->compid = pl_u32(&pl_compid); cand->prio = pl_u32(&pl_prio); (void)pl_strcpy(&pl_type, type, sizeof(type)); cand->type = ice_cand_name2type(type); /* optional */ if (0 == re_regex(pl_opt.p, pl_opt.l, "raddr [^ ]+ rport [0-9]+", &pl_raddr, &pl_rport)) { err = sa_set(&cand->rel_addr, &pl_raddr, pl_u32(&pl_rport)); if (err) return err; } if (cand->proto == IPPROTO_TCP) { struct pl tcptype; err = re_regex(pl_opt.p, pl_opt.l, "tcptype [^ ]+", &tcptype); if (err) return err; cand->tcptype = ice_tcptype_resolve(&tcptype); } return 0; }
/** * Decode a SIP message * * @param msgp Pointer to allocated SIP Message * @param mb Buffer containing SIP Message * * @return 0 if success, otherwise errorcode */ int sip_msg_decode(struct sip_msg **msgp, struct mbuf *mb) { struct pl x, y, z, e, name; const char *p, *v, *cv; struct sip_msg *msg; bool comsep, quote; enum sip_hdrid id = SIP_HDR_NONE; uint32_t ws, lf; size_t l; int err; if (!msgp || !mb) return EINVAL; p = (const char *)mbuf_buf(mb); l = mbuf_get_left(mb); if (re_regex(p, l, "[^ \t\r\n]+ [^ \t\r\n]+ [^\r\n]*[\r]*[\n]1", &x, &y, &z, NULL, &e) || x.p != (char *)mbuf_buf(mb)) return (l > STARTLINE_MAX) ? EBADMSG : ENODATA; msg = mem_zalloc(sizeof(*msg), destructor); if (!msg) return ENOMEM; err = hash_alloc(&msg->hdrht, HDR_HASH_SIZE); if (err) goto out; msg->tag = rand_u64(); msg->mb = mem_ref(mb); msg->req = (0 == pl_strcmp(&z, "SIP/2.0")); if (msg->req) { msg->met = x; msg->ruri = y; msg->ver = z; if (uri_decode(&msg->uri, &y)) { err = EBADMSG; goto out; } } else { msg->ver = x; msg->scode = pl_u32(&y); msg->reason = z; if (!msg->scode) { err = EBADMSG; goto out; } } l -= e.p + e.l - p; p = e.p + e.l; name.p = v = cv = NULL; name.l = ws = lf = 0; comsep = false; quote = false; for (; l > 0; p++, l--) { switch (*p) { case ' ': case '\t': lf = 0; /* folding */ ++ws; break; case '\r': ++ws; break; case '\n': ++ws; if (!lf++) break; ++p; --l; /* eoh */ /*@fallthrough@*/ default: if (lf || (*p == ',' && comsep && !quote)) { if (!name.l) { err = EBADMSG; goto out; } err = hdr_add(msg, &name, id, cv ? cv : p, cv ? p - cv - ws : 0, true, cv == v && lf); if (err) goto out; if (!lf) { /* comma separated */ cv = NULL; break; } if (cv != v) { err = hdr_add(msg, &name, id, v ? v : p, v ? p - v - ws : 0, false, true); if (err) goto out; } if (lf > 1) { /* eoh */ err = 0; goto out; } comsep = false; name.p = NULL; cv = v = NULL; lf = 0; } if (!name.p) { name.p = p; name.l = 0; ws = 0; } if (!name.l) { if (*p != ':') { ws = 0; break; } name.l = MAX((int)(p - name.p - ws), 0); if (!name.l) { err = EBADMSG; goto out; } id = hdr_hash(&name); comsep = hdr_comma_separated(id); break; } if (!cv) { quote = false; cv = p; } if (!v) { v = p; } if (*p == '"') quote = !quote; ws = 0; break; } } err = ENODATA; out: if (err) mem_deref(msg); else { *msgp = msg; mb->pos = mb->end - l; } return err; }
static int cand_decode(struct icem *icem, const char *val) { struct pl foundation, compid, transp, prio, addr, port, cand_type; struct pl extra = pl_null; struct sa caddr, rel_addr; char type[8]; uint8_t cid; int err; sa_init(&rel_addr, AF_INET); err = re_regex(val, strlen(val), "[^ ]+ [0-9]+ [^ ]+ [0-9]+ [^ ]+ [0-9]+ typ [a-z]+[^]*", &foundation, &compid, &transp, &prio, &addr, &port, &cand_type, &extra); if (err) return err; if (ICE_TRANSP_NONE == transp_resolve(&transp)) { DEBUG_NOTICE("<%s> ignoring candidate with" " unknown transport=%r (%r:%r)\n", icem->name, &transp, &cand_type, &addr); return 0; } if (pl_isset(&extra)) { struct pl name, value; /* Loop through " SP attr SP value" pairs */ while (!re_regex(extra.p, extra.l, " [^ ]+ [^ ]+", &name, &value)) { pl_advance(&extra, value.p + value.l - extra.p); if (0 == pl_strcasecmp(&name, rel_addr_str)) { err = sa_set(&rel_addr, &value, sa_port(&rel_addr)); if (err) break; } else if (0 == pl_strcasecmp(&name, rel_port_str)) { sa_set_port(&rel_addr, pl_u32(&value)); } } } err = sa_set(&caddr, &addr, pl_u32(&port)); if (err) return err; cid = pl_u32(&compid); /* add only if not exist */ if (icem_cand_find(&icem->rcandl, cid, &caddr)) return 0; (void)pl_strcpy(&cand_type, type, sizeof(type)); return icem_rcand_add(icem, ice_cand_name2type(type), cid, pl_u32(&prio), &caddr, &rel_addr, &foundation); }
static void response_handler(int err, const struct sip_msg *msg, void *arg) { const struct sip_hdr *minexp; struct sipreg *reg = arg; reg->wait = failwait(reg->failc + 1); if (err || sip_request_loops(®->ls, msg->scode)) { reg->failc++; goto out; } if (msg->scode < 200) { return; } else if (msg->scode < 300) { reg->registered = true; reg->wait = reg->expires; sip_msg_hdr_apply(msg, true, SIP_HDR_CONTACT, contact_handler, reg); reg->wait *= 900; reg->failc = 0; if (reg->regid > 0 && !reg->terminated && !reg->ka) start_outbound(reg, msg); } else { if (reg->terminated && !reg->registered) goto out; switch (msg->scode) { case 401: case 407: err = sip_auth_authenticate(reg->auth, msg); if (err) { err = (err == EAUTH) ? 0 : err; break; } err = request(reg, false); if (err) break; return; case 403: sip_auth_reset(reg->auth); break; case 423: minexp = sip_msg_hdr(msg, SIP_HDR_MIN_EXPIRES); if (!minexp || !pl_u32(&minexp->val) || !reg->expires) break; reg->expires = pl_u32(&minexp->val); err = request(reg, false); if (err) break; return; } ++reg->failc; } out: if (!reg->expires) { mem_deref(reg); } else if (reg->terminated) { if (!reg->registered || request(reg, true)) mem_deref(reg); } else { tmr_start(®->tmr, reg->wait, tmr_handler, reg); reg->resph(err, msg, reg->arg); } }
static int decode_param(struct auenc_state *st, const struct pl *name, const struct pl *val) { int ret; /* mode: List supported Speex decoding modes. The valid modes are different for narrowband and wideband, and are defined as follows: {1,2,3,4,5,6,7,8,any} for narrowband {0,1,2,3,4,5,6,7,8,9,10,any} for wideband and ultra-wideband */ if (0 == pl_strcasecmp(name, "mode")) { struct pl v; int mode; /* parameter is quoted */ if (re_regex(val->p, val->l, "\"[^\"]+\"", &v)) v = *val; if (0 == pl_strcasecmp(&v, "any")) return 0; mode = pl_u32(&v); ret = speex_encoder_ctl(st->enc, SPEEX_SET_MODE, &mode); if (ret) { warning("speex: SPEEX_SET_MODE: ret=%d\n", ret); } } /* vbr: variable bit rate - either 'on' 'off' or 'vad' */ else if (0 == pl_strcasecmp(name, "vbr")) { int vbr = 0, vad = 0; if (0 == pl_strcasecmp(val, "on")) vbr = 1; else if (0 == pl_strcasecmp(val, "off")) vbr = 0; else if (0 == pl_strcasecmp(val, "vad")) vad = 1; else { warning("speex: invalid vbr value %r\n", val); } debug("speex: setting VBR=%d VAD=%d\n", vbr, vad); ret = speex_encoder_ctl(st->enc, SPEEX_SET_VBR, &vbr); if (ret) { warning("speex: SPEEX_SET_VBR: ret=%d\n", ret); } ret = speex_encoder_ctl(st->enc, SPEEX_SET_VAD, &vad); if (ret) { warning("speex: SPEEX_SET_VAD: ret=%d\n", ret); } } else if (0 == pl_strcasecmp(name, "cng")) { int dtx = 0; if (0 == pl_strcasecmp(val, "on")) dtx = 0; else if (0 == pl_strcasecmp(val, "off")) dtx = 1; ret = speex_encoder_ctl(st->enc, SPEEX_SET_DTX, &dtx); if (ret) { warning("speex: SPEEX_SET_DTX: ret=%d\n", ret); } } else { debug("speex: unknown Speex param: %r=%r\n", name, val); } return 0; }
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 } } }
/** * Decode a HTTP message * * @param msgp Pointer to allocated HTTP Message * @param mb Buffer containing HTTP Message * @param req True for request, false for response * * @return 0 if success, otherwise errorcode */ int http_msg_decode(struct http_msg **msgp, struct mbuf *mb, bool req) { struct pl b, s, e, name, scode; const char *p, *cv; struct http_msg *msg; bool comsep, quote; enum http_hdrid id = HTTP_HDR_NONE; uint32_t ws, lf; size_t l; int err; if (!msgp || !mb) return EINVAL; p = (const char *)mbuf_buf(mb); l = mbuf_get_left(mb); if (re_regex(p, l, "[\r\n]*[^\r\n]+[\r]*[\n]1", &b, &s, NULL, &e)) return (l > STARTLINE_MAX) ? EBADMSG : ENODATA; msg = mem_zalloc(sizeof(*msg), destructor); if (!msg) return ENOMEM; msg->mb = mem_ref(mb); if (req) { if (re_regex(s.p, s.l, "[a-z]+ [^? ]+[^ ]* HTTP/[0-9.]+", &msg->met, &msg->path, &msg->prm, &msg->ver) || msg->met.p != s.p) { err = EBADMSG; goto out; } } else { if (re_regex(s.p, s.l, "HTTP/[0-9.]+ [0-9]+ [^]*", &msg->ver, &scode, &msg->reason) || msg->ver.p != s.p + 5) { err = EBADMSG; goto out; } msg->scode = pl_u32(&scode); } l -= e.p + e.l - p; p = e.p + e.l; name.p = cv = NULL; name.l = ws = lf = 0; comsep = false; quote = false; for (; l > 0; p++, l--) { switch (*p) { case ' ': case '\t': lf = 0; /* folding */ ++ws; break; case '\r': ++ws; break; case '\n': ++ws; if (!name.p) { ++p; --l; /* no headers */ err = 0; goto out; } if (!lf++) break; ++p; --l; /* eoh */ /*@fallthrough@*/ default: if (lf || (*p == ',' && comsep && !quote)) { if (!name.l) { err = EBADMSG; goto out; } err = hdr_add(msg, &name, id, cv ? cv : p, cv ? p - cv - ws : 0); if (err) goto out; if (!lf) { /* comma separated */ cv = NULL; break; } if (lf > 1) { /* eoh */ err = 0; goto out; } comsep = false; name.p = NULL; cv = NULL; lf = 0; } if (!name.p) { name.p = p; name.l = 0; ws = 0; } if (!name.l) { if (*p != ':') { ws = 0; break; } name.l = MAX((int)(p - name.p - ws), 0); if (!name.l) { err = EBADMSG; goto out; } id = hdr_hash(&name); comsep = hdr_comma_separated(id); break; } if (!cv) { quote = false; cv = p; } if (*p == '"') quote = !quote; ws = 0; break; } } err = ENODATA; out: if (err) mem_deref(msg); else { *msgp = msg; mb->pos = mb->end - l; } 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; }