Created
January 8, 2016 08:37
-
-
Save alfanick/d051ee6160fb540f3772 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; | |
event.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP; | |
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)) { | |
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 | |
if (events[i].events & EPOLLOUT) { | |
char html[] = "HTTP/1.0 200 OK\r\nDate: Fri, 31 Dec 1999 23:59:59 GMT\r\nContent-Type: text/html\r\nContent-Length: 5\r\n\r\nHello"; | |
write(events[i].data.fd, html, sizeof(html)); | |
fprintf(stdout, "closing on %d\n", events[i].data.fd); | |
close(events[i].data.fd); | |
} else | |
if (events[i].events & EPOLLIN) { | |
int done = 0; | |
while (true) { | |
char buffer[512]; | |
ssize_t count = read(events[i].data.fd, buffer, sizeof(buffer)); | |
events[i].events = EPOLLOUT; //| EPOLLET; | |
result = epoll_ctl(events_fd, EPOLL_CTL_MOD, events[i].data.fd, &(events[i])); | |
assert(result != -1); | |
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) { | |
} | |
} | |
} | |
} | |
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