Exemple #1
0
int test_udp(void)
{
	struct udp_sock *uss2;
	struct udp_test *ut;
	int err;

	ut = mem_zalloc(sizeof(*ut), destructor);
	if (!ut)
		return ENOMEM;

	err  = sa_set_str(&ut->cli, "127.0.0.1", 0);
	err |= sa_set_str(&ut->srv, "127.0.0.1", 0);
	if (err)
		goto out;

	err  = udp_listen(&ut->usc, &ut->cli, udp_recv_client, ut);
	err |= udp_listen(&ut->uss, &ut->srv, udp_recv_server, ut);
	if (err)
		goto out;

	udp_rxbuf_presz_set(ut->uss, 16);

	err  = udp_local_get(ut->usc, &ut->cli);
	err |= udp_local_get(ut->uss, &ut->srv);
	if (err)
		goto out;

	err = udp_register_helper(&ut->uh, ut->usc, 0,
				  udp_helper_send, udp_helper_recv, ut);
	if (err)
		goto out;

	/* expect failure */
	if (!udp_listen(&uss2, &ut->srv, udp_recv_client, ut)) {
		err = EBUSY;
		goto out;
	}

	/* Send from connected client UDP socket */
	err = udp_connect(ut->usc, &ut->srv);
	if (err)
		goto out;

	/* Start test */
	err = send_data(ut->usc, &ut->srv, data0);
	if (err)
		goto out;

	err = re_main_timeout(100);
	if (err)
		goto out;

	if (ut->err)
		err = ut->err;

 out:
	mem_deref(ut);

	return err;
}
Exemple #2
0
int dns_server_alloc(struct dns_server **srvp, bool rotate)
{
	struct dns_server *srv;
	int err;

	if (!srvp)
		return EINVAL;

	srv = mem_zalloc(sizeof(*srv), destructor);
	if (!srv)
		return ENOMEM;

	err = sa_set_str(&srv->addr, "127.0.0.1", LOCAL_PORT);
	if (err)
		goto out;

	err = udp_listen(&srv->us, &srv->addr, udp_recv, srv);
	if (err)
		goto out;

	err = udp_local_get(srv->us, &srv->addr);
	if (err)
		goto out;

	srv->rotate = rotate;

 out:
	if (err)
		mem_deref(srv);
	else
		*srvp = srv;

	return err;
}
Exemple #3
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;
	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;
}
Exemple #4
0
int allocation_create(struct allocator *allocator, unsigned ix, int proto,
		      const struct sa *srv,
		      const char *username, const char *password,
		      struct tls *tls, bool turn_ind,
		      allocation_h *alloch, void *arg)
{
	struct allocation *alloc;
	struct sa laddr;
	int err;

	if (!allocator || !proto || !srv)
		return EINVAL;

	sa_init(&laddr, sa_af(srv));

	alloc = mem_zalloc(sizeof(*alloc), destructor);
	if (!alloc)
		return ENOMEM;

	list_append(&allocator->allocl, &alloc->le, alloc);

	(void)gettimeofday(&alloc->sent, NULL);

	alloc->atime     = -1;
	alloc->ix        = ix;
	alloc->allocator = allocator;
	alloc->proto     = proto;
	alloc->secure    = tls != NULL;
	alloc->srv       = *srv;
	alloc->user      = username;
	alloc->pass      = password;
	alloc->turn_ind  = turn_ind;
	alloc->alloch    = alloch;
	alloc->arg       = arg;
	alloc->tls       = mem_ref(tls);

	receiver_init(&alloc->recv, allocator->session_cookie, alloc->ix);

	err = udp_listen(&alloc->us_tx, &laddr, NULL, NULL);
	if (err) {
		re_fprintf(stderr, "allocation: failed to create UDP tx socket"
			   " (%m)\n", err);
		goto out;
	}

	udp_local_get(alloc->us_tx, &alloc->laddr_tx);

	err = start(alloc);
	if (err)
		goto out;

 out:
	if (err)
		mem_deref(alloc);

	return err;
}
Exemple #5
0
// receive callback
void p2p_receive_handler(const char* data, uint32_t len, struct p2pconnection* p2pcon)
{
	//struct p2pconnection* p2pcon = (struct p2pconnection*)arg;
	int fd = udp_sock_fd(p2pcon->ulsock, AF_INET);
	struct sa* lsa =NULL;
	lsa = (struct sa*)mem_zalloc(sizeof(struct sa),NULL);
	udp_local_get(p2pcon->ulsock, lsa);
	CUDT::postRecv(p2pcon->udtsock, &(lsa->u.sa), data, len);
	re_printf("p2p receive data:%s\n", data);
}
Exemple #6
0
int sip_server_create(struct sip_server **srvp)
{
	struct sip_server *srv;
	struct sa laddr_tp;
	int err;

	srv = mem_zalloc(sizeof *srv, destructor);
	if (!srv)
		return ENOMEM;

	err  = sa_set_str(&laddr_tp, "127.0.0.1", 0);
	err |= sa_set_str(&srv->laddr, "127.0.0.1", 0);
	if (err)
		goto out;

	err = sip_alloc(&srv->sip, NULL, 16, 16, 16,
			"dummy SIP registrar", NULL, NULL);
	if (err)
		goto out;

	err = sip_transp_add(srv->sip, SIP_TRANSP_UDP, &laddr_tp);
	if (err) {
		warning("failed to add sip transport (%m)\n", err);
		goto out;
	}

	err = udp_listen(&srv->us, &srv->laddr, udp_recv, srv);
	if (err) {
		warning("sip: udp_listen on '%J' failed (%d/%m)\n",
			&srv->laddr, err, err);
		goto out;
	}

	err = udp_local_get(srv->us, &srv->laddr);
	if (err) {
		warning("sip: udp_local_get\n");
		goto out;
	}

#if 0
	re_printf("sip: listen on %J\n", &srv->laddr);
#endif

 out:
	if (err)
		mem_deref(srv);
	else
		*srvp = srv;

	return err;
}
void TurnServer::init()
{
	int err;

	err = sa_set_str(&addr, "127.0.0.1", 0);
	if (err)
		goto out;

	err = udp_listen(&us, &addr, turnserver_udp_recv, this);
	if (err)
		goto out;

	err = udp_local_get(us, &addr);
	if (err)
		goto out;

	turnd = (struct turnd *)mem_zalloc(sizeof(*turnd), destructor);

	/* turn_external_addr */
	err = sa_set_str(&turnd->rel_addr, "127.0.0.1", 0);
	if (err) {
		goto out;
	}

	/* turn_max_lifetime, turn_max_allocations, udp_sockbuf_size */
	turnd->lifetime_max = TURN_DEFAULT_LIFETIME;

	err = hash_alloc(&turnd->ht_alloc, 32);
	if (err) {
		error("turnd hash alloc error: %m\n", err);
		goto out;
	}

	err = restund_tcp_init(turnd, fake_certificate_rsa);
	ASSERT_EQ(0, err);

	addr_tcp = *restund_tcp_laddr(turnd, false);
	addr_tls = *restund_tcp_laddr(turnd, true);

	turnd->recvh = tcp_handler;
	turnd->arg = this;

	info("turn: listen=%J, lifetime=%u ext=%j\n", &addr,
	      turnd->lifetime_max, &turnd->rel_addr);

 out:
	ASSERT_EQ(0, err);
}
Exemple #8
0
// connect callback
void p2p_request_handler(struct p2phandle *p2p, const char* peername, struct p2pconnection **p2pcon)
{
	re_fprintf(stderr, "p2p accept from:%s\n", peername);
	int err = p2p_accept(p2p, p2pcon, peername, p2p_receive_handler, *p2pcon);
	int fdaccept = udp_sock_fd((*p2pcon)->ulsock, AF_INET);
	struct sa* lsa = NULL;
	lsa = (struct sa*)mem_zalloc(sizeof(struct sa),NULL);
	udp_local_get((*p2pcon)->ulsock, lsa);
	sa_cpy(lsa, p2p->sactl);
	int fdlisten = tcp_conn_fd(p2p->ltcp);
	UDPSOCKET udpsock = (UDPSOCKET)fdlisten;
	(*p2pcon)->udtsock = CUDT::socket(AF_INET, SOCK_STREAM, 0);
	CUDT::bind((*p2pcon)->udtsock, &udpsock, &(p2p->sactl->u.sa), p2p->sactl->len);
	CUDT::listen((*p2pcon)->udtsock, &(lsa->u.sa), 10);
	if (err)
	{
		re_fprintf(stderr, "p2p accept error:%s\n", strerror(err));
		return ;
	}
}
Exemple #9
0
int turnserver_alloc(struct turnserver **turnp)
{
	struct turnserver *turn;
	struct sa laddr;
	int err = 0;

	if (!turnp)
		return EINVAL;

	turn = mem_zalloc(sizeof(*turn), destructor);
	if (!turn)
		return ENOMEM;

	err = sa_set_str(&laddr, "127.0.0.1", 0);
	if (err)
		goto out;

	err = udp_listen(&turn->us, &laddr, srv_udp_recv, turn);
	if (err)
		goto out;

	err = udp_local_get(turn->us, &turn->laddr);
	if (err)
		goto out;

	err = tcp_listen(&turn->ts, &laddr, tcp_conn_handler, turn);
	if (err)
		goto out;

	err = tcp_sock_local_get(turn->ts, &turn->laddr_tcp);
	if (err)
		goto out;

 out:
	if (err)
		mem_deref(turn);
	else
		*turnp = turn;

	return err;
}
Exemple #10
0
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;
}
Exemple #11
0
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;
}
Exemple #12
0
static void process_msg(struct turnserver *turn, int proto, void *sock,
			const struct sa *src, struct mbuf *mb)
{
	struct stun_msg *msg = NULL;
	struct sa laddr;
	int err = 0;

	if (stun_msg_decode(&msg, mb, NULL)) {

		uint16_t numb, len;
		struct channel *chan;

		if (!turn->us_relay)
			return;

		++turn->n_raw;

		numb = ntohs(mbuf_read_u16(mb));
		len  = ntohs(mbuf_read_u16(mb));

		if (mbuf_get_left(mb) < len) {
			DEBUG_WARNING("short length: %zu < %u\n",
				      mbuf_get_left(mb), len);
		}

		chan = find_channel_numb(turn, numb);
		if (!chan) {
			DEBUG_WARNING("channel not found: numb=%u\n", numb);
			return;
		}

		/* relay data from channel to peer */
		(void)udp_send(turn->us_relay, &chan->peer, mb);
		return;
	}

#if 0
	re_printf("process: %s:%p:%J %s\n",
		  net_proto2name(proto), sock, src,
		  stun_method_name(stun_msg_method(msg)));
#endif

	switch (stun_msg_method(msg)) {

	case STUN_METHOD_ALLOCATE:
		/* Max 1 allocation for now */
		++turn->n_allocate;

		if (turn->us_relay) {
			err = EALREADY;
			goto out;
		}

		turn->cli = *src;

		err = sa_set_str(&laddr, "127.0.0.1", 0);
		if (err)
			goto out;

		err = udp_listen(&turn->us_relay, &laddr,
				 relay_udp_recv, turn);
		if (err)
			goto out;

		err = udp_local_get(turn->us_relay, &turn->relay);
		if (err)
			goto out;

		udp_rxbuf_presz_set(turn->us_relay, 4);

		err = stun_reply(proto, sock, src, 0,
				 msg, NULL, 0, false,
				 2,
				 STUN_ATTR_XOR_MAPPED_ADDR, src,
				 STUN_ATTR_XOR_RELAY_ADDR, &turn->relay);
		break;

	case STUN_METHOD_CREATEPERM: {
		struct stun_attr *peer;

		++turn->n_createperm;

		peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
		TEST_ASSERT(peer != NULL);

		add_permission(turn, &peer->v.xor_peer_addr);

		/* todo: install permissions and check them */
		err = stun_reply(proto, sock, src, 0,
				 msg, NULL, 0, false,
				 0);
	}
		break;

	case STUN_METHOD_CHANBIND: {
		struct stun_attr *chnr, *peer;

		++turn->n_chanbind;

		TEST_ASSERT(turn->us_relay != NULL);

		chnr = stun_msg_attr(msg, STUN_ATTR_CHANNEL_NUMBER);
		peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
		if (!chnr || !peer) {
			DEBUG_WARNING("CHANBIND: missing chnr/peer attrib\n");
		}

		TEST_ASSERT(turn->chanc < ARRAY_SIZE(turn->chanv));
		turn->chanv[turn->chanc].nr   = chnr->v.channel_number;
		turn->chanv[turn->chanc].peer = peer->v.xor_peer_addr;
		++turn->chanc;

		err = stun_reply(proto, sock, src, 0,
				 msg, NULL, 0, false,
				 0);
	}
		break;

	case STUN_METHOD_SEND: {
		struct stun_attr *peer, *data;

		++turn->n_send;

		TEST_ASSERT(turn->us_relay != NULL);

		peer = stun_msg_attr(msg, STUN_ATTR_XOR_PEER_ADDR);
		data = stun_msg_attr(msg, STUN_ATTR_DATA);

		if (!peer || !data) {
			DEBUG_WARNING("SEND: missing peer/data attrib\n");
			goto out;
		}

		/* check for valid Permission */
		if (!find_permission(turn, &peer->v.xor_peer_addr)) {
			DEBUG_NOTICE("no permission to peer %j\n",
				     &peer->v.xor_peer_addr);
			goto out;
		}

		err = udp_send(turn->us_relay, &peer->v.xor_peer_addr,
			       &data->v.data);
	}
		break;

	default:
		DEBUG_WARNING("unknown STUN method: %s\n",
			      stun_method_name(stun_msg_method(msg)));
		err = EPROTO;
		break;
	}

	if (err)
		goto out;

 out:
	if (err && stun_msg_class(msg) == STUN_CLASS_REQUEST) {
		(void)stun_ereply(proto, sock, src, 0, msg,
				  500, "Server Error",
				  NULL, 0, false, 0);
	}

	mem_deref(msg);
}
Exemple #13
0
/**
 * Add a SIP transport
 *
 * @param sip   SIP stack instance
 * @param tp    SIP Transport
 * @param laddr Local network address
 * @param ...   Optional transport parameters such as TLS context
 *
 * @return 0 if success, otherwise errorcode
 */
int sip_transp_add(struct sip *sip, enum sip_transp tp,
		   const struct sa *laddr, ...)
{
	struct sip_transport *transp;
	struct tls *tls;
	va_list ap;
	int err;

	if (!sip || !laddr || !sa_isset(laddr, SA_ADDR))
		return EINVAL;

	transp = mem_zalloc(sizeof(*transp), transp_destructor);
	if (!transp)
		return ENOMEM;

	list_append(&sip->transpl, &transp->le, transp);
	transp->sip = sip;
	transp->tp  = tp;

	va_start(ap, laddr);

	switch (tp) {

	case SIP_TRANSP_UDP:
		err = udp_listen((struct udp_sock **)&transp->sock, laddr,
				 udp_recv_handler, transp);
		if (err)
			break;

		err = udp_local_get(transp->sock, &transp->laddr);
		break;

	case SIP_TRANSP_TLS:
		tls = va_arg(ap, struct tls *);
		if (!tls) {
			err = EINVAL;
			break;
		}

		transp->tls = mem_ref(tls);

		/*@fallthrough@*/

	case SIP_TRANSP_TCP:
		err = tcp_listen((struct tcp_sock **)&transp->sock, laddr,
				 tcp_connect_handler, transp);
		if (err)
			break;

		err = tcp_sock_local_get(transp->sock, &transp->laddr);
		break;

	default:
		err = EPROTONOSUPPORT;
		break;
	}

	va_end(ap);

	if (err)
		mem_deref(transp);

	return err;
}
Exemple #14
0
static int test_stun_request(int proto, bool natted)
{
	struct stunserver *srv = NULL;
	struct stun_ctrans *ct = NULL;
	struct nat *nat = NULL;
	struct test test;
	struct sa laddr, public_addr;
	int err;

	memset(&test, 0, sizeof(test));

	err = stunserver_alloc(&srv);
	if (err)
		goto out;

	err = stun_alloc(&test.stun, NULL, NULL, NULL);
	if (err)
		goto out;

	if (proto == IPPROTO_UDP) {
		err = sa_set_str(&laddr, "127.0.0.1", 0);
		TEST_ERR(err);

		err = udp_listen(&test.us, &laddr, udp_recv_handler, &test);
		if (err)
			goto out;
		err = udp_local_get(test.us, &laddr);
		TEST_ERR(err);
	}

	if (natted) {
		err = sa_set_str(&public_addr, "4.5.6.7", 0);
		TEST_ERR(err);

		err = nat_alloc(&nat, srv->us, &public_addr);
		if (err)
			goto out;

		sa_set_port(&public_addr, sa_port(&laddr));
	}
	else {
		public_addr = laddr;
	}

	err = stun_request(&ct, test.stun, proto, test.us,
			   stunserver_addr(srv, proto), 0,
			   STUN_METHOD_BINDING, NULL, 0, true,
			   stun_resp_handler, &test, 0);
	if (err)
		goto out;

	TEST_ASSERT(ct != NULL);

	err = re_main_timeout(100);
	if (err)
		goto out;

	if (srv->err) {
		err = srv->err;
		goto out;
	}
	if (test.err) {
		err = test.err;
		goto out;
	}

	/* verify results */
	TEST_ASSERT(srv->nrecv >= 1);
	TEST_EQUALS(1, test.n_resp);

	if (proto == IPPROTO_UDP) {
		TEST_SACMP(&public_addr, &test.mapped_addr, SA_ALL);
	}

 out:
	mem_deref(test.stun);
	mem_deref(test.us);
	mem_deref(nat);
	mem_deref(srv);

	return err;
}
Exemple #15
0
static void udp_read(struct udp_sock *us, int fd)
{
	struct mbuf *mb = mbuf_alloc(us->rxsz);
	struct sa src;
	struct le *le;
	int err = 0;
	ssize_t n;

	if (!mb)
		return;

	src.len = sizeof(src.u);
	n = recvfrom(fd, BUF_CAST mb->buf + us->rx_presz,
		     mb->size - us->rx_presz, 0,
		     &src.u.sa, &src.len);
	if (n < 0) {
		err = errno;

		if (EAGAIN == err)
			goto out;

#ifdef EWOULDBLOCK
		if (EWOULDBLOCK == err)
			goto out;
#endif

#if TARGET_OS_IPHONE
		if (ENOTCONN == err) {

			struct udp_sock *us_new;
			struct sa laddr;

			err = udp_local_get(us, &laddr);
			if (err)
				goto out;

			if (-1 != us->fd) {
				fd_close(us->fd);
				(void)close(us->fd);
				us->fd = -1;
			}

			if (-1 != us->fd6) {
				fd_close(us->fd6);
				(void)close(us->fd6);
				us->fd6 = -1;
			}

			err = udp_listen(&us_new, &laddr, NULL, NULL);
			if (err)
				goto out;

			us->fd  = us_new->fd;
			us->fd6 = us_new->fd6;

			us_new->fd  = -1;
			us_new->fd6 = -1;

			mem_deref(us_new);

			udp_thread_attach(us);

			goto out;
		}
#endif

		/* cache error code */
		us->err = err;

		goto out;
	}

	mb->pos = us->rx_presz;
	mb->end = n + us->rx_presz;

	(void)mbuf_resize(mb, mb->end);

	/* call helpers */
	le = us->helpers.head;
	while (le) {
		struct udp_helper *uh = le->data;
		bool hdld;

		le = le->next;

		hdld = uh->recvh(&src, mb, uh->arg);
		if (hdld)
			goto out;
	}

	us->rh(&src, mb, us->arg);

 out:
	mem_deref(mb);
}
/**
 * Allocate a new NAT Mapping Behaviour Discovery session
 *
 * @param nmp       Pointer to allocated NAT Mapping object
 * @param laddr     Local IP address
 * @param srv       STUN Server IP address and port
 * @param proto     Transport protocol
 * @param conf      STUN configuration (Optional)
 * @param mh        Mapping handler
 * @param arg       Handler argument
 *
 * @return 0 if success, errorcode if failure
 */
int nat_mapping_alloc(struct nat_mapping **nmp, const struct sa *laddr,
		      const struct sa *srv, int proto,
		      const struct stun_conf *conf,
		      nat_mapping_h *mh, void *arg)
{
	struct nat_mapping *nm;
	int i, err;

	if (!nmp || !laddr || !srv || !mh)
		return EINVAL;

	nm = mem_zalloc(sizeof(*nm), mapping_destructor);
	if (!nm)
		return ENOMEM;

	err = stun_alloc(&nm->stun, conf, NULL, NULL);
	if (err)
		goto out;

	nm->proto = proto;
	sa_cpy(&nm->laddr, laddr);

	switch (proto) {

	case IPPROTO_UDP:
		err = udp_listen(&nm->us, &nm->laddr, udp_recv_handler, nm);
		if (err)
			goto out;
		err = udp_local_get(nm->us, &nm->laddr);
		if (err)
			goto out;
		break;

	case IPPROTO_TCP:

		/* Allocate and bind 3 TCP Sockets */
		for (i=0; i<3; i++) {
			err = tcp_conn_alloc(&nm->tcv[i], srv,
					     tcp_estab_handler,
					     tcp_recv_handler,
					     tcp_close_handler, nm);
			if (err)
				goto out;

			err = tcp_conn_bind(nm->tcv[i], &nm->laddr);
			if (err)
				goto out;

			err = tcp_conn_local_get(nm->tcv[i], &nm->laddr);
			if (err)
				goto out;
		}
		break;

	default:
		err = EPROTONOSUPPORT;
		goto out;
	}

	sa_cpy(&nm->srv, srv);
	nm->mh  = mh;
	nm->arg = arg;

	*nmp = nm;

 out:
	if (err)
		mem_deref(nm);
	return err;
}
Exemple #17
0
/*
 * you can call this at any time
 *
 * @param addr HOST:     SA_ADDR portion is used
 *             non-HOST: SA_ADDR + SA_PORT portion is used
 *
 * @param base_addr  Optional
 * @param rel_addr   Optional
 *
 * @param layer  mandatory for HOST and RELAY candidates
 */
int trice_lcand_add(struct ice_lcand **lcandp, struct trice *icem,
		    unsigned compid, int proto,
		    uint32_t prio, const struct sa *addr,
		    const struct sa *base_addr,
		    enum ice_cand_type type, const struct sa *rel_addr,
		    enum ice_tcptype tcptype,
		    void *sock, int layer)
{
	struct ice_lcand *lcand;
	int err = 0;

	if (!icem || !compid || !proto || !addr)
		return EINVAL;

	if (!sa_isset(addr, SA_ADDR)) {
		DEBUG_WARNING("lcand_add: SA_ADDR is not set\n");
		return EINVAL;
	}
	if (type != ICE_CAND_TYPE_HOST) {
		if (!sa_isset(addr, SA_PORT)) {
			DEBUG_WARNING("lcand_add: %s: SA_PORT"
				      " must be set (%J)\n",
				      ice_cand_type2name(type), addr);
			return EINVAL;
		}
	}

	/* lookup candidate, replace if PRIO is higher */

	/* TODO: dont look up TCP-ACTIVE types for now (port is zero) */
	if (proto == IPPROTO_UDP) {

		lcand = trice_lcand_find(icem, -1, compid, proto, addr);
		if (lcand) {
			trice_printf(icem,
				    "add_local[%s.%J] --"
				    " candidate already exists"
				    " (%H)\n",
				    ice_cand_type2name(type), addr,
				    trice_cand_print, lcand);

			if (prio > lcand->attr.prio)
				lcand = mem_deref(lcand);
			else {
				goto out;
			}
		}
	}

	err = trice_add_lcandidate(&lcand, icem, &icem->lcandl, compid, NULL,
				   proto, prio, addr, base_addr,
				   type, rel_addr, tcptype);
	if (err)
		return err;

	if (type == ICE_CAND_TYPE_HOST) {

		switch (proto) {

		case IPPROTO_UDP:
			if (sock) {
				struct sa laddr;

				lcand->us = mem_ref(sock);

				err = udp_local_get(lcand->us,
						    &laddr);
				if (err)
					goto out;

				lcand->attr.addr = *addr;
				sa_set_port(&lcand->attr.addr,
					    sa_port(&laddr));
			}
			else {
				err = udp_listen(&lcand->us, addr,
						 dummy_udp_recv, lcand);
				if (err)
					goto out;

				err = udp_local_get(lcand->us,
						    &lcand->attr.addr);
				if (err)
					goto out;
			}

			err = udp_register_helper(&lcand->uh, lcand->us,
						  layer,
						  udp_helper_send_handler,
						  udp_helper_recv_handler,
						  lcand);
			if (err)
				goto out;
			break;

		case IPPROTO_TCP:

			/* TCP-transport has 3 variants:
			   active, passive, so */

			if (lcand->attr.tcptype == ICE_TCP_ACTIVE) {

				/* the port MUST be set to 9 (i.e., Discard) */
				/*sa_set_port(&lcand->attr.addr, 9); */
			}
			else if (lcand->attr.tcptype == ICE_TCP_PASSIVE ||
				 lcand->attr.tcptype == ICE_TCP_SO) {

				err = tcp_listen(&lcand->ts, addr,
						 tcp_conn_handler, lcand);
				if (err)
					goto out;
				err = tcp_local_get(lcand->ts,
						    &lcand->attr.addr);
				if (err)
					goto out;
			}
			else {
				err = EPROTONOSUPPORT;
				goto out;
			}
			break;

		default:
			err = EPROTONOSUPPORT;
			goto out;
		}
	}
	else if (type == ICE_CAND_TYPE_RELAY) {

		switch (proto) {

		case IPPROTO_UDP:

			if (sock) {
				lcand->us = mem_ref(sock);
			}
			else {
				err = udp_listen(&lcand->us, NULL,
						 dummy_udp_recv, lcand);
				if (err)
					goto out;
			}

			err = udp_register_helper(&lcand->uh, lcand->us,
						  layer,
						  udp_helper_send_handler,
						  udp_helper_recv_handler,
						  lcand);
			if (err)
				goto out;

			break;

		default:
			err = EPROTONOSUPPORT;
			goto out;
		}
	}
	else if (type == ICE_CAND_TYPE_SRFLX ||
		 type == ICE_CAND_TYPE_PRFLX) {

		/* Special case for SRFLX UDP candidates, if he has
		 * its own UDP-socket that can be used.
		 */
		if (proto == IPPROTO_UDP && sock) {

			lcand->us = mem_ref(sock);

			err = udp_register_helper(&lcand->uh, lcand->us,
						  layer,
						  udp_helper_send_handler,
						  udp_helper_recv_handler,
						  lcand);
			if (err)
				goto out;
		}
	}

	lcand->layer = layer;

	/* pair this local-candidate with all existing remote-candidates */
	err = trice_candpair_with_local(icem, lcand);
	if (err)
		goto out;

	/* new pair -- refresh the checklist timer */
	trice_checklist_refresh(icem);

 out:
	if (err)
		mem_deref(lcand);
	else if (lcandp)
		*lcandp = lcand;

	return err;
}