int ice_cand_attr_encode(struct re_printf *pf, const struct ice_cand_attr *cand) { int err = 0; if (!cand) return 0; err |= re_hprintf(pf, "%s %u %s %u %j %u typ %s", cand->foundation, cand->compid, net_proto2name(cand->proto), cand->prio, &cand->addr, sa_port(&cand->addr), ice_cand_type2name(cand->type)); if (sa_isset(&cand->rel_addr, SA_ADDR)) err |= re_hprintf(pf, " raddr %j", &cand->rel_addr); if (sa_isset(&cand->rel_addr, SA_PORT)) err |= re_hprintf(pf, " rport %u", sa_port(&cand->rel_addr)); if (cand->proto == IPPROTO_TCP) { err |= re_hprintf(pf, " tcptype %s", ice_tcptype_name(cand->tcptype)); } return err; }
static int cons_alloc(struct ui_st **stp, struct ui_prm *prm, ui_input_h *h, void *arg) { struct sa local; struct ui_st *st; int err; if (!stp) return EINVAL; if (cons_cur) { *stp = mem_ref(cons_cur); return 0; } st = mem_zalloc(sizeof(*st), cons_destructor); if (!st) return ENOMEM; st->ui = mem_ref(cons); st->h = h; st->arg = arg; err = sa_set_str(&local, "0.0.0.0", prm->port ? prm->port : CONS_PORT); if (err) goto out; err = udp_listen(&st->us, &local, udp_recv, st); if (err) { DEBUG_WARNING("failed to listen on UDP port %d (%m)\n", sa_port(&local), err); goto out; } err = tcp_listen(&st->ts, &local, tcp_conn_handler, st); if (err) { DEBUG_WARNING("failed to listen on TCP port %d (%m)\n", sa_port(&local), err); goto out; } out: if (err) mem_deref(st); else *stp = cons_cur = st; return err; }
int tcp_conn_alloc(struct tcp_conn **tcp, const struct sa *peer, tcp_estab_h *eh, tcp_recv_h *rh, tcp_close_h *ch, void *arg) { struct tcp_conn *tc; int err; if (!tcp || !sa_isset(peer, SA_ALL)) return EINVAL; tc = conn_alloc(NULL, eh, rh, ch, arg); if (!tc) return ENOMEM; TInetAddr ia(sa_in(peer), sa_port(peer)); err = tc->ctc->Open(ia); if (err) goto out; *tcp = tc; out: if (err) { DEBUG_WARNING("conn_alloc: %J (%s)\n", peer, strerror(err)); mem_deref(tc); } return err; }
TEST_F(TestMedia, gather_turn) { TurnServer srv; int err; candc_expected = 2; err = mediaflow_gather_turn(mf, &srv.addr, "user", "pass"); ASSERT_EQ(0, err); err = re_main_wait(10000); ASSERT_EQ(0, err); /* verify results after traffic is complete */ ASSERT_TRUE(srv.nrecv > 0); ASSERT_EQ(2, candc); ASSERT_EQ(1, n_local_eoc); ASSERT_TRUE(str_isset(candv[0].foundation)); ASSERT_EQ(1, candv[0].compid); ASSERT_EQ(IPPROTO_UDP, candv[0].proto); ASSERT_TRUE(0 != candv[0].prio); ASSERT_EQ(mediaflow_lport(mf), sa_port(&candv[0].addr)); ASSERT_EQ(ICE_CAND_TYPE_SRFLX, candv[0].type); ASSERT_TRUE(str_isset(candv[1].foundation)); ASSERT_EQ(1, candv[1].compid); ASSERT_EQ(IPPROTO_UDP, candv[1].proto); ASSERT_TRUE(0 != candv[1].prio); ASSERT_TRUE(sa_isset(&candv[1].addr, SA_ALL)); ASSERT_EQ(ICE_CAND_TYPE_RELAY, candv[1].type); }
static int media_alloc(struct mnat_media **mp, struct mnat_sess *sess, int proto, void *sock1, void *sock2, struct sdp_media *sdpm) { struct mnat_media *m; struct sa laddr; struct pcp_map map; unsigned i; int err = 0; if (!mp || !sess || !sdpm || proto != IPPROTO_UDP) return EINVAL; m = mem_zalloc(sizeof(*m), media_destructor); if (!m) return ENOMEM; m->compc = sock2 ? 2 : 1; list_append(&sess->medial, &m->le, m); m->sess = sess; m->sdpm = mem_ref(sdpm); for (i=0; i<m->compc; i++) { struct comp *comp = &m->compv[i]; comp->id = i+1; comp->media = m; err = udp_local_get(i==0 ? sock1 : sock2, &laddr); if (err) goto out; rand_bytes(map.nonce, sizeof(map.nonce)); map.proto = proto; map.int_port = sa_port(&laddr); /* note: using same address-family as the PCP server */ sa_init(&map.ext_addr, sa_af(&pcp_srv)); info("pcp: %s: internal port for %s is %u\n", sdp_media_name(sdpm), i==0 ? "RTP" : "RTCP", map.int_port); err = pcp_request(&comp->pcp, NULL, &pcp_srv, PCP_MAP, LIFETIME, &map, pcp_resp_handler, comp, 0); if (err) goto out; } out: if (err) mem_deref(m); else if (mp) { *mp = m; } return err; }
void sdp_media_align_formats(struct sdp_media *m, bool offer) { struct sdp_format *rfmt, *lfmt; struct le *rle, *lle; if (!m || m->disabled || !sa_port(&m->raddr)) return; for (lle=m->lfmtl.head; lle; lle=lle->next) { lfmt = lle->data; lfmt->sup = false; } for (rle=m->rfmtl.head; rle; rle=rle->next) { rfmt = rle->data; for (lle=m->lfmtl.head; lle; lle=lle->next) { lfmt = lle->data; if (sdp_format_cmp(lfmt, rfmt)) break; } if (!lle) { rfmt->sup = false; continue; } lfmt->sup = true; rfmt->sup = true; if (rfmt->ref) rfmt->data = mem_deref(rfmt->data); else rfmt->data = NULL; if (lfmt->ref) rfmt->data = mem_ref(lfmt->data); else rfmt->data = lfmt->data; rfmt->ref = lfmt->ref; if (offer) { mem_deref(lfmt->id); lfmt->id = mem_ref(rfmt->id); lfmt->pt = atoi(lfmt->id ? lfmt->id : ""); list_unlink(&lfmt->le); list_append(&m->lfmtl, &lfmt->le, lfmt); } } }
/** * Encode SDP candidate attribute * * @param pf Print function * @param cand Candidate to encode * * @return 0 if success, otherwise errorcode */ int ice_cand_encode(struct re_printf *pf, const struct ice_cand *cand) { int err; err = re_hprintf(pf, "%s %u %s %u %j %u typ %s", cand->foundation, cand->compid, transp_name(cand->transp), cand->prio, &cand->addr, sa_port(&cand->addr), ice_cand_type2name(cand->type)); if (sa_isset(&cand->rel, SA_ADDR)) err |= re_hprintf(pf, " raddr %j", &cand->rel); if (sa_isset(&cand->rel, SA_PORT)) err |= re_hprintf(pf, " rport %u", sa_port(&cand->rel)); return err; }
int tcp_conn_bind(struct tcp_conn *tc, const struct sa *local) { if (!tc || !tc->ctc || !local) return EINVAL; TInetAddr ia(sa_in(local), sa_port(local)); return tc->ctc->Bind(ia); }
int tcp_sock_bind(struct tcp_sock *ts, const struct sa *local) { if (!ts || !ts->cts || !local) return EINVAL; TInetAddr ia(sa_in(local), sa_port(local)); return ts->cts->Bind(ia); }
void sdp_media_raddr_rtcp(const struct sdp_media *m, struct sa *raddr) { if (!m || !raddr) return; if (sa_isset(&m->raddr_rtcp, SA_ALL)) { *raddr = m->raddr_rtcp; } else if (sa_isset(&m->raddr_rtcp, SA_PORT)) { *raddr = m->raddr; sa_set_port(raddr, sa_port(&m->raddr_rtcp)); } else { uint16_t port = sa_port(&m->raddr); *raddr = m->raddr; sa_set_port(raddr, port ? port + 1 : 0); } }
static int conn_decode(struct sa *sa, const struct pl *pl) { struct pl v; if (re_regex(pl->p, pl->l, "IN IP[46]1 [^ ]+", NULL, &v)) return EBADMSG; (void)sa_set(sa, &v, sa_port(sa)); return 0; }
int tcp_conn_connect(struct tcp_conn *tc, const struct sa *peer) { if (!tc || !tc->ctc || !sa_isset(peer, SA_ALL)) return EINVAL; tc->active = true; TInetAddr ia(sa_in(peer), sa_port(peer)); return tc->ctc->Connect(ia); }
/** * Bind to a TCP Socket * * @param ts TCP Socket * @param local Local bind address * * @return 0 if success, otherwise errorcode */ int tcp_sock_bind(struct tcp_sock *ts, const struct sa *local) { struct addrinfo hints, *res = NULL, *r; char addr[64] = ""; char serv[NI_MAXSERV] = "0"; int error, err; if (!ts || ts->fd<0) return EINVAL; if (local) { (void)re_snprintf(addr, sizeof(addr), "%H", sa_print_addr, local); (void)re_snprintf(serv, sizeof(serv), "%u", sa_port(local)); } memset(&hints, 0, sizeof(hints)); /* set-up hints structure */ hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; error = getaddrinfo(addr[0] ? addr : NULL, serv, &hints, &res); if (error) { #ifdef WIN32 DEBUG_WARNING("sock_bind: getaddrinfo: wsaerr=%d\n", WSAGetLastError()); #endif DEBUG_WARNING("sock_bind: getaddrinfo: %s:%s error=%d (%s)\n", addr, serv, error, gai_strerror(error)); return EADDRNOTAVAIL; } err = EINVAL; for (r = res; r; r = r->ai_next) { if (bind(ts->fd, r->ai_addr, SIZ_CAST r->ai_addrlen) < 0) { err = errno; DEBUG_WARNING("sock_bind: bind: %m (af=%d, %J)\n", err, r->ai_family, local); continue; } /* OK */ err = 0; break; } freeaddrinfo(res); return err; }
int udp_sock::listen(const struct sa *local) { TInetAddr ia(sa_in(local), sa_port(local)); const TInt ret = cus->iSocket.Bind(ia); if (KErrNone != ret) return kerr2errno(ret); cus->StartReceiving(); return 0; }
struct udp_sock *restund_udp_socket(struct sa *sa, const struct sa *orig, bool ch_ip, bool ch_port) { struct le *le = list_head(&lstnrl); while (le) { struct udp_lstnr *ul = le->data; le = le->next; if (ch_ip && sa_cmp(orig, &ul->bnd_addr, SA_PORT)) continue; if (ch_port && (sa_port(orig) == sa_port(&ul->bnd_addr))) continue; sa_cpy(sa, &ul->bnd_addr); return ul->us; } return NULL; }
int stun_uri_encode(struct re_printf *pf, const struct stun_uri *uri) { const char *scheme; uint16_t dport; int err; if (!uri) return 0; dport = uri->secure ? 5349 : 3478; switch (uri->scheme) { case STUN_SCHEME_STUN: scheme = "stun"; break; case STUN_SCHEME_TURN: scheme = "turn"; break; default: return EINVAL; } err = re_hprintf(pf, "%s%s:%j", scheme, uri->secure ? "s" : "", &uri->addr); if (err) return err; if (sa_port(&uri->addr) != dport) { err |= re_hprintf(pf, ":%u", sa_port(&uri->addr)); } if (uri->proto == IPPROTO_TCP) err |= re_hprintf(pf, "?transport=tcp"); return err; }
static bool udp_helper_send(int *err, struct sa *dst, struct mbuf *mb, void *arg) { struct menc_media *st = arg; unsigned int length; zrtp_status_t s; const char *proto_name = "rtp"; enum pkt_type ptype = get_packet_type(mb); if (drop_packets(st)) return true; length = (unsigned int)mbuf_get_left(mb); /* only RTP/RTCP packets should be processed */ if (ptype == PKT_TYPE_RTCP) { proto_name = "rtcp"; s = zrtp_process_rtcp(st->zrtp_stream, (char *)mbuf_buf(mb), &length); } else if (ptype == PKT_TYPE_RTP) { s = zrtp_process_rtp(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: send(port=%d): zrtp_process_%s failed" " (status = %d '%s')\n", sa_port(dst), proto_name, s, zrtp_log_status2str(s)); return false; } /* make sure target buffer is large enough */ if (length > mbuf_get_space(mb)) { warning("zrtp: zrtp_process_%s: length > space (%u > %u)\n", proto_name, length, mbuf_get_space(mb)); *err = ENOMEM; } mb->end = mb->pos + length; return false; }
/** * Encode the SDP "remote-candidates" Attribute * * @param pf Print function * @param icem ICE Media object * * @return 0 if success, otherwise errorcode */ int ice_remotecands_encode(struct re_printf *pf, const struct icem *icem) { struct le *le; int err = 0; if (!icem) return EINVAL; for (le = icem->rcandl.head; le && !err; le = le->next) { const struct ice_cand *rcand = le->data; err = re_hprintf(pf, "%s%d %j %u", icem->rcandl.head==le ? "" : " ", rcand->compid, &rcand->addr, sa_port(&rcand->addr)); } return err; }
static int listen_handler(const struct pl *addrport, void *arg) { uint32_t sockbuf_size = *(uint32_t *)arg; struct udp_lstnr *ul = NULL; int err = ENOMEM; ul = mem_zalloc(sizeof(*ul), destructor); if (!ul) { restund_warning("udp listen error: %s\n", strerror(err)); goto out; } list_append(&lstnrl, &ul->le, ul); err = sa_decode(&ul->bnd_addr, addrport->p, addrport->l); if (err || sa_is_any(&ul->bnd_addr) || !sa_port(&ul->bnd_addr)) { restund_warning("bad udp_listen directive: '%r'\n", addrport); err = EINVAL; goto out; } err = udp_listen(&ul->us, &ul->bnd_addr, udp_recv, ul); if (err) { restund_warning("udp listen %J: %s\n", &ul->bnd_addr, strerror(err)); goto out; } if (sockbuf_size > 0) (void)udp_sockbuf_set(ul->us, sockbuf_size); restund_debug("udp listen: %J\n", &ul->bnd_addr); out: if (err) mem_deref(ul); return err; }
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; }
const struct sdp_format *sdp_media_rformat(const struct sdp_media *m, const char *name) { struct le *le; if (!m || !sa_port(&m->raddr)) return NULL; for (le=m->rfmtl.head; le; le=le->next) { const struct sdp_format *fmt = le->data; if (!fmt->sup) continue; if (name && str_casecmp(name, fmt->name)) continue; return fmt; } return NULL; }
static int comp_alloc(struct comp *comp, void *sock) { struct sa laddr; int err; err = udp_local_get(sock, &laddr); if (err) goto out; comp->int_port = sa_port(&laddr); info("natpmp: `%s' stream comp %u local UDP port is %u\n", sdp_media_name(comp->media->sdpm), comp->id, comp->int_port); err = natpmp_mapping_request(&comp->natpmp, &natpmp_srv, comp->int_port, 0, comp->lifetime, natpmp_resp_handler, comp); if (err) goto out; out: return err; }
int icem_comp_alloc(struct icem_comp **cp, struct icem *icem, int id, void *sock) { struct icem_comp *comp; struct sa local; int err; if (!cp || !icem || id<1 || id>255 || !sock) return EINVAL; comp = mem_zalloc(sizeof(*comp), destructor); if (!comp) return ENOMEM; comp->id = id; comp->sock = mem_ref(sock); comp->icem = icem; err = udp_register_helper(&comp->uh, sock, icem->layer, NULL, helper_recv_handler, comp); if (err) goto out; err = udp_local_get(comp->sock, &local); if (err) goto out; comp->lport = sa_port(&local); out: if (err) mem_deref(comp); else *cp = comp; return err; }
static void aaaa_handler(int err, const struct dnshdr *hdr, struct list *ansl, struct list *authl, struct list *addl, void *arg) { struct stun_dns *dns = arg; struct dnsrr *rr; (void)hdr; (void)authl; (void)addl; /* Find A answers */ rr = dns_rrlist_find(ansl, NULL, DNS_TYPE_AAAA, DNS_CLASS_IN, false); if (!rr) { err = err ? err : EDESTADDRREQ; goto out; } sa_set_in6(&dns->srv, rr->rdata.aaaa.addr, sa_port(&dns->srv)); DEBUG_INFO("AAAA answer: %j\n", &dns->srv); out: resolved(dns, err); }
int stream_alloc(struct stream **sp, const struct config_avt *cfg, struct call *call, struct sdp_session *sdp_sess, const char *name, int label, const struct mnat *mnat, struct mnat_sess *mnat_sess, const struct menc *menc, struct menc_sess *menc_sess, const char *cname, stream_rtp_h *rtph, stream_rtcp_h *rtcph, void *arg) { struct stream *s; int err; if (!sp || !cfg || !call || !rtph) return EINVAL; s = mem_zalloc(sizeof(*s), stream_destructor); if (!s) return ENOMEM; s->cfg = *cfg; s->call = call; s->rtph = rtph; s->rtcph = rtcph; s->arg = arg; s->pseq = -1; s->rtcp = s->cfg.rtcp_enable; err = stream_sock_alloc(s, call_af(call)); if (err) { warning("stream: failed to create socket for media '%s'" " (%m)\n", name, err); goto out; } err = str_dup(&s->cname, cname); if (err) goto out; /* Jitter buffer */ if (cfg->jbuf_del.min && cfg->jbuf_del.max) { err = jbuf_alloc(&s->jbuf, cfg->jbuf_del.min, cfg->jbuf_del.max); if (err) goto out; } err = sdp_media_add(&s->sdp, sdp_sess, name, sa_port(rtp_local(s->rtp)), (menc && menc->sdp_proto) ? menc->sdp_proto : sdp_proto_rtpavp); if (err) goto out; if (label) { err |= sdp_media_set_lattr(s->sdp, true, "label", "%d", label); } /* RFC 5506 */ if (s->rtcp) err |= sdp_media_set_lattr(s->sdp, true, "rtcp-rsize", NULL); /* RFC 5576 */ if (s->rtcp) { err |= sdp_media_set_lattr(s->sdp, true, "ssrc", "%u cname:%s", rtp_sess_ssrc(s->rtp), cname); } /* RFC 5761 */ if (cfg->rtcp_mux) err |= sdp_media_set_lattr(s->sdp, true, "rtcp-mux", NULL); if (err) goto out; if (mnat) { err = mnat->mediah(&s->mns, mnat_sess, IPPROTO_UDP, rtp_sock(s->rtp), s->rtcp ? rtcp_sock(s->rtp) : NULL, s->sdp); if (err) goto out; } if (menc) { s->menc = menc; s->mencs = mem_ref(menc_sess); err = menc->mediah(&s->mes, menc_sess, s->rtp, IPPROTO_UDP, rtp_sock(s->rtp), s->rtcp ? rtcp_sock(s->rtp) : NULL, s->sdp); if (err) goto out; } if (err) goto out; s->pt_enc = -1; metric_init(&s->metric_tx); metric_init(&s->metric_rx); list_append(call_streaml(call), &s->le, s); out: if (err) mem_deref(s); else *sp = s; 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 stream_alloc(struct stream **sp, struct call *call, struct sdp_session *sdp_sess, const char *name, int label, const struct mnat *mnat, struct mnat_sess *mnat_sess, const struct menc *menc, struct menc_sess *menc_sess, stream_rtp_h *rtph, stream_rtcp_h *rtcph, void *arg) { struct stream *s; int err; if (!sp || !call || !rtph) return EINVAL; s = mem_zalloc(sizeof(*s), stream_destructor); if (!s) return ENOMEM; MAGIC_INIT(s); tmr_init(&s->tmr_stats); s->call = call; if (!str_casecmp(name, "audio")) s->type = STREAM_AUDIO; else if (!str_casecmp(name, "video")) s->type = STREAM_VIDEO; else s->type = STREAM_UNKNOWN; s->rtph = rtph; s->rtcph = rtcph; s->arg = arg; s->pseq = -1; s->rtcp = config.avt.rtcp_enable; err = stream_sock_alloc(s, call_af(call)); if (err) goto out; /* Jitter buffer */ if (config.avt.jbuf_del.min && config.avt.jbuf_del.max) { err = jbuf_alloc(&s->jbuf, config.avt.jbuf_del.min, config.avt.jbuf_del.max); if (err) goto out; } err = sdp_media_add(&s->sdp, sdp_sess, name, sa_port(rtp_local(s->rtp)), (menc && menc->sdp_proto) ? menc->sdp_proto : sdp_proto_rtpavp); if (err) goto out; if (label) { err |= sdp_media_set_lattr(s->sdp, true, "label", "%d", label); } /* RFC 5761 */ if (config.avt.rtcp_mux) err |= sdp_media_set_lattr(s->sdp, true, "rtcp-mux", NULL); if (mnat) { err |= mnat->mediah(&s->mns, mnat_sess, IPPROTO_UDP, rtp_sock(s->rtp), (s->rtcp && !config.avt.rtcp_mux) ? rtcp_sock(s->rtp) : NULL, s->sdp); } if (menc) { s->menc = menc; s->mencs = mem_ref(menc_sess); err |= menc->mediah(&s->mes, menc_sess, IPPROTO_UDP, rtp_sock(s->rtp), s->rtcp ? rtcp_sock(s->rtp) : NULL, s->sdp); } if (err) goto out; s->pt_enc = -1; list_append(call_streaml(call), &s->le, s); out: if (err) mem_deref(s); else *sp = s; return err; }
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; }
/** * Bind a TCP Connection to a local address * * @param tc TCP Connection object * @param local Local bind address * * @return 0 if success, otherwise errorcode */ int tcp_conn_bind(struct tcp_conn *tc, const struct sa *local) { struct addrinfo hints, *res = NULL, *r; char addr[64] = ""; char serv[NI_MAXSERV] = "0"; int error, err; if (!tc) return EINVAL; if (local) { (void)re_snprintf(addr, sizeof(addr), "%H", sa_print_addr, local); (void)re_snprintf(serv, sizeof(serv), "%u", sa_port(local)); } memset(&hints, 0, sizeof(hints)); /* set-up hints structure */ hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; error = getaddrinfo(addr[0] ? addr : NULL, serv, &hints, &res); if (error) { DEBUG_WARNING("conn_bind: getaddrinfo(): (%s)\n", gai_strerror(error)); return EADDRNOTAVAIL; } err = EINVAL; for (r = res; r; r = r->ai_next) { (void)net_sockopt_reuse_set(tc->fdc, true); /* bind to local address */ if (bind(tc->fdc, r->ai_addr, SIZ_CAST r->ai_addrlen) < 0) { /* Special case for mingw32/wine */ if (0 == errno) { goto ok; } err = errno; DEBUG_WARNING("conn_bind: bind(): %J: %m\n", local, err); continue; } ok: /* OK */ err = 0; break; } freeaddrinfo(res); if (err) { DEBUG_WARNING("conn_bind failed: %J (%m)\n", local, err); } return err; }
/** * Connect to a remote peer * * @param tc TCP Connection object * @param peer Network address of peer * * @return 0 if success, otherwise errorcode */ int tcp_conn_connect(struct tcp_conn *tc, const struct sa *peer) { struct addrinfo hints, *res = NULL, *r; char addr[64]; char serv[NI_MAXSERV]; int error, err = 0; if (!tc || !sa_isset(peer, SA_ALL)) return EINVAL; tc->active = true; if (tc->fdc < 0) { DEBUG_WARNING("invalid fd\n"); return EBADF; } memset(&hints, 0, sizeof(hints)); /* set-up hints structure */ hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; (void)re_snprintf(addr, sizeof(addr), "%H", sa_print_addr, peer); (void)re_snprintf(serv, sizeof(serv), "%u", sa_port(peer)); error = getaddrinfo(addr, serv, &hints, &res); if (error) { DEBUG_WARNING("connect: getaddrinfo(): (%s)\n", gai_strerror(error)); return EADDRNOTAVAIL; } for (r = res; r; r = r->ai_next) { struct sockaddr *sa = r->ai_addr; again: if (0 == connect(tc->fdc, sa, SIZ_CAST r->ai_addrlen)) { err = 0; goto out; } else { #ifdef WIN32 /* Special error handling for Windows */ if (WSAEWOULDBLOCK == WSAGetLastError()) { err = 0; goto out; } #endif /* Special case for mingw32/wine */ if (0 == errno) { err = 0; goto out; } if (EINTR == errno) goto again; if (EINPROGRESS != errno && EALREADY != errno) { err = errno; DEBUG_INFO("connect: connect() %J: %m\n", peer, err); } } } out: freeaddrinfo(res); if (err) return err; return fd_listen(tc->fdc, FD_READ | FD_WRITE | FD_EXCEPT, tcp_recv_handler, tc); }