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; }
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); }
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"); }
TEST(chunk, decode_message) { struct mbuf *mb_chunked = mbuf_alloc(1024); struct mbuf *mb_data = mbuf_alloc(1024); int err = 0; ASSERT_TRUE(mb_chunked != NULL); ASSERT_TRUE(mb_data != NULL); mbuf_write_str(mb_chunked, encoded_data); mb_chunked->pos = 0; /* decode all chunks */ for (int i=0; i<16; i++) { uint8_t *p; size_t n; err = chunk_decode(&p, &n, mb_chunked); if (err) break; if (n == 0) break; err = mbuf_write_mem(mb_data, p, n); if (err) break; } ASSERT_EQ(str_len(decoded_data), mb_data->end); ASSERT_TRUE(0 == memcmp(decoded_data, mb_data->buf, mb_data->end)); mem_deref(mb_chunked); mem_deref(mb_data); }
static int output_handler(const char *str) { struct mbuf *mb; int err = 0; if (!str) return EINVAL; mb = mbuf_alloc(256); if (!mb) return ENOMEM; mbuf_write_str(mb, str); if (sa_isset(&cons->udp_peer, SA_ALL)) { mb->pos = 0; err |= udp_send(cons->us, &cons->udp_peer, mb); } if (cons->tc) { mb->pos = 0; err |= tcp_send(cons->tc, mb); } mem_deref(mb); return err; }
/** * 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; }
/** * Test parsing of various SDP messages from various vendors */ int test_sdp_parse(void) { struct sdp_session *sess = NULL; struct sdp_media *audio; struct mbuf *mb; struct sa laddr; uint32_t i; int err; mb = mbuf_alloc(2048); if (!mb) return ENOMEM; sa_init(&laddr, AF_INET); for (i=0; i<ARRAY_SIZE(msgs); i++) { sess = mem_deref(sess); err = sdp_session_alloc(&sess, &laddr); if (err) goto out; err = sdp_media_add(&audio, sess, sdp_media_audio, 5004, sdp_proto_rtpavp); if (err) goto out; err = sdp_format_add(NULL, audio, false, ref_pt, ref_cname, ref_srate, 1, NULL, NULL, NULL, false, NULL); if (err) goto out; err = sdp_format_add(NULL, audio, false, "8", "PCMA", 8000, 1, NULL, NULL, NULL, false, NULL); if (err) goto out; mbuf_rewind(mb); (void)mbuf_write_str(mb, msgs[i]); mb->pos = 0; err = sdp_decode(sess, mb, true); if (err) goto out; } out: mem_deref(sess); mem_deref(mb); return err; }
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 int request_copy(struct mbuf **mbp, struct sip_ctrans *ct, const char *met, const struct sip_msg *resp) { struct mbuf *mb; int err; if (!ct->req) { err = sip_msg_decode(&ct->req, ct->mb); if (err) return err; } mb = mbuf_alloc(1024); if (!mb) return ENOMEM; err = mbuf_printf(mb, "%s %r SIP/2.0\r\n", met, &ct->req->ruri); err |= mbuf_printf(mb, "Via: %r\r\n", &ct->req->via.val); err |= mbuf_write_str(mb, "Max-Forwards: 70\r\n"); err |= sip_msg_hdr_apply(ct->req, true, SIP_HDR_ROUTE, route_handler, mb) ? ENOMEM : 0; err |= mbuf_printf(mb, "To: %r\r\n", resp ? &resp->to.val : &ct->req->to.val); err |= mbuf_printf(mb, "From: %r\r\n", &ct->req->from.val); err |= mbuf_printf(mb, "Call-ID: %r\r\n", &ct->req->callid); err |= mbuf_printf(mb, "CSeq: %u %s\r\n", ct->req->cseq.num, met); if (ct->sip->software) err |= mbuf_printf(mb, "User-Agent: %s\r\n",ct->sip->software); err |= mbuf_write_str(mb, "Content-Length: 0\r\n\r\n"); mb->pos = 0; if (err) mem_deref(mb); else *mbp = mb; return err; }
TEST(chunk, decode_too_short) { struct mbuf *mb_chunked = mbuf_alloc(1024); int err = 0; mbuf_write_str(mb_chunked, "3\r\nab"); mb_chunked->pos = 0; err = chunk_decode(NULL, NULL, mb_chunked); ASSERT_EQ(EBADMSG, err); mem_deref(mb_chunked); }
TEST(chunk, decode_incomplete_header) { struct mbuf *mb = mbuf_alloc(1024); int err = 0; mbuf_write_str(mb, "c8"); /* the CRLF is missing here */ mb->pos = 0; err = chunk_decode(NULL, NULL, mb); ASSERT_EQ(EBADMSG, err); mem_deref(mb); }
TEST(chunk, decode_invalid_header) { struct mbuf *mb = mbuf_alloc(1024); int err = 0; mbuf_write_str(mb, "alfred\r\n"); mb->pos = 0; err = chunk_decode(NULL, NULL, mb); ASSERT_EQ(EBADMSG, err); mem_deref(mb); }
/** * 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 send_data(struct udp_sock *us, const struct sa *peer, const char *data) { struct mbuf *mb = mbuf_alloc(strlen(data) + 1); int err; if (!mb) return ENOMEM; (void)mbuf_write_str(mb, data); mb->pos = 0; err = udp_send(us, peer, mb); mem_deref(mb); return err; }
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 void tmr_ping_handler(void *arg) { struct allocation *alloc = arg; struct mbuf *mb; tmr_start(&alloc->tmr_ping, PING_INTERVAL, tmr_ping_handler, alloc); mb = mbuf_alloc(256); if (!mb) return; mb->pos = 48; mbuf_write_str(mb, "PING"); mb->pos = 48; turnc_send(alloc->turnc, &alloc->peer, mb); mem_deref(mb); }
static bool udp_helper_send(int *err, struct sa *dst, struct mbuf *mb, void *arg) { struct udp_test *ut = arg; const size_t pos = mb->pos; if (!sa_cmp(dst, &ut->srv, SA_ALL)) { *err = EPROTO; return false; } if (!mbuf_compare(mb, data0)) { *err = EBADMSG; return false; } /* Append a fake protocol trailer */ mb->pos = mb->end; *err = mbuf_write_str(mb, "XXXX"); mb->pos = pos; return false; }
static int media_encode(const struct sdp_media *m, struct mbuf *mb, bool offer) { enum sdp_bandwidth i; int err, supc = 0; bool disabled; struct le *le; uint16_t port; for (le=m->lfmtl.head; le; le=le->next) { const struct sdp_format *fmt = le->data; if (fmt->sup) ++supc; } if (m->disabled || supc == 0 || (!offer && !sa_port(&m->raddr))) { disabled = true; port = 0; } else { disabled = false; port = sa_port(&m->laddr); } err = mbuf_printf(mb, "m=%s %u %s", m->name, port, m->proto); if (disabled) { err |= mbuf_write_str(mb, " 0\r\n"); return err; } for (le=m->lfmtl.head; le; le=le->next) { const struct sdp_format *fmt = le->data; if (!fmt->sup) continue; err |= mbuf_printf(mb, " %s", fmt->id); } err |= mbuf_write_str(mb, "\r\n"); if (sa_isset(&m->laddr, SA_ADDR)) { const int ipver = sa_af(&m->laddr) == AF_INET ? 4 : 6; err |= mbuf_printf(mb, "c=IN IP%d %j\r\n", ipver, &m->laddr); } for (i=SDP_BANDWIDTH_MIN; i<SDP_BANDWIDTH_MAX; i++) { if (m->lbwv[i] < 0) continue; err |= mbuf_printf(mb, "b=%s:%i\r\n", sdp_bandwidth_name(i), m->lbwv[i]); } for (le=m->lfmtl.head; le; le=le->next) { const struct sdp_format *fmt = le->data; if (!fmt->sup || !str_len(fmt->name)) continue; err |= mbuf_printf(mb, "a=rtpmap:%s %s/%u", fmt->id, fmt->name, fmt->srate); if (fmt->ch > 1) err |= mbuf_printf(mb, "/%u", fmt->ch); err |= mbuf_printf(mb, "\r\n"); if (str_len(fmt->params)) err |= mbuf_printf(mb, "a=fmtp:%s %s\r\n", fmt->id, fmt->params); } if (sa_isset(&m->laddr_rtcp, SA_ALL)) err |= mbuf_printf(mb, "a=rtcp:%u IN IP%d %j\r\n", sa_port(&m->laddr_rtcp), (AF_INET == sa_af(&m->laddr_rtcp)) ? 4 : 6, &m->laddr_rtcp); else if (sa_isset(&m->laddr_rtcp, SA_PORT)) err |= mbuf_printf(mb, "a=rtcp:%u\r\n", sa_port(&m->laddr_rtcp)); err |= mbuf_printf(mb, "a=%s\r\n", sdp_dir_name(offer ? m->ldir : m->ldir & m->rdir)); for (le = m->lattrl.head; le; le = le->next) err |= mbuf_printf(mb, "%H", sdp_attr_print, le->data); return err; }
static int editor_input(struct commands *commands, struct mbuf *mb, char key, struct re_printf *pf, bool *del, bool is_long) { int err = 0; switch (key) { case KEYCODE_ESC: *del = true; return re_hprintf(pf, "\nCancel\n"); case KEYCODE_NONE: case KEYCODE_REL: break; case '\n': *del = true; return re_hprintf(pf, "\n"); case '\b': case KEYCODE_DEL: if (mb->pos > 0) { err |= re_hprintf(pf, "\b "); mb->pos = mb->end = (mb->pos - 1); } break; case '\t': if (is_long) { const struct cmd *cmd = NULL; size_t n; err = re_hprintf(pf, "TAB completion for \"%b\":\n", mb->buf, mb->end); if (err) return err; /* Find all long commands that matches the N * first characters of the input string. * * If the number of matches is exactly one, * we can regard it as TAB completion. */ err = cmd_print_all(pf, commands, true, false, (char *)mb->buf, mb->end); if (err) return err; n = get_match(commands, &cmd, (char *)mb->buf, mb->end); if (n == 1 && cmd) { mb->pos = 0; mbuf_write_str(mb, cmd->name); } else if (n == 0) { err = re_hprintf(pf, "(none)\n"); } } else { err = mbuf_write_u8(mb, key); } break; default: err = mbuf_write_u8(mb, key); break; } if (is_long) { err |= re_hprintf(pf, "\r/%b", mb->buf, mb->end); } else err |= re_hprintf(pf, "\r> %32b", mb->buf, mb->end); return err; }
static int afb_encode_handler(struct mbuf *mb, void *arg) { return mbuf_write_str(mb, arg); }
/** * 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 pcp_option_encode(struct mbuf *mb, enum pcp_option_code code, const void *v) { const struct sa *sa = v; const struct pcp_option_filter *filt = v; size_t start, len; int err = 0; if (!mb) return EINVAL; mb->pos += 4; start = mb->pos; switch (code) { case PCP_OPTION_THIRD_PARTY: if (!sa) return EINVAL; err |= pcp_ipaddr_encode(mb, sa); break; case PCP_OPTION_PREFER_FAILURE: /* no payload */ break; case PCP_OPTION_FILTER: if (!filt) return EINVAL; err |= mbuf_write_u8(mb, 0x00); err |= mbuf_write_u8(mb, filt->prefix_length); err |= mbuf_write_u16(mb, htons(sa_port(&filt->remote_peer))); err |= pcp_ipaddr_encode(mb, &filt->remote_peer); break; case PCP_OPTION_DESCRIPTION: if (!v) return EINVAL; err |= mbuf_write_str(mb, v); break; default: (void)re_fprintf(stderr, "pcp: unsupported option %d\n", code); return EINVAL; } /* header */ len = mb->pos - start; mb->pos = start - 4; err |= mbuf_write_u8(mb, code); err |= mbuf_write_u8(mb, 0x00); err |= mbuf_write_u16(mb, htons(len)); mb->pos += len; /* padding */ while ((mb->pos - start) & 0x03) err |= mbuf_write_u8(mb, 0x00); return err; }
int stun_attr_encode(struct mbuf *mb, uint16_t type, const void *v, const uint8_t *tid, uint8_t padding) { const struct stun_change_req *ch_req = v; const struct stun_errcode *err_code = v; const struct stun_unknown_attr *ua = v; const unsigned int *num = v; const struct mbuf *mbd = v; size_t start, len; uint32_t i, n; int err = 0; if (!mb || !v) return EINVAL; mb->pos += 4; start = mb->pos; switch (type) { case STUN_ATTR_MAPPED_ADDR: case STUN_ATTR_ALT_SERVER: case STUN_ATTR_RESP_ORIGIN: case STUN_ATTR_OTHER_ADDR: tid = NULL; /*@fallthrough@*/ case STUN_ATTR_XOR_PEER_ADDR: case STUN_ATTR_XOR_RELAY_ADDR: case STUN_ATTR_XOR_MAPPED_ADDR: err |= stun_addr_encode(mb, v, tid); break; case STUN_ATTR_CHANGE_REQ: n = (uint32_t)ch_req->ip << 2 | (uint32_t)ch_req->port << 1; err |= mbuf_write_u32(mb, htonl(n)); break; case STUN_ATTR_USERNAME: case STUN_ATTR_REALM: case STUN_ATTR_NONCE: case STUN_ATTR_SOFTWARE: err |= mbuf_write_str(mb, v); break; case STUN_ATTR_MSG_INTEGRITY: err |= mbuf_write_mem(mb, v, 20); break; case STUN_ATTR_ERR_CODE: err |= mbuf_write_u16(mb, 0x00); err |= mbuf_write_u8(mb, err_code->code/100); err |= mbuf_write_u8(mb, err_code->code%100); err |= mbuf_write_str(mb, err_code->reason); break; case STUN_ATTR_UNKNOWN_ATTR: for (i=0; i<ua->typec; i++) err |= mbuf_write_u16(mb, htons(ua->typev[i])); break; case STUN_ATTR_CHANNEL_NUMBER: case STUN_ATTR_RESP_PORT: err |= mbuf_write_u16(mb, htons(*num)); err |= mbuf_write_u16(mb, 0x0000); break; case STUN_ATTR_LIFETIME: case STUN_ATTR_PRIORITY: case STUN_ATTR_FINGERPRINT: err |= mbuf_write_u32(mb, htonl(*num)); break; case STUN_ATTR_DATA: case STUN_ATTR_PADDING: if (mb == mbd) { mb->pos = mb->end; break; } err |= mbuf_write_mem(mb, mbuf_buf(mbd), mbuf_get_left(mbd)); break; case STUN_ATTR_REQ_ADDR_FAMILY: case STUN_ATTR_REQ_TRANSPORT: err |= mbuf_write_u8(mb, *num); err |= mbuf_write_u8(mb, 0x00); err |= mbuf_write_u16(mb, 0x0000); break; case STUN_ATTR_EVEN_PORT: err |= mbuf_write_u8(mb, ((struct stun_even_port *)v)->r << 7); break; case STUN_ATTR_DONT_FRAGMENT: case STUN_ATTR_USE_CAND: /* no value */ break; case STUN_ATTR_RSV_TOKEN: case STUN_ATTR_CONTROLLED: case STUN_ATTR_CONTROLLING: err |= mbuf_write_u64(mb, sys_htonll(*(uint64_t *)v)); break; default: err = EINVAL; break; } /* header */ len = mb->pos - start; mb->pos = start - 4; err |= mbuf_write_u16(mb, htons(type)); err |= mbuf_write_u16(mb, htons(len)); mb->pos += len; /* padding */ while ((mb->pos - start) & 0x03) err |= mbuf_write_u8(mb, padding); return err; }
int sdp_encode(struct mbuf **mbp, struct sdp_session *sess, bool offer) { const int ipver = sa_af(&sess->laddr) == AF_INET ? 4 : 6; enum sdp_bandwidth i; struct mbuf *mb; struct le *le; int err; if (!mbp || !sess) return EINVAL; mb = mbuf_alloc(512); if (!mb) return ENOMEM; err = mbuf_printf(mb, "v=%u\r\n", SDP_VERSION); err |= mbuf_printf(mb, "o=- %u %u IN IP%d %j\r\n", sess->id, sess->ver++, ipver, &sess->laddr); err |= mbuf_write_str(mb, "s=-\r\n"); err |= mbuf_printf(mb, "c=IN IP%d %j\r\n", ipver, &sess->laddr); for (i=SDP_BANDWIDTH_MIN; i<SDP_BANDWIDTH_MAX; i++) { if (sess->lbwv[i] < 0) continue; err |= mbuf_printf(mb, "b=%s:%i\r\n", sdp_bandwidth_name(i), sess->lbwv[i]); } err |= mbuf_write_str(mb, "t=0 0\r\n"); for (le = sess->lattrl.head; le; le = le->next) err |= mbuf_printf(mb, "%H", sdp_attr_print, le->data); for (le=sess->lmedial.head; offer && le;) { struct sdp_media *m = le->data; le = le->next; if (m->disabled) continue; list_unlink(&m->le); list_append(&sess->medial, &m->le, m); } for (le=sess->medial.head; le; le=le->next) { struct sdp_media *m = le->data; err |= media_encode(m, mb, offer); } mb->pos = 0; if (err) mem_deref(mb); else *mbp = mb; return err; }
int rtcp_vencode(struct mbuf *mb, enum rtcp_type type, uint32_t count, va_list ap) { size_t i, pos; uint16_t len; const uint8_t *data; size_t data_len; const uint32_t *srcv; const char *reason; rtcp_encode_h *ench; void *arg; int err = 0; if (!mb) return EINVAL; pos = mb->pos; /* Skip header - encoded last */ mb->pos = mb->end = (mb->pos + RTCP_HDR_SIZE); switch (type) { case RTCP_SR: for (i=0; i<6; i++) err |= mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t))); ench = va_arg(ap, rtcp_encode_h *); arg = va_arg(ap, void *); if (ench) err |= ench(mb, arg); break; case RTCP_RR: err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t))); ench = va_arg(ap, rtcp_encode_h *); arg = va_arg(ap, void *); if (ench) err |= ench(mb, arg); break; case RTCP_SDES: ench = va_arg(ap, rtcp_encode_h *); arg = va_arg(ap, void *); if (ench) err |= ench(mb, arg); break; case RTCP_BYE: srcv = va_arg(ap, uint32_t *); reason = va_arg(ap, char *); for (i=0; i<count && !err; i++) { err = mbuf_write_u32(mb, htonl(srcv[i])); } if (reason) { err |= mbuf_write_u8(mb, strlen(reason)); err |= mbuf_write_str(mb, reason); } break; case RTCP_APP: err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t))); err |= mbuf_write_mem(mb, va_arg(ap, uint8_t *), 4); data = va_arg(ap, const uint8_t *); data_len = va_arg(ap, size_t); if (data) { if (data_len % 4) { DEBUG_WARNING("not a multiple of 32bits\n"); return EBADMSG; } err |= mbuf_write_mem(mb, data, data_len); } break; case RTCP_FIR: err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t))); break; case RTCP_NACK: err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t))); err |= mbuf_write_u16(mb, htons(va_arg(ap, uint32_t))); err |= mbuf_write_u16(mb, htons(va_arg(ap, uint32_t))); break; case RTCP_RTPFB: case RTCP_PSFB: err = mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t))); err |= mbuf_write_u32(mb, htonl(va_arg(ap, uint32_t))); ench = va_arg(ap, rtcp_encode_h *); arg = va_arg(ap, void *); if (ench) err |= ench(mb, arg); break; default: return EINVAL; } if (err) return err; /* padding to 32 bits */ while ((mb->end - pos) & 0x3) err |= mbuf_write_u8(mb, 0x00); if (err) return err; /* Encode RTCP Header */ mb->pos = pos; len = (mb->end - pos - RTCP_HDR_SIZE)/sizeof(uint32_t); err = rtcp_hdr_encode(mb, count, type, len); if (err) return err; mb->pos = mb->end; return 0; }