Working epoll implementation
This commit is contained in:
parent
7432371fc0
commit
1aa9236240
8 changed files with 220 additions and 14 deletions
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
|
|
@ -29,8 +29,12 @@ int main(int argc, char** argv) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (is_server) donar_server();
|
||||
else if (is_client) donar_client();
|
||||
if (is_server) {
|
||||
struct donar_server_ctx ctx;
|
||||
donar_server(&ctx);
|
||||
} else if (is_client) {
|
||||
donar_client();
|
||||
}
|
||||
|
||||
return 0;
|
||||
/*
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "donar_server.h"
|
||||
|
||||
void create_onion_services(struct tor_os_str* tos, struct tor_ctl* tctl, int* ports, int ports_count) {
|
||||
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);
|
||||
|
||||
|
@ -22,12 +22,136 @@ void destroy_resources(struct tor_os_str* tos, struct tor_ctl* tctl) {
|
|||
tor_os_free (tos);
|
||||
}
|
||||
|
||||
void donar_server() {
|
||||
struct tor_os_str tos;
|
||||
struct tor_ctl tctl = {};
|
||||
int ports[10] = { 7500, 7501, 7502, 7503, 7504, 7505, 7506, 7507, 7508, 7509};
|
||||
create_onion_services (&tos, &tctl, ports, 10);
|
||||
printf("Onion services created\n");
|
||||
|
||||
destroy_resources (&tos, &tctl);
|
||||
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;
|
||||
|
||||
printf("Accepting new TCP client\n");
|
||||
in_len = sizeof(in_addr);
|
||||
conn_sock = accept(evt->data.fd, &in_addr, &in_len);
|
||||
if (conn_sock == -1) goto co_error;
|
||||
printf("accept %d\n", conn_sock);
|
||||
err = make_socket_non_blocking (conn_sock);
|
||||
if (err == -1) goto co_error;
|
||||
printf("make socket non blocking\n");
|
||||
|
||||
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;
|
||||
printf("add to epoll socket descriptor %d\n", conn_sock);
|
||||
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;
|
||||
printf("Exchanging rw info with client for sock %d\n", evt->data.fd);
|
||||
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;
|
||||
printf("successful read of %d", nread);
|
||||
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);
|
||||
}
|
||||
printf("Loop with %d elements\n", num_fd);
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,22 @@
|
|||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <errno.h>
|
||||
#include "socks5.h"
|
||||
#include "tor_os.h"
|
||||
#include "tor_ctl.h"
|
||||
#define PORT_SIZE 10
|
||||
#define MAX_EVENTS 10
|
||||
|
||||
void donar_server();
|
||||
struct donar_server_ctx {
|
||||
struct tor_os_str tos;
|
||||
struct tor_ctl tctl;
|
||||
int connection_count;
|
||||
uint16_t ports[PORT_SIZE];
|
||||
int tcp_socks[PORT_SIZE];
|
||||
int epollfd;
|
||||
int is_server;
|
||||
};
|
||||
|
||||
void donar_server(struct donar_server_ctx* ctx);
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "net_tools.h"
|
||||
|
||||
// some code is inspired by https://github.com/millken/c-example/blob/master/epoll-example.c
|
||||
// (which seems to be copied from https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/epoll-example.c )
|
||||
|
||||
int create_tcp_client(char* host, char* service) {
|
||||
int err, sock;
|
||||
struct addrinfo conf;
|
||||
|
@ -34,6 +37,63 @@ int create_tcp_client(char* host, char* service) {
|
|||
return sock;
|
||||
}
|
||||
|
||||
int create_tcp_server(char* service) {
|
||||
int err, sock;
|
||||
struct addrinfo conf;
|
||||
struct addrinfo *result, *cursor;
|
||||
|
||||
memset(&conf, 0, sizeof(struct addrinfo));
|
||||
conf.ai_family = AF_UNSPEC;
|
||||
conf.ai_socktype = SOCK_STREAM;
|
||||
conf.ai_flags = 0;
|
||||
conf.ai_protocol = 0;
|
||||
|
||||
err = getaddrinfo(NULL, service, &conf, &result);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "Error with getaddrinfo()\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (cursor = result; cursor != NULL; cursor = cursor->ai_next) {
|
||||
sock = socket(cursor->ai_family, cursor->ai_socktype, cursor->ai_protocol);
|
||||
if (sock == -1) continue;
|
||||
if (bind(sock, cursor->ai_addr, cursor->ai_addrlen) != -1) break;
|
||||
close(sock);
|
||||
}
|
||||
|
||||
if (cursor == NULL) {
|
||||
fprintf(stderr, "We failed to bind\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
freeaddrinfo (result);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/*
|
||||
* The idea is to get the file descriptor flags
|
||||
* then we add to the bitmask O_NONBLOCK and set the
|
||||
* new bitmask to the socket
|
||||
*/
|
||||
int make_socket_non_blocking(int fd) {
|
||||
int err, flags;
|
||||
flags = fcntl (fd, F_GETFL);
|
||||
if (flags == -1) {
|
||||
perror("Failed to get socket's flags via fcntl");
|
||||
return -1;
|
||||
}
|
||||
|
||||
flags |= O_NONBLOCK;
|
||||
err = fcntl (fd, F_SETFL, flags);
|
||||
if (err != 0) {
|
||||
perror("Failed to set socket's flags via fcntl");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_entity(int fd, void* entity, int size) {
|
||||
int remaining = size;
|
||||
int total_read = 0;
|
||||
|
@ -53,4 +113,3 @@ void fill_buffer(size_t* written, char* dest, void *src, size_t n) {
|
|||
memcpy(dest+*written, src, n);
|
||||
*written += n;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
|
@ -7,5 +8,7 @@
|
|||
#include <string.h>
|
||||
|
||||
int create_tcp_client(char* host, char* service);
|
||||
int create_tcp_server(char* service);
|
||||
int make_socket_non_blocking(int fd);
|
||||
int read_entity(int fd, void* entity, int size);
|
||||
void fill_buffer(size_t* written, char* dest, void *src, size_t n);
|
||||
|
|
|
@ -30,7 +30,7 @@ int tor_ctl_connect(struct tor_ctl* ctx, char* addr, char* service) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int tor_ctl_add_onion(struct tor_ctl* ctx, struct tor_os_str* tos, int* port) {
|
||||
int tor_ctl_add_onion(struct tor_ctl* ctx, struct tor_os_str* tos, uint16_t* port) {
|
||||
int err = 0;
|
||||
char buffer1[1024] = {0};
|
||||
char buffer2[1024] = {0};
|
||||
|
|
|
@ -15,5 +15,5 @@ struct tor_ctl {
|
|||
};
|
||||
|
||||
int tor_ctl_connect(struct tor_ctl* ctx, char* addr, char* service);
|
||||
int tor_ctl_add_onion(struct tor_ctl* ctx, struct tor_os_str* tos, int* port);
|
||||
int tor_ctl_add_onion(struct tor_ctl* ctx, struct tor_os_str* tos, uint16_t* port);
|
||||
void tor_ctl_close(struct tor_ctl* ctx);
|
||||
|
|
Loading…
Reference in a new issue