Implement Server (#1)
- Generic Server struct - TCP and UDP Reviewed-on: #1
This commit is contained in:
parent
074798ed62
commit
48f773b3ab
|
@ -14,7 +14,7 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
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
|
- name: Build and test
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -5,4 +5,7 @@ compile_commands.json
|
||||||
site
|
site
|
||||||
libflint.so
|
libflint.so
|
||||||
test
|
test
|
||||||
|
tcptest
|
||||||
|
testrunner
|
||||||
.idea
|
.idea
|
||||||
|
netmanual
|
||||||
|
|
|
@ -2,6 +2,10 @@ cmake_minimum_required(VERSION 3.17)
|
||||||
project(flint C)
|
project(flint C)
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
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)
|
set(CMAKE_C_STANDARD 99)
|
||||||
include_directories(include)
|
include_directories(include)
|
||||||
|
|
||||||
|
@ -17,16 +21,17 @@ set(SOURCES
|
||||||
src/utility.c
|
src/utility.c
|
||||||
src/crypto.c
|
src/crypto.c
|
||||||
src/parsing.c
|
src/parsing.c
|
||||||
|
src/network.c
|
||||||
)
|
)
|
||||||
|
|
||||||
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Darwin"))
|
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Darwin"))
|
||||||
add_library(flint ${SOURCES} src/macos/macos.c)
|
add_library(flint ${SOURCES} src/macos.c)
|
||||||
else()
|
else()
|
||||||
add_library(flint ${SOURCES})
|
add_library(flint ${SOURCES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
|
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
|
||||||
target_link_libraries(flint bsd)
|
target_link_libraries(flint pthread bsd)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${CMAKE_PROJECT_NAME} STREQUAL flint)
|
if(${CMAKE_PROJECT_NAME} STREQUAL flint)
|
||||||
|
@ -34,8 +39,17 @@ if(${CMAKE_PROJECT_NAME} STREQUAL flint)
|
||||||
target_include_directories(tests PRIVATE include)
|
target_include_directories(tests PRIVATE include)
|
||||||
|
|
||||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
target_link_libraries(tests flint bsd)
|
target_link_libraries(tests flint pthread bsd)
|
||||||
else()
|
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()
|
||||||
endif()
|
endif()
|
||||||
|
|
32
Makefile
32
Makefile
|
@ -1,32 +0,0 @@
|
||||||
.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
|
|
10
build.sh
10
build.sh
|
@ -1,10 +0,0 @@
|
||||||
#!/bin/sh -e
|
|
||||||
|
|
||||||
# For building outside of CLion
|
|
||||||
|
|
||||||
mkdir -p build
|
|
||||||
cd build
|
|
||||||
cmake ..
|
|
||||||
make
|
|
||||||
cp compile_commands.json ..
|
|
||||||
cd
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/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
|
|
@ -92,7 +92,8 @@ printf("%s\n", sp[0]); // Prints "Split"
|
||||||
|
|
||||||
### del_split
|
### 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
|
```c
|
||||||
void del_split(char **sp);
|
void del_split(char **sp);
|
||||||
|
|
||||||
|
@ -101,3 +102,19 @@ size_t sp_sz = 0;
|
||||||
char **sp = split("Delete Me!", &sp_sz, " ");
|
char **sp = split("Delete Me!", &sp_sz, " ");
|
||||||
void del_split(sp);
|
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);
|
||||||
|
```
|
|
@ -0,0 +1,106 @@
|
||||||
|
# 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
|
||||||
|
```
|
|
@ -17,4 +17,8 @@ void del_split(char **);
|
||||||
|
|
||||||
void del_lines(char **);
|
void del_lines(char **);
|
||||||
|
|
||||||
|
#define DEFAULT_CAPTURE_SYSTEM_BUFSIZE 1024
|
||||||
|
|
||||||
|
const char *capture_system(const char *cmd, int buf_sz);
|
||||||
|
|
||||||
#endif // LIBFLINT_INPUT_H
|
#endif // LIBFLINT_INPUT_H
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
#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
|
|
@ -0,0 +1,12 @@
|
||||||
|
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
|
16
src/input.c
16
src/input.c
|
@ -2,6 +2,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
|
||||||
|
@ -121,3 +122,18 @@ void del_split(char **sp) {
|
||||||
void del_lines(char **lines) {
|
void del_lines(char **lines) {
|
||||||
del_split(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;
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#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);
|
||||||
|
}
|
|
@ -2,8 +2,11 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
#include "lflinkedlist.h"
|
#include "lflinkedlist.h"
|
||||||
|
#include "lfnetwork.h"
|
||||||
#include "lfset.h"
|
#include "lfset.h"
|
||||||
#include "lfstack.h"
|
#include "lfstack.h"
|
||||||
#include "lfbinarytree.h"
|
#include "lfbinarytree.h"
|
||||||
|
@ -12,6 +15,7 @@
|
||||||
#include "lfstring.h"
|
#include "lfstring.h"
|
||||||
#include "lfcrypto.h"
|
#include "lfcrypto.h"
|
||||||
#include "lfparsing.h"
|
#include "lfparsing.h"
|
||||||
|
#include "lfinput.h"
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__MACH__)
|
#if defined(__APPLE__) || defined(__MACH__)
|
||||||
#include "lfmacos.h"
|
#include "lfmacos.h"
|
||||||
|
@ -395,6 +399,60 @@ void test_parsing() {
|
||||||
printf("Passes all parsing tests\n");
|
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__)
|
#if defined(__APPLE__) || defined(__MACH__)
|
||||||
void test_macos() {
|
void test_macos() {
|
||||||
printf("\n--- macOS TEST ---\n");
|
printf("\n--- macOS TEST ---\n");
|
||||||
|
@ -420,6 +478,7 @@ int main() {
|
||||||
test_string();
|
test_string();
|
||||||
test_crypto();
|
test_crypto();
|
||||||
test_parsing();
|
test_parsing();
|
||||||
|
test_network();
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__MACH__)
|
#if defined(__APPLE__) || defined(__MACH__)
|
||||||
test_macos();
|
test_macos();
|
||||||
|
|
Loading…
Reference in New Issue