X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=AcessNative%2Facesskernel_src%2Fserver.c;h=45806e2b4f03f52e8ff2cebb45f186cfcd565035;hb=1b9e758fbf856934974e847c3d5b348d237a0001;hp=7bb503364b0f8894943981c61fec6c73ce739f54;hpb=6d32a3c22e659994d7ae6164ba3722ab12d11421;p=tpg%2Facess2.git diff --git a/AcessNative/acesskernel_src/server.c b/AcessNative/acesskernel_src/server.c index 7bb50336..45806e2b 100644 --- a/AcessNative/acesskernel_src/server.c +++ b/AcessNative/acesskernel_src/server.c @@ -9,17 +9,24 @@ #include #include #ifdef __WIN32__ +# define _WIN32_WINNT 0x0501 # include -# include +# include +# include +# define close(fd) closesocket(fd) +typedef int socklen_t; #else # include # include # include +# include // getaddrinfo #endif +#define DONT_INCLUDE_SYSCALL_NAMES #include "../syscalls.h" -//#include +#include // acess but std +#include -#define USE_TCP 0 +#define USE_TCP 1 #define MAX_CLIENTS 16 // === TYPES === @@ -27,6 +34,7 @@ typedef struct { int ClientID; SDL_Thread *WorkerThread; #if USE_TCP + int Socket; #else tRequestHeader *CurrentRequest; struct sockaddr_in ClientAddr; @@ -39,9 +47,8 @@ typedef struct { extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength); extern int Threads_CreateRootProcess(void); extern void Threads_SetThread(int TID); -// HACK: Should have these in a header -extern void Log_Debug(const char *Subsys, const char *Message, ...); -extern void Log_Notice(const char *Subsys, const char *Message, ...); +extern void *Threads_GetThread(int TID); +extern void Threads_PostEvent(void *Thread, uint32_t Event); // === PROTOTYPES === tClient *Server_GetClient(int ClientID); @@ -102,12 +109,20 @@ tClient *Server_GetClient(int ClientID) // Allocate a thread for the process ret->ClientID = ClientID; + #if USE_TCP + ret->Socket = 0; + #else ret->CurrentRequest = NULL; + #endif if( !ret->WorkerThread ) { + #if USE_TCP + #else ret->WaitFlag = SDL_CreateCond(); ret->Mutex = SDL_CreateMutex(); SDL_mutexP( ret->Mutex ); + #endif + Log_Debug("Server", "Creating worker for %p", ret); ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret ); } @@ -117,28 +132,153 @@ tClient *Server_GetClient(int ClientID) int Server_WorkerThread(void *ClientPtr) { tClient *Client = ClientPtr; + + Log_Debug("Server", "Worker %p", ClientPtr); + + #if USE_TCP + while( *((volatile typeof(Client->Socket)*)&Client->Socket) == 0 ) + ; + Threads_SetThread( Client->ClientID ); + + while( Client->ClientID != -1 ) + { + fd_set fds; + int nfd = Client->Socket+1; + FD_ZERO(&fds); + FD_SET(Client->Socket, &fds); + + int rv = select(nfd, &fds, NULL, NULL, NULL); // TODO: Timeouts? + if(rv < 0) { + perror("select"); + continue ; + } +// Log_Debug("Server", "%p: rv=%i", Client, rv); + + if( FD_ISSET(Client->Socket, &fds) ) + { + const int ciMaxParamCount = 6; + char lbuf[sizeof(tRequestHeader) + ciMaxParamCount*sizeof(tRequestValue)]; + tRequestHeader *hdr = (void*)lbuf; + size_t len = recv(Client->Socket, (void*)hdr, sizeof(*hdr), 0); +// Log_Debug("Server", "%i bytes of header", len); + if( len == 0 ) { + Log_Notice("Server", "Zero RX on %i (worker %p)", Client->Socket, Client); + break; + } + if( len == -1 ) { + perror("recv header"); +// Log_Warning("Server", "recv() error - %s", strerror(errno)); + break; + } + if( len != sizeof(*hdr) ) { + // Oops? + Log_Warning("Server", "FD%i bad sized (%i != exp %i)", + Client->Socket, len, sizeof(*hdr)); + continue ; + } + + if( hdr->NParams > ciMaxParamCount ) { + // Oops. + Log_Warning("Server", "FD%i too many params (%i > max %i)", + Client->Socket, hdr->NParams, ciMaxParamCount); + break ; + } + + if( hdr->NParams > 0 ) + { + len = recv(Client->Socket, (void*)hdr->Params, hdr->NParams*sizeof(tRequestValue), 0); +// Log_Debug("Server", "%i bytes of params", len); + if( len != hdr->NParams*sizeof(tRequestValue) ) { + // Oops. + perror("recv params"); + Log_Warning("Sever", "Recieving params failed"); + break ; + } + } + else + { +// Log_Debug("Server", "No params?"); + } + + // Get buffer size + size_t hdrsize = sizeof(tRequestHeader) + hdr->NParams*sizeof(tRequestValue); + size_t bufsize = hdrsize; + int i; + for( i = 0; i < hdr->NParams; i ++ ) + { + if( hdr->Params[i].Flags & ARG_FLAG_ZEROED ) + ; + else { + bufsize += hdr->Params[i].Length; + } + } + + // Allocate full buffer + hdr = malloc(bufsize); + memcpy(hdr, lbuf, hdrsize); + if( bufsize > hdrsize ) + { + size_t rem = bufsize - hdrsize; + char *ptr = (void*)( hdr->Params + hdr->NParams ); + while( rem ) + { + len = recv(Client->Socket, ptr, rem, 0); +// Log_Debug("Server", "%i bytes of data", len); + if( len == -1 ) { + // Oops? + perror("recv data"); + Log_Warning("Sever", "Recieving data failed"); + break ; + } + rem -= len; + ptr += len; + } + if( rem ) { + break; + } + } +// else +// Log_Debug("Server", "no data"); + + int retlen; + tRequestHeader *retHeader; + retHeader = SyscallRecieve(hdr, &retlen); + if( !retHeader ) { + // Some sort of error + Log_Warning("Server", "SyscallRecieve failed?"); + continue ; + } + + send(Client->Socket, (void*)retHeader, retlen, 0); + + // Clean up + free(hdr); + } + } + #else tRequestHeader *retHeader; tRequestHeader errorHeader; int retSize = 0; int sentSize; int cur_client_id = 0; - - #if USE_TCP - #else - for( ;; ) + while( Client->ClientID != -1 ) { // Wait for something to do - while( Client->CurrentRequest == NULL ) + if( Client->CurrentRequest == NULL ) SDL_CondWait(Client->WaitFlag, Client->Mutex); + if( Client->CurrentRequest == NULL ) + continue ; + +// Log_Debug("AcessSrv", "Worker got message %p", Client->CurrentRequest); if(Client->ClientID != cur_client_id) { +// Log_Debug("AcessSrv", "Client thread ID changed from %i to %i", +// cur_client_id, Client->ClientID); Threads_SetThread( Client->ClientID ); cur_client_id = Client->ClientID; } - // Get the response - retHeader = SyscallRecieve(Client->CurrentRequest, &retSize); - + // Debug { int callid = Client->CurrentRequest->CallID; Log_Debug("AcessSrv", "Client %i request %i %s", @@ -147,7 +287,9 @@ int Server_WorkerThread(void *ClientPtr) ); } - + // Get the response + retHeader = SyscallRecieve(Client->CurrentRequest, &retSize); + if( !retHeader ) { // Return an error to the client printf("ERROR: SyscallRecieve failed\n"); @@ -183,6 +325,8 @@ int Server_WorkerThread(void *ClientPtr) free( retHeader ); } #endif + Log_Notice("Server", "Terminated Worker %p", ClientPtr); + return 0; } int SyscallServer(void) @@ -243,24 +387,94 @@ int SyscallServer(void) return 0; } +int Server_Shutdown(void) +{ + close(gSocket); + for( int i = 0; i < MAX_CLIENTS; i ++ ) + { + if( gaServer_Clients[i].ClientID == 0 ) + continue ; + Threads_PostEvent( Threads_GetThread(gaServer_Clients[i].ClientID), 0 ); + gaServer_Clients[i].ClientID = -1; + #if USE_TCP + close(gaServer_Clients[i].Socket); + #else + SDL_CondSignal(gaServer_Clients[i].WaitFlag); + #endif + } + return 0; +} + int Server_ListenThread(void *Unused) { // Wait for something to do :) for( ;; ) { #if USE_TCP - struct sockaddr_in client; - uint clientSize = sizeof(client); - int clientSock = accept(gSocket, (struct sockaddr*)&client, &clientSize); + struct sockaddr_in clientaddr; + socklen_t clientSize = sizeof(clientaddr); + int clientSock = accept(gSocket, (struct sockaddr*)&clientaddr, &clientSize); if( clientSock < 0 ) { perror("SyscallServer - accept"); break ; } + + char addrstr[4*8+8+1]; + getnameinfo((struct sockaddr*)&clientaddr, sizeof(clientaddr), + addrstr, sizeof(addrstr), NULL, 0, NI_NUMERICHOST); + Log_Debug("Server", "Client connection %s:%i", addrstr, ntohs(clientaddr.sin_port)); - Log("Client connection %x:%i\n", - ntohl(client.sin_addr), ntohs(client.sin_port) - ); + // Perform auth + size_t len; + tRequestAuthHdr authhdr; + len = recv(clientSock, (void*)&authhdr, sizeof(authhdr), 0); + if( len != sizeof(authhdr) ) { + // Some form of error? + Log_Warning("Server", "Client auth block bad size (%i != exp %i)", + len, sizeof(authhdr)); + close(clientSock); + continue ; + } + + Log_Debug("Server", "Client assumed PID %i", authhdr.pid); + + tClient *client; + if( authhdr.pid == 0 ) { + // Allocate PID and client structure/thread + client = Server_GetClient(0); + client->Socket = clientSock; + authhdr.pid = client->ClientID; + } + else { + // Get client structure and make sure it's unused + // - Auth token / verifcation? + client = Server_GetClient(authhdr.pid); + if( !client ) { + Log_Warning("Server", "Can't allocate a client struct for %s:%i", + addrstr, clientaddr.sin_port); + close(clientSock); + continue ; + } + if( client->Socket != 0 ) { + Log_Warning("Server", "Client (%i)%p owned by FD%i but %s:%i tried to use it", + authhdr.pid, client, addrstr, clientaddr.sin_port); + close(clientSock); + continue; + } + else { + client->Socket = clientSock; + } + } + Log_Debug("Server", "Client given PID %i - info %p", authhdr.pid, client); + len = send(clientSock, (void*)&authhdr, sizeof(authhdr), 0); + if( len != sizeof(authhdr) ) { + // Ok, this is an error + perror("Sending auth reply"); + } + + // All done, client thread should be watching now + #else char data[BUFSIZ]; tRequestHeader *req = (void*)data; @@ -302,8 +516,8 @@ int Server_ListenThread(void *Unused) continue; } - Log_Debug("AcessSrv", "Message from Client %i (%p)", - client->ClientID, client); +// Log_Debug("AcessSrv", "Message from Client %i (%p)", +// client->ClientID, client); // Make a copy of the request data req = malloc(length);