示例#1
0
/*
 * Write len bytes from buf to the socket.
 * Returns the return value from send()
 * Assert Class: 0
 */
int sock_write_bytes(SOCKET sockfd, const char *buff, int len)
{
	int t;

	if (!buff) {
		xa_debug(1,
			 "ERROR: sock_write_bytes() called with NULL data");
		return -1;
	} else if (len <= 0) {
		xa_debug(1,
			 "ERROR: sock_write_bytes() called with zero or negative len");
		return -1;
	} else if (!sock_valid(sockfd)) {
		xa_debug(1,
			 "ERROR: sock_write_bytes() called with invalid socket");
		return -1;
	}

	for(t=0 ; len > 0 ; ) {
		int n=send(sockfd, buff+t, len, 0);
		
		if (n < 0)
		    return (t == 0) ? n : t;
		t+=n;
		len-=n;
	}

	return t;
}
示例#2
0
/* return 1 on success
 * return 0 on failure
 */
static int accept_connection(TCP_Server *TCP_server, sock_t sock)
{
    if (!sock_valid(sock))
        return 0;

    if (!set_socket_nonblock(sock)) {
        kill_sock(sock);
        return 0;
    }

    if (!set_socket_nosigpipe(sock)) {
        kill_sock(sock);
        return 0;
    }

    TCP_Secure_Connection *conn =
        &TCP_server->incomming_connection_queue[TCP_server->incomming_connection_queue_index % MAX_INCOMMING_CONNECTIONS];

    if (conn->status != TCP_STATUS_NO_STATUS)
        kill_TCP_connection(conn);

    conn->status = TCP_STATUS_CONNECTED;
    conn->sock = sock;
    conn->next_packet_length = 0;

    ++TCP_server->incomming_connection_queue_index;
    return 1;
}
示例#3
0
static sock_t new_listening_TCP_socket(int family, uint16_t port)
{
    sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP);

    if (!sock_valid(sock)) {
        return ~0;
    }

    int ok = set_socket_nonblock(sock);

    if (ok && family == AF_INET6) {
        ok = set_socket_dualstack(sock);
    }

    if (ok) {
        ok = set_socket_reuseaddr(sock);
    }

    ok = ok && bind_to_port(sock, family, port) && (listen(sock, TCP_MAX_BACKLOG) == 0);

    if (!ok) {
        kill_sock(sock);
        return ~0;
    }

    return sock;
}
示例#4
0
int
sock_del (SOCKET s)
{
	ice_socket_t *is, *ds;

	xa_debug (3, "DEBUG: sock_del(): Removing socket %d", s);

	if (!sock_valid (s)) {
		xa_debug (1, "WARNING: Tried to remove invalid socket %d", s);
		return -1;
	}



	is = sock_find (s);

	if (!is) {
		xa_debug (1, "WARNING: Tried to remove a nonlisted socket %d", s);
		return -1;
	}

	thread_mutex_lock (&sock_mutex);
	ds = avl_delete (sock_sockets, is);

	if (ds) {
		nfree (ds);
		thread_mutex_unlock (&sock_mutex);
		return 1;
	}

	thread_mutex_unlock (&sock_mutex);
	return -1;
}
示例#5
0
/* return index on success
 * return -1 on failure
 */
static int accept_connection(TCP_Server *TCP_server, Socket sock)
{
    if (!sock_valid(sock)) {
        return -1;
    }

    if (!set_socket_nonblock(sock)) {
        kill_sock(sock);
        return -1;
    }

    if (!set_socket_nosigpipe(sock)) {
        kill_sock(sock);
        return -1;
    }

    uint16_t index = TCP_server->incoming_connection_queue_index % MAX_INCOMING_CONNECTIONS;

    TCP_Secure_Connection *conn = &TCP_server->incoming_connection_queue[index];

    if (conn->status != TCP_STATUS_NO_STATUS) {
        kill_TCP_secure_connection(conn);
    }

    conn->status = TCP_STATUS_CONNECTED;
    conn->sock = sock;
    conn->next_packet_length = 0;

    ++TCP_server->incoming_connection_queue_index;
    return index;
}
示例#6
0
static sock_t new_listening_TCP_socket(int family, uint16_t port)
{
    sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP);

    if (!sock_valid(sock)) {
        return ~0;
    }

#ifndef TCP_SERVER_USE_EPOLL
    int ok = set_socket_nonblock(sock);
#else
    int ok = 1;
#endif

    if (ok && family == AF_INET6) {
        ok = set_socket_dualstack(sock);
    }

    ok = ok && bind_to_port(sock, family, port) && (listen(sock, TCP_MAX_BACKLOG) == 0);

    if (!ok) {
        kill_sock(sock);
        return ~0;
    }

    return sock;
}
示例#7
0
/* 
 * Read a HTTP header. A number of lines terminated by a two newlines.
 * Reads no more than len bytes into string pointed to by buff. If the
 * return value is 1, then the string is valid and null terminated.
 * Assert Class: 3
 * Potential Problems: Usage of errno
 */
int sock_read_lines_np(SOCKET sockfd, char *buff, const int len)
{
	char c = '\0';
	int read_bytes, pos = 0;

	if (!sock_valid(sockfd)) {
		xa_debug(1,
			 "ERROR: sock_read_lines_np() called with invalid socket");
		return 0;
	} else if (!buff) {
		xa_debug(1,
			 "ERROR: sock_read_lines_np() called with NULL storage pointer");
		return 0;
	} else if (len <= 0) {
		xa_debug(1,
			 "ERROR: sock_read_lines_np() called with invalid length");
		return 0;
	}
#ifdef _WIN32
	WSASetLastError(0);
#else
	errno = 0;
#endif

	read_bytes = recv(sockfd, &c, 1, 0);

	if (read_bytes < 0) {
		xa_debug(1, "DEBUG: Socket error on socket %d %d", sockfd,
			 errno);
		return 0;
	}

	while ((read_bytes == 1) && (pos < (len - 1))) {
		if (c != '\r')
			buff[pos++] = c;
		if ((pos > 1)
		    && (buff[pos - 1] == '\n'
			&& buff[pos - 2] == '\n')) break;
#ifdef _WIN32
		WSASetLastError(0);
#else
		errno = 0;
#endif
		read_bytes = recv(sockfd, &c, 1, 0);
		if (read_bytes < 0) {
			xa_debug(1, "DEBUG: Socket error on socket %d %d",
				 sockfd, errno);
			return 0;
		}
	}

	if (read_bytes == 1) {
		buff[pos] = '\0';
		return 1;
	} else {
		return 0;
	}
}
TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t *ports, uint8_t *public_key,
                           uint8_t *secret_key, Onion *onion)
{
    if (num_sockets == 0 || ports == NULL)
        return NULL;

    if (networking_at_startup() != 0) {
        return NULL;
    }

    TCP_Server *temp = calloc(1, sizeof(TCP_Server));

    if (temp == NULL)
        return NULL;

    temp->socks_listening = calloc(num_sockets, sizeof(sock_t));

    if (temp->socks_listening == NULL) {
        free(temp);
        return NULL;
    }

    uint8_t family;

    if (ipv6_enabled) {
        family = AF_INET6;
    } else {
        family = AF_INET;
    }

    uint32_t i;

    for (i = 0; i < num_sockets; ++i) {
        sock_t sock = new_listening_TCP_socket(family, ports[i]);

        if (sock_valid(sock)) {
            temp->socks_listening[temp->num_listening_socks] = sock;
            ++temp->num_listening_socks;
        }
    }

    if (temp->num_listening_socks == 0) {
        free(temp);
        return NULL;
    }

    if (onion) {
        temp->onion = onion;
        set_callback_handle_recv_1(onion, &handle_onion_recv_1, temp);
    }

    memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES);
    memcpy(temp->secret_key, secret_key, crypto_box_SECRETKEYBYTES);
    return temp;
}
示例#9
0
/* 
 * Set or the socket to blocking or nonblocking. 
 * Assert Class: 1 
 */
int sock_set_blocking(SOCKET sockfd, const int block)
{
#ifdef _WIN32
	int varblock = block;
#else
	int res;
#endif
	
	xa_debug(3, "Setting fd %d to %s", sockfd,
		 (block == SOCK_BLOCK) ? "blocking" : "nonblocking");
	
	if (!sock_valid(sockfd)) {
		xa_debug(1,
			 "ERROR: sock_set_blocking() called with invalid socket");
		return SOCKET_ERROR;
	} else if ((block < 0) || (block > 1)) {
		xa_debug(1,
			 "ERROR: sock_set_blocking() called with invalid block value");
		return SOCKET_ERROR;
	}
#ifdef _WIN32
	return ioctlsocket(sockfd, FIONBIO, &varblock);
#else
	res = fcntl(sockfd, F_SETFL, (block == SOCK_BLOCK) ? 0 : O_NONBLOCK);

	if (res == -1) {
		xa_debug (1, "WARNING: sock_set_blocking() on socket %d failed", sockfd);
		return -1;
	}

# ifdef DEBUG_SOCKETS
	{
		ice_socket_t *is = sock_find (sockfd);
		if (!is) {
			write_log (LOG_DEFAULT, "WARNING: sock_set_blocking(): Unknown socket %d", sockfd);
			return -1;
		} else {
			is->blocking = block;
		}
	}
# endif
	return res;
#endif
}
示例#10
0
TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t *ports, uint8_t *public_key,
                           uint8_t *secret_key)
{
    if (num_sockets == 0 || ports == NULL)
        return NULL;

    TCP_Server *temp = calloc(1, sizeof(TCP_Server));

    if (temp == NULL)
        return NULL;

    temp->socks_listening = calloc(num_sockets, sizeof(sock_t));

    if (temp->socks_listening == NULL) {
        free(temp);
        return NULL;
    }

    uint8_t family;

    if (ipv6_enabled) {
        family = AF_INET6;
    } else {
        family = AF_INET;
    }

    uint32_t i;

    for (i = 0; i < num_sockets; ++i) {
        sock_t sock = new_listening_TCP_socket(family, ports[i]);

        if (sock_valid(sock)) {
            temp->socks_listening[temp->num_listening_socks] = sock;
            ++temp->num_listening_socks;
        }
    }

    memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES);
    memcpy(temp->secret_key, secret_key, crypto_box_SECRETKEYBYTES);
    return temp;
}
示例#11
0
/* 
 * Write len bytes from buff to the client. Kick him on network errors.
 * Return the number of bytes written and -1 on error.
 * Assert Class: 2
 * Potential problems: Any usage of errno is bad in a threaded application.
 */
int
sock_write_bytes_or_kick(SOCKET sockfd, connection_t * clicon,
			 const char *buff, const int len)
{
	int res, err;

	if (!sock_valid(sockfd)) {
		xa_debug(1,
			 "ERROR: sock_write_bytes_or_kick() called with invalid socket");
		return -1;
	} else if (!clicon) {
		xa_debug(1,
			 "ERROR: sock_write_bytes_or_kick() called with NULL client");
		return -1;
	} else if (!buff) {
		xa_debug(1,
			 "ERROR: sock_write_bytes_or_kick() called with NULL data");
		return -1;
	} else if (len <= 0) {
		xa_debug(1,
			 "ERROR: sock_write_bytes_or_kick() called with invalid length");
		return -1;
	}

	errno = 666;

	res = sock_write_bytes(sockfd, buff, len);

	err = errno;

	if (res < 0) {
		xa_debug(4, "DEBUG: sock_write_bytes_or_kick: %d err [%d]",
			 res, err);

		if (!is_recoverable(errno)) {
			kick_connection(clicon, "Client signed off");
			return -1;
		}
	}
	return res;
}
示例#12
0
int
sock_insert (ice_socket_t *is)
{
	if (!is || !sock_valid (is->sock)) {
		write_log (LOG_DEFAULT, "WARNING: Tried to insert NULL socket");
		return -1;
	}

	xa_debug (4, "DEBUG: inserting socket %d", is->sock);

	thread_mutex_lock (&sock_mutex);

	if (avl_insert (sock_sockets, is)) {
		write_log (LOG_DEFAULT, "WARNING: Tried to insert duplicate socket. Weird!");
		thread_mutex_unlock (&sock_mutex);
		return 0;
	}

	thread_mutex_unlock (&sock_mutex);
	return 1;
}
示例#13
0
/*
 * Write a string to a socket. 
 * Return 1 if all bytes where successfully written, and 0 if not.
 * Assert Class: 2
 */
int sock_write_string(SOCKET sockfd, const char *buff)
{
	int write_bytes = 0, res = 0, len = ice_strlen(buff);

	if (!sock_valid(sockfd)) {
		fprintf(stderr,
			"ERROR: sock_write_string() called with invalid socket\n");
		return -1;
	} else if (!buff) {
		fprintf(stderr,
			"ERROR: sock_write_string() called with NULL format\n");
		return -1;
	}

	/*
	 * Never use send() to sockets 0 or 1 in Win32.
	 */

	if (sockfd == 1 || sockfd == 0) {
		if (running == SERVER_RUNNING) {
			write_bytes = fprintf(stdout, "%s", buff);
			fflush(stdout);
		}
	} else {
		while (write_bytes < len) {
			res =
				send(sockfd, &buff[write_bytes],
				     len - write_bytes, 0);
			if (res < 0 && !is_recoverable(errno))
				return 0;
			if (res > 0)
				write_bytes += res;
			else
				my_sleep(30000);
		}
	}

	return (write_bytes == len ? 1 : 0);
}
示例#14
0
SOCKET sock_accept(SOCKET s, struct sockaddr * addr, socklen_t * addrlen)
{
	SOCKET rs = accept(s, addr, addrlen);

	xa_debug (4, "DEBUG: sock_accept() created socket %d", s);

	if (sock_valid(rs)) {
#ifdef DEBUG_SOCKETS
		sock_add (rs, AF_INET, SOCK_STREAM, 0);
#endif
		/*
		 * Turn on KEEPALIVE to detect crashed hosts 
		 */
		sock_set_keepalive(rs, 1);

#ifdef SO_LINGER
		sock_set_no_linger(rs);
#endif
	}

	return rs;
}
示例#15
0
SOCKET sock_socket(int domain, int type, int protocol)
{
	SOCKET s = socket(domain, type, protocol);

	xa_debug (4, "DEBUG: sock_socket() creating socket %d", s);

	if (sock_valid(s)) {
#ifdef DEBUG_SOCKETS
		sock_add (s, domain, type, protocol);
#endif
		/*
		 * Turn on KEEPALIVE to detect crashed hosts 
		 */
		sock_set_keepalive(s, 1);

#ifdef SO_LINGER
		sock_set_no_linger(s);
#endif
	}

	return s;
}
示例#16
0
static void do_TCP_epoll(TCP_Server *TCP_server)
{
#define MAX_EVENTS 16
    struct epoll_event events[MAX_EVENTS];
    int nfds;

    while ((nfds = epoll_wait(TCP_server->efd, events, MAX_EVENTS, 0)) > 0) {
        int n;

        for (n = 0; n < nfds; ++n) {
            sock_t sock = events[n].data.u64 & 0xFFFFFFFF;
            int status = (events[n].data.u64 >> 32) & 0xFF, index = (events[n].data.u64 >> 40);

            if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP) || (events[n].events & EPOLLRDHUP)) {
                switch (status) {
                    case TCP_SOCKET_LISTENING: {
                        //should never happen
                        break;
                    }

                    case TCP_SOCKET_INCOMING: {
                        kill_TCP_connection(&TCP_server->incomming_connection_queue[index]);
                        break;
                    }

                    case TCP_SOCKET_UNCONFIRMED: {
                        kill_TCP_connection(&TCP_server->unconfirmed_connection_queue[index]);
                        break;
                    }

                    case TCP_SOCKET_CONFIRMED: {
                        kill_accepted(TCP_server, index);
                        break;
                    }
                }

                continue;
            }


            if (!(events[n].events & EPOLLIN)) {
                continue;
            }

            switch (status) {
                case TCP_SOCKET_LISTENING: {
                    //socket is from socks_listening, accept connection
                    struct sockaddr_storage addr;
                    socklen_t addrlen = sizeof(addr);

                    while (1) {
                        sock_t sock_new = accept(sock, (struct sockaddr *)&addr, &addrlen);

                        if (!sock_valid(sock_new)) {
                            break;
                        }

                        int index_new = accept_connection(TCP_server, sock_new);

                        if (index_new == -1) {
                            continue;
                        }

                        struct epoll_event ev = {
                            .events = EPOLLIN | EPOLLET | EPOLLRDHUP,
                            .data.u64 = sock_new | ((uint64_t)TCP_SOCKET_INCOMING << 32) | ((uint64_t)index_new << 40)
                        };

                        if (epoll_ctl(TCP_server->efd, EPOLL_CTL_ADD, sock_new, &ev) == -1) {
                            kill_TCP_connection(&TCP_server->incomming_connection_queue[index_new]);
                            continue;
                        }
                    }

                    break;
                }

                case TCP_SOCKET_INCOMING: {
                    int index_new;

                    if ((index_new = do_incoming(TCP_server, index)) != -1) {
                        events[n].events = EPOLLIN | EPOLLET | EPOLLRDHUP;
                        events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_UNCONFIRMED << 32) | ((uint64_t)index_new << 40);

                        if (epoll_ctl(TCP_server->efd, EPOLL_CTL_MOD, sock, &events[n]) == -1) {
                            kill_TCP_connection(&TCP_server->unconfirmed_connection_queue[index_new]);
                            break;
                        }
                    }

                    break;
                }

                case TCP_SOCKET_UNCONFIRMED: {
                    int index_new;

                    if ((index_new = do_unconfirmed(TCP_server, index)) != -1) {
                        events[n].events = EPOLLIN | EPOLLET | EPOLLRDHUP;
                        events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_CONFIRMED << 32) | ((uint64_t)index_new << 40);

                        if (epoll_ctl(TCP_server->efd, EPOLL_CTL_MOD, sock, &events[n]) == -1) {
                            //remove from confirmed connections
                            kill_accepted(TCP_server, index_new);
                            break;
                        }
                    }

                    break;
                }

                case TCP_SOCKET_CONFIRMED: {
                    do_confirmed_recv(TCP_server, index);
                    break;
                }
            }
        }
    }

#undef MAX_EVENTS
}
#endif

void do_TCP_server(TCP_Server *TCP_server)
{
    unix_time_update();

#ifdef TCP_SERVER_USE_EPOLL
    do_TCP_epoll(TCP_server);

#else
    do_TCP_accept_new(TCP_server);
    do_TCP_incomming(TCP_server);
    do_TCP_unconfirmed(TCP_server);
#endif

    do_TCP_confirmed(TCP_server);
}
示例#17
0
connection_t *
get_connection (sock_t *sock)
{
	int sockfd;
	socklen_t sin_len;
	connection_t *con;
	fd_set rfds;
	struct timeval tv;
	int i, maxport = 0;
	struct sockaddr_in *sin = (struct sockaddr_in *)nmalloc(sizeof(struct sockaddr_in));

	if (!sin)
	{
		write_log (LOG_DEFAULT, "WARNING: Weird stuff in get_connection. nmalloc returned NULL sin");
		return NULL;
	}

	/* setup sockaddr structure */
	sin_len = sizeof(struct sockaddr_in);
	memset(sin, 0, sin_len);
  
	/* try to accept a connection */
	FD_ZERO(&rfds);
	
	for (i = 0; i < MAXLISTEN; i++) {
		if (sock_valid (sock[i])) {
			FD_SET(sock[i], &rfds);
			if (sock[i] > maxport) 
				maxport = sock[i];
		}
	}
	maxport += 1;

	tv.tv_sec = 0;
	tv.tv_usec = 30000;

	if (select(maxport, &rfds, NULL, NULL, &tv) > 0) {
		for (i = 0; i < MAXLISTEN; i++) {
			if (sock_valid (sock[i]) && FD_ISSET(sock[i], &rfds)) 
				break;
		}
	} else {
		nfree(sin);
		return NULL;
	}
	
	sockfd = sock_accept(sock[i], (struct sockaddr *)sin, &sin_len);
  
	if (sockfd >= 0) {
		con = create_connection();
		if (!sin)
		{
			xa_debug (1, "ERROR: NULL sockaddr struct, wft???");
			return NULL;
		}

		con->host = create_malloced_ascii_host(&(sin->sin_addr));
		con->sock = sockfd;
		con->sin = sin;
		con->sinlen = sin_len;
		xa_debug (2, "DEBUG: Getting new connection on socket %d from host %s", sockfd, con->host ? con->host : "(null)");
		con->hostname = NULL;
		con->headervars = NULL;
		con->id = new_id ();
		con->connect_time = get_time ();
#ifdef HAVE_LIBWRAP
		if (!sock_check_libwrap(sockfd, unknown_connection_e))
		{
			kick_not_connected (con, "Access Denied (tcp wrappers) [generic connection]");
			return NULL;
		}
#endif

		return con;
	}

	if (!is_recoverable (errno))
		xa_debug (1, "WARNING: accept() failed with on socket %d, max: %d, [%d:%s]", sock[i], maxport, 
			  errno, strerror(errno));
	nfree (sin);
	return NULL;
}
示例#18
0
TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *public_key,
                           const uint8_t *secret_key, Onion *onion)
{
    if (num_sockets == 0 || ports == NULL)
        return NULL;

    if (networking_at_startup() != 0) {
        return NULL;
    }

    TCP_Server *temp = calloc(1, sizeof(TCP_Server));

    if (temp == NULL)
        return NULL;

    temp->socks_listening = calloc(num_sockets, sizeof(sock_t));

    if (temp->socks_listening == NULL) {
        free(temp);
        return NULL;
    }

#ifdef TCP_SERVER_USE_EPOLL
    temp->efd = epoll_create1(0);

    if (temp->efd == -1) {
        free(temp);
        return NULL;
    }

#endif

    uint8_t family;

    if (ipv6_enabled) {
        family = AF_INET6;
    } else {
        family = AF_INET;
    }

    uint32_t i;
#ifdef TCP_SERVER_USE_EPOLL
    struct epoll_event ev;
#endif

    for (i = 0; i < num_sockets; ++i) {
        sock_t sock = new_listening_TCP_socket(family, ports[i]);

        if (sock_valid(sock)) {
#ifdef TCP_SERVER_USE_EPOLL
            ev.events = EPOLLIN;
            ev.data.u64 = sock | ((uint64_t)TCP_SOCKET_LISTENING << 32);

            if (epoll_ctl(temp->efd, EPOLL_CTL_ADD, sock, &ev) == -1) {
                continue;
            }

#endif

            temp->socks_listening[temp->num_listening_socks] = sock;
            ++temp->num_listening_socks;
        }
    }

    if (temp->num_listening_socks == 0) {
        free(temp);
        return NULL;
    }

    if (onion) {
        temp->onion = onion;
        set_callback_handle_recv_1(onion, &handle_onion_recv_1, temp);
    }

    memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES);
    memcpy(temp->secret_key, secret_key, crypto_box_SECRETKEYBYTES);

    bs_list_init(&temp->accepted_key_list, crypto_box_PUBLICKEYBYTES, 8);

    return temp;
}
示例#19
0
/* Create new TCP connection to ip_port/public_key
 */
TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public_key, const uint8_t *self_public_key,
        const uint8_t *self_secret_key, TCP_Proxy_Info *proxy_info)
{
    if (networking_at_startup() != 0) {
        return NULL;
    }

    if (ip_port.ip.family != AF_INET && ip_port.ip.family != AF_INET6) {
        return NULL;
    }

    uint8_t family = ip_port.ip.family;

    TCP_Proxy_Info default_proxyinfo;

    if (proxy_info == NULL) {
        default_proxyinfo.proxy_type = TCP_PROXY_NONE;
        proxy_info = &default_proxyinfo;
    }

    if (proxy_info->proxy_type != TCP_PROXY_NONE) {
        family = proxy_info->ip_port.ip.family;
    }

    Socket sock = net_socket(family, TOX_SOCK_STREAM, TOX_PROTO_TCP);

    if (!sock_valid(sock)) {
        return NULL;
    }

    if (!set_socket_nosigpipe(sock)) {
        kill_sock(sock);
        return 0;
    }

    if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port, proxy_info))) {
        kill_sock(sock);
        return NULL;
    }

    TCP_Client_Connection *temp = (TCP_Client_Connection *)calloc(sizeof(TCP_Client_Connection), 1);

    if (temp == NULL) {
        kill_sock(sock);
        return NULL;
    }

    temp->sock = sock;
    memcpy(temp->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
    memcpy(temp->self_public_key, self_public_key, CRYPTO_PUBLIC_KEY_SIZE);
    encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key);
    temp->ip_port = ip_port;
    temp->proxy_info = *proxy_info;

    switch (proxy_info->proxy_type) {
        case TCP_PROXY_HTTP:
            temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING;
            proxy_http_generate_connection_request(temp);
            break;

        case TCP_PROXY_SOCKS5:
            temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING;
            proxy_socks5_generate_handshake(temp);
            break;

        case TCP_PROXY_NONE:
            temp->status = TCP_CLIENT_CONNECTING;

            if (generate_handshake(temp) == -1) {
                kill_sock(sock);
                free(temp);
                return NULL;
            }

            break;
    }

    temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT;

    return temp;
}