Created
January 7, 2016 21:32
-
-
Save alfanick/73f10c0c216e958807f3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 (buffer[0] != '.') { | |
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