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;
|
||||
}
|
||||
Reference in New Issue
Block a user