/** * 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; }
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); }