diff options
author | nirav <nirav@teisuu.com> | 2019-09-15 09:26:41 +0000 |
---|---|---|
committer | nirav <nirav@teisuu.com> | 2019-09-15 09:26:41 +0000 |
commit | e985bfa6b8facac58da9a20c3c840498e2517bb5 (patch) | |
tree | e38c1b5d9eed792d770ccb3deff9f4dd29be41be | |
download | gopherd-e985bfa6b8facac58da9a20c3c840498e2517bb5.tar.gz gopherd-e985bfa6b8facac58da9a20c3c840498e2517bb5.zip |
Initial commit
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | log.c | 36 | ||||
-rw-r--r-- | log.h | 12 | ||||
-rw-r--r-- | main.c | 179 |
5 files changed, 241 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b7e5ac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tags +gopherd diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a989775 --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +CC=cc +CFLAGS=-ansi -Wall -Wextra -pedantic + +all: gopherd + +OBJ=main.o log.o + +gopherd: $(OBJ) + $(CC) -o $@ $(OBJ) + +clean: + rm -f gopherd *.o @@ -0,0 +1,36 @@ +#define _POSIX_C_SOURCE 200112L + +#include <time.h> +#include <errno.h> +#include <stdio.h> +#include <stdarg.h> + +#include "log.h" + +static int save; +static time_t now; +static struct tm *tm; +static char buf[25]; /* "2011-10-08T07:07:09+1111" */ +static va_list ap; +static enum loglevel def_loglevel = LOG_DEBUG; + +void +logmsg(enum loglevel level, const char *format,...) +{ + if (def_loglevel < level) { + return; + } + save = errno; + + time(&now); + tm = localtime(&now); + strftime(buf, sizeof buf, "%FT%T%z", tm); + + printf("%s ", buf); + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + printf("\n"); + + errno = save; +} @@ -0,0 +1,12 @@ +#ifndef __LOG_H +#define __LOG_H + +enum loglevel { + LOG_NONE, + LOG_INFO, + LOG_DEBUG +}; + +void logmsg(enum loglevel level, const char *format,...); + +#endif @@ -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; +} |