Skip to content

Instantly share code, notes, and snippets.

@alfanick
Created January 7, 2016 22:31
Show Gist options
  • Save alfanick/37cf411d8fd1b02ab5b6 to your computer and use it in GitHub Desktop.
Save alfanick/37cf411d8fd1b02ab5b6 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#define MAXEVENTS 64
static int make_socket_non_blocking(int fd) {
int result;
int flags = fcntl(fd, F_GETFL, 0);
assert(flags != -1);
flags |= O_NONBLOCK;
result = fcntl(fd, F_SETFL, flags);
assert(result != -1);
return 0;
}
static int create_server_socket(char* port) {
struct addrinfo hints;
struct addrinfo* addr;
int server_fd;
int result;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; // IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_PASSIVE;
result = getaddrinfo(NULL, port, &hints, &addr);
assert(result == 0);
for (struct addrinfo* rp = addr; rp != NULL; rp->ai_next) {
server_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (server_fd == -1)
continue;
result = bind(server_fd, rp->ai_addr, rp->ai_addrlen);
if (result == 0)
break;
close(server_fd);
}
assert(addr != NULL);
freeaddrinfo(addr);
return server_fd;
}
int main (int argc, char* argv[]) {
assert(argc == 2);
int result;
int server_fd = create_server_socket(argv[1]);
assert(server_fd != -1);
result = make_socket_non_blocking(server_fd);
assert(result != -1);
result = listen(server_fd, SOMAXCONN);
assert(result != -1);
int events_fd = epoll_create1(0);
assert(events_fd != -1);
struct epoll_event event;
event.data.fd = server_fd;
event.events = EPOLLIN;// | EPOLLET;
result = epoll_ctl(events_fd, EPOLL_CTL_ADD, server_fd, &event);
assert(result != -1);
struct epoll_event* events = calloc(MAXEVENTS, sizeof(event));
while (true) {
int events_count = epoll_wait(events_fd, events, MAXEVENTS, -1);
for (int i = 0; i < events_count; i++) {
if ((events[i].events & EPOLLERR) ||
(events[i].events & EPOLLHUP) ||
(!(events[i].events & EPOLLIN))) {
fprintf(stderr, "epoll error on %d\n", events[i].data.fd);
close(events[i].data.fd);
continue;
} else
// server events - new connections
if (events[i].data.fd == server_fd) {
while (true) {
struct sockaddr incoming;
socklen_t incoming_size = sizeof(incoming);
int incoming_fd;
char incoming_hostname[NI_MAXHOST], incoming_port[NI_MAXSERV];
incoming_fd = accept(server_fd, &incoming, &incoming_size);
if (incoming_fd == -1)
break;
result = getnameinfo(&incoming, incoming_size,
incoming_hostname, sizeof(incoming_hostname),
incoming_port, sizeof(incoming_size),
NI_NUMERICHOST | NI_NUMERICSERV);
if (result == 0)
fprintf(stdout, "new connection on %d from %s:%s\n", incoming_fd, incoming_hostname, incoming_port);
result = make_socket_non_blocking(incoming_fd);
assert(result != -1);
event.data.fd = incoming_fd;
event.events = EPOLLIN; //| EPOLLET;
result = epoll_ctl(events_fd, EPOLL_CTL_ADD, incoming_fd, &event);
assert(result != -1);
}
}
else {
int done = 0;
while (true) {
char buffer[512];
ssize_t count = read(events[i].data.fd, buffer, sizeof(buffer));
if (count == -1) {
if (errno != EAGAIN) {
fprintf(stdout, "done reading -1 from %d\n", events[i].data.fd);
done = 1;
}
break;
} else
if (count == 0) {
fprintf(stdout, "done reading 0 from %d\n", events[i].data.fd);
done = 1;
break;
}
if (count == 2 && (buffer[0] == 'a' || buffer[0] == 'b' || buffer[0] == 'c')) {
fprintf(stdout, "got data from %d - first %c (length %ld)\n", events[i].data.fd, buffer[0], count);
}
}
if (done) {
fprintf(stdout, "closing on %d\n", events[i].data.fd);
close(events[i].data.fd);
}
}
}
}
free(events);
close(server_fd);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment