#include "donar_server.h" void create_onion_services(struct tor_os_str* tos, struct tor_ctl* tctl, uint16_t* ports, int ports_count) { tor_os_create (tos, "onion_services.pub", "onion_services.txt", ports_count); tor_os_read (tos); int err = 0; err = tor_ctl_connect (tctl, "127.0.0.1", "9051"); if (err < 0) { fprintf(stderr, "Unable to open Tor Socket\n"); exit(EXIT_FAILURE); } err = tor_ctl_add_onion (tctl, tos, ports); if (err != 0) { fprintf(stderr, "Unable to create Onion Services (error: %d)\n", err); exit(EXIT_FAILURE); } } void destroy_resources(struct tor_os_str* tos, struct tor_ctl* tctl) { tor_ctl_close (tctl); tor_os_free (tos); } void init_tcp_servers(struct donar_server_ctx* ctx) { char buffer[6]; int err = 0; for (int i = 0; i < ctx->connection_count; i++) { sprintf (buffer, "%d", ctx->ports[i]); ctx->tcp_socks[i] = create_tcp_server (buffer); if (ctx->tcp_socks[i] < 0) goto socket_create_err; // Might be needed only with EPOLLET - might not be needed at all //err = make_socket_non_blocking (ctx->tcp_socks[i]); //if (err != 0) goto socket_create_err; err = listen(ctx->tcp_socks[i], SOMAXCONN); if (err != 0) goto socket_create_err; } return; socket_create_err: fprintf(stderr, "Unable to create a TCP socket\n"); exit(EXIT_FAILURE); } int is_listening_socket(struct donar_server_ctx* ctx, int sock) { int i; for (i = 0; i < ctx->connection_count && ctx->is_server; i++) { if (sock == ctx->tcp_socks[i]) return 1; } return 0; } void handle_new_tcp_client_connection(struct donar_server_ctx* ctx, struct epoll_event* evt) { int conn_sock, err; struct sockaddr in_addr; socklen_t in_len; struct epoll_event current_event; in_len = sizeof(in_addr); conn_sock = accept(evt->data.fd, &in_addr, &in_len); if (conn_sock == -1) goto co_error; err = make_socket_non_blocking (conn_sock); if (err == -1) goto co_error; current_event.events = EPOLLIN | EPOLLET; current_event.data.fd = conn_sock; if (epoll_ctl(ctx->epollfd, EPOLL_CTL_ADD, conn_sock, ¤t_event) == -1) goto co_error; return; co_error: perror("Failed to handle new connection"); exit(EXIT_FAILURE); } void handle_new_tcp_client_rw(struct donar_server_ctx* ctx, struct epoll_event* evt) { char buffer[128]; int nread, nwrite; while(1) { nread = read(evt->data.fd, buffer, sizeof(buffer)); if (nread == 0) break; if (nread == -1 && errno == EAGAIN) break; if (nread == -1) goto co_error; nwrite = write(evt->data.fd, buffer, nread); if (nwrite == -1 && errno == EAGAIN) { printf("Lost data EAGAIN\n"); break; } if (nwrite == -1) goto co_error; if (nwrite != nread) { printf("Lost data not everything has been written\n"); break; } } return; co_error: perror("Failed to handle read write"); exit(EXIT_FAILURE); } void donar_server(struct donar_server_ctx* ctx) { ctx->is_server = 1; ctx->connection_count = PORT_SIZE; for (uint16_t i = 0; i < ctx->connection_count ; i++) { ctx->ports[i] = 7500 + i; } create_onion_services (&(ctx->tos), &(ctx->tctl), ctx->ports, ctx->connection_count); printf("--- Onion services created\n"); init_tcp_servers(ctx); ctx->epollfd = epoll_create1(0); if (ctx->epollfd == -1) { perror("Failed to create epoll file descriptor epoll_create1"); exit(EXIT_FAILURE); } struct epoll_event current_event, events[MAX_EVENTS]; for (int i = 0; i < ctx->connection_count; i++) { current_event.events = EPOLLIN; current_event.data.fd = ctx->tcp_socks[i]; if (epoll_ctl (ctx->epollfd, EPOLL_CTL_ADD, ctx->tcp_socks[i], ¤t_event) == -1) { perror("Failed to add a file descriptor to epoll with epoll_ctl"); exit(EXIT_FAILURE); } } printf("--- Start main loop\n"); int num_fd, n = 0; while(1) { num_fd = epoll_wait(ctx->epollfd, events, MAX_EVENTS, -1); if (num_fd == -1) { perror("Failed to epoll_wait"); exit(EXIT_FAILURE); } for (n = 0 ; n < num_fd; n++) { if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP) || (!(events[n].events & EPOLLIN))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ fprintf (stderr, "epoll error\n"); close (events[n].data.fd); continue; } else if (is_listening_socket (ctx, events[n].data.fd)) handle_new_tcp_client_connection (ctx, &(events[n])); else handle_new_tcp_client_rw(ctx, &(events[n])); } } destroy_resources (&(ctx->tos), &(ctx->tctl)); }