static int do_unconfirmed(TCP_Server *TCP_server, uint32_t i) { TCP_Secure_Connection *conn = &TCP_server->unconfirmed_connection_queue[i]; if (conn->status != TCP_STATUS_UNCONFIRMED) return -1; uint8_t packet[MAX_PACKET_SIZE]; int len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, conn->recv_nonce, packet, sizeof(packet)); if (len == 0) { return -1; } else if (len == -1) { kill_TCP_connection(conn); return -1; } else { int index_new; if ((index_new = confirm_TCP_connection(TCP_server, conn, packet, len)) == -1) { kill_TCP_connection(conn); } else { memset(conn, 0, sizeof(TCP_Secure_Connection)); } return index_new; } }
static void do_TCP_incomming(TCP_Server *TCP_server) { uint32_t i; for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) { if (TCP_server->incomming_connection_queue[i].status != TCP_STATUS_CONNECTED) continue; int ret = read_connection_handshake(&TCP_server->incomming_connection_queue[i], TCP_server->secret_key); if (ret == -1) { kill_TCP_connection(&TCP_server->incomming_connection_queue[i]); } else if (ret == 1) { TCP_Secure_Connection *conn_old = &TCP_server->incomming_connection_queue[i]; TCP_Secure_Connection *conn_new = &TCP_server->unconfirmed_connection_queue[TCP_server->unconfirmed_connection_queue_index % MAX_INCOMMING_CONNECTIONS]; if (conn_new->status != TCP_STATUS_NO_STATUS) kill_TCP_connection(conn_new); memcpy(conn_new, conn_old, sizeof(TCP_Secure_Connection)); memset(conn_old, 0, sizeof(TCP_Secure_Connection)); ++TCP_server->unconfirmed_connection_queue_index; } } }
static int do_incoming(TCP_Server *TCP_server, uint32_t i) { if (TCP_server->incomming_connection_queue[i].status != TCP_STATUS_CONNECTED) return -1; int ret = read_connection_handshake(&TCP_server->incomming_connection_queue[i], TCP_server->secret_key); if (ret == -1) { kill_TCP_connection(&TCP_server->incomming_connection_queue[i]); } else if (ret == 1) { int index_new = TCP_server->unconfirmed_connection_queue_index % MAX_INCOMMING_CONNECTIONS; TCP_Secure_Connection *conn_old = &TCP_server->incomming_connection_queue[i]; TCP_Secure_Connection *conn_new = &TCP_server->unconfirmed_connection_queue[index_new]; if (conn_new->status != TCP_STATUS_NO_STATUS) kill_TCP_connection(conn_new); memcpy(conn_new, conn_old, sizeof(TCP_Secure_Connection)); memset(conn_old, 0, sizeof(TCP_Secure_Connection)); ++TCP_server->unconfirmed_connection_queue_index; return index_new; } return -1; }
static void do_TCP_unconfirmed(TCP_Server *TCP_server) { uint32_t i; for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) { TCP_Secure_Connection *conn = &TCP_server->unconfirmed_connection_queue[i]; if (conn->status != TCP_STATUS_UNCONFIRMED) continue; uint8_t packet[MAX_PACKET_SIZE]; int len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, conn->recv_nonce, packet, sizeof(packet)); if (len == 0) { continue; } else if (len == -1) { kill_TCP_connection(conn); continue; } else { if (confirm_TCP_connection(TCP_server, conn, packet, len) == -1) { kill_TCP_connection(conn); } else { memset(conn, 0, sizeof(TCP_Secure_Connection)); } } } }
static void do_TCP_unconfirmed(TCP_Server *TCP_server) { uint32_t i; for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) { TCP_Secure_Connection *conn = &TCP_server->unconfirmed_connection_queue[i]; if (conn->status != TCP_STATUS_UNCONFIRMED) continue; uint8_t packet[MAX_PACKET_SIZE]; int len = read_packet_TCP_secure_connection(conn, packet, sizeof(packet)); if (len == 0) { continue; } else if (len == -1) { kill_TCP_connection(conn); continue; } else { //TODO confirm_TCP_connection(conn, packet, len); kill_TCP_connection(conn); } } }
static void do_TCP_confirmed(TCP_Server *TCP_server) { uint32_t i; for (i = 0; i < TCP_server->size_accepted_connections; ++i) { TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[i]; if (conn->status != TCP_STATUS_CONFIRMED) continue; if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) { uint8_t ping[1 + sizeof(uint64_t)]; ping[0] = TCP_PACKET_PING; uint64_t ping_id = random_64b(); if (!ping_id) ++ping_id; memcpy(ping + 1, &ping_id, sizeof(uint64_t)); int ret = write_packet_TCP_secure_connection(conn, ping, sizeof(ping)); if (ret == 1) { conn->last_pinged = unix_time(); conn->ping_id = ping_id; } } if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) { kill_TCP_connection(conn); del_accepted(TCP_server, i); continue; } send_pending_data(conn); uint8_t packet[MAX_PACKET_SIZE]; int len; while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, conn->recv_nonce, packet, sizeof(packet)))) { if (len == -1) { kill_TCP_connection(conn); del_accepted(TCP_server, i); break; } if (handle_TCP_packet(TCP_server, i, packet, len) == -1) { kill_TCP_connection(conn); del_accepted(TCP_server, i); break; } } } }
/* 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; }
/* Kill a TCP relay connection. * * return 0 on success. * return -1 on failure. */ static int kill_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) { TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); if (!tcp_con) { return -1; } unsigned int i; for (i = 0; i < tcp_c->connections_length; ++i) { TCP_Connection_to *con_to = get_connection(tcp_c, i); if (con_to) { rm_tcp_connection_from_conn(con_to, tcp_connections_number); } } if (tcp_con->onion) { --tcp_c->onion_num_conns; } kill_TCP_connection(tcp_con->connection); return wipe_tcp_connection(tcp_c, tcp_connections_number); }
void kill_tcp_connections(TCP_Connections *tcp_c) { unsigned int i; for (i = 0; i < tcp_c->tcp_connections_length; ++i) { kill_TCP_connection(tcp_c->tcp_connections[i].connection); } free(tcp_c->tcp_connections); free(tcp_c->connections); free(tcp_c); }
static int confirm_TCP_connection(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t *data, uint16_t length) { int index = add_accepted(TCP_server, con); if (index == -1) return -1; TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[index]; if (handle_TCP_packet(TCP_server, index, data, length) == -1) { kill_TCP_connection(conn); del_accepted(TCP_server, index); } return 0; }
static int reconnect_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) { TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); if (!tcp_con) { return -1; } if (tcp_con->status == TCP_CONN_SLEEPING) { return -1; } IP_Port ip_port = tcp_con_ip_port(tcp_con->connection); uint8_t relay_pk[CRYPTO_PUBLIC_KEY_SIZE]; memcpy(relay_pk, tcp_con_public_key(tcp_con->connection), CRYPTO_PUBLIC_KEY_SIZE); kill_TCP_connection(tcp_con->connection); tcp_con->connection = new_TCP_connection(ip_port, relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, &tcp_c->proxy_info); if (!tcp_con->connection) { kill_tcp_relay_connection(tcp_c, tcp_connections_number); return -1; } unsigned int i; for (i = 0; i < tcp_c->connections_length; ++i) { TCP_Connection_to *con_to = get_connection(tcp_c, i); if (con_to) { set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0); } } if (tcp_con->onion) { --tcp_c->onion_num_conns; tcp_con->onion = 0; } tcp_con->lock_count = 0; tcp_con->sleep_count = 0; tcp_con->connected_time = 0; tcp_con->status = TCP_CONN_VALID; tcp_con->unsleep = 0; return 0; }
static int sleep_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) { TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); if (!tcp_con) { return -1; } if (tcp_con->status != TCP_CONN_CONNECTED) { return -1; } if (tcp_con->lock_count != tcp_con->sleep_count) { return -1; } tcp_con->ip_port = tcp_con_ip_port(tcp_con->connection); memcpy(tcp_con->relay_pk, tcp_con_public_key(tcp_con->connection), CRYPTO_PUBLIC_KEY_SIZE); kill_TCP_connection(tcp_con->connection); tcp_con->connection = nullptr; unsigned int i; for (i = 0; i < tcp_c->connections_length; ++i) { TCP_Connection_to *con_to = get_connection(tcp_c, i); if (con_to) { set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0); } } if (tcp_con->onion) { --tcp_c->onion_num_conns; tcp_con->onion = 0; } tcp_con->lock_count = 0; tcp_con->sleep_count = 0; tcp_con->connected_time = 0; tcp_con->status = TCP_CONN_SLEEPING; tcp_con->unsleep = 0; return 0; }
static int confirm_TCP_connection(TCP_Server *TCP_server, TCP_Secure_Connection *con, const uint8_t *data, uint16_t length) { int index = add_accepted(TCP_server, con); if (index == -1) { kill_TCP_connection(con); return -1; } sodium_memzero(con, sizeof(TCP_Secure_Connection)); if (handle_TCP_packet(TCP_server, index, data, length) == -1) { kill_accepted(TCP_server, index); return -1; } return index; }
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) & 0xFFFF, index = (events[n].data.u64 >> 48); if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP)) { 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; unsigned int addrlen = sizeof(addr); sock_t sock_new; sock_new = accept(sock, (struct sockaddr *)&addr, &addrlen); int index_new = TCP_server->incomming_connection_queue_index % MAX_INCOMMING_CONNECTIONS; if (!accept_connection(TCP_server, sock_new)) { break; } struct epoll_event ev = { .events = EPOLLIN | EPOLLET, .data.u64 = sock_new | ((uint64_t)TCP_SOCKET_INCOMING << 32) | ((uint64_t)index_new << 48) }; if (epoll_ctl(TCP_server->efd, EPOLL_CTL_ADD, sock_new, &ev) == -1) { kill_TCP_connection(&TCP_server->incomming_connection_queue[index_new]); break; } break; } case TCP_SOCKET_INCOMING: { int index_new; if ((index_new = do_incoming(TCP_server, index)) != -1) { events[n].events = EPOLLIN | EPOLLET; events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_UNCONFIRMED << 32) | ((uint64_t)index_new << 48); 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; events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_CONFIRMED << 32) | ((uint64_t)index_new << 48); 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); }