Added client, fixed typo

This commit is contained in:
Nikita Tyukalov, ASUS, Linux
2026-03-27 00:44:50 +03:00
parent 93c83dc40f
commit 2b870aec34
5 changed files with 197 additions and 3 deletions

140
client.c Normal file
View File

@@ -0,0 +1,140 @@
#include "client.h"
#include <stdio.h>
#include <string.h>
#include <endian.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <unistd.h>
#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;
}

39
client.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef __CLIENT_H
#define __CLIENT_H
#include <stdbool.h>
#include <stdint.h>
// 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

View File

@@ -288,7 +288,7 @@ uint32_t connection_send(uint32_t id, const void *data_void, uint32_t size) {
); );
size -= will_write; size -= will_write;
data += will_write; data += will_write;
write += will_write; wrote += will_write;
} }
// add to epoll if not added // add to epoll if not added
if (!(c->ev_mask & EPOLLOUT)) { if (!(c->ev_mask & EPOLLOUT)) {

17
main.c
View File

@@ -9,8 +9,9 @@
#include <sys/epoll.h> #include <sys/epoll.h>
#include <sys/signalfd.h> #include <sys/signalfd.h>
#include "event_loop.h" #include "client.h"
#include "connection.h" #include "connection.h"
#include "event_loop.h"
#include "server.h" #include "server.h"
#include "utils.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)) { else if (connection_is_socket_managed(fd)) {
connection_event(fd, events); connection_event(fd, events);
} }
// Client event
else if (client_event(fd, events)) {
// nothing here
}
else { else {
fprintf(stderr, "[!] Event has happened on an unknown file descriptor\n"); fprintf(stderr, "[!] Event has happened on an unknown file descriptor\n");
} }
@@ -209,6 +214,13 @@ int main(int argc, char **argv) {
return 1; return 1;
} }
} }
else {
if (!client_init()) {
signals_deinit();
loop_deinit();
return 1;
}
}
// Loop // Loop
while (_to_work) { while (_to_work) {
if (!loop_wait()) { if (!loop_wait()) {
@@ -221,6 +233,9 @@ int main(int argc, char **argv) {
if (_is_server) { if (_is_server) {
server_close(); server_close();
} }
else {
client_deinit();
}
connection_cleanup(); connection_cleanup();
signals_deinit(); signals_deinit();
loop_deinit(); loop_deinit();

View File

@@ -51,7 +51,7 @@ bool _accept() {
int server_open(const char* host, int port) { int server_open(const char* host, int port) {
struct hostent *he = gethostbyname(host); struct hostent *he = gethostbyname(host);
if (!he) { 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; return -1;
} }
_fd = socket( _fd = socket(