diff --git a/src/femtotcp.c b/src/femtotcp.c index df194ae..0585566 100644 --- a/src/femtotcp.c +++ b/src/femtotcp.c @@ -8,17 +8,10 @@ #include #include #include "femtotcp.h" +#include "config.h" -/* Config (TODO: move to some config.h later) */ - -#define LINK_MTU 1536 - -#define MAX_TCPSOCKETS 2 -#define MAX_UDPSOCKETS 2 -#define RXBUF_SIZE LINK_MTU * 8 -#define TXBUF_SIZE LINK_MTU * 2 - -#define MAX_NEIGHBORS 16 +/* Fixed size binary heap: each element is a timer. */ +#define MAX_TIMERS MAX_TCPSOCKETS * 3 /* Constants */ #define MARK_TCP_SOCKET 0x1000 /* Mark a socket as TCP */ @@ -519,8 +512,6 @@ struct ipstack_timer { void (*cb)(void *arg); }; -/* Fixed size binary heap: each element is a timer. */ -#define MAX_TIMERS MAX_TCPSOCKETS * 3 /* Timer binary heap */ struct timers_binheap { struct ipstack_timer timers[MAX_TIMERS]; @@ -1038,6 +1029,13 @@ static void tcp_input(struct ipstack *S, struct ipstack_tcp_seg *tcp, uint32_t f return; /* discard */ } + if (t->sock.tcp.state > TCP_LISTEN) { + if (t->dst_port != ee16(tcp->src_port) || t->remote_ip != ee32(tcp->ip.src)) { + /* Not the right socket */ + continue; + } + } + /* Check IP ttl */ if (tcp->ip.ttl == 0) { /* Send ICMP TTL exceeded */ @@ -1200,7 +1198,15 @@ int ft_connect(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *add struct ipstack_tcp_seg tcp; if (!addr) return -2; - ts = &s->tcpsockets[sockfd]; + if (sockfd & MARK_UDP_SOCKET) { + ts = &s->udpsockets[sockfd & ~MARK_UDP_SOCKET]; + ts->dst_port = ee16(sin->sin_port); + ts->remote_ip = ee32(sin->sin_addr.s_addr); + return 0; + } + if ((sockfd & MARK_TCP_SOCKET) == 0) + return -1; + ts = &s->tcpsockets[sockfd & ~MARK_TCP_SOCKET]; if (ts->sock.tcp.state == TCP_ESTABLISHED) return 0; if (ts->sock.tcp.state == TCP_SYN_SENT) @@ -1216,7 +1222,7 @@ int ft_connect(struct ipstack *s, int sockfd, const struct ipstack_sockaddr *add if (ts->src_port < 1024) ts->src_port += 1024; ts->dst_port = ee16(sin->sin_port); - tcp.src_port = ts->src_port; + tcp.src_port = ee16(ts->src_port); tcp.dst_port = sin->sin_port; tcp.seq = ts->sock.tcp.seq; tcp.ack = 0; diff --git a/test/test-linux.c b/test/test-linux.c index 118b32c..22afa99 100644 --- a/test/test-linux.c +++ b/test/test-linux.c @@ -7,6 +7,7 @@ #include #include #include +#include //#define DHCP #define FEMTOTCP_IP "10.10.10.2" @@ -20,13 +21,16 @@ static int exit_ok = 0, exit_count = 0; static uint8_t buf[TEST_SIZE]; static int tot_sent = 0; static int tot_recv = 0; -static int server_closing = 0; +static int femtotcp_closing = 0; static int closed = 0; +static int conn_fd = -1; +static int client_connected = 0; +static const uint8_t test_pattern[16] = "Test pattern - -"; -static void socket_cb(int fd, uint16_t event, void *arg) +static void server_cb(int fd, uint16_t event, void *arg) { int ret = 0; - printf("Called socket_cb, events: %04x fd %d\n", event, fd & (~0x1000)); + printf("Called server_cb, events: %04x fd %d\n", event, fd & (~0x1000)); if ((fd == listen_fd) && (event & CB_EVENT_READABLE) && (client_fd == -1)) { client_fd = ft_accept((struct ipstack *)arg, listen_fd, NULL, NULL); @@ -52,7 +56,7 @@ static void socket_cb(int fd, uint16_t event, void *arg) } if ((event & CB_EVENT_WRITABLE) || ((ret > 0) && !closed)) { int snd_ret; - if ((tot_sent >= 4096) && server_closing) { + if ((tot_sent >= 4096) && femtotcp_closing) { ft_close((struct ipstack *)arg, client_fd); printf("Server: I closed the connection.\n"); closed = 1; @@ -88,13 +92,74 @@ static void socket_cb(int fd, uint16_t event, void *arg) (void)arg; } +static void client_cb(int fd, uint16_t event, void *arg) +{ + struct ipstack *s = (struct ipstack *)arg; + uint32_t i; + int ret; + static unsigned int total_r = 0, total_w = 0; + printf("Called client_cb, events: %04x fd %d\n", event, fd & (~0x1000)); + if (fd == conn_fd) { + if ((event & CB_EVENT_WRITABLE) && (client_connected == 0)) { + printf("Client: connected\n"); + client_connected = 1; + } + } + if (total_w == 0) { + for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) { + memcpy(buf + i, test_pattern, sizeof(test_pattern)); + } + } + if (client_connected && (event & CB_EVENT_WRITABLE) && (total_w < sizeof(buf))) { + ret = ft_sendto(s, fd, buf + total_w, sizeof(buf) - total_w, 0, NULL, 0); + if (ret <= 0) { + printf("Test client write: %d\n", ret); + return; + } + total_w += ret; + } -static int test_echoserver(struct ipstack *s, int active_close) + while ((total_r < total_w) && (event & CB_EVENT_READABLE)) { + ret = ft_recvfrom(s, fd, buf + total_r, sizeof(buf) - total_r, 0, NULL, NULL); + if (ret < 0){ + if (ret != -11) { + printf("Client read: %d\n", ret); + } + return; + } + if (ret == 0) { + printf("Client read: server has closed the connection.\n"); + return; + } + total_r += ret; + printf("Client RX total: %u\n", total_r); + } + if (total_r == sizeof(buf)) { + exit_ok = 1; + for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) { + if (memcmp(buf + i, test_pattern, sizeof(test_pattern))) { + printf("test client: pattern mismatch\n"); + printf("at position %d\n", i); + buf[i + 16] = 0; + printf("%s\n", &buf[i]); + return; + } + } + if (femtotcp_closing) { + ft_close(s, fd); + conn_fd = -1; + } + printf("Test client: success\n"); + } +} + + +static int test_loop(struct ipstack *s, int active_close) { exit_ok = 0; exit_count = 0; tot_sent = 0; - server_closing = active_close; + femtotcp_closing = active_close; closed = 0; while(1) { @@ -118,7 +183,6 @@ void *pt_echoclient(void *arg) unsigned total_r = 0; unsigned i; uint8_t buf[BUFFER_SIZE]; - uint8_t test_pattern[16] = "Test pattern - -"; uint32_t *srv_addr = (uint32_t *)arg; struct sockaddr_in remote_sock = { .sin_family = AF_INET, @@ -131,6 +195,7 @@ void *pt_echoclient(void *arg) return (void *)-1; } sleep(1); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)); printf("Connecting to echo server\n"); ret = connect(fd, (struct sockaddr *)&remote_sock, sizeof(remote_sock)); if (ret < 0) { @@ -154,7 +219,7 @@ void *pt_echoclient(void *arg) } if (ret == 0) { printf("test client read: server has closed the connection.\n"); - if (server_closing) + if (femtotcp_closing) return (void *)0; else return (void *)-1; @@ -175,6 +240,60 @@ void *pt_echoclient(void *arg) return (void *)0; } +static void *pt_echoserver(void *arg) +{ + int fd, ret; + unsigned total_r = 0; + uint8_t buf[BUFFER_SIZE]; + struct sockaddr_in local_sock = { + .sin_family = AF_INET, + .sin_port = ntohs(8), /* Echo */ + .sin_addr.s_addr = 0 + }; + femtotcp_closing = (uintptr_t)arg; + fd = socket(AF_INET, IPSTACK_SOCK_STREAM, 0); + if (fd < 0) { + printf("test server socket: %d\n", fd); + return (void *)-1; + } + local_sock.sin_addr.s_addr = inet_addr(LINUX_IP); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)); + ret = bind(fd, (struct sockaddr *)&local_sock, sizeof(local_sock)); + if (ret < 0) { + printf("test server bind: %d (%s)\n", ret, strerror(errno)); + return (void *)-1; + } + ret = listen(fd, 1); + if (ret < 0) { + printf("test server listen: %d\n", ret); + return (void *)-1; + } + printf("Waiting for client\n"); + ret = accept(fd, NULL, NULL); + if (ret < 0) { + printf("test server accept: %d\n", ret); + return (void *)-1; + } + printf("test server: client %d connected\n", ret); + fd = ret; + while (1) { + ret = read(fd, buf + total_r, sizeof(buf) - total_r); + if (ret < 0) { + printf("failed test server read: %d (%s) \n", ret, strerror(errno)); + return (void *)-1; + } + if (ret == 0) { + printf("test server read: client has closed the connection.\n"); + if (femtotcp_closing) + return (void *)0; + else + return (void *)-1; + } + total_r += ret; + write(fd, buf + total_r - ret, ret); + } +} + extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip); int main(int argc, char **argv) @@ -191,6 +310,7 @@ int main(int argc, char **argv) .sin_port = ee16(8), /* Echo */ .sin_addr.s_addr = 0 }; + struct ipstack_sockaddr_in remote_sock; int ret, test_ret = 0; (void)argc; @@ -210,7 +330,6 @@ int main(int argc, char **argv) perror("tap init"); return 2; } - system("tcpdump -i femt0 -w test.pcap &"); #ifdef DHCP @@ -233,9 +352,11 @@ int main(int argc, char **argv) inet_pton(AF_INET, FEMTOTCP_IP, &srv_ip); #endif + printf("TCP server tests\n"); + listen_fd = ft_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0); printf("socket: %04x\n", listen_fd); - ipstack_register_callback(s, listen_fd, socket_cb, s); + ipstack_register_callback(s, listen_fd, server_cb, s); pthread_create(&pt, NULL, pt_echoclient, &srv_ip); printf("Starting test: echo server close-wait\n"); @@ -243,7 +364,7 @@ int main(int argc, char **argv) printf("bind: %d\n", ret); ret = ft_listen(s, listen_fd, 1); printf("listen: %d\n", ret); - ret = test_echoserver(s, 0); + ret = test_loop(s, 0); pthread_join(pt, (void **)&test_ret); printf("Test echo server close-wait: %d\n", ret); printf("Test linux client: %d\n", test_ret); @@ -251,12 +372,56 @@ int main(int argc, char **argv) pthread_create(&pt, NULL, pt_echoclient, &srv_ip); printf("Starting test: echo server active close\n"); - ret = test_echoserver(s, 1); + ret = test_loop(s, 1); printf("Test echo server close-wait: %d\n", ret); pthread_join(pt, (void **)&test_ret); printf("Test linux client: %d\n", test_ret); sleep(1); + ft_close(s, listen_fd); + /* End TCP Server tests */ + + + /* Client side test: client is closing the connection */ + remote_sock.sin_family = AF_INET; + remote_sock.sin_port = ee16(8); + remote_sock.sin_addr.s_addr = inet_addr(LINUX_IP); + printf("TCP client tests\n"); + conn_fd = ft_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0); + printf("client socket: %04x\n", conn_fd); + ipstack_register_callback(s, conn_fd, client_cb, s); + printf("Connecting to %s:8\n", LINUX_IP); + ft_connect(s, conn_fd, (struct ipstack_sockaddr *)&remote_sock, sizeof(remote_sock)); + pthread_create(&pt, NULL, pt_echoserver, (void*)1); + printf("Starting test: echo client active close\n"); + ret = test_loop(s, 1); + printf("Test echo client active close: %d\n", ret); + pthread_join(pt, (void **)&test_ret); + printf("Test linux server: %d\n", test_ret); + + if (conn_fd >= 0) { + ft_close(s, conn_fd); + conn_fd = -1; + } + + /* Client side test: server is closing the connection */ + /* Excluded for now as linux cannot bind twice on port 8 */ +#if 0 + conn_fd = ft_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0); + if (conn_fd < 0) { + printf("cannot create socket: %d\n", conn_fd); + } + printf("client socket: %04x\n", conn_fd); + ipstack_register_callback(s, conn_fd, client_cb, s); + printf("Connecting to %s:8\n", LINUX_IP); + ft_connect(s, conn_fd, (struct ipstack_sockaddr *)&remote_sock, sizeof(remote_sock)); + pthread_create(&pt, NULL, pt_echoserver, (void*)0); + printf("Starting test: echo client passive close\n"); + ret = test_loop(s, 0); + printf("Test echo client, server closing: %d\n", ret); + pthread_join(pt, (void **)&test_ret); + printf("Test linux server: %d\n", test_ret); +#endif system("killall tcpdump");