#define _GNU_SOURCE
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <unistd.h>
#include "common.h"
struct fdinfo {
enum {
LSOCK,
CLIENT
} type;
int fd;
};
static void print_event(int fd, struct epoll_event ev) {
char flags_str[200];
flags_str[0] = 0;
flags_str[1] = 0; /* dirty */
if (ev.
events & EPOLLIN
) strcat(flags_str
, "|EPOLLIN");
if (ev.
events & EPOLLOUT
) strcat(flags_str
, "|EPOLLOUT");
if (ev.
events & EPOLLERR
) strcat(flags_str
, "|EPOLLERR");
if (ev.
events & EPOLLHUP
) strcat(flags_str
, "|EPOLLHUP");
if (ev.
events & EPOLLRDHUP
) strcat(flags_str
, "|EPOLLRDHUP");
if (ev.
events & EPOLLPRI
) strcat(flags_str
, "|EPOLLPRI");
if (ev.
events & EPOLLET
) strcat(flags_str
, "|EPOLLET");
if (ev.
events & EPOLLONESHOT
) strcat(flags_str
, "|EPOLLONESHOT");
fprintf(stderr
, "Event for fd %i. Flags=(%s).\n",
fd, flags_str+1);
}
int start_listener(int port);
void service(int epfd);
int main () {
int epfd = epoll_create(1);
int lsock = start_listener(9000);
struct epoll_event ev;
struct fdinfo *fdinfo;
int ret;
fdinfo
= malloc(sizeof (struct fdinfo
));
fdinfo->type = LSOCK;
fdinfo->fd = lsock;
ev.data.ptr = fdinfo;
ev.events = EPOLLIN;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, lsock, &ev);
if (ret < 0)
die("epoll_ctl.1");
service(epfd);
close(epfd);
return 0;
}
int start_listener(int port) {
struct sockaddr_in listen_addr;
int lsock;
int ret;
lsock = socket(AF_INET, SOCK_STREAM, 0);
if (lsock < 0)
die("socket");
memset(&listen_addr
, 0, sizeof listen_addr
);
listen_addr.sin_family = AF_INET;
listen_addr.sin_port = htons(port);
listen_addr.sin_addr.s_addr = INADDR_ANY;
ret = bind(lsock, (sad*)&listen_addr, sizeof listen_addr);
if (ret < 0)
die("bind");
ret = listen(lsock, 10);
if (ret < 0)
die("listen");
return lsock;
}
void accept_one(int epfd, int lsock) {
int cli;
struct fdinfo *fdinfo;
struct epoll_event ev;
socklen_t crap
= sizeof fdinfo
->sin;
int ret;
fdinfo
= malloc(sizeof *fdinfo
);
cli
= accept4
(lsock
, (sad
*)&fdinfo
->sin, &crap
, SOCK_NONBLOCK
);
if (cli < 0)
die("accept");
fdinfo->fd = cli;
fdinfo->type = CLIENT;
ev.data.ptr = fdinfo;
ev.events = EPOLLIN | EPOLLRDHUP;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, cli, &ev);
if (ret < 0)
die("epoll_ctl.2");
}
void handle_cli(struct fdinfo *fdinfo) {
int fd = fdinfo->fd;
int t;
char buf1[101], buf2[101];
inet_ntop
(AF_INET
, &fdinfo
->sin.
sin_addr, buf1
, sizeof fdinfo
->sin);
buf2[0] = 0;
t = read(fd, buf2, 100);
if (t > 0) {
buf2[t] = 0;
printf("%s mandó %s\n"n"
, buf1
, buf2
);
}
write(fd, buf2, t);
}
void kill_cli(int epfd, struct fdinfo *fdinfo) {
char buf[100];
int fd = fdinfo->fd;
inet_ntop
(AF_INET
, &fdinfo
->sin.
sin_addr, buf
, sizeof fdinfo
->sin);
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
}
void handle_event(int epfd, struct epoll_event ev) {
struct fdinfo *fdinfo = ev.data.ptr;
switch (fdinfo->type) {
case LSOCK:
accept_one(epfd, fdinfo->fd);
break;
case CLIENT:
print_event(fdinfo->fd, ev);
if (ev.events & EPOLLIN && !(ev.events & EPOLLRDHUP))
handle_cli(fdinfo);
else if (ev.events & EPOLLRDHUP)
kill_cli(epfd, fdinfo);
break;
}
}
void service(int epfd) {
int i, n;
struct epoll_event evs[10];
for (;;) {
n = epoll_wait(epfd, evs, 10, 5000);
if (n < 0)
die("epoll_wait");
if (n == 0) {
printf("Que aburrimiento che....\n"
);
continue;
}
for (i=0; i<n; i++)
handle_event(epfd, evs[i]);
}