diff --git a/client.c b/client.c new file mode 100644 index 0000000..97e1764 --- /dev/null +++ b/client.c @@ -0,0 +1,140 @@ +#include "client.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "connection.h" +#include "event_loop.h" +#include "utils.h" + +/* + * Macros + */ +#define MAX_PENDING_CONNECTIONS (100) + +/* + * Data + */ +static int _fds[MAX_PENDING_CONNECTIONS]; + + +/* + * Public API + */ +bool client_init() { + for (int i = 0; i < MAX_PENDING_CONNECTIONS; ++i) { + _fds[i] = -1; + } + return true; +} + +void client_deinit() { + for (int i = 0; i < MAX_PENDING_CONNECTIONS; ++i) { + if (_fds[i] == -1) { + continue; + } + shutdown(_fds[i], SHUT_RDWR); + close(_fds[i]); + } +} + +bool client_connect(const char *host, uint16_t port) { + int index = -1; + for (int i = 0; i < MAX_PENDING_CONNECTIONS; ++i) { + if (_fds[i] == -1) { + index = i; + break; + } + } + if (index == -1) { + fprintf(stderr, "[!] no more space for new connect attempts\n"); + return false; + } + struct hostent *he = gethostbyname(host); + if (!he) { + fprintf(stderr, "[!] gethostbyname (%s) failed: %d (h_errno)\n", host, h_errno); + return false; + } + int fd = socket( + AF_INET, + SOCK_STREAM | SOCK_NONBLOCK, + IPPROTO_TCP + ); + if (fd == -1) { + fprintf(stderr, "[!] socket failed: %d\n", errno); + return false; + } + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htobe16(port); + memcpy(&addr.sin_addr, he->h_addr, he->h_length); + int res = connect(fd, (const struct sockaddr *)&addr, sizeof(addr)); + if (res == -1) { + if (errno != EINPROGRESS) { + fprintf(stderr, "[!] connect failed: %d\n", errno); + return false; + } + else { + _fds[index] = fd; + struct epoll_event ev; + ev.data.fd = fd; + ev.events = EPOLLOUT; + loop_ctl(EPOLL_CTL_ADD, fd, &ev); + return true; + } + } + uint32_t id = connection_add(fd); + if (id == 0) { + shutdown(fd, SHUT_RDWR); + close(fd); + return false; + } + return true; +} + +bool client_event(int fd, uint32_t events) { + int index = -1; + for (int i = 0; i < MAX_PENDING_CONNECTIONS; ++i) { + if (_fds[i] == fd) { + index = i; + break; + } + } + if (index == -1) { + return false; + } + if (events & (EPOLLERR | EPOLLHUP)) { + shutdown(fd, SHUT_RDWR); + close(fd); + _fds[index] = -1; + fprintf(stderr, "[!] connect failed\n"); + return true; + } + // check if socket has an error set + int err = 0; + socklen_t len = sizeof(err); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0 || err != 0) { + shutdown(fd, SHUT_RDWR); + close(fd); + _fds[index] = -1; + fprintf(stderr, "[!] connect failed: %d\n", err); + return true; + } + // connected + loop_ctl(EPOLL_CTL_DEL, fd, NULL); + uint32_t id = connection_add(fd); + if (id == 0) { + shutdown(fd, SHUT_RDWR); + close(fd); + } + _fds[index] = -1; + return true; +} diff --git a/client.h b/client.h new file mode 100644 index 0000000..2ede0e0 --- /dev/null +++ b/client.h @@ -0,0 +1,39 @@ +#ifndef __CLIENT_H +#define __CLIENT_H + +#include +#include + +// Setup client module. +// Returns: +// - true on success +// - false on failure +bool client_init(); + +// Cleanup all pending connections. +void client_deinit(); + +// Connect to the server. +// Parameters: +// - host - server host +// - port - server port +// Returns: +// - true on success +// Remarks: +// - the socket is managed by this module. It will be +// added to connection module after connection succeeds. +bool client_connect(const char *host, uint16_t port); + +// Handle event on the socket managed by this module. +// Parameters: +// - fd - socket +// - events - events as returned by epoll +// Returns: +// - true if the socket is managed by this module +// - false if the socket is not managed by this module +// Remarks: +// - no checks are done +bool client_event(int fd, uint32_t events); + + +#endif diff --git a/connection.c b/connection.c index 7030510..4623c2a 100644 --- a/connection.c +++ b/connection.c @@ -288,7 +288,7 @@ uint32_t connection_send(uint32_t id, const void *data_void, uint32_t size) { ); size -= will_write; data += will_write; - write += will_write; + wrote += will_write; } // add to epoll if not added if (!(c->ev_mask & EPOLLOUT)) { diff --git a/main.c b/main.c index 2e0b137..6aef0b1 100644 --- a/main.c +++ b/main.c @@ -9,8 +9,9 @@ #include #include -#include "event_loop.h" +#include "client.h" #include "connection.h" +#include "event_loop.h" #include "server.h" #include "utils.h" @@ -184,6 +185,10 @@ static void on_fd_event(int fd, uint32_t events) { else if (connection_is_socket_managed(fd)) { connection_event(fd, events); } + // Client event + else if (client_event(fd, events)) { + // nothing here + } else { fprintf(stderr, "[!] Event has happened on an unknown file descriptor\n"); } @@ -209,6 +214,13 @@ int main(int argc, char **argv) { return 1; } } + else { + if (!client_init()) { + signals_deinit(); + loop_deinit(); + return 1; + } + } // Loop while (_to_work) { if (!loop_wait()) { @@ -221,6 +233,9 @@ int main(int argc, char **argv) { if (_is_server) { server_close(); } + else { + client_deinit(); + } connection_cleanup(); signals_deinit(); loop_deinit(); diff --git a/server.c b/server.c index be4f3e3..3b7facb 100644 --- a/server.c +++ b/server.c @@ -51,7 +51,7 @@ bool _accept() { int server_open(const char* host, int port) { struct hostent *he = gethostbyname(host); if (!he) { - fprintf(stderr, "[!] gethostbyname failed: %d (h_errno)\n", h_errno); + fprintf(stderr, "[!] gethostbyname (%s) failed: %d (h_errno)\n", host, h_errno); return -1; } _fd = socket(