Added client, fixed typo
This commit is contained in:
140
client.c
Normal file
140
client.c
Normal 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
39
client.h
Normal 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
|
||||||
@@ -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
17
main.c
@@ -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();
|
||||||
|
|||||||
2
server.c
2
server.c
@@ -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(
|
||||||
|
|||||||
Reference in New Issue
Block a user