Added posix non-blocking sockets, new tests
All checks were successful
/ unit_test (push) Successful in 51s
All checks were successful
/ unit_test (push) Successful in 51s
This commit is contained in:
parent
5c3cd8bf1e
commit
1490f8dba1
8 changed files with 310 additions and 42 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
|||
*.o
|
||||
*.a
|
||||
*.pcap
|
||||
*.so
|
||||
build/*
|
||||
test/unit/unit
|
||||
tags
|
||||
|
|
39
Makefile
39
Makefile
|
@ -1,39 +1,62 @@
|
|||
CC?=gcc
|
||||
CFLAGS:=-Wall -Werror -Wextra -I.
|
||||
CFLAGS+=-g -ggdb
|
||||
LDFLAGS+=-pthread
|
||||
|
||||
OBJ=build/femtotcp.o \
|
||||
build/test/test_linux_eventloop.o build/port/posix/linux_tap.o
|
||||
build/port/posix/linux_tap.o
|
||||
|
||||
all: build/test-evloop
|
||||
EXE=build/tcpecho build/test-evloop
|
||||
LIB=libfemtotcp.so
|
||||
|
||||
|
||||
all: $(EXE) $(LIB)
|
||||
|
||||
#Static library
|
||||
static: CFLAGS+=-static
|
||||
static: libtcpip.a
|
||||
|
||||
|
||||
|
||||
libtcpip.a: $(OBJ)
|
||||
@ar rcs $@ $^
|
||||
|
||||
libfemtotcp.so:CFLAGS+=-fPIC
|
||||
libfemtotcp.so: build/pie/port/posix/bsd_socket.o build/pie/femtotcp.o \
|
||||
build/pie/port/posix/linux_tap.o
|
||||
@mkdir -p `dirname $@` || true
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ -Wl,--start-group $(^) -Wl,--end-group
|
||||
|
||||
|
||||
clean:
|
||||
@rm -rf build
|
||||
@make -C src/test/unit clean
|
||||
|
||||
# Test
|
||||
asan: build/test-evloop
|
||||
asan: $(EXE) $(LIB)
|
||||
asan:CFLAGS+=-fsanitize=address
|
||||
asan:LDFLAGS+=-static-libasan
|
||||
build/test:CFLAGS+=-g -ggdb -DTEST_MAIN -DETHERNET
|
||||
build/test:LDFLAGS+=-pthread
|
||||
|
||||
|
||||
build/test-evloop: $(OBJ)
|
||||
# Test
|
||||
build/test-evloop: $(OBJ) build/test/test_linux_eventloop.o
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ)
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -Wl,--end-group
|
||||
|
||||
build/tcpecho: $(OBJ) build/port/posix/bsd_socket.o build/test/tcp_echo.o
|
||||
@echo "[LD] $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ -Wl,--start-group $(^) -Wl,--end-group
|
||||
|
||||
build/%.o: src/%.c
|
||||
@mkdir -p `dirname $@` || true
|
||||
@echo "[CC] $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
build/pie/%.o: src/%.c
|
||||
@mkdir -p `dirname $@` || true
|
||||
@echo "[CC] $<"
|
||||
@$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
unit:
|
||||
@make -C src/test/unit
|
||||
@mkdir -p build/test/
|
||||
|
|
4
config.h
4
config.h
|
@ -11,4 +11,8 @@
|
|||
|
||||
#define MAX_NEIGHBORS 16
|
||||
|
||||
/* Linux test configuration */
|
||||
#define FEMTOTCP_IP "10.10.10.2"
|
||||
#define LINUX_IP "10.10.10.1"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,7 @@ typedef uint32_t ip4;
|
|||
#define ee32(x) __builtin_bswap32(x)
|
||||
#define DEBUG
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#define LOG(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
||||
|
@ -39,9 +40,15 @@ struct ipconf {
|
|||
};
|
||||
|
||||
/* Socket interface */
|
||||
#define MARK_TCP_SOCKET 0x1000 /* Mark a socket as TCP */
|
||||
#define MARK_UDP_SOCKET 0x4000 /* Mark a socket as UDP */
|
||||
|
||||
|
||||
#ifndef FEMTO_POSIX
|
||||
#define IPSTACK_SOCK_STREAM 1
|
||||
#define IPSTACK_SOCK_DGRAM 2
|
||||
|
||||
|
||||
struct ipstack_sockaddr_in {
|
||||
uint16_t sin_family;
|
||||
uint16_t sin_port;
|
||||
|
@ -96,6 +103,8 @@ ip4 atoip4(const char *ip);
|
|||
#define CB_EVENT_TIMEOUT 0x08 /* Timeout */
|
||||
void ipstack_register_callback(struct ipstack *s, int sock_fd, void (*cb)(int sock_fd, uint16_t events, void *arg), void *arg);
|
||||
|
||||
/* External requirements */
|
||||
uint32_t ipstack_getrandom(void);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#define MAX_TIMERS MAX_TCPSOCKETS * 3
|
||||
|
||||
/* Constants */
|
||||
#define MARK_TCP_SOCKET 0x1000 /* Mark a socket as TCP */
|
||||
#define MARK_UDP_SOCKET 0x4000 /* Mark a socket as UDP */
|
||||
|
||||
#define IPPROTO_ICMP 0x01
|
||||
#define IPPROTO_TCP 0x06
|
||||
|
|
|
@ -1,11 +1,39 @@
|
|||
/* POSIX socket calls wrapper for femtoTCP */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/time.h>
|
||||
#define FEMTO_POSIX
|
||||
#include "config.h"
|
||||
#include "femtotcp.h"
|
||||
|
||||
static __thread int in_the_stack = 0;
|
||||
static __thread struct ipstack IPSTACK;
|
||||
static __thread int in_the_stack = 1;
|
||||
static struct ipstack *IPSTACK = NULL;
|
||||
|
||||
/* host_ functions are the original functions from the libc */
|
||||
static int (*host_socket ) (int domain, int type, int protocol) = NULL;
|
||||
static int (*host_bind ) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
static int (*host_connect ) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
static int (*host_accept ) (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
static int (*host_listen ) (int sockfd, int backlog);
|
||||
static ssize_t (*host_recvfrom) (int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen);
|
||||
static ssize_t (*host_recv ) (int sockfd, void *buf, size_t len, int flags);
|
||||
static ssize_t (*host_read ) (int sockfd, void *buf, size_t len);
|
||||
static ssize_t (*host_sendto ) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen);
|
||||
static ssize_t (*host_send ) (int sockfd, const void *buf, size_t len, int flags);
|
||||
static ssize_t (*host_write ) (int sockfd, const void *buf, size_t len);
|
||||
static int (*host_close ) (int sockfd);
|
||||
static int (*host_setsockopt) (int sockfd, int level, int optname, const void *optval, socklen_t optlen);
|
||||
static int (*host_getsockopt) (int sockfd, int level, int optname, void *optval, socklen_t *optlen);
|
||||
static int (*host_getsockname) (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
static int (*host_getpeername) (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
|
||||
|
||||
|
||||
#define swap_socketcall(call, name) \
|
||||
{ \
|
||||
|
@ -13,51 +41,192 @@ static __thread struct ipstack IPSTACK;
|
|||
if (host_##call == NULL) { \
|
||||
*(void **)(&host_##call) = dlsym(RTLD_NEXT, name); \
|
||||
if ((msg = dlerror()) != NULL) \
|
||||
fprintf (stderr, "%s: dlsym(%s): %s\n", "picotcp", name, msg); \
|
||||
fprintf (stderr, "%s: dlsym(%s): %s\n", "femtoTCP", name, msg); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define conditional_steal_call(call, fd, ...) \
|
||||
if(in_the_stack) { \
|
||||
return host_##call(i, ## __VA_ARGS__); \
|
||||
return host_##call(fd, ## __VA_ARGS__); \
|
||||
} else { \
|
||||
if (get_femto_fd(i) > -1) { \
|
||||
int __femto_retval = ft_posix_##call(&IPSTACK, fd, ## __VA_ARGS__); \
|
||||
if ((fd & (MARK_TCP_SOCKET | MARK_UDP_SOCKET)) != 0) { \
|
||||
int __femto_retval = ft_##call(IPSTACK, fd, ## __VA_ARGS__); \
|
||||
if (__femto_retval < 0) { \
|
||||
errno = __femto_retval; \
|
||||
return -1; \
|
||||
} \
|
||||
return __femto_retval; \
|
||||
}else { \
|
||||
return host_##call(i, ## __VA_ARGS__); \
|
||||
return host_##call(fd, ## __VA_ARGS__); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Generator for a wrapper function intercepting the return value
|
||||
* '-11' (EAGAIN). It keeps blocking until the underlying femtoTCP
|
||||
* stack is ready to process the call.
|
||||
*/
|
||||
#define GEN_SOCKET_CALL(call) \
|
||||
int ft_posix_##call(struct ipstack *ipstack, int fd, ...) { \
|
||||
int ret; \
|
||||
va_list args; \
|
||||
va_start(args, fd); \
|
||||
do { \
|
||||
ret = call(fd, args); \
|
||||
if (ret == -11) { \
|
||||
pthread_yield(); \
|
||||
#define conditional_steal_blocking_call(call, fd, ...) \
|
||||
if(in_the_stack) { \
|
||||
return host_##call(fd, ## __VA_ARGS__); \
|
||||
} else { \
|
||||
if ((fd & (MARK_TCP_SOCKET | MARK_UDP_SOCKET)) != 0) { \
|
||||
int __femto_retval; \
|
||||
do { \
|
||||
__femto_retval = ft_##call(IPSTACK, fd, ## __VA_ARGS__); \
|
||||
if (__femto_retval == -11) { \
|
||||
usleep(1000); \
|
||||
} \
|
||||
} while (__femto_retval == -11); \
|
||||
if (__femto_retval < 0) { \
|
||||
errno = __femto_retval; \
|
||||
return -1; \
|
||||
} \
|
||||
return __femto_retval; \
|
||||
}else { \
|
||||
return host_##call(fd, ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (ret == -11); \
|
||||
va_end(args); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
|
||||
int ft_setsockopt(struct ipstack *ipstack, int fd, int level, int optname, const void *optval, socklen_t optlen) {
|
||||
(void)ipstack;
|
||||
(void)fd;
|
||||
(void)level;
|
||||
(void)optname;
|
||||
(void)optval;
|
||||
(void)optlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ft_getsockopt(struct ipstack *ipstack, int fd, int level, int optname, void *optval, socklen_t *optlen) {
|
||||
(void)ipstack;
|
||||
(void)fd;
|
||||
(void)level;
|
||||
(void)optname;
|
||||
(void)optval;
|
||||
(void)optlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket(int domain, int type, int protocol) {
|
||||
if (in_the_stack) {
|
||||
return host_socket(domain, type, protocol);
|
||||
} else {
|
||||
return ft_socket(IPSTACK, domain, type, protocol);
|
||||
}
|
||||
}
|
||||
|
||||
int listen(int sockfd, int backlog) {
|
||||
conditional_steal_call(listen, sockfd, backlog);
|
||||
}
|
||||
|
||||
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
conditional_steal_call(bind, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) {
|
||||
conditional_steal_call(getsockopt, sockfd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
conditional_steal_call(getpeername, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
conditional_steal_call(getsockname, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) {
|
||||
conditional_steal_call(setsockopt, sockfd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int close(int sockfd) {
|
||||
conditional_steal_call(close, sockfd);
|
||||
}
|
||||
|
||||
/* Blocking calls */
|
||||
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
conditional_steal_blocking_call(accept, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
conditional_steal_blocking_call(connect, sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen) {
|
||||
conditional_steal_blocking_call(recvfrom, sockfd, buf, len, flags, addr, addrlen);
|
||||
}
|
||||
|
||||
ssize_t recv(int sockfd, void *buf, size_t len, int flags) {
|
||||
conditional_steal_blocking_call(recv, sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
ssize_t read(int sockfd, void *buf, size_t len) {
|
||||
conditional_steal_blocking_call(read, sockfd, buf, len);
|
||||
}
|
||||
|
||||
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen) {
|
||||
conditional_steal_blocking_call(sendto, sockfd, buf, len, flags, addr, addrlen);
|
||||
}
|
||||
|
||||
ssize_t send(int sockfd, const void *buf, size_t len, int flags) {
|
||||
conditional_steal_blocking_call(send, sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
ssize_t write(int sockfd, const void *buf, size_t len) {
|
||||
conditional_steal_blocking_call(write, sockfd, buf, len);
|
||||
}
|
||||
|
||||
|
||||
GEN_SOCKET_CALL(acccept)
|
||||
GEN_SOCKET_CALL(bind)
|
||||
GEN_SOCKET_CALL(close)
|
||||
GEN_SOCKET_CALL(connect)
|
||||
GEN_SOCKET_CALL(sendto)
|
||||
GEN_SOCKET_CALL(recvfrom)
|
||||
|
||||
/* Catch-all function to initialize a new tap device as the network interface.
|
||||
* This is defined in port/linux.c
|
||||
* */
|
||||
extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip);
|
||||
|
||||
void *ft_posix_ip_loop(void *arg) {
|
||||
struct ipstack *ipstack = (struct ipstack *)arg;
|
||||
uint32_t ms_next;
|
||||
struct timeval tv;
|
||||
while (1) {
|
||||
gettimeofday(&tv, NULL);
|
||||
ms_next = ipstack_poll(ipstack, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||
usleep(ms_next * 1000);
|
||||
in_the_stack = 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __attribute__((constructor)) init_femto_posix() {
|
||||
struct in_addr linux_ip;
|
||||
struct ll *tapdev;
|
||||
pthread_t ipstack_thread;
|
||||
if (IPSTACK)
|
||||
return;
|
||||
inet_aton(LINUX_IP, &linux_ip);
|
||||
swap_socketcall(socket, "socket");
|
||||
swap_socketcall(bind, "bind");
|
||||
swap_socketcall(listen, "listen");
|
||||
swap_socketcall(accept, "accept");
|
||||
swap_socketcall(connect, "connect");
|
||||
swap_socketcall(sendto, "sendto");
|
||||
swap_socketcall(recvfrom, "recvfrom");
|
||||
swap_socketcall(recv, "recv");
|
||||
swap_socketcall(send, "send");
|
||||
swap_socketcall(close, "close");
|
||||
swap_socketcall(write, "write");
|
||||
swap_socketcall(read, "read");
|
||||
swap_socketcall(getsockname, "getsockname");
|
||||
swap_socketcall(getpeername, "getpeername");
|
||||
swap_socketcall(setsockopt, "getaddrinfo");
|
||||
swap_socketcall(getsockopt, "freeaddrinfo");
|
||||
ipstack_init_static(&IPSTACK);
|
||||
tapdev = ipstack_getdev(IPSTACK);
|
||||
if (tap_init(tapdev, "femt0", linux_ip.s_addr) < 0) {
|
||||
perror("tap init");
|
||||
}
|
||||
ipstack_ipconfig_set(IPSTACK, atoip4(FEMTOTCP_IP), atoip4("255.255.255.0"),
|
||||
atoip4(LINUX_IP));
|
||||
printf("IP: manually configured - %s\n", FEMTOTCP_IP);
|
||||
sleep(1);
|
||||
pthread_create(&ipstack_thread, NULL, ft_posix_ip_loop, IPSTACK);
|
||||
in_the_stack = 0;
|
||||
}
|
||||
|
||||
|
|
65
src/test/tcp_echo.c
Normal file
65
src/test/tcp_echo.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define PORT 8
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
int main() {
|
||||
int server_fd, client_fd;
|
||||
struct sockaddr_in address;
|
||||
int addrlen = sizeof(address);
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
// Create a socket
|
||||
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
|
||||
perror("Socket failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("Socket created: %d\n", server_fd);
|
||||
|
||||
// Bind to the specified port
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons(PORT);
|
||||
|
||||
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
|
||||
perror("Bind failed");
|
||||
close(server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("Bind successful\n");
|
||||
|
||||
// Start listening for incoming connections
|
||||
if (listen(server_fd, 3) < 0) {
|
||||
perror("Listen failed");
|
||||
close(server_fd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
printf("Echo server listening on port %d\n", PORT);
|
||||
|
||||
while (1) {
|
||||
// Accept a client connection
|
||||
if ((client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t *)&addrlen)) < 0) {
|
||||
perror("Accept failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Client connected, fd: %d\n", client_fd);
|
||||
|
||||
ssize_t bytes_read;
|
||||
while ((bytes_read = read(client_fd, buffer, BUFFER_SIZE)) > 0) {
|
||||
write(client_fd, buffer, bytes_read); // Echo data back to the client
|
||||
}
|
||||
|
||||
printf("Client disconnected\n");
|
||||
close(client_fd);
|
||||
}
|
||||
|
||||
close(server_fd);
|
||||
return 0;
|
||||
}
|
|
@ -3,15 +3,14 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "femtotcp.h"
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "femtotcp.h"
|
||||
|
||||
//#define DHCP
|
||||
#define FEMTOTCP_IP "10.10.10.2"
|
||||
#define LINUX_IP "10.10.10.1"
|
||||
#define TEST_SIZE (8 * 1024)
|
||||
|
||||
#define BUFFER_SIZE TEST_SIZE
|
||||
|
|
Loading…
Reference in a new issue