commit - 074798ed626bafae8efcea1413bf3f9571338d70
commit + 48f773b3abbc8524ddb57b4a6a6d37a0749deac6
blob - 5cf184209f166fd81670f72bb612aa7a92629697
blob + 288ac9dbb72a00d89672c8a551b4ce624a7268c2
--- .gitea/workflows/jobs.yaml
+++ .gitea/workflows/jobs.yaml
- name: Install dependencies
run: |
sudo apt-get update
- sudo apt-get install -y libbsd-dev cmake build-essential
+ sudo apt-get install -y libbsd-dev cmake build-essential netcat
- name: Build and test
run: |
blob - c3157f7e765fc8a62f20693def316be0b5739d91
blob + 221cf5558f79da78e54a00bb1e33cb3b7b840279
--- .gitignore
+++ .gitignore
site
libflint.so
test
+tcptest
+testrunner
.idea
+netmanual
blob - a8dc82399ae04425657d6b38ea7d34122bda06b6
blob + fa09448298f620bf1b6c9500a71ad2f59b8ff92e
--- CMakeLists.txt
+++ CMakeLists.txt
project(flint C)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
+ add_compile_definitions(flint __USE_XOPEN_EXTENDED)
+endif()
+
set(CMAKE_C_STANDARD 99)
include_directories(include)
src/utility.c
src/crypto.c
src/parsing.c
+ src/network.c
)
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Darwin"))
- add_library(flint ${SOURCES} src/macos/macos.c)
+ add_library(flint ${SOURCES} src/macos.c)
else()
add_library(flint ${SOURCES})
endif()
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
- target_link_libraries(flint bsd)
+ target_link_libraries(flint pthread bsd)
endif()
if(${CMAKE_PROJECT_NAME} STREQUAL flint)
target_include_directories(tests PRIVATE include)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
- target_link_libraries(tests flint bsd)
+ target_link_libraries(tests flint pthread bsd)
else()
- target_link_libraries(tests flint)
+ target_link_libraries(tests flint pthread)
endif()
+
+ add_executable(netmanual tests/netmanual.c)
+ target_include_directories(netmanual PRIVATE include)
+
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+ target_link_libraries(netmanual flint pthread bsd)
+ else()
+ target_link_libraries(netmanual flint pthread)
+ endif()
endif()
blob - e4a25820995867a5ef353a5e246145fb255afef8 (mode 644)
blob + /dev/null
--- Makefile
+++ /dev/null
-.PHONY : clean
-
-CFLAGS = -std=c99 -Iinclude -pedantic -Wall -Wextra
-LDFLAGS = -fPIC -shared
-
-TARGET = libflint.so
-SRC != ls src/*.c
-OBJ = $(SRC:./src/$.c=./obj/%.o)
-
-PREFIX = $(DESTDIR)/usr/local
-LIBDIR = $(PREFIX)/lib
-
-all: $(TARGET)
-
-$(TARGET): $(OBJ)
- cc $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(OBJ)
-
-./obj/%.o: ./src/%.c
- cc $(CFLAGS) -c $< -o $@
-
-install: $(TARGET)
- cp $(TARGET) $(LIBDIR)
-
-uninstall:
- rm -f $(LIBDIR)/$(TARGET)
-
-clean:
- rm -f $(TARGET)
- rm -f test
-
-test:
- cc $(CFLAGS) -o test tests/tests.c src/*.c
blob - /dev/null
blob + fbcb53112ec7ad10d51ee0c8136c63e0daa44f90 (mode 755)
--- /dev/null
+++ clanggen.sh
+#!/usr/bin/env sh
+
+set -e
+
+CFLAGS="-I./include -I/usr/local/include"
+
+rm -f compile_commands.json
+
+for f in $(find ./src -type f | grep -v macos); do
+ n=$(echo $f | grep -o '[^/]*$' | sed 's/c$/json/')
+ cc -MJ $n $CFLAGS -c $f
+done
+
+rm *.o
+sed -e '1s/^/[/' -e '$s/,$/]/' *.json > compile_commands.out
+rm *.json
+mv compile_commands.out compile_commands.json
blob - c8603550b60da781c8d7936d293d293916f1ce73 (mode 755)
blob + /dev/null
--- build.sh
+++ /dev/null
-#!/bin/sh -e
-
-# For building outside of CLion
-
-mkdir -p build
-cd build
-cmake ..
-make
-cp compile_commands.json ..
-cd
blob - 8537d0e64d60f6afc713db24394f31ec71301cab
blob + dae3f84edc29eae7c81087250269466fff5d2326
--- docs/input.md
+++ docs/input.md
### del_split
-Frees all memory used by `split()`. Just like `split`, it does not touch the original string
+Frees all memory used by `split()`. Just like `split`, it does not touch the original string.
+
```c
void del_split(char **sp);
char **sp = split("Delete Me!", &sp_sz, " ");
void del_split(sp);
```
+
+### capture_system
+
+Runs a command on the system shell and returns stdout as a string. `buffsize` is the size of
+the returned buffer that holds `stdout`. Passing `0` to `buffsize` will use the default buffer size of `1024`.
+
+User is responsible for freeing the returned string.
+
+```c
+const char *capture_system(const char *cmd, int buffsize);
+
+/* Usage */
+const char *cap = capture_system("ls $HOME", 0);
+printf("%s\n", cap);
+free(cap);
+```
\ No newline at end of file
blob - /dev/null
blob + b47a96c84956411541fa5365cf203828337e9174 (mode 644)
--- /dev/null
+++ docs/network.md
+# network
+
+This module provides a generic `Server` type that abstracts away the setup and teardown of a socket
+
+## Enums
+
+### ServerType
+
+Types of servers. Currently supports TCP and UDP, will eventually add UNIX sockets.
+
+```c
+typedef enum ServerType {
+ SERVERTYPE_TCP,
+ SERVERTYPE_UDP
+} ServerType;
+```
+
+## Structs
+
+### Server
+
+Server is a generic abstraction over sockets. The type of the server is defined by `server_type`.
+
+```c
+typedef struct Server {
+ ServerType server_type;
+ int fd;
+ int port;
+ void (*handler)(struct Server *s);
+} Server;
+```
+
+## Functions
+
+### new_server
+
+Create a `Server*`. User is responsible for freeing the memory.
+
+```c
+Server *new_server(ServerType type, const char *port, void(handler)(Server *s));
+```
+
+### delete_server
+
+Frees the memory allocated for `Server*` and sets the pointer to `NULL`.
+
+```c
+void delete_server(Server *s);
+```
+
+### serve
+
+Starts up the server. `backlog_size` is the size of the backlog buffer for the underlying socket. Use the macro
+`DEFAULT_BACKLOG_SIZE` or pass `0` to use a reasonable default.
+
+```c
+int serve(Server *s, int backlog_size);
+```
+
+### get_in_addr
+
+Convenience method to get an IP address from a `struct sockaddr_storage` of either IPV4 or IPV6.
+
+```c
+void *get_in_addr(struct sockaddr *sa);
+
+/* Usage */
+struct sockaddr_storage client_addr;
+socklen_t client_addr_sz = sizeof(client_addr);
+char buf[33];
+
+if (new_fd = accept(s->fd, (struct sockaddr *)&client_addr, &client_addr_sz) == -1) {
+ /* error handling */
+}
+inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), buf, 32);
+printf("Received connection from %s\n", buf);
+
+```
+
+### handler_tcp_echo
+
+An example handler for a multithreaded tcp echo server.
+
+```c
+void handler_tcp_echo(Server *s);
+
+/* Usage */
+#include "lfnetwork.h"
+
+int main(int argc, char **argv) {
+ Server *server = new_server(SERVERTYPE_TCP, "80", handler_tcp_echo);
+ serve(server, DEFAULT_BACKLOG);
+ delete_server(server);
+}
+```
+
+## Macros
+
+### DEFAULT_BACKLOG_SIZE
+
+A default size for the socket's backlog buffer. `5` is a standard default size, providing some backlog but not
+enough to make huge buffers for each socket
+
+```c
+#define DEFAULT_BACKLOG_SIZE 5
+```
\ No newline at end of file
blob - 53ecb0c1769a6ec9fa5362aa7b4717137f9cdd7c
blob + 3e5bc239140cb52650fb5c582e14275216e684a3
--- include/lfinput.h
+++ include/lfinput.h
void del_lines(char **);
+#define DEFAULT_CAPTURE_SYSTEM_BUFSIZE 1024
+
+const char *capture_system(const char *cmd, int buf_sz);
+
#endif // LIBFLINT_INPUT_H
blob - /dev/null
blob + b4869f0bd0d8c622974b9284ac3623d794dedffb (mode 644)
--- /dev/null
+++ include/lfnetwork.h
+#ifndef LIBFLINT_NET_H
+#define LIBFLINT_NET_H
+
+#include <netdb.h>
+
+typedef enum ServerType {
+ SERVERTYPE_TCP,
+ SERVERTYPE_UDP
+} ServerType;
+
+typedef struct Server {
+ ServerType server_type;
+ int fd;
+ int port;
+ void (*handler)(struct Server *s);
+} Server;
+
+#define DEFAULT_BACKLOG 5
+
+Server *new_server(ServerType type, const char *port, void(handler)(Server *s));
+void delete_server(Server *s);
+int serve(Server *s, int backlog_size);
+void *get_in_addr(struct sockaddr *sa);
+
+// Example handlers
+void handler_tcp_echo(Server *s);
+
+#endif //LIBFLINT_NET_H
blob - /dev/null
blob + ba1a8603f7586d7eeb17a88cfc6ff4b521905727 (mode 755)
--- /dev/null
+++ run_tests.sh
+set -e
+
+#./testrunner
+./tcptest &
+tcpout=$(echo "hello" | nc localhost 18632)
+echo "tcpout: $tcpout"
+if [ "$tcpout" != "TEST SEND" ]; then
+ echo "Error: \"$tcpout\" != \"TEST SEND\""
+ exit 1
+fi
+
+exit 0
blob - f20b8200a38aa43fd268e959f03dee2969515d13
blob + 23d54c9df9d8498a4e6c0e3b3fc2ff863ecb955e
--- src/input.c
+++ src/input.c
#include <stdlib.h>
#include <string.h>
#include <limits.h>
+#include <errno.h>
#ifdef __linux__
void del_lines(char **lines) {
del_split(lines);
}
+
+const char *capture_system(const char *cmd, int buf_sz) {
+ if (buf_sz == 0) {
+ buf_sz = DEFAULT_CAPTURE_SYSTEM_BUFSIZE;
+ }
+ char *buf = malloc(buf_sz);
+ FILE *tmp = popen(cmd, "r");
+ if (tmp == NULL) {
+ fprintf(stderr, "libflint: failed to open FILE *tmp in capture_system. Errno: %d\n", errno);
+ free(buf);
+ return NULL;
+ }
+ fgets(buf, buf_sz, tmp);
+ return buf;
+}
\ No newline at end of file
blob - 3bbcf1c246a5b5475ef1fb51e62831f676c6dcf6 (mode 644)
blob + /dev/null
--- src/macos/macos.c
+++ /dev/null
-#include <libproc.h>
-#include <time.h>
-#include <mach/mach_time.h>
-#include <sys/errno.h>
-#include <stdlib.h>
-
-#include "lfmacos.h"
-
-#define NS_TO_SECONDS 1000000000.0
-#define NEW_PROCESS_SENTINEL (-1.0)
-
-ProcessData *new_ProcessData() {
- ProcessData *pd = malloc(sizeof(ProcessData));
- pd->last_total_consumed = NEW_PROCESS_SENTINEL;
- return pd;
-}
-
-int update_process(pid_t pid, ProcessData *proc) {
- struct proc_taskinfo taskinfo;
- const int r = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &taskinfo, PROC_PIDTASKINFO_SIZE);
- if (r != PROC_PIDTASKINFO_SIZE) {
- return 1;
- }
-
- mach_timebase_info_data_t info;
- mach_timebase_info(&info);
- const double ns_per_tick = (double)info.numer / (double)info.denom;
-
- time(&(proc->timestamp));
- proc->total_kernel_time = (taskinfo.pti_total_system * ns_per_tick) / NS_TO_SECONDS;
- proc->total_user_time = (taskinfo.pti_total_user * ns_per_tick) / NS_TO_SECONDS;
- proc->virtual_memory = taskinfo.pti_virtual_size;
- proc->resident_memory = taskinfo.pti_resident_size;
-
- if (proc->last_total_consumed != NEW_PROCESS_SENTINEL) {
- time_t t = proc->timestamp - proc->last_timestamp;
- proc->percent_cpu = 100.0 * (proc->total_user_time + proc->total_kernel_time - proc->last_total_consumed) / t;
- } else {
- proc->percent_cpu = 0.0;
- }
-
- proc->last_timestamp = proc->timestamp;
- proc->last_total_consumed = proc->total_kernel_time + proc->total_user_time;
-
- return 0;
-}
-
-/* reallocarray is reimplemented here for macOS because Apple doesn't expose
- * their implementation. This is taken straight from the OpenBSD source as
- * shown in the below copyright notice
- */
-
-/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
-/*
- * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
- *
- * Permission to use, copy, modify, and 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.
- */
-
-/* OPENBSD ORIGINAL: lib/libc/stdlib/reallocarray.c */
-
-#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
-
-void *reallocarray(void *optr, size_t nmemb, size_t size)
-{
- if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
- nmemb > 0 && SIZE_MAX / nmemb < size) {
- errno = ENOMEM;
- return NULL;
- }
- return realloc(optr, size * nmemb);
-}
blob - /dev/null
blob + 3bbcf1c246a5b5475ef1fb51e62831f676c6dcf6 (mode 644)
--- /dev/null
+++ src/macos.c
+#include <libproc.h>
+#include <time.h>
+#include <mach/mach_time.h>
+#include <sys/errno.h>
+#include <stdlib.h>
+
+#include "lfmacos.h"
+
+#define NS_TO_SECONDS 1000000000.0
+#define NEW_PROCESS_SENTINEL (-1.0)
+
+ProcessData *new_ProcessData() {
+ ProcessData *pd = malloc(sizeof(ProcessData));
+ pd->last_total_consumed = NEW_PROCESS_SENTINEL;
+ return pd;
+}
+
+int update_process(pid_t pid, ProcessData *proc) {
+ struct proc_taskinfo taskinfo;
+ const int r = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &taskinfo, PROC_PIDTASKINFO_SIZE);
+ if (r != PROC_PIDTASKINFO_SIZE) {
+ return 1;
+ }
+
+ mach_timebase_info_data_t info;
+ mach_timebase_info(&info);
+ const double ns_per_tick = (double)info.numer / (double)info.denom;
+
+ time(&(proc->timestamp));
+ proc->total_kernel_time = (taskinfo.pti_total_system * ns_per_tick) / NS_TO_SECONDS;
+ proc->total_user_time = (taskinfo.pti_total_user * ns_per_tick) / NS_TO_SECONDS;
+ proc->virtual_memory = taskinfo.pti_virtual_size;
+ proc->resident_memory = taskinfo.pti_resident_size;
+
+ if (proc->last_total_consumed != NEW_PROCESS_SENTINEL) {
+ time_t t = proc->timestamp - proc->last_timestamp;
+ proc->percent_cpu = 100.0 * (proc->total_user_time + proc->total_kernel_time - proc->last_total_consumed) / t;
+ } else {
+ proc->percent_cpu = 0.0;
+ }
+
+ proc->last_timestamp = proc->timestamp;
+ proc->last_total_consumed = proc->total_kernel_time + proc->total_user_time;
+
+ return 0;
+}
+
+/* reallocarray is reimplemented here for macOS because Apple doesn't expose
+ * their implementation. This is taken straight from the OpenBSD source as
+ * shown in the below copyright notice
+ */
+
+/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/reallocarray.c */
+
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *reallocarray(void *optr, size_t nmemb, size_t size)
+{
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return realloc(optr, size * nmemb);
+}
blob - /dev/null
blob + 29841222c56782549f59bf4c7bff135b55aafe67 (mode 644)
--- /dev/null
+++ src/network.c
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <sys/wait.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+#include <pthread.h>
+
+#include "lfnetwork.h"
+
+static void sighandler(int s) {
+ int saved_errno = errno;
+ while (waitpid(-1, NULL, WNOHANG) > 0);
+ errno = saved_errno;
+}
+
+void *get_in_addr(struct sockaddr *sa)
+{
+ if (sa->sa_family == AF_INET) {
+ return &(((struct sockaddr_in*)sa)->sin_addr);
+ }
+
+ return &(((struct sockaddr_in6*)sa)->sin6_addr);
+}
+
+Server *new_server(ServerType type, const char *port, void(handler)(Server *s)) {
+ Server *s = (Server *)malloc(sizeof(Server));
+ if (s == NULL) {
+ return NULL;
+ }
+ s->server_type = type;
+ s->handler = handler;
+
+ struct addrinfo *addr = NULL;
+ if (getaddrinfo(NULL, port, NULL, &addr) != 0) {
+ free(s);
+ return NULL;
+ }
+ s->port = (int)strtol(port, NULL, 10);
+
+ int socktype = 0;
+ switch (type) {
+ case SERVERTYPE_TCP:
+ socktype = SOCK_STREAM;
+ break;
+ case SERVERTYPE_UDP:
+ socktype = SOCK_DGRAM;
+ break;
+ }
+
+ struct addrinfo *p;
+ for (p = addr; p != NULL; p = p->ai_next) {
+ s->fd = socket(AF_INET, socktype, 0);
+ if (s->fd == -1) {
+ continue;
+ }
+
+ if (bind(s->fd, p->ai_addr, p->ai_addrlen) != 0) {
+ close(s->fd);
+ continue;
+ }
+
+ break;
+ }
+
+ if (p == NULL) {
+ fprintf(stderr, "Failed to bind\n");
+ free(s);
+ return NULL;
+ }
+
+ freeaddrinfo(addr);
+ return s;
+}
+
+void delete_server(Server *s) {
+ free(s);
+ s = NULL;
+}
+
+int serve(Server *s, int backlog_size) {
+ if (backlog_size == 0) {
+ backlog_size = DEFAULT_BACKLOG;
+ }
+
+ if (listen(s->fd, backlog_size) != 0) {
+ return 1;
+ }
+
+ // Linux doesn't handle SA_RESTART properly, and I don't know about Windows (nor do I care)
+ // This is just for macOS and BSDs
+ #if !defined(__linux__) && !defined(_WIN32)
+ struct sigaction sa;
+ sa.sa_handler = sighandler;
+ sa.sa_flags = SA_RESTART;
+ if (sigaction(SIGCHLD, &sa, NULL) == -1) {
+ fprintf(stderr, "Failed to set sigaction\n");
+ return 1;
+ }
+ #endif
+
+ s->handler(s);
+
+ return 0;
+}
+
+static void *tcp_echo_thread(void *vargp) {
+ while (1) {
+ char recv_buf[256];
+ int fd = *(int *) vargp;
+
+ int r = (int)recv(fd, recv_buf, 256, 0);
+ if (r < 1) {
+ if (r == -1) {
+ fprintf(stderr, "Failed to recv. Errno: %d\n", errno);
+ }
+ close(fd);
+ break;
+ }
+
+ if (send(fd, recv_buf, strlen(recv_buf), 0) == -1) {
+ fprintf(stderr, "Failed to send echo. Errno: %d\n", errno);
+ close(fd);
+ break;
+ }
+ }
+}
+
+void handler_tcp_echo(Server *s) {
+ while (1) {
+ struct sockaddr_storage client_addr;
+ socklen_t client_addr_sz = sizeof(client_addr);
+ int new_fd = accept(s->fd, (struct sockaddr *)&client_addr, &client_addr_sz);
+ if (new_fd == -1) {
+ fprintf(stderr, "failed to accept. Errno: %d\n", errno);
+ continue;
+ }
+
+ pthread_t srv_tid;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_create(&srv_tid, &attr, tcp_echo_thread, &new_fd);
+ }
+}
blob - 541550ed203d975a79e17157c67a45991f80cbba
blob + 663631f37f739d19158a37db96eaed3a4b6c30db
--- tests/tests.c
+++ tests/tests.c
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
+#include <arpa/inet.h>
+#include <pthread.h>
#include "lflinkedlist.h"
+#include "lfnetwork.h"
#include "lfset.h"
#include "lfstack.h"
#include "lfbinarytree.h"
#include "lfstring.h"
#include "lfcrypto.h"
#include "lfparsing.h"
+#include "lfinput.h"
#if defined(__APPLE__) || defined(__MACH__)
#include "lfmacos.h"
printf("Passes all parsing tests\n");
}
+#define NET_MSG "TEST SEND"
+
+void tcp_test_handler(Server *s) {
+ struct sockaddr_storage client_addr;
+ socklen_t client_addr_sz = sizeof(client_addr);
+ int new_fd = accept(s->fd, (struct sockaddr *)&client_addr, &client_addr_sz);
+ assert(new_fd != -1);
+ assert(send(new_fd, NET_MSG, 10, 0) != -1);
+ close(new_fd);
+}
+
+void *tcp_server_thread(void *vargp) {
+ Server *server = new_server(SERVERTYPE_TCP, "18632", tcp_test_handler);
+ serve(server, DEFAULT_BACKLOG);
+ delete_server(server);
+}
+
+void udp_test_handler(Server *s) {
+ struct sockaddr_storage client_addr;
+ socklen_t client_addr_sz = sizeof(client_addr);
+ char recv_buf[128];
+
+ int r = (int)recvfrom(s->fd, recv_buf, 128, 0, (struct sockaddr*)&client_addr, &client_addr_sz);
+ assert(r > 0);
+ assert(strcmp(recv_buf, NET_MSG) == 0);
+}
+
+void *udp_server_thread(void *vargp) {
+ Server *server = new_server(SERVERTYPE_UDP, "18633", udp_test_handler);
+ serve(server, DEFAULT_BACKLOG);
+ delete_server(server);
+}
+
+void test_network() {
+ printf("\n--- NETWORK TEST ---\n");
+ pthread_t srv_tid;
+ pthread_create(&srv_tid, NULL, tcp_server_thread, NULL);
+
+ sleep(1);
+ const char *s = capture_system("echo hello | nc localhost 18632", 0);
+ assert(strcmp(s, NET_MSG) == 0);
+ free((char *)s);
+
+ pthread_join(srv_tid, NULL);
+ printf("Passed TCP test\n");
+
+ pthread_create(&srv_tid, NULL, udp_server_thread, NULL);
+ sleep(1);
+ system("echo hello | nc localhost 18633");
+
+ pthread_join(srv_tid, NULL);
+ printf("Passed UDP test\n");
+}
+
#if defined(__APPLE__) || defined(__MACH__)
void test_macos() {
printf("\n--- macOS TEST ---\n");
test_string();
test_crypto();
test_parsing();
+ test_network();
#if defined(__APPLE__) || defined(__MACH__)
test_macos();
#endif
return 0;
-}
\ No newline at end of file
+}
blob - /dev/null
blob + c1eb3dfb79f83d7264007e335b15a1530a8956dd (mode 644)
--- /dev/null
+++ tests/netmanual.c
+#include "lfnetwork.h"
+
+int main(int argc, char **argv) {
+ Server *server = new_server(SERVERTYPE_TCP, "18632", handler_tcp_echo);
+ serve(server, DEFAULT_BACKLOG);
+ delete_server(server);
+}