265 lines
7.9 KiB
C
265 lines
7.9 KiB
C
#include <stdio.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#include "femtotcp.h"
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <string.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
|
|
|
|
static int listen_fd = -1, client_fd = -1;
|
|
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 closed = 0;
|
|
|
|
static void socket_cb(int fd, uint16_t event, void *arg)
|
|
{
|
|
int ret = 0;
|
|
printf("Called socket_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);
|
|
if (client_fd > 0) {
|
|
printf("accept: %04x\n", client_fd);
|
|
}
|
|
} else if ((fd == client_fd) && (event & CB_EVENT_READABLE )) {
|
|
ret = ft_recvfrom((struct ipstack *)arg, client_fd, buf, sizeof(buf), 0, NULL, NULL);
|
|
if (ret != -11) {
|
|
if (ret < 0) {
|
|
printf("Recv error: %d\n", ret);
|
|
ft_close((struct ipstack *)arg, client_fd);
|
|
} else if (ret == 0) {
|
|
printf("Client side closed the connection.\n");
|
|
ft_close((struct ipstack *)arg, client_fd);
|
|
printf("Server: Exiting.\n");
|
|
exit_ok = 1;
|
|
} else if (ret > 0) {
|
|
printf("recv: %d, echoing back\n", ret);
|
|
tot_recv += ret;
|
|
}
|
|
}
|
|
}
|
|
if ((event & CB_EVENT_WRITABLE) || ((ret > 0) && !closed)) {
|
|
int snd_ret;
|
|
if ((tot_sent >= 4096) && server_closing) {
|
|
ft_close((struct ipstack *)arg, client_fd);
|
|
printf("Server: I closed the connection.\n");
|
|
closed = 1;
|
|
exit_ok = 1;
|
|
}
|
|
if ((!closed) && (tot_sent < tot_recv)) {
|
|
snd_ret = ft_sendto((struct ipstack *)arg, client_fd, buf + tot_sent, tot_recv - tot_sent, 0, NULL, 0);
|
|
if (snd_ret != -11) {
|
|
if (snd_ret < 0) {
|
|
printf("Send error: %d\n", snd_ret);
|
|
ft_close((struct ipstack *)arg, client_fd);
|
|
} else {
|
|
tot_sent += snd_ret;
|
|
printf("sent %d bytes\n", snd_ret);
|
|
if (tot_recv == tot_sent) {
|
|
tot_sent = 0;
|
|
tot_recv = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (event & CB_EVENT_CLOSED) {
|
|
printf("Closing %d, client fd: %d\n", fd, client_fd);
|
|
}
|
|
if ((fd == client_fd) && (event & CB_EVENT_CLOSED)) {
|
|
printf("Client side closed the connection (EVENT_CLOSED)\n");
|
|
ft_close((struct ipstack *)arg, client_fd);
|
|
client_fd = -1;
|
|
printf("Server: Exiting.\n");
|
|
exit_ok = 1;
|
|
}
|
|
(void)arg;
|
|
}
|
|
|
|
|
|
static int test_echoserver(struct ipstack *s, int active_close)
|
|
{
|
|
exit_ok = 0;
|
|
exit_count = 0;
|
|
tot_sent = 0;
|
|
server_closing = active_close;
|
|
closed = 0;
|
|
|
|
while(1) {
|
|
uint32_t ms_next;
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
ms_next = ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
|
usleep(ms_next * 1000);
|
|
if (exit_ok > 0) {
|
|
if (exit_count++ < 10)
|
|
continue;
|
|
else break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void *pt_echoclient(void *arg)
|
|
{
|
|
int fd, ret;
|
|
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,
|
|
.sin_port = ntohs(8), /* Echo */
|
|
};
|
|
remote_sock.sin_addr.s_addr = *srv_addr;
|
|
fd = socket(AF_INET, IPSTACK_SOCK_STREAM, 0);
|
|
if (fd < 0) {
|
|
printf("test client socket: %d\n", fd);
|
|
return (void *)-1;
|
|
}
|
|
sleep(1);
|
|
printf("Connecting to echo server\n");
|
|
ret = connect(fd, (struct sockaddr *)&remote_sock, sizeof(remote_sock));
|
|
if (ret < 0) {
|
|
printf("test client connect: %d\n", ret);
|
|
perror("connect");
|
|
return (void *)-1;
|
|
}
|
|
for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) {
|
|
memcpy(buf + i, test_pattern, sizeof(test_pattern));
|
|
}
|
|
ret = write(fd, buf, sizeof(buf));
|
|
if (ret < 0) {
|
|
printf("test client write: %d\n", ret);
|
|
return (void *)-1;
|
|
}
|
|
while (total_r < sizeof(buf)) {
|
|
ret = read(fd, buf + total_r, sizeof(buf) - total_r);
|
|
if (ret < 0) {
|
|
printf("failed test client read: %d\n", ret);
|
|
return (void *)-1;
|
|
}
|
|
if (ret == 0) {
|
|
printf("test client read: server has closed the connection.\n");
|
|
if (server_closing)
|
|
return (void *)0;
|
|
else
|
|
return (void *)-1;
|
|
}
|
|
total_r += ret;
|
|
}
|
|
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 (void *)-1;
|
|
}
|
|
}
|
|
close(fd);
|
|
printf("Test client: success\n");
|
|
return (void *)0;
|
|
}
|
|
|
|
extern int tap_init(struct ll *dev, const char *name, uint32_t host_ip);
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct ipstack *s;
|
|
struct ll *tapdev;
|
|
pthread_t pt;
|
|
struct timeval tv;
|
|
struct in_addr linux_ip;
|
|
ip4 ip = 0, nm = 0, gw = 0;
|
|
uint32_t srv_ip;
|
|
struct ipstack_sockaddr_in local_sock = {
|
|
.sin_family = AF_INET,
|
|
.sin_port = ee16(8), /* Echo */
|
|
.sin_addr.s_addr = 0
|
|
};
|
|
|
|
int ret, test_ret = 0;
|
|
(void)argc;
|
|
(void)argv;
|
|
(void)ip;
|
|
(void)nm;
|
|
(void)gw;
|
|
(void)tv;
|
|
(void)pt;
|
|
(void)srv_ip;
|
|
ipstack_init_static(&s);
|
|
tapdev = ipstack_getdev(s);
|
|
if (!tapdev)
|
|
return 1;
|
|
inet_aton(LINUX_IP, &linux_ip);
|
|
if (tap_init(tapdev, "femt0", linux_ip.s_addr) < 0) {
|
|
perror("tap init");
|
|
return 2;
|
|
}
|
|
|
|
system("tcpdump -i femt0 -w test.pcap &");
|
|
|
|
#ifdef DHCP
|
|
gettimeofday(&tv, NULL);
|
|
ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
|
dhcp_client_init(s);
|
|
do {
|
|
gettimeofday(&tv, NULL);
|
|
ipstack_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
|
usleep(1000);
|
|
ipstack_ipconfig_get(s, &ip, &nm, &gw);
|
|
} while (!dhcp_bound(s));
|
|
printf("DHCP: obtained IP address.\n");
|
|
ipstack_ipconfig_get(s, &ip, &nm, &gw);
|
|
srv_ip = htonl(ip);
|
|
#else
|
|
ipstack_ipconfig_set(s, atoip4(FEMTOTCP_IP), atoip4("255.255.255.0"),
|
|
atoip4(LINUX_IP));
|
|
printf("IP: manually configured\n");
|
|
inet_pton(AF_INET, FEMTOTCP_IP, &srv_ip);
|
|
#endif
|
|
|
|
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);
|
|
|
|
pthread_create(&pt, NULL, pt_echoclient, &srv_ip);
|
|
printf("Starting test: echo server close-wait\n");
|
|
ret = ft_bind(s, listen_fd, (struct ipstack_sockaddr *)&local_sock, sizeof(local_sock));
|
|
printf("bind: %d\n", ret);
|
|
ret = ft_listen(s, listen_fd, 1);
|
|
printf("listen: %d\n", ret);
|
|
ret = test_echoserver(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);
|
|
sleep(1);
|
|
|
|
pthread_create(&pt, NULL, pt_echoclient, &srv_ip);
|
|
printf("Starting test: echo server active close\n");
|
|
ret = test_echoserver(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);
|
|
|
|
|
|
|
|
system("killall tcpdump");
|
|
return 0;
|
|
}
|
|
|