summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..466ab83
--- /dev/null
+++ b/main.c
@@ -0,0 +1,179 @@
+#define _POSIX_C_SOURCE 200112L
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+
+#ifndef OPEN_MAX
+#define OPEN_MAX 1024
+#endif
+
+#define PORT "3000"
+#define BUFSIZE 1024
+
+static int
+create_server(const char *port)
+{
+ int fd, yes = 1;
+ struct addrinfo *res, *p, hints;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+
+ if (getaddrinfo(NULL, port, &hints, &res) != 0) {
+ perror("getaddrinfo");
+ return -1;
+ }
+ for (p = res; p != NULL; p = p->ai_next) {
+ if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol))
+ == -1) {
+ perror("socket");
+ continue;
+ }
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes,
+ sizeof(int)) == -1) {
+ perror("setsockopt");
+ close(fd);
+ return -1;
+ }
+ if (ioctl(fd, FIONBIO, &yes) == -1) {
+ perror("ioctl");
+ close(fd);
+ return -1;
+ }
+ if (bind(fd, p->ai_addr, p->ai_addrlen) == -1) {
+ perror("bind");
+ continue;
+ }
+ break;
+ }
+
+ freeaddrinfo(res);
+
+ if (p == NULL) {
+ fprintf(stderr, "failed to bind\n");
+ return -1;
+ }
+ if (listen(fd, 32) == -1) {
+ perror("listen");
+ return -1;
+ }
+ logmsg(LOG_INFO, "listening on %s", port);
+ return fd;
+}
+
+static int
+accept_connection(int s_fd)
+{
+ int c_fd;
+
+ if ((c_fd = accept(s_fd, NULL, NULL)) == -1) {
+ if (errno != EWOULDBLOCK || errno != EAGAIN) {
+ perror("accept");
+ exit(1);
+ }
+ return -1;
+ }
+ logmsg(LOG_INFO, "connection accepted");
+
+ return c_fd;
+}
+
+static void
+handle_client(int c_fd)
+{
+ int n;
+ char buf[BUFSIZE];
+
+ n = recv(c_fd, &buf, BUFSIZE - 1, 0);
+ switch (n) {
+ case -1:
+ if (errno != EWOULDBLOCK || errno != EAGAIN) {
+ perror("recv");
+ }
+ case 0:
+ logmsg(LOG_INFO, "connection closed by client");
+ default:
+ buf[n] = '\0';
+ if (send(c_fd, buf, n, 0) == -1) {
+ perror("send");
+ }
+ }
+ close(c_fd);
+}
+
+static void
+main_loop(int s_fd)
+{
+ int i, rc, end_server = 0;
+ int c_fd, nfds = 1, curr_size = 0;
+ struct pollfd pfds[OPEN_MAX];
+
+ memset(pfds, 0, sizeof(pfds));
+ pfds[0].fd = s_fd;
+ pfds[0].events = POLLIN;
+
+ do {
+ rc = poll(pfds, nfds, -1);
+ if (rc == -1) {
+ perror("poll");
+ break;
+ }
+ if (rc == 0) {
+ fprintf(stderr, "poll timeout\n");
+ break;
+ }
+ curr_size = nfds;
+ for (i = 0; i < curr_size; i++) {
+ if (pfds[i].revents == 0)
+ continue;
+
+ if (pfds[i].revents != POLLIN) {
+ logmsg(LOG_INFO, "revents not POLLIN\n");
+ end_server = 1;
+ break;
+ }
+ if (pfds[i].fd == s_fd) {
+ do {
+ c_fd = accept_connection(s_fd);
+ if (c_fd != -1) {
+ pfds[nfds].fd = c_fd;
+ pfds[nfds].events = POLLIN;
+ nfds++;
+ }
+ } while (c_fd != -1);
+ } else {
+ handle_client(pfds[i].fd);
+ pfds[i].fd = -1;
+ }
+ }
+ } while (end_server == 0);
+}
+
+int
+main()
+{
+ int s_fd;
+
+ s_fd = create_server(PORT);
+ if (s_fd == -1) {
+ fprintf(stderr, "failed to create server\n");
+ exit(0);
+ }
+ main_loop(s_fd);
+
+ return 0;
+}