nserver

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

commit 0c5b08ea58f88252e950ecaf40125a22b79fa83c
Author: rsiddharth <s@ricketyspace.net>
Date:   Sat, 24 Aug 2019 19:26:17 -0400

Add nserver.

For now it contains only "statserve".

Diffstat:
nserver/LICENSE | 15+++++++++++++++
nserver/Makefile | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
nserver/README.md | 11+++++++++++
nserver/bin/statserve.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
nserver/src/dbg.h | 43+++++++++++++++++++++++++++++++++++++++++++
nserver/tests/minunit.h | 33+++++++++++++++++++++++++++++++++
nserver/tests/runtests.sh | 19+++++++++++++++++++
7 files changed, 302 insertions(+), 0 deletions(-)

diff --git a/nserver/LICENSE b/nserver/LICENSE @@ -0,0 +1,15 @@ +Copyright 2019 rsiddharth <s@ricketyspace.net> + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted, provided that the +above copyright notice and this permission notice appear in all +copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/nserver/Makefile b/nserver/Makefile @@ -0,0 +1,63 @@ +CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS) +LIBS=-ldl $(OPTLIBS) +PREFIX?=/usr/local +CTAGS=`which ectags` + +SOURCES=$(wildcard src/**/*.c src/*.c) +OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) + +TEST_SRC=$(wildcard tests/*_tests.c) +TESTS=$(patsubst %.c,%,$(TEST_SRC)) + +PROGRAMS_SRC=$(wildcard bin/*.c) +PROGRAMS=$(patsubst %.c,%,$(PROGRAMS_SRC)) + +TARGET=build/libnserve.a +SO_TARGET=$(patsubst %.a,%.so,$(TARGET)) + +# The Target Build +all: $(PROGRAMS) TAGS + +dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS) +dev: all + +$(TARGET): CFLAGS += -fPIC +$(TARGET): build $(OBJECTS) + ar rcs $@ $(OBJECTS) + ranlib $@ +$(SO_TARGET): $(TARGET) $(OBJECTS) + $(CC) -shared -o $@ $(OBJECTS) + +$(PROGRAMS): LDLIBS += -lm + +build: + @mkdir -p build + @mkdir -p bin + +# The Unit Tests +.PHONY: tests +tests: CFLAGS += $(TARGET) +tests: $(TESTS) + sh ./tests/runtests.sh + +# The Cleaner +clean: + rm -rf build $(OBJECTS) $(TESTS) + rm -f tests/tests.log + find . -name "*.gc" -exec rm {} \; + rm -rf `find . -name "*.dSYM" -print` + +# The Install +install: all + install -d $(DESTDIR)/$(PREFIX)/lib/ + install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/ + +# Generate TAGS file +TAGS: $(SOURCES) $(TEST_SRC) + find ./ -type f -name '*.h' -or -name '*.c' | $(CTAGS) -e -L - + +# The Checker +check: + @echo Files with potentially dangerous functions. + @egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)\ + |stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true diff --git a/nserver/README.md b/nserver/README.md @@ -0,0 +1,11 @@ +# nserver + +## statserve + +To start this server, do: + +``` +./bin/statserve +``` + +It'll be listening on port 7899. diff --git a/nserver/bin/statserve.c b/nserver/bin/statserve.c @@ -0,0 +1,118 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> + +#include <dbg.h> + +#define PORT "7899" +#define BACKLOG 10 + +int echo(int sock, char *buf, int len) +{ + int bytes = 0; + + bytes = send(sock, buf, len, 0); + check(bytes >= 0, "statserv: send failed"); + + return bytes; + error: + return -1; +} + +void serve(int sock) +{ + int rc = 0; + int buf_len = 1000; + char buf[buf_len]; + ssize_t bytes; + + do { + bytes = recv(sock, buf, buf_len, 0); + check(bytes >= 0, "statserv: recv failed"); + + if (bytes < 1) { + break; + } + + rc = echo(sock, buf, bytes); + check(rc != -1, "statserv: echo failed"); + } while(1); + + rc = close(sock); + check(rc == 0, "statserv: close failed"); + + exit(0); + error: + rc = close(sock); + check(rc == 0, "statserv: close failed"); + exit(1); +} + +int main(void) +{ + int rc = 0; + int sockfd_s = 0, sockfd_c = 0; + struct addrinfo hints; + struct addrinfo *servinfo = NULL; + struct sockaddr sockaddr_c; + socklen_t sockaddr_c_len; + pid_t pidc; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + rc = getaddrinfo(NULL, PORT, &hints, &servinfo); + check(rc == 0, "statserve: getaddrinfo failed"); + + sockfd_s = socket(servinfo->ai_family, servinfo->ai_socktype, + servinfo->ai_protocol); + check(sockfd_s != 0, "statserve: socket failed"); + + rc = bind(sockfd_s, servinfo->ai_addr, servinfo->ai_addrlen); + check(rc == 0, "statserve: bind failed"); + + rc = listen(sockfd_s, BACKLOG); + check(rc == 0, "statserve: listen failed"); + + do { + printf("Waiting for connection...\n"); + sockfd_c = accept(sockfd_s, &sockaddr_c, &sockaddr_c_len); + + pidc = fork(); + check(pidc != -1, "statserve: fork failed"); + + if (pidc == 0) { + serve(sockfd_c); + } + + rc = close(sockfd_c); + check(rc == 0, "statserv: close failed"); + } while(1); + + // Clean up. + freeaddrinfo(servinfo); + + rc = close(sockfd_s); + check(rc == 0, "statserv: close failed"); + + return 0; + + error: + if (servinfo) + freeaddrinfo(servinfo); + if (sockfd_s) { + rc = close(sockfd_s); + check(rc == 0, "statserv: close failed"); + } + if (sockfd_c) { + rc = close(sockfd_c); + check(rc == 0, "statserv: close failed"); + } + + return -1; +} diff --git a/nserver/src/dbg.h b/nserver/src/dbg.h @@ -0,0 +1,43 @@ +#ifndef __dbg_h__ +#define __dbg_h__ + +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#ifdef NDEBUG +#define debug(M, ...) +#else +#define debug(M, ...) fprintf(stderr, "DEBUG %s:%s:%d: " M "\n", \ + __FILE__, __FUNCTION__, __LINE__, \ + ##__VA_ARGS__) +#endif + +#define clean_errno() (errno == 0 ? "None" : strerror(errno)) + +#define log_err(M, ...) fprintf(stderr, \ + "[ERROR] (%s:%s:%d: errno: %s) " M "\n", __FILE__, \ + __FUNCTION__, __LINE__, \ + clean_errno(), ##__VA_ARGS__) + +#define log_warn(M, ...) fprintf(stderr, \ + "[WARN] (%s:%s:%d: errno: %s) " M "\n", \ + __FILE__, __FUNCTION__, __LINE__, \ + clean_errno(), ##__VA_ARGS__) + +#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", \ + __FILE__, __FUNCTION__, __LINE__, \ + ##__VA_ARGS__) + +#define check(A, M, ...) if(!(A)) {\ + log_err(M, ##__VA_ARGS__); errno=0; goto error; } + +#define sentinel(M, ...) { log_err(M, ##__VA_ARGS__);\ + errno=0; goto error; } + +#define check_mem(A) check((A), "Out of memory.") + +#define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__);\ + errno=0; goto error; } + +#endif diff --git a/nserver/tests/minunit.h b/nserver/tests/minunit.h @@ -0,0 +1,33 @@ +#undef NDEBUG +#ifndef _minunit_h +#define _minunit_h + +#include <stdio.h> +#include <dbg.h> +#include <stdlib.h> + +#define mu_suite_start() char *message = NULL + +#define mu_assert(test, message) if (!(test)) {\ + log_err(message); return message; } +#define mu_run_test(test) debug("\n-----%s", " " #test); \ + message = test(); tests_run++; if (message) return message; + +#define RUN_TESTS(name) int main(int argc, char *argv[]) {\ + argc = 1; \ + debug("----- RUNNING: %s", argv[0]); \ + printf("----\nRUNNING: %s\n", argv[0]);\ + char *result = name();\ + if (result != 0) {\ + printf("FAILED: %s\n", result); \ + }\ + else {\ + printf("ALL TESTS PASSED\n");\ + }\ + printf("Tests run: %d\n", tests_run);\ + exit(result != 0);\ + } + +int tests_run; + +#endif diff --git a/nserver/tests/runtests.sh b/nserver/tests/runtests.sh @@ -0,0 +1,19 @@ +echo "Running unit tests:" + +for i in tests/*_tests +do + if test -f $i + then + if $VALGRIND ./$i 2>> tests/tests.log + then + echo $i PASS + else + echo "ERROR in test $i: here's tests/tests.log" + echo "------" + tail tests/tests.log + exit 1 + fi + fi +done + +echo ""