#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
int fd_srv = -1, fd_epoll = -1;
#define FAILED(msg) perror(msg); \
if (fd_epoll > -1) close(fd_epoll); \
if (fd_srv > -1) close(fd_srv); \
return -1;
#define BACKLOG 5
#define EPOLL_SIZE 65535
#define EPOLL_EVENTS_SIZE 1024
#define READ_BUFFER_SIZE 1024
int main(int argc, char *argv[])
{
const char *host;
int port;
struct sockaddr_in addr_srv = {}, addr_cli = {};
int fd_cli;
struct epoll_event evt = {}, events[EPOLL_EVENTS_SIZE] = {};
int epoll_events_n, i, flags_cli;
socklen_t n_cli;
char buffer[READ_BUFFER_SIZE] = {};
ssize_t n_read, n_write;
if (argc < 3)
{
printf("Usage: %s SERVER_IP SERVER_PORT\n", argv[0]);
return -1;
}
host = argv[1];
port = atoi(argv[2]);
addr_srv.sin_family = AF_INET;
addr_srv.sin_port = htons(port);
addr_srv.sin_addr.s_addr = inet_addr(host);
if ((fd_srv = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
FAILED("socket()");
}
if ((bind(fd_srv, (struct sockaddr *)&addr_srv, sizeof(struct sockaddr_in))) == -1)
{
FAILED("bind()");
}
if (listen(fd_srv, BACKLOG) == -1)
{
FAILED("bind()");
}
if ((fd_epoll = epoll_create(EPOLL_SIZE)) == -1)
{
FAILED("epoll_create()");
}
evt.events = EPOLLIN;
evt.data.fd = fd_srv;
if (epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd_srv, &evt))
{
FAILED("epoll_ctl()");
}
while (1)
{
epoll_events_n = epoll_wait(fd_epoll, events, EPOLL_EVENTS_SIZE, -1);
if (epoll_events_n == -1)
{
if (errno != EINTR)
{
FAILED("epoll_wait()");
}
continue;
}
for (i = 0; i < epoll_events_n; i++)
{
if (events[i].data.fd == fd_srv)
{
if ((fd_cli = accept(fd_srv, (struct sockaddr *)&addr_cli, &n_cli)) == -1)
{
FAILED("accept()");
}
flags_cli = fcntl(fd_cli, F_GETFL);
if (fcntl(fd_cli, F_SETFL, flags_cli | O_NONBLOCK) == -1)
{
FAILED("fcntl()");
}
evt.events = EPOLLIN;
evt.data.fd = fd_cli;
if (epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd_cli, &evt))
{
FAILED("epoll_ctl()");
}
}
else
{
if (events[i].events & EPOLLIN)
{
while (1)
{
n_read = read(events[i].data.fd, buffer, READ_BUFFER_SIZE);
if (n_read < 0)
{
if (errno != EAGAIN)
{
perror("read()");
epoll_ctl(fd_epoll, EPOLL_CTL_DEL, events[i].data.fd, &events[i]);
close(events[i].data.fd);
}
break;
}
else if (n_read == 0)
{
epoll_ctl(fd_epoll, EPOLL_CTL_DEL, events[i].data.fd, &events[i]);
close(events[i].data.fd);
break;
}
n_write = write(events[i].data.fd, buffer, n_read);
}
}
if (events[i].events & EPOLLOUT)
{
}
}
}
}
close(fd_epoll);
close(fd_srv);
return 0;
}