static int general_packetize(struct mbuf *mb, size_t pktsize, videnc_packet_h *pkth, void *arg) { int err = 0; /* Assemble frame into smaller packets */ while (!err) { size_t sz, left = mbuf_get_left(mb); bool last = (left < pktsize); if (!left) break; sz = last ? left : pktsize; err = pkth(last, NULL, 0, mbuf_buf(mb), sz, arg); mbuf_advance(mb, sz); } 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); } }
/** * Encoder audio and send via stream * * @note This function has REAL-TIME properties * * @param a Audio object * @param tx Audio transmit object * @param sampv Audio samples * @param sampc Number of audio samples */ static void encode_rtp_send(struct audio *a, struct autx *tx, int16_t *sampv, size_t sampc) { size_t frame_size; /* number of samples per channel */ size_t len; int err; if (!tx->ac) return; tx->mb->pos = tx->mb->end = STREAM_PRESZ; len = mbuf_get_space(tx->mb); err = tx->ac->ench(tx->enc, mbuf_buf(tx->mb), &len, sampv, sampc); if (err) { warning("audio: %s encode error: %d samples (%m)\n", tx->ac->name, sampc, err); goto out; } tx->mb->pos = STREAM_PRESZ; tx->mb->end = STREAM_PRESZ + len; if (mbuf_get_left(tx->mb)) { err = stream_send(a->strm, tx->marker, -1, tx->ts, tx->mb); if (err) goto out; } /* The RTP clock rate used for generating the RTP timestamp is * independent of the number of channels and the encoding */ frame_size = (tx->is_g722 ? sampc/2 : sampc) / tx->ac->ch; tx->ts += (uint32_t)frame_size; out: tx->marker = false; }
void http_request_h(struct http_conn *conn, const struct http_msg *msg, void *arg) { int err; enum app_cmd cmd; const struct http_hdr * expect_hdr; struct mbuf *mb = msg->mb; uint8_t *ret_buf; size_t ret_len; if(pl_strcmp(&msg->met, "POST")) { http_creply(conn, 405, "Method not allowed", "text/plain", "EMET"); return; } expect_hdr = http_msg_hdr(msg, HTTP_HDR_EXPECT); if(expect_hdr != NULL && version_cmp(version, &expect_hdr->val) < 0) { http_creply(conn, 417, "Expectation Failed", "text/plain", "%s", version); return; } cmd = (enum app_cmd)(hash_joaat_ci(msg->path.p, msg->path.l) & 0xfff); err = app_handle(cmd, mbuf_buf(mb), mbuf_get_left(mb), &ret_buf, &ret_len); if(err < 0) { http_creply(conn, 500, "Internal Server Error", "text/plain", "EINT"); return; } if(err > 200) { http_creply(conn, err, "Error", "text/plain", "NO", 2); return; } if(err == 0) { http_creply(conn, 200, "OK", "text/plain; charset=utf-8", "%b", ret_buf, ret_len); } else { http_creply(conn, 403, "Forbidden", "text/plain", "%b", ret_buf, ret_len); } free(ret_buf); }
static void message_handler(const struct pl *peer, const struct pl *ctype, struct mbuf *body, void *arg) { struct gtk_mod *mod = arg; char title[128]; char msg[512]; #if GLIB_CHECK_VERSION(2,40,0) GNotification *notification; #elif defined(USE_LIBNOTIFY) NotifyNotification *notification; #endif (void)ctype; /* Display notification of chat */ re_snprintf(title, sizeof title, "Chat from %r", peer); title[sizeof title - 1] = '\0'; re_snprintf(msg, sizeof msg, "%b", mbuf_buf(body), mbuf_get_left(body)); #if GLIB_CHECK_VERSION(2,40,0) notification = g_notification_new(title); g_notification_set_body(notification, msg); g_application_send_notification(mod->app, NULL, notification); g_object_unref(notification); #elif defined(USE_LIBNOTIFY) (void)mod; if (!notify_is_initted()) return; notification = notify_notification_new(title, msg, "baresip"); notify_notification_show(notification, NULL); g_object_unref(notification); #endif }
static bool send_handler(int *err, struct sa *dst, struct mbuf *mb, void *arg) { struct tls_sock *ts = arg; struct tls_conn *tc; int r; tc = tls_udp_conn(ts, dst); if (!tc) { /* No connection found, assuming Client role */ tc = conn_alloc(ts, dst); if (!tc) { *err = ENOMEM; return true; } SSL_set_connect_state(tc->ssl); check_timer(tc); } r = SSL_write(tc->ssl, mbuf_buf(mb), (int)mbuf_get_left(mb)); if (r < 0) { switch (SSL_get_error(tc->ssl, r)) { case SSL_ERROR_WANT_READ: break; default: DEBUG_WARNING("SSL_write: %d\n", SSL_get_error(tc->ssl, r)); *err = EPROTO; return true; } } return true; }
/* 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; }
/** * Decode a multipart/mixed message and find the part with application/sdp * * @param ctype_prm Content type parameter * @param mb Mbuffer containing the SDP * * @return 0 if success, otherwise errorcode */ int sdp_decode_multipart(const struct pl *ctype_prm, struct mbuf *mb) { struct pl bnd, s, e, p; char expr[64]; int err; if (!ctype_prm || !mb) return EINVAL; /* fetch the boundary tag, excluding quotes */ err = re_regex(ctype_prm->p, ctype_prm->l, "boundary=[~]+", &bnd); if (err) return err; if (re_snprintf(expr, sizeof(expr), "--%r[^]+", &bnd) < 0) return ENOMEM; /* find 1st boundary */ err = re_regex((char *)mbuf_buf(mb), mbuf_get_left(mb), expr, &s); if (err) return err; /* iterate over each part */ while (s.l > 2) { if (re_regex(s.p, s.l, expr, &e)) return 0; p.p = s.p + 2; p.l = e.p - p.p - bnd.l - 2; /* valid part in "p" */ decode_part(&p, mb); s = e; } return 0; }
static bool udp_helper_recv(struct sa *src, struct mbuf *mb, void *arg) { struct menc_media *st = arg; unsigned int length; zrtp_status_t s; const char *proto_name = "srtp"; enum pkt_type ptype = get_packet_type(mb); if (drop_packets(st)) return true; length = (unsigned int)mbuf_get_left(mb); if (ptype == PKT_TYPE_RTCP) { proto_name = "srtcp"; s = zrtp_process_srtcp(st->zrtp_stream, (char *)mbuf_buf(mb), &length); } else if (ptype == PKT_TYPE_RTP || ptype == PKT_TYPE_ZRTP) { s = zrtp_process_srtp(st->zrtp_stream, (char *)mbuf_buf(mb), &length); } else return false; if (s != zrtp_status_ok) { if (s == zrtp_status_drop) return true; warning("zrtp: recv(port=%d): zrtp_process_%s: %d '%s'\n", sa_port(src), proto_name, s, zrtp_log_status2str(s)); return false; } mb->end = mb->pos + length; return false; }
static void udp_recv(const struct sa *src, struct mbuf *mb, void *arg) { struct sip_server *srv = arg; struct sip_msg *msg; int err; #if 0 re_printf("sip: %zu bytes from %J\n", mbuf_get_left(mb), src); re_printf("%b\n", mb->buf, mb->end); #endif err = sip_msg_decode(&msg, mb); if (err) { warning("selftest: sip_msg_decode: %m\n", err); return; } if (0 == pl_strcmp(&msg->met, "REGISTER")) srv->got_register_req = true; msg->sock = mem_ref(srv->us); msg->src = *src; msg->dst = srv->laddr; msg->tp = SIP_TRANSP_UDP; if (srv->terminate) err = sip_reply(srv->sip, msg, 503, "Server Error"); else err = sip_reply(srv->sip, msg, 200, "OK"); if (err) { warning("selftest: could not reply: %m\n", err); } mem_deref(msg); if (srv->terminate) re_cancel(); }
static void udp_recv(const struct sa *src, struct mbuf *mb, void *arg) { struct ui_st *st = arg; struct mbuf *mbr = mbuf_alloc(64); struct re_printf pf; pf.vph = print_handler; pf.arg = mbr; while (mbuf_get_left(mb)) { char ch = mbuf_read_u8(mb); if (ch == '\r') ch = '\n'; ui_input_key(ch, &pf); } mbr->pos = 0; (void)udp_send(st->us, src, mbr); mem_deref(mbr); }
static bool udp_helper_recv(struct sa *src, struct mbuf *mb, void *arg) { struct menc_media *st = arg; unsigned int length; zrtp_status_t s; (void)src; length = (unsigned int)mbuf_get_left(mb); s = zrtp_process_srtp(st->zrtp_stream, (char *)mbuf_buf(mb), &length); if (s != zrtp_status_ok) { if (s == zrtp_status_drop) return true; warning("zrtp: zrtp_process_srtp: %d\n", s); return false; } mb->end = mb->pos + length; return false; }
/** * Decode an RTCP Payload-Specific Feedback Message * * @param mb Buffer to decode * @param msg RTCP Message to decode into * * @return 0 for success, otherwise errorcode */ int rtcp_psfb_decode(struct mbuf *mb, struct rtcp_msg *msg) { size_t i, sz; if (!msg) return EINVAL; switch (msg->hdr.count) { case RTCP_PSFB_PLI: /* no params */ break; case RTCP_PSFB_SLI: sz = msg->r.fb.n * sizeof(*msg->r.fb.fci.sliv); msg->r.fb.fci.sliv = mem_alloc(sz, NULL); if (!msg->r.fb.fci.sliv) return ENOMEM; if (mbuf_get_left(mb) < msg->r.fb.n * SLI_SIZE) return EBADMSG; for (i=0; i<msg->r.fb.n; i++) { const uint32_t v = ntohl(mbuf_read_u32(mb)); msg->r.fb.fci.sliv[i].first = v>>19 & 0x1fff; msg->r.fb.fci.sliv[i].number = v>> 6 & 0x1fff; msg->r.fb.fci.sliv[i].picid = v>> 0 & 0x003f; } break; default: DEBUG_NOTICE("unknown PSFB fmt %d\n", msg->hdr.count); break; } return 0; }
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); } else if (sc >= 200) { call_event_handler(call, CALL_EVENT_CLOSED, "Call transfered"); } }
static bool send_handler(int *err, struct sa *dst, struct mbuf *mb, void *arg) { struct menc_st *st = arg; err_status_t e; int len; (void)dst; if (!st->use_srtp || !is_rtp_or_rtcp(mb)) return false; len = (int)mbuf_get_left(mb); if (mbuf_get_space(mb) < ((size_t)len + SRTP_MAX_TRAILER_LEN)) { mbuf_resize(mb, mb->pos + len + SRTP_MAX_TRAILER_LEN); } if (is_rtcp_packet(mb)) { e = srtp_protect_rtcp(st->srtp_tx, mbuf_buf(mb), &len); } else { e = srtp_protect(st->srtp_tx, mbuf_buf(mb), &len); } if (err_status_ok != e) { DEBUG_WARNING("send: failed to protect %s-packet" " with %d bytes (%H)\n", is_rtcp_packet(mb) ? "RTCP" : "RTP", len, errstatus_print, e); *err = EPROTO; return false; } mbuf_set_end(mb, mb->pos + len); return false; /* continue processing */ }
/** * NOTE: DSP cannot be destroyed inside handler */ static bool write_handler(uint8_t *buf, size_t sz, void *arg) { struct play *play = arg; lock_write_get(play->lock); if (play->eof) goto silence; if (mbuf_get_left(play->mb) < sz) { play->eof = true; } else { (void)mbuf_read_mem(play->mb, buf, sz); } silence: if (play->eof) memset(buf, 0, sz); lock_rel(play->lock); return true; }
void stun_attr_dump(const struct stun_attr *a) { uint32_t i; size_t len; if (!a) return; (void)re_printf(" %-25s", stun_attr_name(a->type)); switch (a->type) { case STUN_ATTR_MAPPED_ADDR: case STUN_ATTR_XOR_PEER_ADDR: case STUN_ATTR_XOR_RELAY_ADDR: case STUN_ATTR_XOR_MAPPED_ADDR: case STUN_ATTR_ALT_SERVER: case STUN_ATTR_RESP_ORIGIN: case STUN_ATTR_OTHER_ADDR: (void)re_printf("%J", &a->v.sa); break; case STUN_ATTR_CHANGE_REQ: (void)re_printf("ip=%u port=%u", a->v.change_req.ip, a->v.change_req.port); break; case STUN_ATTR_USERNAME: case STUN_ATTR_REALM: case STUN_ATTR_NONCE: case STUN_ATTR_SOFTWARE: (void)re_printf("%s", a->v.str); break; case STUN_ATTR_MSG_INTEGRITY: (void)re_printf("%w", &a->v.msg_integrity, 20); break; case STUN_ATTR_ERR_CODE: (void)re_printf("%u %s", a->v.err_code.code, a->v.err_code.reason); break; case STUN_ATTR_UNKNOWN_ATTR: for (i=0; i<a->v.unknown_attr.typec; i++) (void)re_printf("0x%04x ", a->v.unknown_attr.typev[i]); break; case STUN_ATTR_CHANNEL_NUMBER: (void)re_printf("0x%04x", a->v.uint16); break; case STUN_ATTR_LIFETIME: case STUN_ATTR_PRIORITY: (void)re_printf("%u", a->v.uint32); break; case STUN_ATTR_DATA: case STUN_ATTR_PADDING: len = mbuf_get_left(&a->v.mb); (void)re_printf("%w%s (%u bytes)", mbuf_buf(&a->v.mb), MIN(len, 16), len > 16 ? "..." : "", len); break; case STUN_ATTR_REQ_ADDR_FAMILY: case STUN_ATTR_REQ_TRANSPORT: (void)re_printf("%u", a->v.uint8); break; case STUN_ATTR_EVEN_PORT: (void)re_printf("r=%u", a->v.even_port.r); break; case STUN_ATTR_DONT_FRAGMENT: case STUN_ATTR_USE_CAND: /* no value */ break; case STUN_ATTR_RSV_TOKEN: (void)re_printf("0x%016llx", a->v.rsv_token); break; case STUN_ATTR_RESP_PORT: (void)re_printf("%u", a->v.uint16); break; case STUN_ATTR_FINGERPRINT: (void)re_printf("0x%08x", a->v.fingerprint); break; case STUN_ATTR_CONTROLLING: case STUN_ATTR_CONTROLLED: (void)re_printf("%llu", a->v.uint64); break; default: (void)re_printf("???"); break; } (void)re_printf("\n"); }
int srtp_decrypt(struct srtp *srtp, struct mbuf *mb) { struct srtp_stream *strm; struct rtp_header hdr; struct comp *comp; uint64_t ix; size_t start; int diff; int err; if (!srtp || !mb) return EINVAL; comp = &srtp->rtp; start = mb->pos; err = rtp_hdr_decode(&hdr, mb); if (err) return err; err = stream_get_seq(&strm, srtp, hdr.ssrc, hdr.seq); if (err) return err; diff = seq_diff(strm->s_l, hdr.seq); if (diff > 32768) return ETIMEDOUT; /* Roll-Over Counter (ROC) */ if (diff <= -32768) { strm->roc++; strm->s_l = 0; } ix = srtp_get_index(strm->roc, strm->s_l, hdr.seq); if (comp->hmac) { uint8_t tag_calc[SHA_DIGEST_LENGTH]; uint8_t tag_pkt[SHA_DIGEST_LENGTH]; size_t pld_start, tag_start; if (mbuf_get_left(mb) < comp->tag_len) return EBADMSG; pld_start = mb->pos; tag_start = mb->end - comp->tag_len; mb->pos = tag_start; err = mbuf_read_mem(mb, tag_pkt, comp->tag_len); if (err) return err; mb->pos = mb->end = tag_start; err = mbuf_write_u32(mb, htonl(strm->roc)); if (err) return err; mb->pos = start; err = hmac_digest(comp->hmac, tag_calc, sizeof(tag_calc), mbuf_buf(mb), mbuf_get_left(mb)); if (err) return err; mb->pos = pld_start; mb->end = tag_start; if (0 != memcmp(tag_calc, tag_pkt, comp->tag_len)) return EAUTH; /* * 3.3.2. Replay Protection * * Secure replay protection is only possible when * integrity protection is present. */ if (!srtp_replay_check(&strm->replay_rtp, ix)) return EALREADY; } if (comp->aes) { union vect128 iv; uint8_t *p = mbuf_buf(mb); srtp_iv_calc(&iv, &comp->k_s, strm->ssrc, ix); aes_set_iv(comp->aes, iv.u8); err = aes_decr(comp->aes, p, p, mbuf_get_left(mb)); if (err) return err; } if (hdr.seq > strm->s_l) strm->s_l = hdr.seq; mb->pos = start; return 0; }
static void rtp_recv(const struct sa *src, const struct rtp_header *hdr, struct mbuf *mb, void *arg) { struct stream *s = arg; bool flush = false; int err; s->ts_last = tmr_jiffies(); if (!mbuf_get_left(mb)) return; if (!(sdp_media_ldir(s->sdp) & SDP_RECVONLY)) return; metric_add_packet(&s->metric_rx, mbuf_get_left(mb)); if (hdr->ssrc != s->ssrc_rx) { if (s->ssrc_rx) { flush = true; info("stream: %s: SSRC changed %x -> %x" " (%u bytes from %J)\n", sdp_media_name(s->sdp), s->ssrc_rx, hdr->ssrc, mbuf_get_left(mb), src); } s->ssrc_rx = hdr->ssrc; } if (s->jbuf) { struct rtp_header hdr2; void *mb2 = NULL; /* Put frame in Jitter Buffer */ if (flush) jbuf_flush(s->jbuf); err = jbuf_put(s->jbuf, hdr, mb); if (err) { info("%s: dropping %u bytes from %J (%m)\n", sdp_media_name(s->sdp), mb->end, src, err); s->metric_rx.n_err++; } if (jbuf_get(s->jbuf, &hdr2, &mb2)) { if (!s->jbuf_started) return; memset(&hdr2, 0, sizeof(hdr2)); } s->jbuf_started = true; if (lostcalc(s, hdr2.seq) > 0) s->rtph(hdr, NULL, s->arg); s->rtph(&hdr2, mb2, s->arg); mem_deref(mb2); } else { if (lostcalc(s, hdr->seq) > 0) s->rtph(hdr, NULL, s->arg); s->rtph(hdr, mb, s->arg); } }
int turnc_recv(struct turnc *turnc, struct sa *src, struct mbuf *mb) { struct stun_attr *peer, *data; struct stun_unknown_attr ua; struct stun_msg *msg; int err = 0; if (!turnc || !src || !mb) return EINVAL; if (stun_msg_decode(&msg, mb, &ua)) { struct chan_hdr hdr; struct chan *chan; if (turnc_chan_hdr_decode(&hdr, mb)) return EBADMSG; if (mbuf_get_left(mb) < hdr.len) return EBADMSG; chan = turnc_chan_find_numb(turnc, hdr.nr); if (!chan) return EBADMSG; *src = *turnc_chan_peer(chan); return 0; } switch (stun_msg_class(msg)) { case STUN_CLASS_INDICATION: if (ua.typec > 0) { err = ENOSYS; break; } if (stun_msg_method(msg) != STUN_METHOD_DATA) { err = ENOSYS; break; } peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR); data = stun_msg_attr(msg, STUN_ATTR_DATA); if (!peer || !data) { err = EPROTO; break; } *src = peer->v.xor_peer_addr; mb->pos = data->v.data.pos; mb->end = data->v.data.end; break; case STUN_CLASS_ERROR_RESP: case STUN_CLASS_SUCCESS_RESP: (void)stun_ctrans_recv(turnc->stun, msg, &ua); mb->pos = mb->end; break; default: err = ENOSYS; break; } mem_deref(msg); return err; }
static int publish(struct publisher *pub) { int err; const char *aor = ua_aor(pub->ua); struct mbuf *mb; mb = mbuf_alloc(1024); if (!mb) return ENOMEM; if (pub->expires && !pub->refresh) err = mbuf_printf(mb, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n" "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\r\n" " xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\"\r\n" " xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\"\r\n" " entity=\"%s\">\r\n" " <dm:person id=\"p4159\"><rpid:activities/></dm:person>\r\n" " <tuple id=\"t4109\">\r\n" " <status>\r\n" " <basic>%s</basic>\r\n" " </status>\r\n" " <contact>%s</contact>\r\n" " </tuple>\r\n" "</presence>\r\n" ,aor, presence_status_str(ua_presence_status(pub->ua)), aor); else err = mbuf_printf(mb, ""); if (err) goto out; mb->pos = 0; /* XXX: can be simplified with 1 function call, by adding a print-handler that prints "SIP-If-Match: ETAG" */ if (pub->etag) err = sip_req_send(pub->ua, "PUBLISH", aor, pub->expires ? response_handler : NULL, pub, "%s" "Event: presence\r\n" "Expires: %u\r\n" "SIP-If-Match: %s\r\n" "Content-Length: %zu\r\n" "\r\n" "%b", pub->expires ? "Content-Type: application/pidf+xml\r\n" : "", pub->expires, pub->etag, mbuf_get_left(mb), mbuf_buf(mb), mbuf_get_left(mb)); else err = sip_req_send(pub->ua, "PUBLISH", aor, pub->expires ? response_handler : NULL, pub, "%s" "Event: presence\r\n" "Expires: %u\r\n" "Content-Length: %zu\r\n" "\r\n" "%b", pub->expires ? "Content-Type: application/pidf+xml\r\n" : "", pub->expires, mbuf_get_left(mb), mbuf_buf(mb), mbuf_get_left(mb)); if (err) { warning("publisher: send PUBLISH: (%m)\n", err); } out: mem_deref(mb); return err; }
static bool udp_recv_handler(struct sa *src, struct mbuf *mb, void *arg) { struct stun_attr *peer, *data; struct stun_unknown_attr ua; struct turnc *turnc = arg; struct stun_msg *msg; bool hdld = true; if (!sa_cmp(&turnc->srv, src, SA_ALL) && !sa_cmp(&turnc->psrv, src, SA_ALL)) return false; if (stun_msg_decode(&msg, mb, &ua)) { struct chan_hdr hdr; struct chan *chan; if (turnc_chan_hdr_decode(&hdr, mb)) return true; if (mbuf_get_left(mb) < hdr.len) return true; chan = turnc_chan_find_numb(turnc, hdr.nr); if (!chan) return true; *src = *turnc_chan_peer(chan); return false; } switch (stun_msg_class(msg)) { case STUN_CLASS_INDICATION: if (ua.typec > 0) break; if (stun_msg_method(msg) != STUN_METHOD_DATA) break; peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR); data = stun_msg_attr(msg, STUN_ATTR_DATA); if (!peer || !data) break; *src = peer->v.xor_peer_addr; mb->pos = data->v.data.pos; mb->end = data->v.data.end; hdld = false; break; case STUN_CLASS_ERROR_RESP: case STUN_CLASS_SUCCESS_RESP: (void)stun_ctrans_recv(turnc->stun, msg, &ua); break; default: break; } mem_deref(msg); return hdld; }
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 udp_sock::send(const struct sa *dst, struct mbuf *mb) { struct sa hdst; TRequestStatus stat; int err = 0; DEBUG_INFO("udp_sock::send %u bytes to %J\n", mbuf_get_left(mb), dst); /* Check for error in e.g. connected state */ if (cerr) { err = cerr; cerr = 0; /* clear error */ return err; } /* call helpers in reverse order */ struct le *le = list_tail(&helpers); while (le) { struct udp_helper *uh; uh = (struct udp_helper *)le->data; le = le->prev; if (dst != &hdst) { sa_cpy(&hdst, dst); dst = &hdst; } if (uh->sendh(&err, &hdst, mb, uh->arg) || err) return err; } TInetAddr ia(sa_in(dst), sa_port(dst)); const TPtrC8 buf_tx(mb->buf + mb->pos, mb->end - mb->pos); if (conn) { cus->iSocket.Connect(ia, stat); User::WaitForRequest(stat); if (KErrNone != stat.Int()) { DEBUG_WARNING("udp_sock::send Connect: kerr=%d\n", stat.Int()); if (KErrGeneral == stat.Int()) return ECONNREFUSED; } #if 0 /* TODO: Cause Access-Violation in WINS emulator! */ cus->iSocket.Send(buf_tx, 0, stat); #else cus->iSocket.SendTo(buf_tx, ia, 0, stat); #endif } else { cus->iSocket.SendTo(buf_tx, ia, 0, stat); } User::WaitForRequest(stat); return kerr2errno(stat.Int()); }
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_decode(struct sdp_session *sess, struct mbuf *mb, bool offer) { struct sdp_media *m; struct pl pl, val; struct le *le; char type = 0; int err = 0; if (!sess || !mb) return EINVAL; sdp_session_rreset(sess); for (le=sess->medial.head; le; le=le->next) { m = le->data; sdp_media_rreset(m); } pl.p = (const char *)mbuf_buf(mb); pl.l = mbuf_get_left(mb); m = NULL; for (;pl.l && !err; pl.p++, pl.l--) { switch (*pl.p) { case '\r': case '\n': if (!type) break; switch (type) { case 'a': err = attr_decode(sess, m, m ? &m->rdir : &sess->rdir, &val); break; case 'b': err = bandwidth_decode(m? m->rbwv : sess->rbwv, &val); break; case 'c': err = conn_decode(m ? &m->raddr : &sess->raddr, &val); break; case 'm': err = media_decode(&m, sess, offer, &val); break; case 'v': err = version_decode(&val); break; } #if 0 if (err) re_printf("*** %c='%r': %s\n", type, &val, strerror(err)); #endif type = 0; break; default: if (type) { val.l++; break; } if (pl.l < 2 || *(pl.p + 1) != '=') { err = EBADMSG; break; } type = *pl.p; val.p = pl.p + 2; val.l = 0; pl.p += 1; pl.l -= 1; break; } } if (err) return err; if (type) return EBADMSG; for (le=sess->medial.head; le; le=le->next) sdp_media_align_formats(le->data, offer); return 0; }
int stun_attr_decode(struct stun_attr **attrp, struct mbuf *mb, const uint8_t *tid, struct stun_unknown_attr *ua) { struct stun_attr *attr; size_t start, len; uint32_t i, n; int err = 0; if (!mb || !attrp) return EINVAL; if (mbuf_get_left(mb) < 4) return EBADMSG; attr = mem_zalloc(sizeof(*attr), destructor); if (!attr) return ENOMEM; attr->type = htons(mbuf_read_u16(mb)); len = htons(mbuf_read_u16(mb)); if (mbuf_get_left(mb) < len) goto badmsg; start = mb->pos; switch (attr->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_decode(mb, &attr->v.sa, tid); break; case STUN_ATTR_CHANGE_REQ: if (len != 4) goto badmsg; n = ntohl(mbuf_read_u32(mb)); attr->v.change_req.ip = (n >> 2) & 0x1; attr->v.change_req.port = (n >> 1) & 0x1; break; case STUN_ATTR_USERNAME: case STUN_ATTR_REALM: case STUN_ATTR_NONCE: case STUN_ATTR_SOFTWARE: err = str_decode(mb, &attr->v.str, len); break; case STUN_ATTR_MSG_INTEGRITY: if (len != 20) goto badmsg; err = mbuf_read_mem(mb, attr->v.msg_integrity, 20); break; case STUN_ATTR_ERR_CODE: if (len < 4) goto badmsg; mb->pos += 2; attr->v.err_code.code = (mbuf_read_u8(mb) & 0x7) * 100; attr->v.err_code.code += mbuf_read_u8(mb); err = str_decode(mb, &attr->v.err_code.reason, len - 4); break; case STUN_ATTR_UNKNOWN_ATTR: for (i=0; i<len/2; i++) { uint16_t type = ntohs(mbuf_read_u16(mb)); if (i >= ARRAY_SIZE(attr->v.unknown_attr.typev)) continue; attr->v.unknown_attr.typev[i] = type; attr->v.unknown_attr.typec++; } break; case STUN_ATTR_CHANNEL_NUMBER: case STUN_ATTR_RESP_PORT: if (len < 2) goto badmsg; attr->v.uint16 = ntohs(mbuf_read_u16(mb)); break; case STUN_ATTR_LIFETIME: case STUN_ATTR_PRIORITY: case STUN_ATTR_FINGERPRINT: if (len != 4) goto badmsg; attr->v.uint32 = ntohl(mbuf_read_u32(mb)); break; case STUN_ATTR_DATA: case STUN_ATTR_PADDING: attr->v.mb.buf = mem_ref(mb->buf); attr->v.mb.size = mb->size; attr->v.mb.pos = mb->pos; attr->v.mb.end = mb->pos + len; mb->pos += len; break; case STUN_ATTR_REQ_ADDR_FAMILY: case STUN_ATTR_REQ_TRANSPORT: if (len < 1) goto badmsg; attr->v.uint8 = mbuf_read_u8(mb); break; case STUN_ATTR_EVEN_PORT: if (len < 1) goto badmsg; attr->v.even_port.r = (mbuf_read_u8(mb) >> 7) & 0x1; break; case STUN_ATTR_DONT_FRAGMENT: case STUN_ATTR_USE_CAND: if (len > 0) goto badmsg; /* no value */ break; case STUN_ATTR_RSV_TOKEN: case STUN_ATTR_CONTROLLING: case STUN_ATTR_CONTROLLED: if (len != 8) goto badmsg; attr->v.uint64 = sys_ntohll(mbuf_read_u64(mb)); break; default: mb->pos += len; if (attr->type >= 0x8000) break; if (ua && ua->typec < ARRAY_SIZE(ua->typev)) ua->typev[ua->typec++] = attr->type; break; } if (err) goto error; /* padding */ while (((mb->pos - start) & 0x03) && mbuf_get_left(mb)) ++mb->pos; *attrp = attr; return 0; badmsg: err = EBADMSG; error: mem_deref(attr); return err; }
int call_accept(struct call *call, struct sipsess_sock *sess_sock, const struct sip_msg *msg) { bool got_offer; int err; if (!call || !msg) return EINVAL; call->outgoing = false; got_offer = (mbuf_get_left(msg->mb) > 0); err = pl_strdup(&call->peer_uri, &msg->from.auri); if (err) return err; if (pl_isset(&msg->from.dname)) { err = pl_strdup(&call->peer_name, &msg->from.dname); if (err) return err; } if (got_offer) { struct sdp_media *m; const struct sa *raddr; err = sdp_decode(call->sdp, msg->mb, true); if (err) return err; call->got_offer = true; /* * Each media description in the SDP answer MUST * use the same network type as the corresponding * media description in the offer. * * See RFC 6157 */ m = stream_sdpmedia(audio_strm(call->audio)); raddr = sdp_media_raddr(m); if (sa_af(raddr) != call->af) { info("call: incompatible address-family" " (local=%s, remote=%s)\n", net_af2name(call->af), net_af2name(sa_af(raddr))); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "Wrong address family"); return 0; } /* Check if we have any common audio codecs, after * the SDP offer has been parsed */ if (!have_common_audio_codecs(call)) { info("call: no common audio codecs - rejected\n"); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "No audio codecs"); return 0; } } err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing", ua_cuser(call->ua), "application/sdp", NULL, auth_handler, call->acc, true, sipsess_offer_handler, sipsess_answer_handler, sipsess_estab_handler, sipsess_info_handler, sipsess_refer_handler, sipsess_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: sipsess_accept: %m\n", err); return err; } set_state(call, STATE_INCOMING); /* New call */ tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call); if (!call->acc->mnat) call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri); return err; }
/** * Allocate a new Call state object * * @param callp Pointer to allocated Call state object * @param cfg Global configuration * @param lst List of call objects * @param local_name Local display name (optional) * @param local_uri Local SIP uri * @param acc Account parameters * @param ua User-Agent * @param prm Call parameters * @param msg SIP message for incoming calls * @param xcall Optional call to inherit properties from * @param eh Call event handler * @param arg Handler argument * * @return 0 if success, otherwise errorcode */ int call_alloc(struct call **callp, const struct config *cfg, struct list *lst, const char *local_name, const char *local_uri, struct account *acc, struct ua *ua, const struct call_prm *prm, const struct sip_msg *msg, struct call *xcall, call_event_h *eh, void *arg) { struct call *call; enum vidmode vidmode = prm ? prm->vidmode : VIDMODE_OFF; bool use_video = true, got_offer = false; int label = 0; int err = 0; if (!cfg || !local_uri || !acc || !ua) return EINVAL; call = mem_zalloc(sizeof(*call), call_destructor); if (!call) return ENOMEM; MAGIC_INIT(call); call->config_avt = cfg->avt; tmr_init(&call->tmr_inv); call->acc = mem_ref(acc); call->ua = ua; call->state = STATE_IDLE; call->eh = eh; call->arg = arg; call->af = prm ? prm->af : AF_INET; err = str_dup(&call->local_uri, local_uri); if (local_name) err |= str_dup(&call->local_name, local_name); if (err) goto out; /* Init SDP info */ err = sdp_session_alloc(&call->sdp, net_laddr_af(call->af)); if (err) goto out; err = sdp_session_set_lattr(call->sdp, true, "tool", "baresip " BARESIP_VERSION); if (err) goto out; /* Check for incoming SDP Offer */ if (msg && mbuf_get_left(msg->mb)) got_offer = true; /* Initialise media NAT handling */ if (acc->mnat) { err = acc->mnat->sessh(&call->mnats, net_dnsc(), call->af, acc->stun_host, acc->stun_port, acc->stun_user, acc->stun_pass, call->sdp, !got_offer, mnat_handler, call); if (err) { warning("call: medianat session: %m\n", err); goto out; } } call->mnat_wait = true; /* Media encryption */ if (acc->menc) { if (acc->menc->sessh) { err = acc->menc->sessh(&call->mencs, call->sdp, !got_offer, menc_error_handler, call); if (err) { warning("call: mediaenc session: %m\n", err); goto out; } } } /* Audio stream */ err = audio_alloc(&call->audio, cfg, call, call->sdp, ++label, acc->mnat, call->mnats, acc->menc, call->mencs, acc->ptime, account_aucodecl(call->acc), audio_event_handler, audio_error_handler, call); if (err) goto out; #ifdef USE_VIDEO /* We require at least one video codec, and at least one video source or video display */ use_video = (vidmode != VIDMODE_OFF) && (list_head(account_vidcodecl(call->acc)) != NULL) && (NULL != vidsrc_find(NULL) || NULL != vidisp_find(NULL)); /* Video stream */ if (use_video) { err = video_alloc(&call->video, cfg, call, call->sdp, ++label, acc->mnat, call->mnats, acc->menc, call->mencs, "main", account_vidcodecl(call->acc), video_error_handler, call); if (err) goto out; } if (str_isset(cfg->bfcp.proto)) { err = bfcp_alloc(&call->bfcp, call->sdp, cfg->bfcp.proto, !got_offer, acc->mnat, call->mnats); if (err) goto out; } #else (void)use_video; (void)vidmode; #endif /* inherit certain properties from original call */ if (xcall) { call->not = mem_ref(xcall->not); } list_append(lst, &call->le, call); out: if (err) mem_deref(call); else if (callp) *callp = call; return err; }
int decode_h263(struct viddec_state *st, struct vidframe *frame, bool marker, uint16_t seq, struct mbuf *src) { struct h263_hdr hdr; int err; if (!st || !frame) return EINVAL; if (!src) return 0; (void)seq; err = h263_hdr_decode(&hdr, src); if (err) return err; #if 0 debug(".....[%s seq=%5u ] MODE %s -" " SBIT=%u EBIT=%u I=%s" " (%5u/%5u bytes)\n", marker ? "M" : " ", seq, h263_hdr_mode(&hdr) == H263_MODE_A ? "A" : "B", hdr.sbit, hdr.ebit, hdr.i ? "Inter" : "Intra", mbuf_get_left(src), st->mb->end); #endif if (!hdr.i) st->got_keyframe = true; #if 0 if (st->mb->pos == 0) { uint8_t *p = mbuf_buf(src); if (p[0] != 0x00 || p[1] != 0x00) { warning("invalid PSC detected (%02x %02x)\n", p[0], p[1]); return EPROTO; } } #endif /* * The H.263 Bit-stream can be fragmented on bit-level, * indicated by SBIT and EBIT. Example: * * 8 bit 2 bit * .--------.--. * Packet 1 | | | * SBIT=0 '--------'--' * EBIT=6 * .------.--------.--------. * Packet 2 | | | | * SBIT=2 '------'--------'--------' * EBIT=0 6bit 8bit 8bit * */ if (hdr.sbit > 0) { const uint8_t mask = (1 << (8 - hdr.sbit)) - 1; const uint8_t sbyte = mbuf_read_u8(src) & mask; st->mb->buf[st->mb->end - 1] |= sbyte; } return ffdecode(st, frame, marker, src); }