diff options
Diffstat (limited to 'bittorrent/epoll_server')
| -rw-r--r-- | bittorrent/epoll_server/connection.c | 58 | ||||
| -rw-r--r-- | bittorrent/epoll_server/connection.h | 54 | ||||
| -rw-r--r-- | bittorrent/epoll_server/epoll_server.c | 134 | ||||
| -rw-r--r-- | bittorrent/epoll_server/epoll_server.h | 58 | ||||
| -rw-r--r-- | bittorrent/epoll_server/meson.build | 32 | ||||
| -rw-r--r-- | bittorrent/epoll_server/utils/xalloc.c | 31 | ||||
| -rw-r--r-- | bittorrent/epoll_server/utils/xalloc.h | 32 |
7 files changed, 399 insertions, 0 deletions
diff --git a/bittorrent/epoll_server/connection.c b/bittorrent/epoll_server/connection.c new file mode 100644 index 0000000..62560c5 --- /dev/null +++ b/bittorrent/epoll_server/connection.c @@ -0,0 +1,58 @@ +#include "connection.h" + +#include <err.h> +#include <stdlib.h> +#include <unistd.h> + +#include "utils/xalloc.h" + +struct connection_t *add_client(struct connection_t *head, int client_socket) +{ + struct connection_t *new_connection = xmalloc(sizeof(struct connection_t)); + + new_connection->client_socket = client_socket; + new_connection->buffer = NULL; + new_connection->nb_read = 0; + new_connection->next = head; + + return new_connection; +} + +struct connection_t *remove_client(struct connection_t *head, int client_socket) +{ + if (head && head->client_socket == client_socket) + { + struct connection_t *client_connection = head->next; + if (close(head->client_socket) == -1) + err(EXIT_FAILURE, "Failed to close socket"); + free(head->buffer); + free(head); + return client_connection; + } + + struct connection_t *tmp = head; + while (tmp->next) + { + if (tmp->next->client_socket == client_socket) + { + struct connection_t *client_connection = tmp->next; + tmp->next = client_connection->next; + if (close(client_connection->client_socket) == -1) + err(EXIT_FAILURE, "Failed to close socket"); + free(client_connection->buffer); + free(client_connection); + break; + } + tmp = tmp->next; + } + + return head; +} + +struct connection_t *find_client(struct connection_t *head, int client_socket) +{ + while (head != NULL && head->client_socket != client_socket) + head = head->next; + + return head; +} diff --git a/bittorrent/epoll_server/connection.h b/bittorrent/epoll_server/connection.h new file mode 100644 index 0000000..40e2370 --- /dev/null +++ b/bittorrent/epoll_server/connection.h @@ -0,0 +1,54 @@ +#ifndef CONNECTION_H +#define CONNECTION_H + +#include <sys/types.h> + +/** + * \brief Contains the information about the clients (linked list) + */ +struct connection_t +{ + int client_socket; /**< socket fd of the client */ + + char *buffer; /**< buffer containing the data received by this client */ + + ssize_t nb_read; /**< number of bytes read (also size of the buffer) */ + + struct connection_t *next; /**< the next client */ +}; + +/** + * \brief Adds a new client connection_t to the linked list + * + * \param connection: the connection_t linked list with all the clients + * + * \param client_socket: the client socket fd to add + * + * \return The connection_t linked list with the element added + */ +struct connection_t *add_client(struct connection_t *head, int client_socket); + +/** + * \brief Removes the client connection_t from the linked list connection + * + * \param connection: the connection_t linked list with all the clients + * + * \param client_socket: the client socket fd to remove + * + * \return The connection_t linked list with element removed + */ +struct connection_t *remove_client(struct connection_t *head, + int client_socket); + +/** + * \brief Find the connection_t element where the socket is equal to client sock + * + * \param connection: the connection_t linked list with all the clients + * + * \param client_socket: the client socket to find + * + * \return The connection_t element of the specific client + */ +struct connection_t *find_client(struct connection_t *head, int client_socket); + +#endif /* !CONNECTION_H */ diff --git a/bittorrent/epoll_server/epoll_server.c b/bittorrent/epoll_server/epoll_server.c new file mode 100644 index 0000000..dc010e6 --- /dev/null +++ b/bittorrent/epoll_server/epoll_server.c @@ -0,0 +1,134 @@ +#include "epoll_server.h" + +#include <netdb.h> +#include <stdlib.h> +#include <sys/epoll.h> +#include <sys/socket.h> +#include <unistd.h> + +#include "connection.h" +#include "string.h" + +int create_and_bind(struct addrinfo *addrinfo) +{ + for (struct addrinfo *info = addrinfo; info != NULL; info = info->ai_next) + { + int sock_fd = + socket(info->ai_family, info->ai_socktype, info->ai_protocol); + if (sock_fd != -1) + { + int feur = bind(sock_fd, info->ai_addr, info->ai_addrlen); + if (feur != -1) + { + return sock_fd; + } + else + { + close(sock_fd); + } + } + } + exit(1); +} + +int prepare_socket(const char *ip, const char *port) +{ + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + struct addrinfo *addrinfo; + int e = getaddrinfo(ip, port, &hints, &addrinfo); + if (e != 0) + { + exit(1); + } + e = create_and_bind(addrinfo); + int e2 = listen(e, 1000); + freeaddrinfo(addrinfo); + if (e2 == -1) + { + close(e); + exit(1); + } + return e; +} + +struct connection_t *accept_client(int epoll_instance, int server_socket, + struct connection_t *connection) +{ + int e = accept(server_socket, NULL, 0); + if (e == -1) + { + close(server_socket); + exit(1); + } + struct epoll_event tmp; + tmp.events = EPOLLIN; + tmp.data.fd = e; + int er = epoll_ctl(epoll_instance, EPOLL_CTL_ADD, e, &tmp); + if (er == -1) + { + close(server_socket); + close(e); + exit(1); + } + return add_client(connection, e); +} + +int main(int argc, char **argv) +{ + if (argc != 3) + { + exit(1); + } + int epoll_instance = epoll_create1(0); + if (epoll_instance == -1) + { + exit(1); + } + int e = prepare_socket(argv[1], argv[2]); + struct connection_t *co = NULL; + struct epoll_event tmp; + tmp.events = EPOLLIN; + tmp.data.fd = e; + if (epoll_ctl(epoll_instance, EPOLL_CTL_ADD, e, &tmp) == -1) + { + close(e); + exit(1); + } + while (1) + { + struct epoll_event elist[MAX_EVENTS]; + int info = epoll_wait(epoll_instance, elist, MAX_EVENTS, -1); + if (info == -1) + { + exit(1); + } + for (int i = 0; i < info; i++) + { + int fd = elist[i].data.fd; + if (fd == e) + { + co = accept_client(epoll_instance, e, co); + } + else + { + char buf[100] = { 0 }; + int info1 = recv(fd, buf, 100, 0); + if (info1 < 1) + { + co = remove_client(co, fd); + close(fd); + } + else + { + struct connection_t *tmp = co; + while (tmp != NULL) + { + send(tmp->client_socket, buf, info1, 0); + tmp = tmp->next; + } + } + } + } + } +} diff --git a/bittorrent/epoll_server/epoll_server.h b/bittorrent/epoll_server/epoll_server.h new file mode 100644 index 0000000..ba5de4f --- /dev/null +++ b/bittorrent/epoll_server/epoll_server.h @@ -0,0 +1,58 @@ +#ifndef EPOLL_SERVER_H +#define EPOLL_SERVER_H + +#include <netdb.h> +#include <sys/socket.h> +#include <sys/types.h> + +#include "connection.h" + +/** + * \brief The length of the event array, must be greater than zero + */ +#define MAX_EVENTS 64 + +#define DEFAULT_BUFFER_SIZE 2048 + +/** + * \brief Iterate over the struct addrinfo elements to create and bind a socket + * + * \param addrinfo: struct addrinfo elements + * + * \return The created socket or exit with 1 if there is an error + * + * Try to create and connect a socket with every addrinfo element until it + * succeeds + * + */ +int create_and_bind(struct addrinfo *addrinfo); + +/** + * \brief Initialize the Addrinfo struct and call create_and bind() and + * listen(2) + * + * \param ip: IP address of the server + * \param port: Port of the server + * + * \return The created socket + * + * Initialize the struct addrinfo needed by create_and_bind() before calling + * it. When create_and_bind() returns a valid socket, set the socket to + * listening and return it. + */ +int prepare_socket(const char *ip, const char *port); + +/** + * \brief Accept a new client and add it to the connection_t struct + * + * \param epoll_instance: the epoll instance + * \param server_socket: listening socket + * \param connection: the connection linked list with all the current + * connections + * + * \return The connection struct with the new client added + */ +struct connection_t *accept_client(int epoll_instance, int server_socket, + struct connection_t *connection); + +#endif /* !EPOLL_SERVER_H */ diff --git a/bittorrent/epoll_server/meson.build b/bittorrent/epoll_server/meson.build new file mode 100644 index 0000000..de9bba1 --- /dev/null +++ b/bittorrent/epoll_server/meson.build @@ -0,0 +1,32 @@ +project( + 'epoll_server', + 'c', + version : '1.0.0', + default_options : [ + 'debug=true', + 'c_std=c99', + 'buildtype=debug', + 'warning_level=2', + 'werror=true', + 'b_sanitize=address,undefined', + 'optimization=plain', + ], +) + +deps = [] +pubinc = [] +inc = [include_directories('./')] +src = files( + 'connection.c', + 'epoll_server.c', + 'utils/xalloc.c' +) + +executable( + 'epoll_server', + sources : src, + include_directories : pubinc + inc, + dependencies : deps, + c_args : '-D_DEFAULT_SOURCE', + install : true, +) diff --git a/bittorrent/epoll_server/utils/xalloc.c b/bittorrent/epoll_server/utils/xalloc.c new file mode 100644 index 0000000..e4dc6b8 --- /dev/null +++ b/bittorrent/epoll_server/utils/xalloc.c @@ -0,0 +1,31 @@ +#include "xalloc.h" + +#include <err.h> +#include <stdlib.h> + +void *xmalloc(size_t size) +{ + void *res = malloc(size); + if (!res) + err(EXIT_FAILURE, "Impossible to malloc"); + + return res; +} + +void *xcalloc(size_t nmemb, size_t size) +{ + void *res = calloc(nmemb, size); + if (!res) + err(EXIT_FAILURE, "Impossible to calloc"); + + return res; +} + +void *xrealloc(void *ptr, size_t size) +{ + void *res = realloc(ptr, size); + if (!res) + err(EXIT_FAILURE, "Impossible to realloc"); + + return res; +} diff --git a/bittorrent/epoll_server/utils/xalloc.h b/bittorrent/epoll_server/utils/xalloc.h new file mode 100644 index 0000000..e7655b8 --- /dev/null +++ b/bittorrent/epoll_server/utils/xalloc.h @@ -0,0 +1,32 @@ +#ifndef XALLOC_H +#define XALLOC_H + +#include <stddef.h> + +/** +** \brief Malloc wrapper that exits on failure. +** +** \param size The size to malloc. +** \return The malloc return. +*/ +void *xmalloc(size_t size); + +/** +** \brief Calloc wrapper that exits on failure. +** +** \param nmemb The number of elements. +** \param size The size of an element. +** \return The calloc return. +*/ +void *xcalloc(size_t nmemb, size_t size); + +/** +** \brief Realloc wrapper that exits on failure. +** +** \param ptr The mem pointer. +** \param size The size to realloc. +** \return The realloc return. +*/ +void *xrealloc(void *ptr, size_t size); + +#endif /* !XALLOC_H */ |
