From: John Hodge Date: Thu, 28 Nov 2013 05:48:41 +0000 (+0800) Subject: AcessNative - TCP emulation working X-Git-Tag: rel0.15~73 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=c3cbbd71507f45fae706cb1396327a9f7abc02f9;p=tpg%2Facess2.git AcessNative - TCP emulation working - Cleanup is lacking, but Rx/Tx works --- diff --git a/AcessNative/acesskernel_src/Makefile b/AcessNative/acesskernel_src/Makefile index f831a431..00ba7757 100644 --- a/AcessNative/acesskernel_src/Makefile +++ b/AcessNative/acesskernel_src/Makefile @@ -14,6 +14,7 @@ endif KERNEL_SRC = ../../KernelLand/Kernel/ LDACESS_SRC = ../../Usermode/Libraries/ld-acess.so_src/ +# - Kernel objects (from KernelLand/Kernel) KERNEL_OBJ := logging.o adt.o lib.o debug.o messages.o drvutil_disk.o drvutil_video.o KERNEL_OBJ += mutex.o semaphore.o rwlock.o workqueue.o events.o #KERNEL_OBJ += libc.o @@ -24,16 +25,16 @@ KERNEL_OBJ += drv/fifo.o drv/proc.o drv/dgram_pipe.o KERNEL_OBJ += drv/vterm.o drv/vterm_font.o drv/vterm_output.o drv/vterm_input.o drv/vterm_termbuf.o KERNEL_OBJ += drv/vterm_vt100.o drv/vterm_2d.o KERNEL_OBJ += drv/pty.o - -N_OBJ := main.o +# - Native (unsullied) objects +N_OBJ := main.o net_wrap.o +# - Local objects (use the kernel includes) +OBJ := helpers.o threads.o threads_glue.o server.o syscalls.o time.o +OBJ += video.o keyboard.o mouse.o nativefs.o vfs_handle.o ui_sdl.o +OBJ += net.o BUILDINFO_OBJ := obj-$(PLATFORM)/buildinfo.o BUILDINFO_SRC := $(BUILDINFO_OBJ:%.o=%.c) -OBJ := helpers.o threads.o threads_glue.o server.o syscalls.o time.o -OBJ += video.o keyboard.o mouse.o nativefs.o vfs_handle.o ui_sdl.o -OBJ += net.o net_wrap.o - OBJ := $(addprefix obj-$(PLATFORM)/,$(OBJ)) N_OBJ := $(addprefix obj-$(PLATFORM)/,$(N_OBJ)) K_OBJ := $(addprefix $(KERNEL_SRC)obj-native-$(PLATFORM)/,$(KERNEL_OBJ)) diff --git a/AcessNative/acesskernel_src/include/arch.h b/AcessNative/acesskernel_src/include/arch.h index 1e2be703..ab27de1f 100644 --- a/AcessNative/acesskernel_src/include/arch.h +++ b/AcessNative/acesskernel_src/include/arch.h @@ -40,10 +40,11 @@ struct sShortSpinlock extern void Threads_int_ShortLock(void **Ptr); extern void Threads_int_ShortRel(void **Ptr); +extern int Threads_int_ShortHas(void **Ptr); #define SHORTLOCK(l) Threads_int_ShortLock(&(l)->Mutex) #define SHORTREL(l) Threads_int_ShortRel(&(l)->Mutex) -#define CPU_HAS_LOCK(...) 0 +#define CPU_HAS_LOCK(l) Threads_int_ShortHas(&(l)->Mutex) //#define NUM_CFG_ENTRIES 10 diff --git a/AcessNative/acesskernel_src/net.c b/AcessNative/acesskernel_src/net.c index 1f0f977d..940827e3 100644 --- a/AcessNative/acesskernel_src/net.c +++ b/AcessNative/acesskernel_src/net.c @@ -63,6 +63,7 @@ tVFS_Node gNet_Node_Routes = { int Net_Install(char **Arguments) { DevFS_AddDevice(&gNet_DevInfo); + Net_Wrap_Init(); return 0; } @@ -154,7 +155,7 @@ int Net_TCPC_IOCtl(tVFS_Node *Node, int IOCtl, void *Data) case 7: // Connect Node->Data = Net_Wrap_ConnectTcp(Node, tcpc->SrcPort, tcpc->DstPort, tcpc->AddrType, tcpc->DestAddr); - return (Node->Data == NULL); + return (Node->Data != NULL); case 8: Debug("TODO: TCPC rx buffer length"); return -1; diff --git a/AcessNative/acesskernel_src/net_wrap.c b/AcessNative/acesskernel_src/net_wrap.c index 0b22e77c..730eda02 100644 --- a/AcessNative/acesskernel_src/net_wrap.c +++ b/AcessNative/acesskernel_src/net_wrap.c @@ -5,43 +5,228 @@ * net.c * - Networking */ +#define DEBUG 1 +#include #include -#include +#include "../../KernelLand/Kernel/include/logdebug.h" #include "net_wrap.h" +#include +#include +#include +#include +#include +#include + +#include // for worker typedef struct sNetSocket tNetSocket; struct sNetSocket { tNetSocket *Next; + tNetSocket *Prev; + void *Node; int FD; + char bSkipRead; + char bSkipWrite; + char bSkipError; }; + + int Net_Wrap_WatcherThread(void *arg); + + int gNet_Wrap_EventFD; tNetSocket *gNet_Wrap_FirstSocket; tNetSocket *gNet_Wrap_LastSocket; +SDL_Thread *gNet_Wrap_SelectChecker; // === CODE === -void *Net_Wrap_ConnectTcp(void *Node, short SrcPort, short DstPtr, int Type, const void *Addr) +void Net_Wrap_Init(void) { - return NULL; + gNet_Wrap_EventFD = eventfd(0, 0); + gNet_Wrap_SelectChecker = SDL_CreateThread( Net_Wrap_WatcherThread, NULL ); +} + +static inline void Net_Wrap_ProdWatcher(void) +{ + uint64_t val = 1; + write(gNet_Wrap_EventFD, &val, sizeof(val)); +} + +int Net_Wrap_WatcherThread(void *arg) +{ + for(;;) + { + int maxfd = gNet_Wrap_EventFD; + fd_set rfds, wfds, efds; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&efds); + // Event FD used to wake this thread when the list changes + FD_SET(gNet_Wrap_EventFD, &rfds); + // Populate socket FDs + for( tNetSocket *s = gNet_Wrap_FirstSocket; s; s = s->Next ) + { + if( s->FD > maxfd ) + maxfd = s->FD; + if( !s->bSkipRead ) FD_SET(s->FD, &rfds); + if( !s->bSkipWrite ) FD_SET(s->FD, &wfds); + if( !s->bSkipError ) FD_SET(s->FD, &efds); + } + + LOG("select(%i+1, ...)", maxfd); + int rv = select(maxfd+1, &rfds, &wfds, &efds, NULL); + LOG("rv = %i"); + if( rv <= 0 ) + continue ; + + if( FD_ISSET(gNet_Wrap_EventFD, &rfds) ) + { + uint64_t val; + read(gNet_Wrap_EventFD, &val, 8); + } + + for( tNetSocket *s = gNet_Wrap_FirstSocket; s; s = s->Next ) + { + if( FD_ISSET(s->FD, &rfds) ) { + VFS_MarkAvaliable(s->Node, 1); + s->bSkipRead = 1; + } + if( FD_ISSET(s->FD, &wfds) ) { + VFS_MarkFull(s->Node, 0); + s->bSkipWrite = 1; + } + if( FD_ISSET(s->FD, &efds) ) { + VFS_MarkError(s->Node, 1); + s->bSkipError = 1; // TODO: how will err be acked? + } + } + } +} + +void *Net_Wrap_ConnectTcp(void *Node, short SrcPort, short DstPort, int Type, const void *Addr) +{ + struct sockaddr_in addr4; + struct sockaddr *addr; + socklen_t addr_size; + + int af; + switch(Type) + { + case 4: + af = AF_INET; + addr = (struct sockaddr*)&addr4; + addr_size = sizeof(addr4); + memset(addr, 0, addr_size); + LOG("%02x%02x%02x%02x", + ((uint8_t*)Addr)[0], ((uint8_t*)Addr)[1], + ((uint8_t*)Addr)[2], ((uint8_t*)Addr)[3]); + memcpy(&addr4.sin_addr, Addr, 4); + //addr4.sin_addr.s_addr = htonl( addr4.sin_addr.s_addr); + addr4.sin_port = htons(DstPort); + break; + //case 6: af = AF_INET6; break; + default: + return NULL; + } + + addr->sa_family = af; + + int fd = socket(af, SOCK_STREAM, 0); + if( SrcPort ) { + Log_Warning("NetWrap", "TODO: Support setting TCP source port"); + } + Debug_HexDump("NetWrap: addr=", addr, addr_size); + if( connect(fd, addr, addr_size) ) { + close(fd); + Log_Notice("NetWrap", "connect() failed: %s", strerror(errno)); + char tmp[64] = {0}; + inet_ntop(af, addr->sa_data+2, tmp, sizeof(tmp)); + printf("addr = %p %s\n", tmp, tmp); + return NULL; + } + + tNetSocket *ret = malloc( sizeof(tNetSocket) ); + if(!ret) { + close(fd); + return NULL; + } + + ret->Next = NULL; + ret->Node = Node; + ret->FD = fd; + ret->bSkipRead = 0; + ret->bSkipWrite = 0; + ret->bSkipError = 0; + + if( gNet_Wrap_FirstSocket ) { + gNet_Wrap_LastSocket->Next = ret; + ret->Prev = gNet_Wrap_LastSocket; + } + else { + gNet_Wrap_FirstSocket = ret; + ret->Prev = NULL; + } + gNet_Wrap_LastSocket = ret; + + Net_Wrap_ProdWatcher(); + + return ret; +} + +static void Net_Wrap_UpdateFlags(tNetSocket *hdl) +{ + struct pollfd fdinfo = {.fd = hdl->FD, .events=POLLIN|POLLOUT, .revents=0}; + + poll(&fdinfo, 1, 0); + + VFS_MarkAvaliable(hdl->Node, !!(fdinfo.revents & POLLIN)); + VFS_MarkFull(hdl->Node, !(fdinfo.revents & POLLOUT)); + + // If no data can be written, re-enable select + if( !(fdinfo.revents & POLLOUT) ) + hdl->bSkipWrite = 0; + // Same for if no data to read + if( !(fdinfo.revents & POLLIN) ) + hdl->bSkipRead = 0; + + Net_Wrap_ProdWatcher(); } size_t Net_Wrap_ReadSocket(void *Handle, size_t Bytes, void *Dest) { tNetSocket *hdl = Handle; if(!hdl) return -1; - return read(hdl->FD, Dest, Bytes); + size_t rv = read(hdl->FD, Dest, Bytes); + Net_Wrap_UpdateFlags(hdl); + return rv; } size_t Net_Wrap_WriteSocket(void *Handle, size_t Bytes, const void *Dest) { tNetSocket *hdl = Handle; if(!hdl) return -1; - return write(hdl->FD, Dest, Bytes); + size_t rv = write(hdl->FD, Dest, Bytes); + Net_Wrap_UpdateFlags(hdl); + return rv; } void Net_Wrap_CloseSocket(void *Handle) { - // TODO + tNetSocket *hdl = Handle; + + // TODO: Lock + if(hdl->Prev) + hdl->Prev->Next = hdl->Next; + else + gNet_Wrap_FirstSocket = hdl->Next; + if(hdl->Next) + hdl->Next->Prev = hdl->Prev; + else + gNet_Wrap_LastSocket = hdl->Prev; + Net_Wrap_ProdWatcher(); + + close(hdl->FD); + free(hdl); } diff --git a/AcessNative/acesskernel_src/net_wrap.h b/AcessNative/acesskernel_src/net_wrap.h index 8d655d2a..73dfc99c 100644 --- a/AcessNative/acesskernel_src/net_wrap.h +++ b/AcessNative/acesskernel_src/net_wrap.h @@ -2,6 +2,7 @@ #ifndef _NET_WRAP_H_ #define _NET_WRAP_H_ +extern void Net_Wrap_Init(void); extern void *Net_Wrap_ConnectTcp(void *Node, short SrcPort, short DstPtr, int Type, const void *Addr); extern size_t Net_Wrap_ReadSocket(void *Handle, size_t Bytes, void *Dest); extern size_t Net_Wrap_WriteSocket(void *Handle, size_t Bytes, const void *Dest); diff --git a/AcessNative/acesskernel_src/threads_glue.c b/AcessNative/acesskernel_src/threads_glue.c index c2efb713..fa83980e 100644 --- a/AcessNative/acesskernel_src/threads_glue.c +++ b/AcessNative/acesskernel_src/threads_glue.c @@ -21,6 +21,7 @@ typedef void **tShortSpinlock; #define NORETURN __attribute__((noreturn)) #include // Kernel land, but uses standards +#include // === CODE === void Threads_Glue_Yield(void) @@ -82,9 +83,15 @@ void Threads_int_ShortLock(void **MutexPtr) { if( !*MutexPtr ) { *MutexPtr = malloc( sizeof(pthread_mutex_t) ); + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); pthread_mutex_init(*MutexPtr, NULL); } - pthread_mutex_lock(*MutexPtr); + if( pthread_mutex_lock(*MutexPtr) ) { + fprintf(stderr, "ERROR: Mutex pointer %p double locked\n", MutexPtr); + AcessNative_Exit(); + } } void Threads_int_ShortRel(void **MutexPtr) @@ -92,4 +99,18 @@ void Threads_int_ShortRel(void **MutexPtr) pthread_mutex_unlock(*MutexPtr); } +int Threads_int_ShortHas(void **Ptr) +{ + if( !*Ptr ) + return 0; + int rv = pthread_mutex_trylock(*Ptr); + if( rv == 0 ) { + pthread_mutex_unlock(*Ptr); + return 0; + } + if( rv == EBUSY ) { + return 0; + } + return 1; +}