#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; }