1
0
Fork 0
mirror of https://github.com/hermitcore/libhermit.git synced 2025-03-09 00:00:03 +01:00

increase the interoperability between LwIP and newlib

- create own socket functions for newlib
- exchange error numbers between newlib and LwIP
- add LWIP_FD_BIT to mark a file descriptor as LwIP file descriptor
- add netio example
This commit is contained in:
Stefan Lankes 2016-01-10 03:13:31 +01:00
parent e53c126bf3
commit f9058f51e5
12 changed files with 666 additions and 88 deletions

View file

@ -41,7 +41,7 @@ RM = rm -rf
CFLAGS_FOR_NEWLIB = -m64 -mtls-direct-seg-refs -mno-red-zone -O3 -mavx2 -mfma -mtune=intel $(STACKPROT)
FFLAGS_FOR_NEWLIB = -m64 -mtls-direct-seg-refs -mno-red-zone -O3 -mavx2 -mfma -mtune=intel
CXXFLAGS_FOR_NEWLIB = $(CFLAGS_FOR_NEWLIB)
CXXFLAGS_FOR_NEWLIB =
LDFLAGS_FOR_NEWLIB =
NASMFLAGS_FOR_NEWLIB = -felf64
CFLAGS_FOR_TOOLS = -O2 -Wall

View file

@ -59,7 +59,6 @@ static inline void enter_user_task(size_t ep, size_t stack)
static int thread_entry(void* arg, size_t ep)
{
task_t* curr_task = per_core(current_task);
#if 0
size_t addr, stack = 0;
size_t flags;
@ -95,21 +94,11 @@ static int thread_entry(void* arg, size_t ep)
vma_add(stack, stack+npages*PAGE_SIZE-1, flags);
#endif
if (init_tls())
return -ENOMEM;
//vma_dump();
// do we have to create a TLS segement?
if (curr_task->tls_addr && curr_task->tls_size) {
char* tls_addr = NULL;
tls_addr = kmalloc(curr_task->tls_size);
// copy default TLS segment to stack
memcpy((void*) (tls_addr), (void*) curr_task->tls_addr, curr_task->tls_size);
// set fs register to the TLS segment
writefs((size_t) tls_addr);
kprintf("Task %d set fs to %p\n", curr_task->id, tls_addr);
} else writefs(0); // no TLS => clear fs register
// set first argument
//asm volatile ("mov %0, %%rdi" :: "r"(arg));
//enter_user_task(ep, stack+offset);

View file

@ -137,10 +137,19 @@ int create_kernel_task_on_core(tid_t* id, entry_point_t ep, void* args, uint8_t
*
* @return
* - 0 on success
* - -EINVAL (-22) or -ENOMEM (-12)on failure
* - -EINVAL (-22) or -ENOMEM (-12) on failure
*/
int create_user_task_on_core(tid_t* id, const char* fame, char** argv, uint8_t prio, uint32_t core_id);
/** @brief Create a thread local storage for the current task
*
* @return
* - 0 on success
* - -EONMEM on failure
*/
int init_tls(void);
/** @brief Cleanup function for the task termination
*
* On termination, the task call this function to cleanup its address space.

View file

@ -54,12 +54,11 @@
#include <netif/etharp.h>
#include <net/mmnif.h>
#define HERMIT_PORT 0x494F
#define HERMIT_PORT 0x494E
#define HEMRIT_MAGIC 0x7E317
static struct netif mmnif_netif;
static const int sobufsize = 131072;
volatile int8_t shutdown = 0;
/*
* Note that linker symbols are not variables, they have no memory allocated for
@ -193,7 +192,7 @@ int network_shutdown(void)
kputs("Shutdown LwIP\n");
if (libc_sd > 0)
closesocket(libc_sd);
lwip_close(libc_sd);
mmnif_shutdown();
netifapi_netif_set_down(&mmnif_netif);
@ -281,33 +280,13 @@ static int initd(void* arg)
//create_kernel_task(NULL, foo, "foo1", NORMAL_PRIO);
//create_kernel_task(NULL, foo, "foo2", NORMAL_PRIO);
// initialize network
init_netifs();
// do we have a thread local storage?
if (((size_t) &tls_end - (size_t) &tls_start) > 0) {
char* tls_addr = NULL;
curr_task->tls_addr = (size_t) &tls_start;
curr_task->tls_size = (size_t) &tls_end - (size_t) &tls_start;
// TODO: free TLS after termination
tls_addr = kmalloc(curr_task->tls_size);
if (BUILTIN_EXPECT(!tls_addr, 0)) {
kprintf("load_task: heap is missing!\n");
kfree(curr_task->heap);
return -ENOMEM;
}
memcpy((void*) tls_addr, (void*) curr_task->tls_addr, curr_task->tls_size);
// set fs register to the TLS segment
set_tls((size_t) tls_addr);
kprintf("Task %d set fs to 0x%zx\n", curr_task->id, tls_addr);
} else set_tls(0); // no TLS => clear fs register
// initialize iRCCE
//init_rcce();
s = socket(PF_INET , SOCK_STREAM , 0);
s = lwip_socket(PF_INET , SOCK_STREAM , 0);
if (s < 0) {
kprintf("socket failed: %d\n", server);
return -1;
@ -319,17 +298,17 @@ static int initd(void* arg)
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(HERMIT_PORT);
if ((err = bind(s, (struct sockaddr *) &server, sizeof(server))) < 0)
if ((err = lwip_bind(s, (struct sockaddr *) &server, sizeof(server))) < 0)
{
kprintf("bind failed: %d\n", errno);
closesocket(s);
lwip_close(s);
return -1;
}
if ((err = listen(s, 2)) < 0)
if ((err = lwip_listen(s, 2)) < 0)
{
kprintf("listen failed: %d\n", errno);
closesocket(s);
lwip_close(s);
return -1;
}
@ -337,28 +316,28 @@ static int initd(void* arg)
kputs("TCP server listening.\n");
if ((c = accept(s, (struct sockaddr *)&client, (socklen_t*)&len)) < 0)
if ((c = lwip_accept(s, (struct sockaddr *)&client, (socklen_t*)&len)) < 0)
{
kprintf("accept faild: %d\n", errno);
closesocket(s);
lwip_close(s);
return -1;
}
kputs("Establish IP connection\n");
setsockopt(c, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
setsockopt(c, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag));
lwip_setsockopt(c, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
lwip_setsockopt(c, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
lwip_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag));
read(c, &magic, sizeof(magic));
lwip_read(c, &magic, sizeof(magic));
if (magic != HEMRIT_MAGIC)
{
kprintf("Invalid magic number %d\n", magic);
closesocket(c);
lwip_close(c);
return -1;
}
err = read(c, &argc, sizeof(argc));
err = lwip_read(c, &argc, sizeof(argc));
if (err != sizeof(argc))
goto out;
@ -369,7 +348,7 @@ static int initd(void* arg)
for(i=0; i<argc; i++)
{
err = read(c, &len, sizeof(len));
err = lwip_read(c, &len, sizeof(len));
if (err != sizeof(len))
goto out;
@ -379,7 +358,7 @@ static int initd(void* arg)
j = 0;
while(j < len) {
err = read(c, argv[i]+j, len-j);
err = lwip_read(c, argv[i]+j, len-j);
if (err < 0)
goto out;
j += err;
@ -387,7 +366,7 @@ static int initd(void* arg)
}
err = read(c, &envc, sizeof(envc));
err = lwip_read(c, &envc, sizeof(envc));
if (err != sizeof(envc))
goto out;
@ -398,7 +377,7 @@ static int initd(void* arg)
for(i=0; i<envc; i++)
{
err = read(c, &len, sizeof(len));
err = lwip_read(c, &len, sizeof(len));
if (err != sizeof(len))
goto out;
@ -408,7 +387,7 @@ static int initd(void* arg)
j = 0;
while(j < len) {
err = read(c, environ[i]+j, len-j);
err = lwip_read(c, environ[i]+j, len-j);
if (err < 0)
goto out;
j += err;
@ -440,11 +419,11 @@ out:
}
if (c > 0)
closesocket(c);
lwip_close(c);
libc_sd = -1;
if (s > 0)
closesocket(s);
lwip_close(s);
//network_shutdown();

View file

@ -47,6 +47,15 @@ extern int32_t isle;
extern int32_t possible_isles;
extern int libc_sd;
int* __getreent(void);
static inline int* libc_errno(void)
{
return __getreent();
}
tid_t sys_getpid(void)
{
task_t* task = per_core(current_task);
@ -83,10 +92,10 @@ void NORETURN sys_exit(int arg)
if (libc_sd >= 0)
{
spinlock_lock(&lwip_lock);
write(libc_sd, &sysargs, sizeof(sysargs));
lwip_write(libc_sd, &sysargs, sizeof(sysargs));
spinlock_unlock(&lwip_lock);
closesocket(libc_sd);
lwip_close(libc_sd);
libc_sd = -1;
}
@ -104,20 +113,32 @@ ssize_t sys_read(int fd, char* buf, size_t len)
sys_read_t sysargs = {__NR_read, fd, len};
ssize_t j, ret;
// do we have an LwIP file descriptor?
if (fd & LWIP_FD_BIT) {
ret = lwip_read(fd & ~LWIP_FD_BIT, buf, len);
if (ret)
{
*libc_errno() = errno;
return -1;
}
return 0;
}
if (libc_sd < 0)
return -ENOSYS;
spinlock_lock(&lwip_lock);
write(libc_sd, &sysargs, sizeof(sysargs));
lwip_write(libc_sd, &sysargs, sizeof(sysargs));
read(libc_sd, &j, sizeof(j));
lwip_read(libc_sd, &j, sizeof(j));
if (j > 0)
{
ssize_t i = 0;
while(i < j)
{
ret = read(libc_sd, buf+i, j-i);
ret = lwip_read(libc_sd, buf+i, j-i);
if (ret < 0) {
spinlock_unlock(&lwip_lock);
return ret;
@ -147,6 +168,18 @@ ssize_t sys_write(int fd, const char* buf, size_t len)
if (BUILTIN_EXPECT(!buf, 0))
return -1;
// do we have an LwIP file descriptor?
if (fd & LWIP_FD_BIT) {
ret = lwip_write(fd & ~LWIP_FD_BIT, buf, len);
if (ret)
{
*libc_errno() = errno;
return -1;
}
return 0;
}
if (libc_sd < 0)
{
for(i=0; i<len; i++)
@ -158,14 +191,14 @@ ssize_t sys_write(int fd, const char* buf, size_t len)
spinlock_lock(&lwip_lock);
flag = 0;
setsockopt(libc_sd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag));
lwip_setsockopt(libc_sd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag));
write(libc_sd, &sysargs, sizeof(sysargs));
lwip_write(libc_sd, &sysargs, sizeof(sysargs));
i=0;
while(i < len)
{
ret = write(libc_sd, (char*)buf+i, len-i);
ret = lwip_write(libc_sd, (char*)buf+i, len-i);
if (ret < 0) {
spinlock_unlock(&lwip_lock);
return ret;
@ -175,10 +208,10 @@ ssize_t sys_write(int fd, const char* buf, size_t len)
}
flag = 1;
setsockopt(libc_sd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag));
lwip_setsockopt(libc_sd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag));
if (fd > 2) {
ret = read(libc_sd, &i, sizeof(i));
ret = lwip_read(libc_sd, &i, sizeof(i));
if (ret < 0)
i = ret;
} else i = len;
@ -227,37 +260,37 @@ int sys_open(const char* name, int flags, int mode)
spinlock_lock(&lwip_lock);
i = 0;
setsockopt(libc_sd, IPPROTO_TCP, TCP_NODELAY, (char *) &i, sizeof(i));
lwip_setsockopt(libc_sd, IPPROTO_TCP, TCP_NODELAY, (char *) &i, sizeof(i));
ret = write(libc_sd, &sysnr, sizeof(sysnr));
ret = lwip_write(libc_sd, &sysnr, sizeof(sysnr));
if (ret < 0)
goto out;
ret = write(libc_sd, &len, sizeof(len));
ret = lwip_write(libc_sd, &len, sizeof(len));
if (ret < 0)
goto out;
i=0;
while(i<len)
{
ret = write(libc_sd, name+i, len-i);
ret = lwip_write(libc_sd, name+i, len-i);
if (ret < 0)
goto out;
i += ret;
}
ret = write(libc_sd, &flags, sizeof(flags));
ret = lwip_write(libc_sd, &flags, sizeof(flags));
if (ret < 0)
goto out;
ret = write(libc_sd, &mode, sizeof(mode));
ret = lwip_write(libc_sd, &mode, sizeof(mode));
if (ret < 0)
goto out;
i = 1;
setsockopt(libc_sd, IPPROTO_TCP, TCP_NODELAY, (char *) &i, sizeof(i));
lwip_setsockopt(libc_sd, IPPROTO_TCP, TCP_NODELAY, (char *) &i, sizeof(i));
read(libc_sd, &ret, sizeof(ret));
lwip_read(libc_sd, &ret, sizeof(ret));
out:
spinlock_unlock(&lwip_lock);
@ -275,15 +308,27 @@ int sys_close(int fd)
int ret;
sys_close_t sysargs = {__NR_close, fd};
// do we have an LwIP file descriptor?
if (fd & LWIP_FD_BIT) {
ret = lwip_close(fd & ~LWIP_FD_BIT);
if (ret)
{
*libc_errno() = errno;
return -1;
}
return 0;
}
if (libc_sd < 0)
return 0;
spinlock_lock(&lwip_lock);
ret = write(libc_sd, &sysargs, sizeof(sysargs));
ret = lwip_write(libc_sd, &sysargs, sizeof(sysargs));
if (ret != sizeof(sysargs))
goto out;
read(libc_sd, &ret, sizeof(ret));
lwip_read(libc_sd, &ret, sizeof(ret));
out:
spinlock_unlock(&lwip_lock);
@ -387,8 +432,8 @@ off_t sys_lseek(int fd, off_t offset, int whence)
spinlock_lock(&lwip_lock);
write(libc_sd, &sysargs, sizeof(sysargs));
read(libc_sd, &off, sizeof(off));
lwip_write(libc_sd, &sysargs, sizeof(sysargs));
lwip_read(libc_sd, &off, sizeof(off));
spinlock_unlock(&lwip_lock);

View file

@ -37,6 +37,13 @@
#include <hermit/syscall.h>
#include <hermit/memory.h>
/*
* Note that linker symbols are not variables, they have no memory allocated for
* maintaining a value, rather their address is their value.
*/
extern const void tls_start;
extern const void tls_end;
/*
* HermitCore is a single address space OS
* => we need only a lock to protect the page tables & VMA
@ -174,6 +181,33 @@ int set_idle_task(void)
return ret;
}
int init_tls(void)
{
task_t* curr_task = per_core(current_task);
// do we have a thread local storage?
if (((size_t) &tls_end - (size_t) &tls_start) > 0) {
char* tls_addr = NULL;
curr_task->tls_addr = (size_t) &tls_start;
curr_task->tls_size = (size_t) &tls_end - (size_t) &tls_start;
tls_addr = kmalloc(curr_task->tls_size);
if (BUILTIN_EXPECT(!tls_addr, 0)) {
kprintf("load_task: heap is missing!\n");
return -ENOMEM;
}
memcpy((void*) tls_addr, (void*) curr_task->tls_addr, curr_task->tls_size);
// set fs register to the TLS segment
set_tls((size_t) tls_addr);
kprintf("Task %d set fs to 0x%zx\n", curr_task->id, tls_addr);
} else set_tls(0); // no TLS => clear fs register
return 0;
}
void finish_task_switch(void)
{
task_t* old;

@ -1 +1 @@
Subproject commit cf00aee089047c3356b558423b368a85fc76caa7
Subproject commit 9e76e0b89f21173c1a311be6789360c1054eb269

39
hermit/tools/netinet/in.h Normal file
View file

@ -0,0 +1,39 @@
#ifndef __NETINET_IN_H__
#define __NETINET_IN_H__
#include <stddef.h>
#include <sys/types.h>
#ifdef __cplusplus
{
#endif
#if 0
struct in_addr {
uint32_t s_addr;
};
#endif
/** 255.255.255.255 */
#define IPADDR_NONE ((uint32_t)0xffffffffUL)
/** 127.0.0.1 */
#define IPADDR_LOOPBACK ((uint32_t)0x7f000001UL)
/** 0.0.0.0 */
#define IPADDR_ANY ((uint32_t)0x00000000UL)
/** 255.255.255.255 */
#define IPADDR_BROADCAST ((uint32_t)0xffffffffUL)
/** 255.255.255.255 */
#define INADDR_NONE IPADDR_NONE
/** 127.0.0.1 */
#define INADDR_LOOPBACK IPADDR_LOOPBACK
/** 0.0.0.0 */
#define INADDR_ANY IPADDR_ANY
/** 255.255.255.255 */
#define INADDR_BROADCAST IPADDR_BROADCAST
#ifdef __cplusplus
}
#endif
#endif /* __NETINET_IN_H__ */

View file

@ -37,7 +37,7 @@
#include <arpa/inet.h>
#include <linux/tcp.h>
#define HERMIT_PORT 0x494F
#define HERMIT_PORT 0x494E
#define HERMIT_MAGIC 0x7E317
#define MAX_PATH 255

View file

@ -3,9 +3,11 @@ ARCH = x86
TARGET=x86_64-hermit
NJOBS=-j20
CROSSCOMPREFIX = x86_64-hermit
NEWLIB = $(TOPDIR)/$(ARCH)/$(TARGET)
RM = rm -rf
CD = cd
CP = cp
MKDIR = mkdir
TMP = $(TOPDIR)/tmp
OPT = --disable-shared --disable-multilib --enable-newlib-io-c99-formats --enable-newlib-multithread #--enable-newlib-reent-small
@ -43,7 +45,7 @@ $(TMP)/bootstrap:
$Q$(MKDIR) $(TMP)/bootstrap
$Q$(CD) $(TMP)/bootstrap; $(TOPDIR)/gcc/configure --target=$(TARGET) --prefix=$(TOPDIR)/$(ARCH) --without-headers --enable-languages=c --disable-nls --disable-shared --disable-libssp --disable-libgomp --enable-threads=posix --enable-tls && $(MAKE) $(NJOBS) all-gcc && $(MAKE) install-gcc
toolchain: $(TMP)/newlib libs $(TMP)/gcc demo
toolchain: $(TMP)/newlib libs $(TMP)/gcc headers demo
$(TMP)/newlib:
@echo Build newlib, libpthread and libgomp
@ -58,6 +60,13 @@ libs:
$Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall" -C ircce depend
$Q$(MAKE) TARGET=$(TARGET) CC_FOR_TARGET=$(CC_FOR_TARGET) AR_FOR_TARGET=$(AR_FOR_TARGET) CFLAGS_FOR_TARGET+="-I. -Wall" -C ircce
headers:
@echo [CP] Copy headers
$Q$(CP) -R ../lwip/src/include/posix/* $(TOPDIR)/$(ARCH)/$(CROSSCOMPREFIX)/include/
$Q$(CP) -R ../lwip/src/include/arch $(TOPDIR)/$(ARCH)/$(CROSSCOMPREFIX)/include/
$Q$(CP) -R ../lwip/src/include/lwip* $(TOPDIR)/$(ARCH)/$(CROSSCOMPREFIX)/include/
$Q$(CP) -R ../lwip/src/include/ipv4/lwip/* $(TOPDIR)/$(ARCH)/$(CROSSCOMPREFIX)/include/lwip/
$Q$(CP) -R ../tools/neti* $(TOPDIR)/$(ARCH)/$(CROSSCOMPREFIX)/include/
$(TMP)/gcc:
@echo Build final gcc
@ -81,3 +90,5 @@ veryclean:
$Q$(MAKE) -C benchmarks veryclean
$Q$(RM) $(TOPDIR)/$(ARCH)
$Q$(RM) $(TMP)
.PHONY: default all clean veryclean headers libs

View file

@ -48,7 +48,7 @@ endif
default: all
all: stream.bin hg.bin #RCCE_pingping RCCE_pingpong
all: stream.bin hg.bin netio.bin #RCCE_pingping RCCE_pingpong
stream.o: stream.c
@echo [CC] $@
@ -75,6 +75,13 @@ RCCE_pingpong: RCCE_pingpong.o
$Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@
$Qchmod a-x $@.sym
netio: netio.o
@echo [LD] $@
$Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $<
$Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym
$Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@
$Qchmod a-x $@.sym
hg: hg.o hist.o rdtsc.o run.o init.o opt.o report.o setup.o
@echo [LD] $@
$Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $< hist.o rdtsc.o run.o init.o opt.o report.o setup.o
@ -84,7 +91,7 @@ hg: hg.o hist.o rdtsc.o run.o init.o opt.o report.o setup.o
clean:
@echo Cleaning benchmarks
$Q$(RM) stream hg RCCE_pingping RCCE_pingpong *.sym *.o *~ *.bin
$Q$(RM) stream hg netio RCCE_pingping RCCE_pingpong *.sym *.o *~ *.bin
veryclean:
@echo Propper cleaning benchmarks

View file

@ -0,0 +1,465 @@
/*
* Copyright (c) 2011, Stefan Lankes, RWTH Aachen University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR AN
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <errno.h>
/*
* This implements a netio server and client (only TCP version).
* The client sends a command word (4 bytes) then a data length word (4 bytes).
* If the command is "receive", the server is to consume "data length" bytes into
* a circular buffer until the first byte is non-zero, then it is to consume
* another command/data pair.
* If the command is "send", the server is to send "data length" bytes from a circular
* buffer with the first byte being zero, until "some time" (6 seconds in the
* current netio131.zip download) has passed and then send one final buffer with
* the first byte being non-zero. Then it is to consume another command/data pair.
*/
/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netdb.h>
typedef struct
{
uint32_t cmd;
uint32_t data;
} CONTROL;
#define CMD_QUIT 0
#define CMD_C2S 1
#define CMD_S2C 2
#define CMD_RES 3
#define CTLSIZE sizeof(CONTROL)
#define DEFAULTPORT 0x494F
#define TMAXSIZE 65536
static int tSizes[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32767};
static size_t ntSizes = sizeof(tSizes) / sizeof(int);
static int nPort = DEFAULTPORT;
static const int sobufsize = 131072;
static struct in_addr addr_local;
static struct in_addr addr_server;
extern unsigned int get_cpufreq(void);
inline static unsigned long long rdtsc(void)
{
unsigned long lo, hi;
asm volatile ("rdtsc" : "=a"(lo), "=d"(hi) :: "memory");
return ((unsigned long long) hi << 32ULL | (unsigned long long) lo);
}
static int send_data(int socket, void *buffer, size_t size, int flags)
{
ssize_t rc = send(socket, buffer, size, flags);
if (rc < 0)
{
printf("send failed: %d\n", errno);
return -1;
}
if (rc != size)
return 1;
return 0;
}
static int recv_data(int socket, void *buffer, size_t size, int flags)
{
ssize_t rc = recv(socket, buffer, size, flags);
if (rc < 0) {
printf("recv failed: %d\n", errno);
return -1;
}
if (rc != size)
return 1;
return 0;
}
static char *InitBuffer(size_t nSize)
{
char *cBuffer = malloc(nSize);
memset(cBuffer, 0xFF, nSize);
cBuffer[0] = 0;
return cBuffer;
}
static char *PacketSize(int nSize)
{
static char szBuffer[64];
if ((nSize % 1024) == 0 || (nSize % 1024) == 1023)
sprintf(szBuffer, "%2dk", (nSize + 512) / 1024);
else
sprintf(szBuffer, "%d", nSize);
return szBuffer;
}
static int TCPServer(void)
{
char *cBuffer;
CONTROL ctl;
uint64_t nData;
struct sockaddr_in sa_server, sa_client;
int server, client;
socklen_t length;
struct timeval tv;
fd_set fds;
int rc;
int nByte;
int err;
uint64_t start, end;
uint32_t freq = get_cpufreq(); /* in MHz */
if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL) {
printf("Netio: Not enough memory\n");
return -1;
}
if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
printf("socket failed: %d\n", server);
free(cBuffer);
return -1;
}
setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
memset((char *) &sa_server, 0x00, sizeof(sa_server));
sa_server.sin_family = AF_INET;
sa_server.sin_port = htons(nPort);
sa_server.sin_addr = addr_local;
if ((err = bind(server, (struct sockaddr *) &sa_server, sizeof(sa_server))) < 0)
{
printf("bind failed: %d\n", errno);
close(server);
free(cBuffer);
return -1;
}
if ((err = listen(server, 2)) != 0)
{
printf("listen failed: %d\n", errno);
close(server);
free(cBuffer);
return -1;
}
for (;;)
{
printf("TCP server listening.\n");
FD_ZERO(&fds);
FD_SET(server, &fds);
tv.tv_sec = 3600;
tv.tv_usec = 0;
if ((rc = select(FD_SETSIZE, &fds, 0, 0, &tv)) < 0)
{
printf("select failed: %d\n", errno);
break;
}
if (rc == 0 || FD_ISSET(server, &fds) == 0)
continue;
length = sizeof(sa_client);
if ((client = accept(server, (struct sockaddr *) &sa_client, &length)) < 0) {
printf("accept faild: %d\n", errno);
continue;
}
setsockopt(client, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
setsockopt(client, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
printf("TCP connection established ... ");
for (;;)
{
if (recv_data(client, (void *) &ctl, CTLSIZE, 0))
break;
ctl.cmd = ntohl(ctl.cmd);
ctl.data = ntohl(ctl.data);
if (ctl.cmd == CMD_C2S)
{
start = rdtsc();
printf("\nReceiving from client, packet size %s ... \n", PacketSize(ctl.data));
cBuffer[0] = 0;
nData = 0;
do {
for (nByte = 0; nByte < ctl.data; )
{
rc = recv(client, cBuffer + nByte, ctl.data - nByte, 0);
if (rc < 0)
{
printf("recv failed: %d\n", errno);
break;
}
if (rc > 0)
nByte += rc;
}
nData += ctl.data;
} while (cBuffer[0] == 0 && rc > 0);
end = rdtsc();
printf("Time to receive %llu bytes: %llu nsec (ticks %llu)\n", nData, ((end-start)*1000ULL)/freq, end-start);
} else if (ctl.cmd == CMD_S2C) {
start = rdtsc();
printf("\nSending to client, packet size %s ... \n", PacketSize(ctl.data));
cBuffer[0] = 0;
nData = 0;
do
{
//GenerateRandomData(cBuffer, ctl.data);
for (nByte = 0; nByte < ctl.data; )
{
rc = send(client, cBuffer + nByte, ctl.data - nByte, 0);
if (rc < 0)
{
printf("send failed: %d\n", errno);
break;
}
if (rc > 0)
nByte += rc;
}
nData += ctl.data;
end = rdtsc();
} while((end-start)/freq < 6000000ULL /* = 6s */);
cBuffer[0] = 1;
if (send_data(client, cBuffer, ctl.data, 0))
break;
end = rdtsc();
printf("Time to send %llu bytes: %llu nsec (ticks %llu)\n", nData, ((end-start)*1000ULL)/freq, end-start);
} else /* quit */
break;
}
printf("\nDone.\n");
close(client);
if (rc < 0)
break;
}
close(server);
free(cBuffer);
return 0;
}
int TCP_Bench(void)
{
char *cBuffer;
CONTROL ctl;
uint64_t nData;
int i;
struct sockaddr_in sa_server;
int server;
int rc, err;
int nByte;
uint64_t start, end;
uint32_t freq = get_cpufreq(); /* in MHz */
if ((cBuffer = InitBuffer(TMAXSIZE)) == NULL)
{
printf("Netio: Not enough memory\n");
return -1;
}
if ((server = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
printf("socket failed: %d\n", errno);
free(cBuffer);
return -2;
}
setsockopt(server, SOL_SOCKET, SO_RCVBUF, (char *) &sobufsize, sizeof(sobufsize));
setsockopt(server, SOL_SOCKET, SO_SNDBUF, (char *) &sobufsize, sizeof(sobufsize));
sa_server.sin_family = AF_INET;
sa_server.sin_port = htons(nPort);
sa_server.sin_addr = addr_server;
if ((err = connect(server, (struct sockaddr *) &sa_server, sizeof(sa_server))) < 0)
{
printf("connect failed: %d\n", errno);
close(server);
free(cBuffer);
return -2;
}
printf("\nTCP connection established.\n");
for (i = 0; i < ntSizes; i++)
{
printf("Packet size %s bytes: ", PacketSize(tSizes[i]));
/* tell the server we will send it data now */
ctl.cmd = htonl(CMD_C2S);
ctl.data = htonl(tSizes[i]);
if (send_data(server, (void *) &ctl, CTLSIZE, 0))
break;
/* 1 - Tx test */
start = rdtsc();
nData = 0;
cBuffer[0] = 0;
do
{
//GenerateRandomData(cBuffer, tSizes[i]);
for (nByte = 0; nByte < tSizes[i]; )
{
rc = send(server, cBuffer + nByte, tSizes[i] - nByte, 0);
if (rc < 0)
{
printf("send failed: %d\n", errno);
return -1;
}
if (rc > 0)
nByte += rc;
}
nData += tSizes[i];
end = rdtsc();
} while((end-start)/freq < 6000000ULL /* = 6s */);
printf("%llu/100 MBytes/s", ((100ULL*nData)/(1024ULL*1024ULL))/((end-start)/(1000000ULL*freq)));
printf(" Tx, ");
cBuffer[0] = 1;
if (send_data(server, cBuffer, tSizes[i], 0))
break;
/* tell the server we expect him to send us data now */
ctl.cmd = htonl(CMD_S2C);
ctl.data = htonl(tSizes[i]);
if (send_data(server, (void *) &ctl, CTLSIZE, 0))
break;
/* 2 - Rx test */
start = rdtsc();
nData = 0;
cBuffer[0] = 0;
rc = 0;
do
{
for (nByte = 0; nByte < tSizes[i]; )
{
rc = recv(server, cBuffer + nByte, tSizes[i] - nByte, 0);
if (rc < 0)
{
printf("recv failed: %d\n", errno);
return -1;
}
if (rc > 0)
nByte += rc;
}
nData += tSizes[i];
} while (cBuffer[0] == 0 && rc > 0);
end = rdtsc();
printf("%llu/100 MBytes/s", ((100ULL*nData)/(1024ULL*1024ULL))/((end-start)/(1000000ULL*freq)));
printf(" Rx.\n");
}
ctl.cmd = htonl(CMD_QUIT);
ctl.data = 0;
send_data(server, (void *) &ctl, CTLSIZE, 0);
printf("Done.\n");
close(server);
free(cBuffer);
return 0;
}
int main(int argc, char** argv)
{
int err = 0;
addr_local.s_addr = INADDR_ANY;
//addr_server.s_addr = inet_addr("192.168.28.254");
addr_server.s_addr = inet_addr("192.168.28.1");
err = TCPServer();
return err;
}