/** * Encode an RTCP Generic NACK (GNACK) message * * @param mb Buffer to encode into * @param pid Packet ID * @param blp Bitmask of following lost packets (BLP) * * @return 0 for success, otherwise errorcode */ int rtcp_rtpfb_gnack_encode(struct mbuf *mb, uint16_t pid, uint16_t blp) { int err; err = mbuf_write_u16(mb, htons(pid)); err |= mbuf_write_u16(mb, htons(blp)); return err; }
static int aufile_load(struct mbuf *mb, const char *filename, uint32_t *srate, uint8_t *channels) { struct aufile_prm prm; struct aufile *af; int err; err = aufile_open(&af, &prm, filename, AUFILE_READ); if (err) return err; while (!err) { uint8_t buf[4096]; size_t i, n; n = sizeof(buf); err = aufile_read(af, buf, &n); if (err || !n) break; switch (prm.fmt) { case AUFMT_S16LE: err = mbuf_write_mem(mb, buf, n); break; case AUFMT_PCMA: for (i=0; i<n; i++) { err |= mbuf_write_u16(mb, g711_alaw2pcm(buf[i])); } break; case AUFMT_PCMU: for (i=0; i<n; i++) { err |= mbuf_write_u16(mb, g711_ulaw2pcm(buf[i])); } break; default: err = ENOSYS; break; } } mem_deref(af); if (!err) { mb->pos = 0; *srate = prm.srate; *channels = prm.channels; } return err; }
static int gnack_encode(struct mbuf *mb, void *arg) { int err = 0, n=3; (void)arg; while (n--) { err |= mbuf_write_u16(mb, htons(0x0123)); err |= mbuf_write_u16(mb, htons(0x0456)); } return err; }
int stun_hdr_encode(struct mbuf *mb, const struct stun_hdr *hdr) { int err = 0; if (!mb || !hdr) return EINVAL; err |= mbuf_write_u16(mb, htons(hdr->type & 0x3fff)); err |= mbuf_write_u16(mb, htons(hdr->len)); err |= mbuf_write_u32(mb, htonl(hdr->cookie)); err |= mbuf_write_mem(mb, hdr->tid, sizeof(hdr->tid)); return err; }
static int pcp_write_port(struct mbuf *mb, const struct sa *sa) { uint16_t port_be; if (!mb || !sa) return EINVAL; switch (sa->u.sa.sa_family) { case AF_INET: port_be = sa->u.in.sin_port; break; #ifdef HAVE_INET6 case AF_INET6: port_be = sa->u.in6.sin6_port; break; #endif default: return EAFNOSUPPORT; } return mbuf_write_u16(mb, port_be); }
/** * Encode the RTP header into a buffer * * @param mb Buffer to encode into * @param hdr RTP Header to be encoded * * @return 0 if success, otherwise errorcode */ int rtp_hdr_encode(struct mbuf *mb, const struct rtp_header *hdr) { uint8_t buf[2]; int err, i; if (!mb || !hdr) return EINVAL; buf[0] = (hdr->ver & 0x02) << 6; buf[0] |= (hdr->pad & 0x01) << 5; buf[0] |= (hdr->ext & 0x01) << 4; buf[0] |= (hdr->cc & 0x0f) << 0; buf[1] = (hdr->m & 0x01) << 7; buf[1] |= (hdr->pt & 0x7f) << 0; err = mbuf_write_mem(mb, buf, sizeof(buf)); err |= mbuf_write_u16(mb, htons(hdr->seq)); err |= mbuf_write_u32(mb, htonl(hdr->ts)); err |= mbuf_write_u32(mb, htonl(hdr->ssrc)); for (i=0; i<hdr->cc; i++) { err |= mbuf_write_u32(mb, htonl(hdr->csrc[i])); } return err; }
static int test_rtcp_decode_badmsg(void) { struct rtcp_msg *msg = NULL; uint32_t ssrc = 0xcafebabe; struct mbuf *mb; int err = 0; mb = mbuf_alloc(128); if (!mb) { err = ENOMEM; goto out; } err = rtcp_encode(mb, RTCP_PSFB, RTCP_PSFB_SLI, ssrc, ssrc, NULL, NULL); if (err) goto out; /* simulate a corrupt RTCP packet */ mb->pos = 2; (void)mbuf_write_u16(mb, htons(0)); mb->pos = 0; if (EBADMSG != rtcp_decode(&msg, mb)) { err = EBADMSG; goto out; } out: mem_deref(msg); mem_deref(mb); return err; }
/* Receive packet on the "relayed" address -- relay to the client */ static void relay_udp_recv(const struct sa *src, struct mbuf *mb, void *arg) { struct turnserver *turn = arg; struct channel *chan; int err = 0; ++turn->n_recv; chan = find_channel_peer(turn, src); if (chan) { uint16_t len = mbuf_get_left(mb); size_t start; if (mb->pos < 4) { DEBUG_WARNING("relay_udp_recv: mb pos < 4\n"); return; } mb->pos -= 4; start = mb->pos; (void)mbuf_write_u16(mb, htons(chan->nr)); (void)mbuf_write_u16(mb, htons(len)); mb->pos = start; err = udp_send(turn->us, &turn->cli, mb); } else { err = stun_indication(IPPROTO_UDP, turn->us, &turn->cli, 0, STUN_METHOD_DATA, NULL, 0, false, 2, STUN_ATTR_XOR_PEER_ADDR, src, STUN_ATTR_DATA, mb); } if (err) { DEBUG_WARNING("relay_udp_recv: error %m\n", err); } }
/** * Encode the RTCP Header * * @param mb Buffer to encode into * @param count Number of sub-elemements * @param type RTCP Packet type * @param length Packet length in words * * @return 0 for success, otherwise errorcode */ int rtcp_hdr_encode(struct mbuf *mb, uint8_t count, enum rtcp_type type, uint16_t length) { int err; if (!mb) return EINVAL; err = mbuf_write_u8(mb, RTCP_VERSION<<6 | count); err |= mbuf_write_u8(mb, type); err |= mbuf_write_u16(mb, htons(length)); 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; }
/* responsible for adding the SHIM header - assumes that the sent MBUF contains a complete packet */ static bool shim_send_handler(int *err, struct mbuf *mb, void *arg) { struct shim *shim = arg; size_t len; (void)shim; if (mb->pos < SHIM_HDR_SIZE) { DEBUG_WARNING("send: not enough space for SHIM header\n"); *err = ENOMEM; return true; } len = mbuf_get_left(mb); mb->pos -= SHIM_HDR_SIZE; *err = mbuf_write_u16(mb, htons(len)); mb->pos -= SHIM_HDR_SIZE; ++shim->n_tx; return false; }
/** * Generate a dual-tone sine wave into a PCM buffer * * @param mb Buffer for PCM samples * @param srate Sample rate in [Hz] * @param f1 Frequency number one * @param l1 Level of f1 from 0-100 * @param f2 Frequency number two * @param l2 Level of f2 from 0-100 * * @return 0 for success, otherwise error code */ int autone_sine(struct mbuf *mb, uint32_t srate, uint32_t f1, int l1, uint32_t f2, int l2) { double d1, d2; uint32_t i; int err = 0; if (!mb || !srate) return EINVAL; d1 = 1.0f * f1 / srate; d2 = 1.0f * f2 / srate; for (i=0; i<srate; i++) { int16_t s1, s2; s1 = (int16_t)(SCALE * l1 / 100.0f * sin(2 * M_PI * d1 * i)); s2 = (int16_t)(SCALE * l2 / 100.0f * sin(2 * M_PI * d2 * i)); err |= mbuf_write_u16(mb, saturate_add16(s1, s2)); } return err; }
static int pcp_peer_encode(struct mbuf *mb, const struct pcp_peer *peer) { int err; if (!mb || !peer) return EINVAL; /* Protocol MUST NOT be zero. * Internal port MUST NOT be zero. */ if (!peer->map.proto || !peer->map.int_port) return EPROTO; /* note: the MAP and PEER opcodes are quite similar */ err = pcp_map_encode(mb, &peer->map); if (err) return err; err = pcp_write_port(mb, &peer->remote_addr); err |= mbuf_write_u16(mb, 0x0000); err |= pcp_ipaddr_encode(mb, &peer->remote_addr); 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; }
static int query(struct dns_query **qp, struct dnsc *dnsc, uint8_t opcode, const char *name, uint16_t type, uint16_t dnsclass, const struct dnsrr *ans_rr, int proto, const struct sa *srvv, const uint32_t *srvc, bool aa, bool rd, dns_query_h *qh, void *arg) { struct dns_query *q = NULL; struct dnshdr hdr; int err = 0; uint32_t i; if (!dnsc || !name || !srvv || !srvc || !(*srvc)) return EINVAL; if (DNS_QTYPE_AXFR == type) proto = IPPROTO_TCP; q = mem_zalloc(sizeof(*q), query_destructor); if (!q) goto nmerr; hash_append(dnsc->ht_query, hash_joaat_str_ci(name), &q->le, q); tmr_init(&q->tmr); mbuf_init(&q->mb); for (i=0; i<ARRAY_SIZE(q->rrlv); i++) list_init(&q->rrlv[i]); err = str_dup(&q->name, name); if (err) goto error; q->srvv = srvv; q->srvc = srvc; q->id = rand_u16(); q->type = type; q->opcode = opcode; q->dnsclass = dnsclass; q->dnsc = dnsc; memset(&hdr, 0, sizeof(hdr)); hdr.id = q->id; hdr.opcode = q->opcode; hdr.aa = aa; hdr.rd = rd; hdr.nq = 1; hdr.nans = ans_rr ? 1 : 0; if (proto == IPPROTO_TCP) q->mb.pos += 2; err = dns_hdr_encode(&q->mb, &hdr); if (err) goto error; err = dns_dname_encode(&q->mb, name, NULL, 0, false); if (err) goto error; err |= mbuf_write_u16(&q->mb, htons(type)); err |= mbuf_write_u16(&q->mb, htons(dnsclass)); if (err) goto error; if (ans_rr) { err = dns_rr_encode(&q->mb, ans_rr, 0, NULL, 0); if (err) goto error; } q->qh = qh; q->arg = arg; switch (proto) { case IPPROTO_TCP: q->mb.pos = 0; (void)mbuf_write_u16(&q->mb, htons(q->mb.end - 2)); err = send_tcp(q); if (err) goto error; tmr_start(&q->tmr, 60 * 1000, tcp_timeout_handler, q); break; case IPPROTO_UDP: err = send_udp(q); if (err) goto error; tmr_start(&q->tmr, 500, udp_timeout_handler, q); break; default: err = EPROTONOSUPPORT; goto error; } if (qp) { q->qp = qp; *qp = q; } return 0; nmerr: err = ENOMEM; error: mem_deref(q); return err; }
static inline int dname_encode_pointer(struct mbuf *mb, size_t pos) { return mbuf_write_u16(mb, htons(pos | (COMP_MASK<<8))); }
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; }