/**
 * Allocate a new NAT Hairpinning discovery session
 *
 * @param nhp      Pointer to allocated NAT Hairpinning object
 * @param proto    Transport protocol
 * @param srv      STUN Server IP address and port number
 * @param proto    Transport protocol
 * @param conf     STUN configuration (Optional)
 * @param hph      Hairpinning result handler
 * @param arg      Handler argument
 *
 * @return 0 if success, errorcode if failure
 */
int nat_hairpinning_alloc(struct nat_hairpinning **nhp,
			  const struct sa *srv, int proto,
			  const struct stun_conf *conf,
			  nat_hairpinning_h *hph, void *arg)
{
	struct nat_hairpinning *nh;
	struct sa local;
	int err;

	if (!srv || !hph)
		return EINVAL;

	nh = mem_zalloc(sizeof(*nh), hairpinning_destructor);
	if (!nh)
		return ENOMEM;

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

	sa_cpy(&nh->srv, srv);
	nh->proto = proto;
	nh->hph   = hph;
	nh->arg   = arg;

	switch (proto) {

	case IPPROTO_UDP:
		err = udp_listen(&nh->us, NULL, udp_recv_handler, nh);
		break;

	case IPPROTO_TCP:
		sa_set_in(&local, 0, 0);

		/*
		 * Part I - Allocate and bind all sockets
		 */
		err = tcp_sock_alloc(&nh->ts, &local, tcp_conn_handler, nh);
		if (err)
			break;

		err = tcp_conn_alloc(&nh->tc, &nh->srv,
				     tcp_estab_handler, tcp_recv_handler,
				     tcp_close_handler, nh);
		if (err)
			break;

		err = tcp_sock_bind(nh->ts, &local);
		if (err)
			break;

		err = tcp_sock_local_get(nh->ts, &local);
		if (err)
			break;

		err = tcp_conn_bind(nh->tc, &local);
		if (err)
			break;

		/*
		 * Part II - Listen and connect all sockets
		 */
		err = tcp_sock_listen(nh->ts, 5);
		break;

	default:
		err = EPROTONOSUPPORT;
		break;
	}

 out:
	if (err)
		mem_deref(nh);
	else
		*nhp = nh;

	return err;
}
Esempio n. 2
0
static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
{
	ipc_callid_t callid;
	ipc_call_t call;
	tcp_client_t client;

	/* Accept the connection */
	async_answer_0(iid, EOK);

	client.sess = async_callback_receive(EXCHANGE_SERIALIZE);
	socket_cores_initialize(&client.sockets);

	while (true) {
		callid = async_get_call(&call);
		if (!IPC_GET_IMETHOD(call))
			break;

		log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
		    (int)IPC_GET_IMETHOD(call));

		switch (IPC_GET_IMETHOD(call)) {
		case NET_SOCKET:
			tcp_sock_socket(&client, callid, call);
			break;
		case NET_SOCKET_BIND:
			tcp_sock_bind(&client, callid, call);
			break;
		case NET_SOCKET_LISTEN:
			tcp_sock_listen(&client, callid, call);
			break;
		case NET_SOCKET_CONNECT:
			tcp_sock_connect(&client, callid, call);
			break;
		case NET_SOCKET_ACCEPT:
			tcp_sock_accept(&client, callid, call);
			break;
		case NET_SOCKET_SEND:
			tcp_sock_send(&client, callid, call);
			break;
		case NET_SOCKET_SENDTO:
			tcp_sock_sendto(&client, callid, call);
			break;
		case NET_SOCKET_RECV:
		case NET_SOCKET_RECVFROM:
			tcp_sock_recvfrom(&client, callid, call);
			break;
		case NET_SOCKET_CLOSE:
			tcp_sock_close(&client, callid, call);
			break;
		case NET_SOCKET_GETSOCKOPT:
			tcp_sock_getsockopt(&client, callid, call);
			break;
		case NET_SOCKET_SETSOCKOPT:
			tcp_sock_setsockopt(&client, callid, call);
			break;
		default:
			async_answer_0(callid, ENOTSUP);
			break;
		}
	}

	/* Clean up */
	log_msg(LVL_DEBUG, "tcp_sock_connection: Clean up");
	async_hangup(client.sess);
	socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data);
}