/** * Encode one SDES chunk into mbuffer * * @param mb Buffer to encode into * @param src First SSRC/CSRC * @param itemc Number of SDES items to encode * * @return 0 if success, otherwise errorcode */ int rtcp_sdes_encode(struct mbuf *mb, uint32_t src, uint32_t itemc, ...) { va_list ap; size_t start; int err = 0; if (!mb || !itemc) return EINVAL; va_start(ap, itemc); start = mb->pos; err = mbuf_write_u32(mb, htonl(src)); /* add all SDES items */ while (itemc-- && !err) { const uint8_t type = va_arg(ap, int); const char *v = va_arg(ap, const char *); size_t len; if (!v) continue; len = strlen(v); /* note: max 255 chars */ if (len > 255) { err = EINVAL; goto out; } err = mbuf_write_u8(mb, type); err |= mbuf_write_u8(mb, len & 0xff); err |= mbuf_write_mem(mb, (uint8_t *)v, len); } /* END padding */ err |= mbuf_write_u8(mb, RTCP_SDES_END); while ((mb->pos - start) & 0x3) err |= mbuf_write_u8(mb, RTCP_SDES_END); out: va_end(ap); return err; }
/** * Encode a DNS character string into a memory buffer * * @param mb Memory buffer to encode into * @param str Character string * * @return 0 if success, otherwise errorcode */ int dns_cstr_encode(struct mbuf *mb, const char *str) { uint8_t len; int err = 0; if (!mb || !str) return EINVAL; len = (uint8_t)strlen(str); err |= mbuf_write_u8(mb, len); err |= mbuf_write_mem(mb, (const uint8_t *)str, len); return err; }
static int pcp_map_encode(struct mbuf *mb, const struct pcp_map *map) { int err = 0; if (!mb || !map) return EINVAL; err |= mbuf_write_mem(mb, map->nonce, sizeof(map->nonce)); err |= mbuf_write_u8(mb, map->proto); err |= mbuf_fill(mb, 0x00, 3); err |= mbuf_write_u16(mb, htons(map->int_port)); err |= pcp_write_port(mb, &map->ext_addr); err |= pcp_ipaddr_encode(mb, &map->ext_addr); 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; }
int turnc_send(struct turnc *turnc, const struct sa *dst, struct mbuf *mb) { size_t pos, indlen; struct chan *chan; int err; if (!turnc || !dst || !mb) return EINVAL; chan = turnc_chan_find_peer(turnc, dst); if (chan) { struct chan_hdr hdr; if (mb->pos < CHAN_HDR_SIZE) return EINVAL; hdr.nr = turnc_chan_numb(chan); hdr.len = mbuf_get_left(mb); mb->pos -= CHAN_HDR_SIZE; pos = mb->pos; err = turnc_chan_hdr_encode(&hdr, mb); if (err) return err; if (turnc->proto == IPPROTO_TCP) { mb->pos = mb->end; /* padding */ while (hdr.len++ & 0x03) { err = mbuf_write_u8(mb, 0x00); if (err) return err; } } mb->pos = pos; } else { indlen = stun_indlen(dst); if (mb->pos < indlen) return EINVAL; mb->pos -= indlen; pos = mb->pos; err = stun_msg_encode(mb, STUN_METHOD_SEND, STUN_CLASS_INDICATION, sendind_tid, NULL, NULL, 0, false, 0x00, 2, STUN_ATTR_XOR_PEER_ADDR, dst, STUN_ATTR_DATA, mb); if (err) return err; mb->pos = pos; } switch (turnc->proto) { case IPPROTO_UDP: err = udp_send(turnc->sock, &turnc->srv, mb); break; case IPPROTO_TCP: err = tcp_send(turnc->sock, mb); break; #ifdef USE_DTLS case STUN_TRANSP_DTLS: err = dtls_send(turnc->sock, mb); break; #endif default: err = EPROTONOSUPPORT; break; } 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 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 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; }