static int update(struct mnat_sess *sess) { struct le *le; int err = 0; if (!sess) return EINVAL; for (le=sess->medial.head; le; le=le->next) { struct mnat_media *m = le->data; struct sa raddr1, raddr2; raddr1 = *sdp_media_raddr(m->sdpm); sdp_media_raddr_rtcp(m->sdpm, &raddr2); if (m->turnc1 && sa_isset(&raddr1, SA_ALL)) err |= turnc_add_chan(m->turnc1, &raddr1, NULL, NULL); if (m->turnc2 && sa_isset(&raddr2, SA_ALL)) err |= turnc_add_chan(m->turnc2, &raddr2, NULL, NULL); } return err; }
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; }
/** * Get the local IP address of the device * * @note Requires at least one IP packet sent in advance! */ int net_if_getaddr4(const char *ifname, int af, struct sa *ip) { (void)ifname; if (AF_INET != af) return EAFNOSUPPORT; /* Already cached? */ if (sa_isset(&local_ip, SA_ADDR)) { sa_cpy(ip, &local_ip); return 0; } RSocketServ ss; RSocket s; TInt ret; ret = ss.Connect(); if (KErrNone != ret) { DEBUG_WARNING("connecting to socket server fail (ret=%d)\n", ret); return ECONNREFUSED; } ret = s.Open(ss, KAfInet, KSockDatagram, KProtocolInetUdp); if (KErrNone != ret) { DEBUG_WARNING("open socket failed (ret=%d)\n", ret); return ECONNREFUSED; } TInetAddr bind; bind.SetPort(0); bind.SetAddress(KInetAddrAny); ret = s.Bind(bind); if (KErrNone != ret) { DEBUG_WARNING("bind socket failed (ret=%d)\n", ret); return ECONNREFUSED; } TInetAddr local; s.LocalName(local); s.Close(); ss.Close(); sa_set_in(&local_ip, local.Address(), local.Port()); DEBUG_NOTICE("local IP addr: %j\n", &local_ip); if (!sa_isset(&local_ip, SA_ADDR)) return EINVAL; sa_cpy(ip, &local_ip); return 0; }
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 void turn_handler2(int err, uint16_t scode, const char *reason, const struct sa *relay_addr, const struct sa *mapped_addr, const struct stun_msg *msg, void *arg) { struct mnat_media *m = arg; (void)mapped_addr; (void)msg; if (!err && !scode) { sdp_media_set_laddr_rtcp(m->sdpm, relay_addr); m->addr2 = *relay_addr; if (m->turnc1 && !sa_isset(&m->addr1, SA_ALL)) return; if (--m->sess->mediac) return; } m->sess->estabh(err, scode, reason, m->sess->arg); }
static void turnc_handler(int err, uint16_t scode, const char *reason, const struct sa *relay, const struct sa *mapped, const struct stun_msg *msg, void *arg) { (void)msg; (void)arg; /* Transaction errors */ if (err) { DEBUG_WARNING("TURN Client error: %m\n", err); turn_done(); return; } /* STUN errors */ if (scode) { DEBUG_WARNING("TURN Client error: %u %s\n", scode, reason); turn_done(); return; } (void)re_fprintf(stderr, "Allocate Request: relay_addr=%J" ", mapped_addr=%J\n", relay, mapped); if (sa_isset(turnc.peer, SA_ALL)) { (void)re_fprintf(stderr, "ChannelBind: %J\n", turnc.peer); err = turnc_add_chan(turnc.tc, turnc.peer, NULL, NULL); if (err) { DEBUG_WARNING("TURN add channel: %m\n", err); } } }
static bool if_getaddr_handler(const char *ifname, const struct sa *sa, void *arg) { struct ifentry *ife = arg; /* Match name of interface? */ if (str_isset(ife->ifname) && 0 != str_casecmp(ife->ifname, ifname)) return false; if (!sa_isset(sa, SA_ADDR)) return false; #if 1 /* skip loopback and link-local IP */ if (sa_is_loopback(sa) || sa_is_linklocal(sa)) return false; #endif /* Match address family */ if (ife->af != sa_af(sa)) return false; /* Match - copy address */ sa_cpy(ife->ip, sa); ife->found = true; return ife->found; }
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; }
static int on_send_packet(const zrtp_stream_t *stream, char *rtp_packet, unsigned int rtp_packet_length) { struct menc_media *st = zrtp_stream_get_userdata(stream); struct mbuf *mb; int err; if (drop_packets(st)) return zrtp_status_ok; if (!sa_isset(&st->raddr, SA_ALL)) return zrtp_status_ok; mb = mbuf_alloc(PRESZ + rtp_packet_length); if (!mb) return zrtp_status_alloc_fail; mb->pos = PRESZ; (void)mbuf_write_mem(mb, (void *)rtp_packet, rtp_packet_length); mb->pos = PRESZ; err = udp_send_helper(st->rtpsock, &st->raddr, mb, st->uh_rtp); if (err) { warning("zrtp: udp_send %u bytes (%m)\n", rtp_packet_length, err); } mem_deref(mb); return zrtp_status_ok; }
int stream_send(struct stream *s, bool marker, int pt, uint32_t ts, struct mbuf *mb) { int err = 0; if (!s) return EINVAL; if (!sa_isset(sdp_media_raddr(s->sdp), SA_ALL)) return 0; if (sdp_media_dir(s->sdp) != SDP_SENDRECV) return 0; s->stats.b_tx += mbuf_get_left(mb); if (pt < 0) pt = s->pt_enc; if (pt >= 0) { err = rtp_send(s->rtp, sdp_media_raddr(s->sdp), marker, pt, ts, mb); } rtpkeep_refresh(s->rtpkeep, ts); ++s->stats.n_tx; return err; }
static int ua_add_transp(void) { int err = 0; if (!uag.prefer_ipv6) { if (sa_isset(net_laddr_af(AF_INET), SA_ADDR)) err |= add_transp_af(net_laddr_af(AF_INET)); } #if HAVE_INET6 if (sa_isset(net_laddr_af(AF_INET6), SA_ADDR)) err |= add_transp_af(net_laddr_af(AF_INET6)); #endif return err; }
int stream_send(struct stream *s, bool marker, int pt, uint32_t ts, struct mbuf *mb) { int err = 0; if (!s) return EINVAL; if (!sa_isset(sdp_media_raddr(s->sdp), SA_ALL)) return 0; if (sdp_media_dir(s->sdp) != SDP_SENDRECV) return 0; metric_add_packet(&s->metric_tx, mbuf_get_left(mb)); if (pt < 0) pt = s->pt_enc; if (pt >= 0) { err = rtp_send(s->rtp, sdp_media_raddr(s->sdp), marker, pt, ts, mb); if (err) s->metric_tx.n_err++; } rtpkeep_refresh(s->rtpkeep, ts); return err; }
/** * Get the Link-local address for a specific network interface * * @param ifname Name of the interface * @param af Address family * @param ip Returned link-local address * * @return 0 if success, otherwise errorcode */ int net_if_getlinklocal(const char *ifname, int af, struct sa *ip) { struct sa addr; void *argv[3]; int err; if (!ip) return EINVAL; sa_init(&addr, sa_af(ip)); argv[0] = (void *)ifname; argv[1] = ⁡ argv[2] = &addr; err = net_if_apply(linklocal_handler, argv); if (err) return err; if (!sa_isset(&addr, SA_ADDR)) return ENOENT; *ip = addr; return 0; }
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; int err = 0; if (!mp || !sess || !sdpm) return EINVAL; m = mem_zalloc(sizeof(*m), media_destructor); if (!m) return ENOMEM; list_append(&sess->medial, &m->le, m); m->sdpm = mem_ref(sdpm); m->sess = sess; m->sock1 = mem_ref(sock1); m->sock2 = mem_ref(sock2); m->proto = proto; if (sa_isset(&sess->srv, SA_ALL)) err = media_start(sess, m); if (err) mem_deref(m); else { *mp = m; ++sess->mediac; } return err; }
static int media_alloc(struct menc_media **stp, struct menc_sess *sess, struct rtp_sock *rtp, int proto, void *rtpsock, void *rtcpsock, struct sdp_media *sdpm) { struct menc_media *st; zrtp_status_t s; int layer = 10; /* above zero */ int err = 0; (void)rtcpsock; if (!stp || !sess || proto != IPPROTO_UDP) return EINVAL; st = *stp; if (st) goto start; st = mem_zalloc(sizeof(*st), media_destructor); if (!st) return ENOMEM; st->sess = sess; st->rtpsock = mem_ref(rtpsock); err = udp_register_helper(&st->uh, rtpsock, layer, udp_helper_send, udp_helper_recv, st); if (err) goto out; s = zrtp_stream_attach(sess->zrtp_session, &st->zrtp_stream); if (s != zrtp_status_ok) { warning("zrtp: zrtp_stream_attach failed (status=%d)\n", s); err = EPROTO; goto out; } zrtp_stream_set_userdata(st->zrtp_stream, st); out: if (err) { mem_deref(st); return err; } else *stp = st; start: if (sa_isset(sdp_media_raddr(sdpm), SA_ALL)) { st->raddr = *sdp_media_raddr(sdpm); s = zrtp_stream_start(st->zrtp_stream, rtp_sess_ssrc(rtp)); if (s != zrtp_status_ok) { warning("zrtp: zrtp_stream_start: status = %d\n", s); } } return err; }
/** * Send RTCP packet(s) to the Peer * * @param rs RTP Socket * @param mb Buffer containing the RTCP Packet(s) * * @return 0 for success, otherwise errorcode */ int rtcp_send(struct rtp_sock *rs, struct mbuf *mb) { if (!rs || !rs->sock_rtcp || !sa_isset(&rs->rtcp_peer, SA_ALL)) return EINVAL; return udp_send(rs->rtcp_mux ? rs->sock_rtp : rs->sock_rtcp, &rs->rtcp_peer, mb); }
/** * 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; }
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); } }
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); }
int trice_lcands_debug(struct re_printf *pf, const struct list *lst) { struct le *le; int err; err = re_hprintf(pf, " (%u)\n", list_count(lst)); for (le = list_head(lst); le && !err; le = le->next) { const struct ice_lcand *cand = le->data; err |= re_hprintf(pf, " {%u} [tx=%3zu, rx=%3zu] " "fnd=%-8s prio=%08x ", cand->attr.compid, cand->stats.n_tx, cand->stats.n_rx, cand->attr.foundation, cand->attr.prio); if (str_isset(cand->ifname)) err |= re_hprintf(pf, "%s:", cand->ifname); err |= re_hprintf(pf, "%24H", trice_cand_print, cand); if (sa_isset(&cand->base_addr, SA_ADDR)) { err |= re_hprintf(pf, " (base-addr = %J)", &cand->base_addr); } if (sa_isset(&cand->attr.rel_addr, SA_ADDR)) { err |= re_hprintf(pf, " (rel-addr = %J)", &cand->attr.rel_addr); } err |= re_hprintf(pf, "\n"); } return err; }
void *trice_lcand_sock(struct trice *icem, const struct ice_lcand *lcand) { struct ice_lcand *base = NULL; if (!icem || !lcand) return NULL; if (sa_isset(&lcand->base_addr, SA_ALL)) { enum ice_cand_type base_type; base_type = ice_cand_type_base(lcand->attr.type); base = trice_lcand_find(icem, base_type, lcand->attr.compid, lcand->attr.proto, &lcand->base_addr); } /* note: original lcand has presedence, fallback to base-candidate */ switch (lcand->attr.type) { case ICE_CAND_TYPE_HOST: return lcand->us; case ICE_CAND_TYPE_SRFLX: case ICE_CAND_TYPE_PRFLX: if (lcand->us) return lcand->us; else if (base && base->us) return base->us; else { DEBUG_NOTICE("lcand_sock: no SOCK or BASE for " " type '%s'\n", ice_cand_type2name(lcand->attr.type)); return NULL; } break; case ICE_CAND_TYPE_RELAY: return lcand->us; default: return NULL; } return NULL; }
static void mediaflow_localcand_handler( const struct zapi_candidate *candv, size_t candc, void *arg) { TestMedia *tm = static_cast<TestMedia *>(arg); ASSERT_TRUE(tm->candc < ARRAY_SIZE(tm->candv)); for (size_t i=0; i<candc; i++) { struct ice_cand_attr *cand = &tm->candv[tm->candc]; const struct zapi_candidate *zcand = &candv[i]; int err; if (0 == str_casecmp(zcand->sdp, "a=end-of-candidates")) { ++tm->n_local_eoc; continue; } tm->candc++; err = ice_cand_attr_decode(cand, zcand->sdp); ASSERT_EQ(0, err); ASSERT_STREQ("audio", zcand->mid); ASSERT_EQ(0, zcand->mline_index); /* verify that SRFLX and RELAY candidates contain the related address */ switch (cand->type) { case ICE_CAND_TYPE_SRFLX: case ICE_CAND_TYPE_RELAY: ASSERT_TRUE(sa_isset(&cand->rel_addr, SA_ALL)); break; default: break; } } if (tm->candc >= tm->candc_expected) re_cancel(); }
static void stun_response_handler(int err, uint16_t scode, const char *reason, const struct stun_msg *msg, void *arg) { struct sip_udpconn *uc = arg; struct stun_attr *attr; (void)reason; if (err || scode) { err = err ? err : EPROTO; goto out; } attr = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR); if (!attr) { attr = stun_msg_attr(msg, STUN_ATTR_MAPPED_ADDR); if (!attr) { err = EPROTO; goto out; } } if (!sa_isset(&uc->maddr, SA_ALL)) { uc->maddr = attr->v.sa; } else if (!sa_cmp(&uc->maddr, &attr->v.sa, SA_ALL)) { err = ENOTCONN; goto out; } out: if (err) { udpconn_close(uc, err); mem_deref(uc); } else { tmr_start(&uc->tmr_ka, sip_keepalive_wait(uc->ka_interval), udpconn_keepalive_handler, uc); } }
int icem_cands_debug(struct re_printf *pf, const struct list *lst) { struct le *le; int err; err = re_hprintf(pf, " (%u)\n", list_count(lst)); for (le = list_head(lst); le && !err; le = le->next) { const struct cand *cand = le->data; err |= re_hprintf(pf, " {%u} fnd=%-2s prio=%08x %24H", cand->compid, cand->foundation, cand->prio, icem_cand_print, cand); if (sa_isset(&cand->rel, SA_ADDR)) err |= re_hprintf(pf, " (rel-addr=%J)", &cand->rel); err |= re_hprintf(pf, "\n"); } return err; }
static void udp_loop_recv(const struct sa *src, struct mbuf *mb, void *arg) { int err; (void)arg; sa_cpy(&turnc.loop_src, src); if (!turnc.tc) { DEBUG_WARNING("no turn client\n"); return; } if (!sa_isset(turnc.peer, SA_ALL)) { DEBUG_WARNING("Peer not set\n"); return; } err = udp_send(turnc.us, turnc.peer, mb); if (err) { DEBUG_WARNING("turnc send data: %m\n", 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); }
static int module_init(void) { uint32_t x, bsize = ALLOC_DEFAULT_BSIZE; struct pl opt; int err = 0; restund_stun_register_handler(&stun); restund_cmd_subscribe(&cmd_turn); restund_cmd_subscribe(&cmd_turnstats); /* turn_external_addr */ if (!conf_get(restund_conf(), "turn_relay_addr", &opt)) err = sa_set(&turnd.rel_addr, &opt, 0); else sa_init(&turnd.rel_addr, AF_UNSPEC); if (err) { restund_error("turn: bad turn_relay_addr: '%r'\n", &opt); goto out; } /* turn_external_addr6 */ if (!conf_get(restund_conf(), "turn_relay_addr6", &opt)) err = sa_set(&turnd.rel_addr6, &opt, 0); else sa_init(&turnd.rel_addr6, AF_UNSPEC); if (err) { restund_error("turn: bad turn_relay_addr6: '%r'\n", &opt); goto out; } if (!sa_isset(&turnd.rel_addr, SA_ADDR) && !sa_isset(&turnd.rel_addr6, SA_ADDR)) { restund_error("turn: no relay address configured\n"); err = EINVAL; goto out; } /* turn_max_lifetime, turn_max_allocations, udp_sockbuf_size */ turnd.lifetime_max = TURN_DEFAULT_LIFETIME; conf_get_u32(restund_conf(), "turn_max_lifetime", &turnd.lifetime_max); conf_get_u32(restund_conf(), "turn_max_allocations", &bsize); conf_get_u32(restund_conf(), "udp_sockbuf_size", &turnd.udp_sockbuf_size); for (x=2; (uint32_t)1<<x<bsize; x++); bsize = 1<<x; err = hash_alloc(&turnd.ht_alloc, bsize); if (err) { restund_error("turnd hash alloc error: %m\n", err); goto out; } restund_debug("turn: lifetime=%u ext=%j ext6=%j bsz=%u\n", turnd.lifetime_max, &turnd.rel_addr, &turnd.rel_addr6, bsize); out: 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; }
/** * Allocate a TCP Connection * * @param tcp Returned TCP Connection object * @param peer Network address of peer * @param eh TCP Connection Established handler * @param rh TCP Connection Receive data handler * @param ch TCP Connection close handler * @param arg Handler argument * * @return 0 if success, otherwise errorcode */ 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; struct addrinfo hints, *res = NULL, *r; char addr[64]; char serv[NI_MAXSERV] = "0"; int error, err; if (!tcp || !sa_isset(peer, SA_ALL)) return EINVAL; tc = conn_alloc(eh, rh, ch, arg); if (!tc) return ENOMEM; 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)); err = EADDRNOTAVAIL; goto out; } err = EINVAL; for (r = res; r; r = r->ai_next) { tc->fdc = SOK_CAST socket(r->ai_family, SOCK_STREAM, IPPROTO_TCP); if (tc->fdc < 0) { err = errno; continue; } err = net_sockopt_blocking_set(tc->fdc, false); if (err) { DEBUG_WARNING("connect: nonblock set: %m\n", err); (void)close(tc->fdc); tc->fdc = -1; continue; } tcp_sockopt_set(tc->fdc); err = 0; break; } freeaddrinfo(res); out: if (err) mem_deref(tc); else *tcp = tc; return err; }