AcessNative - Reworked protocol to be simpler
authorJohn Hodge <[email protected]>
Sun, 23 Jan 2011 02:41:09 +0000 (10:41 +0800)
committerJohn Hodge <[email protected]>
Sun, 23 Jan 2011 02:41:09 +0000 (10:41 +0800)
- Completed the interface code, not tested yet
- Switched to a single list of parameters, with flags for returned values

AcessNative/acesskernel_src/server.c [new file with mode: 0644]
AcessNative/acesskernel_src/syscalls.c
AcessNative/ld-acess_src/request.c
AcessNative/ld-acess_src/request.h
AcessNative/ld-acess_src/syscalls.c
AcessNative/syscalls.h

diff --git a/AcessNative/acesskernel_src/server.c b/AcessNative/acesskernel_src/server.c
new file mode 100644 (file)
index 0000000..7491d74
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Acess2 Native Kernel
+ * - Acess kernel emulation on another OS using SDL and UDP
+ *
+ * Syscall Server
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <SDL/SDL.h>
+#ifdef __WIN32__
+# include <windows.h>
+# include <winsock.h>
+#else
+# include <unistd.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+#endif
+#include "../syscalls.h"
+
+#define        USE_TCP 0
+#define MAX_CLIENTS    16
+
+// === TYPES ===
+typedef struct {
+        int    ClientID;
+       SDL_Thread      *WorkerThread;
+       #if USE_TCP
+       #else
+       tRequestHeader  *CurrentRequest;
+       struct sockaddr_in      ClientAddr;
+       SDL_cond        *WaitFlag;
+       SDL_mutex       *Mutex;
+       #endif
+}      tClient;
+
+// === IMPORTS ===
+extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength);
+
+// === PROTOTYPES ===
+tClient        *Server_GetClient(int ClientID);
+ int   Server_WorkerThread(void *ClientPtr);
+ int   SyscallServer(void);
+
+// === GLOBALS ===
+#ifdef __WIN32__
+WSADATA        gWinsock;
+SOCKET gSocket = INVALID_SOCKET;
+#else
+# define INVALID_SOCKET -1
+ int   gSocket = INVALID_SOCKET;
+#endif
+ int   giServer_NextClientID = 1;
+tClient        gaServer_Clients[MAX_CLIENTS];
+
+// === CODE ===
+tClient *Server_GetClient(int ClientID)
+{
+       tClient *ret = NULL;
+        int    i;
+       
+       for( i = 0; i < MAX_CLIENTS; i ++ )
+       {
+               if( gaServer_Clients[i].ClientID == ClientID ) {
+                       ret = &gaServer_Clients[i];
+                       break;
+               }
+       }
+       
+       // Uh oh, no free slots
+       // TODO: Dynamic allocation
+       if( !ret )
+               return NULL;
+       
+       if( ClientID == 0 )
+       {
+               ret->ClientID = giServer_NextClientID ++;
+               ret->CurrentRequest = NULL;
+               
+               if( !ret->WorkerThread ) {
+                       ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
+                       ret->WaitFlag = SDL_CreateCond();
+                       ret->Mutex = SDL_CreateMutex();
+                       SDL_mutexP( ret->Mutex );
+               }
+       }
+       
+       return &gaServer_Clients[i];
+}
+
+int Server_WorkerThread(void *ClientPtr)
+{
+       tClient *Client = ClientPtr;
+       tRequestHeader  *retHeader;
+        int    retSize = 0;
+        int    sentSize;
+       
+       #if USE_TCP
+       #else
+       for( ;; )
+       {
+               // Wait for something to do
+               while( !Client->CurrentRequest )        ;
+               
+               // Get the response
+               retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
+               
+               if( !retHeader ) {
+                       // Return an error to the client
+                       printf("Error returned by SyscallRecieve\n");
+               }
+               
+               // Return the data
+               sentSize = sendto(gSocket, retHeader, retSize, 0,
+                       (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
+                       );
+               if( sentSize != retSize ) {
+                       perror("Server_WorkerThread - send");
+               }
+               
+               // Free allocated header
+               free( retHeader );
+               
+               Client->CurrentRequest = 0;
+               
+               // Wait for something else
+               SDL_CondWait(Client->WaitFlag, Client->Mutex);
+       }
+       #endif
+}
+
+int SyscallServer(void)
+{
+       struct sockaddr_in      server;
+       
+       #ifdef __WIN32__
+       /* Open windows connection */
+       if (WSAStartup(0x0101, &gWinsock) != 0)
+       {
+               fprintf(stderr, "Could not open Windows connection.\n");
+               exit(0);
+       }
+       #endif
+       
+       #if USE_TCP
+       // Open TCP Connection
+       gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       #else
+       // Open UDP Connection
+       gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       #endif
+       if (gSocket == INVALID_SOCKET)
+       {
+               fprintf(stderr, "Could not create socket.\n");
+               #if __WIN32__
+               WSACleanup();
+               #endif
+               exit(0);
+       }
+       
+       // Set server address
+       memset(&server, 0, sizeof(struct sockaddr_in));
+       server.sin_family = AF_INET;
+       server.sin_port = htons(SERVER_PORT);
+       server.sin_addr.s_addr = htonl(INADDR_ANY);
+       
+       // Bind
+       if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
+       {
+               fprintf(stderr, "Cannot bind address to socket.\n");
+               perror("SyscallServer - bind");
+               #if __WIN32__
+               closesocket(gSocket);
+               WSACleanup();
+               #else
+               close(gSocket);
+               #endif
+               exit(0);
+       }
+       
+       #if USE_TCP
+       listen(gSocket, 5);
+       #endif
+       
+       Log_Notice("Syscall", "Listening on 0.0.0.0:%i\n", SERVER_PORT);
+       
+       // 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);
+               if( clientSock < 0 ) {
+                       perror("SyscallServer - accept");
+                       break ;
+               }
+               
+               printf("Client connection %x:%i",
+                       ntohl(client.sin_addr), ntohs(client.sin_port)
+                       );
+               
+               #else
+               char    data[BUFSIZ];
+               tRequestHeader  *req = (void*)data;
+               struct sockaddr_in      addr;
+               uint    clientSize = sizeof(addr);
+                int    length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
+               tClient *client;
+               
+               if( length == -1 ) {
+                       perror("SyscallServer - recv");
+                       break;
+               }
+               
+               // Hand off to a worker thread
+               // - TODO: Actually have worker threads
+               printf("%i bytes from %x:%i\n", length,
+                       ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
+               
+               client = Server_GetClient(req->ClientID);
+               if( req->ClientID == 0 )
+               {
+                       memcpy(&client->ClientAddr, &addr, sizeof(addr));
+               }
+               else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
+               {
+                       printf("ClientID %i used by %x:%i\n",
+                               client->ClientID, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
+                       printf(" actually owned by %x:%i\n",
+                               ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
+                       continue;
+               }
+               
+               if( client->CurrentRequest ) {
+                       printf("Worker thread for %x:%i is busy\n",
+                               ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
+                       continue;
+               }
+               
+               client->CurrentRequest = req;
+               SDL_CondSignal(client->WaitFlag);
+               #endif
+       }
+       
+       return -1;
+}
index 7e8d1ec..85a8232 100644 (file)
@@ -42,7 +42,7 @@ int Syscall_Null(const char *Format, void *Args)
        return 0;
 }
 
-SYSCALL2(Syscall_Open, VFS_Open, "di", const char *, int);
+SYSCALL2(Syscall_Open, VFS_Open, "si", const char *, int);
 SYSCALL1V(Syscall_Close, VFS_Close, "i", int);
 SYSCALL3(Syscall_Read, VFS_Read, "iid", int, int, void *);
 SYSCALL3(Syscall_Write, VFS_Write, "iid", int, int, const void *);
@@ -59,13 +59,18 @@ const int   ciNumSyscalls = sizeof(caSyscalls)/sizeof(caSyscalls[0]);
 /**
  * \brief Recieve a syscall structure from the server code
  */
-tRequestHeader *SyscallRecieve(tRequestHeader *Request)
+tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength)
 {
        char    formatString[Request->NParams+1];
-       char    *inData = (char*)&Request->Params[Request->NParams+Request->NReturn];
+       char    *inData = (char*)&Request->Params[Request->NParams];
         int    argListLen = 0;
         int    i, retVal;
+       tRequestHeader  *ret;
+        int    retValueCount = 1;
+        int    retDataLen = sizeof(Uint64);
+       void    *mallocdData[Request->NParams];
        
+       // Sanity check
        if( Request->CallID > ciNumSyscalls ) {
                return NULL;
        }
@@ -90,6 +95,10 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request)
                        formatString[i] = 'd';
                        argListLen += sizeof(void*);
                        break;
+               case ARG_TYPE_STRING:
+                       formatString[i] = 's';
+                       argListLen += sizeof(char*);
+                       break;
                default:
                        return NULL;    // ERROR!
                }
@@ -115,11 +124,36 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request)
                                argListLen += sizeof(Uint64);
                                inData += sizeof(Uint64);
                                break;
-                       case ARG_TYPE_DATA:
                        case ARG_TYPE_STRING:
                                *(void**)&argListData[argListLen] = *(void**)inData;
                                argListLen += sizeof(void*);
-                               inData += sizeof(void*);
+                               inData += Request->Params[i].Length;
+                               break;
+                       
+                       // Data gets special handling, because only it can be returned to the user
+                       // (ARG_TYPE_DATA is a pointer)
+                       case ARG_TYPE_DATA:
+                               // Prepare the return values
+                               if( Request->Params[i].Flags & ARG_FLAG_RETURN )
+                               {
+                                       retDataLen += Request->Params[i].Length;
+                                       retValueCount ++;
+                               }
+                               
+                               // Check for non-resident data
+                               if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
+                               {
+                                       // Allocate and zero the buffer
+                                       mallocdData[i] = calloc(1, Request->Params[i].Length);
+                                       *(void**)&argListData[argListLen] = mallocdData[i];
+                                       argListLen += sizeof(void*);
+                               }
+                               else
+                               {
+                                       *(void**)&argListData[argListLen] = (void*)inData;
+                                       argListLen += sizeof(void*);
+                                       inData += Request->Params[i].Length;
+                               }
                                break;
                        }
                }
@@ -127,5 +161,35 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request)
                retVal = caSyscalls[Request->CallID](formatString, argListData);
        }
        
-       return NULL;
+       // Allocate the return
+       ret = malloc(sizeof(tRequestHeader) + retValueCount * sizeof(tRequestValue)
+               + retDataLen);
+       ret->ClientID = Request->ClientID;
+       ret->CallID = Request->CallID;
+       ret->NParams = retValueCount;
+       inData = &ret->Params[ ret->NParams ];
+       
+       // Static Uint64 return value
+       ret->Params[0].Type = ARG_TYPE_INT64;
+       ret->Params[0].Flags = 0;
+       ret->Params[0].Length = sizeof(Uint64);
+       *(Uint64*)inData = retVal;
+       inData += sizeof(Uint64);
+       
+       for( i = 0; i < Request->NParams; i ++ )
+       {
+               if( Request->Params[i].Type != ARG_TYPE_DATA )  continue;
+               if( !(Request->Params[i].Flags & ARG_FLAG_RETURN) )     continue;
+               
+               ret->Params[1 + i].Type = Request->Params[i].Type;
+               ret->Params[1 + i].Flags = 0;
+               ret->Params[1 + i].Length = Request->Params[i].Length;
+               
+               memcpy(inData, mallocdData[i], Request->Params[i].Length);
+               inData += Request->Params[i].Length;
+               
+               free( mallocdData[i] ); // Free temp buffer from above
+       }
+       
+       return ret;
 }
index 1fff68e..3bef3d3 100644 (file)
@@ -114,11 +114,14 @@ int _InitSyscalls()
                req.ClientID = 0;
                req.CallID = 0;
                req.NParams = 0;
-               req.NReturn = 0;
                
                SendData(&req, sizeof(req));
                
                len = ReadData(&req, sizeof(req), 5);
+               if( len == 0 ) {
+                       fprintf(stderr, "Unable to connect to server (localhost:%i)\n", SERVER_PORT);
+                       exit(-1);
+               }
                
                giSyscall_ClientID = req.ClientID;
        }
@@ -127,81 +130,21 @@ int _InitSyscalls()
        return 0;
 }
 
-int SendRequest(int RequestID, int NumOutput, tOutValue **Output, int NumInput, tInValue **Input)
+int SendRequest(tRequestHeader *Request, int RequestSize)
 {
-       tRequestHeader  *request;
-       tRequestValue   *value;
-       char    *data;
-        int    requestLen;
-        int    i;
-       
        if( gSocket == INVALID_SOCKET )
        {
                _InitSyscalls();                
        }
        
-       // See ../syscalls.h for details of request format
-       requestLen = sizeof(tRequestHeader) + (NumOutput + NumInput) * sizeof(tRequestValue);
-       
-       // Get total param length
-       for( i = 0; i < NumOutput; i ++ )
-               requestLen += Output[i]->Length;
-       
-       // Allocate request
-       request = malloc( requestLen );
-       value = request->Params;
-       data = (char*)&request->Params[ NumOutput + NumInput ];
-       
        // Set header
-       request->ClientID = giSyscall_ClientID;
-       request->CallID = RequestID;    // Syscall
-       request->NParams = NumOutput;
-       request->NReturn = NumInput;
+       Request->ClientID = giSyscall_ClientID;
        
-       // Set parameters
-       for( i = 0; i < NumOutput; i ++ )
-       {
-               switch(Output[i]->Type)
-               {
-               case 'i':       value->Type = ARG_TYPE_INT32;   break;
-               case 'I':       value->Type = ARG_TYPE_INT64;   break;
-               case 'd':       value->Type = ARG_TYPE_DATA;    break;
-               case 's':       value->Type = ARG_TYPE_DATA;    break;
-               default:
-                       fprintf(stderr, __FILE__" SendRequest: Unknown output type '%c'\n",
-                               Output[i]->Type);
-                       return -1;
-               }
-               value->Length = Output[i]->Length;
-               
-               memcpy(data, Output[i]->Data, Output[i]->Length);
-               
-               value ++;
-               data += Output[i]->Length;
-       }
-       
-       // Set return values
-       for( i = 0; i < NumInput; i ++ )
-       {
-               switch(Input[i]->Type)
-               {
-               case 'i':       value->Type = ARG_TYPE_INT32;   break;
-               case 'I':       value->Type = ARG_TYPE_INT64;   break;
-               case 'd':       value->Type = ARG_TYPE_DATA;    break;
-               default:
-                       fprintf(stderr, " SendRequest: Unknown input type '%c'\n",
-                               Input[i]->Type);
-                       return -1;
-               }
-               value->Length = Input[i]->Length;
-               value ++;
-       }
        #if 0
-       printf("value = %p\n", value);
        {
-               for(i=0;i<requestLen;i++)
+               for(i=0;i<RequestSize;i++)
                {
-                       printf("%02x ", ((uint8_t*)request)[i]);
+                       printf("%02x ", ((uint8_t*)Request)[i]);
                        if( i % 16 == 15 )      printf("\n");
                }
                printf("\n");
@@ -209,24 +152,10 @@ int SendRequest(int RequestID, int NumOutput, tOutValue **Output, int NumInput,
        #endif
        
        // Send it off
-       SendData(request, requestLen);
+       SendData(Request, RequestSize);
        
        // Wait for a response (no timeout)
-       requestLen = ReadData(request, requestLen, -1);
-       
-       // Parse response out
-       if( request->NParams != NumInput ) {
-               fprintf(stderr, "SendRequest: Unexpected number of values retured (%i, exp %i)\n",
-                       request->NParams, NumInput
-                       );
-               free( request );
-               return -1;
-       }
-       
-       // Free memory
-       free( request );
-       
-       return 0;
+       return ReadData(Request, RequestSize, -1);
 }
 
 void SendData(void *Data, int Length)
index 8c89e6f..b33a80f 100644 (file)
@@ -8,19 +8,8 @@
 #ifndef _REQUEST_H_
 #define _REQUEST_H_
 
-typedef struct {
-       char    Type;
-        int    Length;
-       char    Data[];
-}      tOutValue;
+#include "../syscalls.h"
 
-typedef struct {
-       char    Type;
-        int    Length;
-       void    *Data;
-}      tInValue;
-
-extern int SendRequest(int RequestID, int NumOutput, tOutValue **Output,
-       int NumInput, tInValue **Input);
+extern int     SendRequest(tRequestHeader *Request, int RequestSize);
 
 #endif
index 9bdde9b..50352f8 100644 (file)
 // === IMPORTS ===
 
 // === CODE ===
-const char *ReadEntry(tOutValue **OutDest, tInValue **InDest,
-       int *Direction, const char *ArgTypes, va_list Args)
+const char *ReadEntry(tRequestValue *Dest, void *DataDest, void **PtrDest, const char *ArgTypes, va_list Args)
 {
-       uint64_t        val64, *ptr64;
-       uint32_t        val32, *ptr32;
+       uint64_t        val64;
+       uint32_t        val32;
         int    direction = 0;  // 0: Invalid, 1: Out, 2: In, 3: Out
        char    *str;
         int    len;
@@ -31,11 +30,10 @@ const char *ReadEntry(tOutValue **OutDest, tInValue **InDest,
        // Get direction
        switch(*ArgTypes)
        {
+       default:        // Defaults to output
        case '>':       direction = 1;  break;
        case '<':       direction = 2;  break;
        case '?':       direction = 3;  break;
-       default:
-               return NULL;
        }
        ArgTypes ++;
        
@@ -43,99 +41,90 @@ const char *ReadEntry(tOutValue **OutDest, tInValue **InDest,
        while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
        if( *ArgTypes == '\0' ) return ArgTypes;
        
-       // Internal helper macro
-       #define MAKE_OUT(_dest,_typeChar,_typeName,_value) do{if((_dest)){\
-               *(_dest) = (tOutValue*)malloc(sizeof(tOutValue)+sizeof(_typeName));\
-               (*(_dest))->Type=(_typeChar);(*(_dest))->Length=sizeof(_typeName);\
-               *(_typeName*)((*(_dest))->Data) = (_value);\
-               }}while(0)
-       #define MAKE_IN(_dest,_typeChar,_typeName,_value) do{if((_dest)){\
-               *(_dest) = (tInValue*)malloc(sizeof(tInValue));\
-               (*(_dest))->Type=(_typeChar);(*(_dest))->Length=sizeof(_typeName);\
-               (*(_dest))->Data = (_value);\
-               }}while(0)
-       
        // Get type
        switch(*ArgTypes)
        {
-       case 'i':       // 32-bit integer
-               // Input?
-               if( direction & 2 )
-               {
-                       ptr32 = va_arg(Args, uint32_t*);
-                       MAKE_IN(InDest, 'i', uint32_t*, ptr32);
-                       if( direction & 1 )
-                               MAKE_OUT(OutDest, 'i', uint32_t, *ptr32);
-               }
-               else
-               {
-                       val32 = va_arg(Args, uint32_t);
-                       MAKE_OUT(OutDest, 'i', uint32_t, val32);
+       // 32-bit integer
+       case 'i':
+               
+               if( direction != 1 ) {
+                       fprintf(stderr, "ReadEntry: Recieving an integer is not defined\n");
+                       return NULL;
                }
+               
+               val32 = va_arg(Args, uint32_t);
+               
+               Dest->Type = ARG_TYPE_INT32;
+               Dest->Length = sizeof(uint32_t);
+               Dest->Flags = 0;
+               
+               if( DataDest )
+                       *(uint32_t*)DataDest = val32;
                break;
-       case 'I':       // 64-bit integer
-               // Input?
-               if( direction & 2 )
-               {
-                       ptr64 = va_arg(Args, uint64_t*);
-                       MAKE_IN(InDest, 'I', uint64_t*, ptr64);
-                       if( direction & 1 )
-                               MAKE_OUT(OutDest, 'I', uint64_t, *ptr64);
-               }
-               else
-               {
-                       val64 = va_arg(Args, uint64_t);
-                       MAKE_OUT(OutDest, 'I', uint64_t, val64);
+       // 64-bit integer
+       case 'I':
+               
+               if( direction != 1 ) {
+                       fprintf(stderr, "ReadEntry: Recieving an integer is not defined\n");
+                       return NULL;
                }
+               
+               val64 = va_arg(Args, uint64_t);
+               
+               Dest->Type = ARG_TYPE_INT64;
+               Dest->Length = sizeof(uint64_t);
+               Dest->Flags = 0;
+               if( DataDest )
+                       *(uint64_t*)DataDest = val64;
                break;
+       // String
        case 's':
                // Input string makes no sense!
-               if( direction & 2 ) {
-                       fprintf(stderr, "ReadEntry: Incoming string is not defined\n");
+               if( direction != 1 ) {
+                       fprintf(stderr, "ReadEntry: Recieving a string is not defined\n");
                        return NULL;
                }
                
                str = va_arg(Args, char*);
-               if( OutDest )
+               
+               Dest->Type = ARG_TYPE_STRING;
+               Dest->Length = strlen(str) + 1;
+               Dest->Flags = 0;
+               
+               if( DataDest )
                {
-                        int    len = strlen(str) + 1;
-                       *OutDest = malloc( sizeof(tOutValue) + len );
-                       (*OutDest)->Type = 's';
-                       (*OutDest)->Length = len;
-                       memcpy((*OutDest)->Data, str, len);
+                       memcpy(DataDest, str, Dest->Length);
                }
                break;
-       
+       // Data (special handling)
        case 'd':
                len = va_arg(Args, int);
                str = va_arg(Args, char*);
                
-               // Input ?
-               if( (direction & 2) && InDest )
-               {
-                       *InDest = (tInValue*)malloc( sizeof(tInValue) );
-                       (*InDest)->Type = 'd';
-                       (*InDest)->Length = len;
-                       (*InDest)->Data = str;
-               }
+               // Save the pointer for later
+               if( PtrDest )   *PtrDest = str;
+               
+               // Create parameter block
+               Dest->Type = ARG_TYPE_INT64;
+               Dest->Length = sizeof(uint64_t);
+               Dest->Flags = 0;
+               if( direction & 2 )
+                       Dest->Flags |= ARG_FLAG_RETURN;
                
-               // Output ?
-               if( (direction & 1) && InDest )
+               // Has data?
+               if( direction & 1 )
                {
-                       *OutDest = (tOutValue*)malloc( sizeof(tOutValue) + len );
-                       (*OutDest)->Type = 'd';
-                       (*OutDest)->Length = len;
-                       memcpy((*OutDest)->Data, str, len);
+                       if( DataDest )
+                               memcpy(DataDest, str, len);
                }
+               else
+                       Dest->Flags |= ARG_FLAG_ZEROED;
                break;
        
        default:
                return NULL;
        }
        ArgTypes ++;
-       #undef MAKE_ASSIGN
-       
-       *Direction = direction;
        
        return ArgTypes;
 }
@@ -153,82 +142,118 @@ const char *ReadEntry(tOutValue **OutDest, tInValue **InDest,
  * ?d:  Bi-directional buffer (Preceded by valid size), buffer contents
  *      are returned
  */
-void _Syscall(int SyscallID, const char *ArgTypes, ...)
+uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...)
 {
        va_list args;
-        int    outCount;
-        int    inCount;
+        int    paramCount, dataLength;
+        int    retCount = 1, retLength = sizeof(uint64_t);
+       void    **retPtrs;      // Pointers to return buffers
        const char      *str;
-       tOutValue       **output;
-       tInValue        **input;
+       tRequestHeader  *req;
+       void    *dataPtr;
+       uint64_t        retValue;
+        int    i;
        
        // Get data size
        va_start(args, ArgTypes);
        str = ArgTypes;
-       outCount = 0;
-       inCount = 0;
+       paramCount = 0;
+       dataLength = 0;
        while(*str)
        {
-                int    dir;
+               tRequestValue   tmpVal;
                
-               str = ReadEntry(NULL, NULL, &dir, str, args);
+               str = ReadEntry(&tmpVal, NULL, NULL, str, args);
                if( !str ) {
                        fprintf(stderr, "syscalls.c: ReadEntry failed (SyscallID = %i)\n", SyscallID);
                        exit(127);
                }
+               paramCount ++;
+               if( !(tmpVal.Flags & ARG_FLAG_ZEROED) )
+                       dataLength += tmpVal.Length;
                
-               // Out!
-               if( dir & 1 )   outCount ++;
-               
-               // and.. In!
-               if( dir & 2 )   inCount ++;
+               if( tmpVal.Flags & ARG_FLAG_RETURN ) {
+                       retLength += tmpVal.Length;
+                       retCount ++;
+               }
        }
        va_end(args);
        
+       dataLength += sizeof(tRequestHeader) + paramCount*sizeof(tRequestValue);
+       retLength += sizeof(tRequestHeader) + retCount*sizeof(tRequestValue);
+       
        // Allocate buffers
-       output = malloc( outCount*sizeof(tOutValue*) );
-       input = malloc( inCount*sizeof(tInValue*) );
+       retPtrs = malloc( sizeof(void*) * (retCount+1) );
+       if( dataLength > retLength)
+               req = malloc( dataLength );
+       else
+               req = malloc( retLength );
+       req->ClientID = 0;      //< Filled later
+       req->CallID = SyscallID;
+       req->NParams = paramCount;
+       dataPtr = &req->Params[paramCount];
        
        // Fill `output` and `input`
        va_start(args, ArgTypes);
        str = ArgTypes;
        // - re-zero so they can be used as indicies
-       outCount = 0;
-       inCount = 0;
+       paramCount = 0;
+       retCount = 0;
        while(*str)
-       {
-               tOutValue       *outParam;
-               tInValue        *inParam;
-                int    dir;
-               
-               str = ReadEntry(&outParam, &inParam, &dir, str, args);
+       {               
+               str = ReadEntry(&req->Params[paramCount], dataPtr, &retPtrs[retCount], str, args);
                if( !str )      break;
                
-               if( dir & 1 )
-                       output[outCount++] = outParam;
-               if( dir & 2 )
-                       input[inCount++] = inParam;
+               if( !(req->Params[paramCount].Flags & ARG_FLAG_ZEROED) )
+                       dataPtr += req->Params[paramCount].Length;
+               if( req->Params[paramCount].Flags & ARG_FLAG_RETURN )
+                       retCount ++;
+               
+               paramCount ++;
        }
        va_end(args);
        
        // Send syscall request
-       if( SendRequest(SyscallID, outCount, output, inCount, input) ) {
+       if( SendRequest(req, dataLength) ) {
                fprintf(stderr, "syscalls.c: SendRequest failed (SyscallID = %i)\n", SyscallID);
                exit(127);
        }
        
-       // Clean up
-       while(outCount--)       free(output[outCount]);
-       free(output);
-       while(inCount--)        free(input[inCount]);
-       free(input);
+       // Parse return value
+       dataPtr = &req->Params[req->NParams];
+       retValue = 0;
+       if( req->NParams > 1 )
+       {
+               switch(req->Params[0].Type)
+               {
+               case ARG_TYPE_INT64:
+                       retValue = *(uint64_t*)dataPtr;
+                       dataPtr += req->Params[0].Length;
+                       break;
+               case ARG_TYPE_INT32:
+                       retValue = *(uint32_t*)dataPtr;
+                       dataPtr += req->Params[0].Length;
+                       break;
+               }       
+       }
+       
+       // Write changes to buffers
+       va_start(args, ArgTypes);
+       for( i = 1; i < req->NParams; i ++ )
+       {
+               memcpy( retPtrs[i-1], dataPtr, req->Params[i].Length );
+               dataPtr += req->Params[i].Length;
+       }
+       va_end(args);
+       
+       free( req );
+       
+       return 0;
 }
 
 // --- VFS Calls
 int open(const char *Path, int Flags) {
-        int    ret = 0;
-       _Syscall(SYS_OPEN, "<i >s >i", &ret, Path, Flags);
-       return ret;
+       return _Syscall(SYS_OPEN, ">s >i", Path, Flags);
 }
 
 void close(int FD) {
@@ -236,27 +261,19 @@ void close(int FD) {
 }
 
 size_t read(int FD, size_t Bytes, void *Dest) {
-        int    ret = 0;
-       _Syscall(SYS_READ, "<i >i >i <d", &ret, FD, Bytes, Bytes, Dest);
-       return ret;
+       return _Syscall(SYS_READ, "<i >i >i <d", FD, Bytes, Bytes, Dest);
 }
 
 size_t write(int FD, size_t Bytes, void *Src) {
-        int    ret = 0;
-       _Syscall(SYS_WRITE, "<i >i >i >d", &ret, FD, Bytes, Bytes, Src);
-       return ret;
+       return _Syscall(SYS_WRITE, ">i >i >d", FD, Bytes, Bytes, Src);
 }
 
 int seek(int FD, int64_t Ofs, int Dir) {
-        int    ret = 0;
-       _Syscall(SYS_SEEK, "<i >i >I >i", &ret, FD, Ofs, Dir);
-       return ret;
+       return _Syscall(SYS_SEEK, ">i >I >i", FD, Ofs, Dir);
 }
 
 uint64_t tell(int FD) {
-       uint64_t        ret;
-       _Syscall(SYS_TELL, "<I >i", &ret, FD);
-       return ret;
+       return _Syscall(SYS_TELL, ">i", FD);
 }
 
 int ioctl(int fd, int id, void *data) {
index 903cbfa..4a64474 100644 (file)
@@ -17,6 +17,7 @@
 typedef struct sRequestValue {
        /// \see eArgumentTypes
        uint16_t        Type;
+        uint8_t        Flags;
        uint16_t        Length;
 }      tRequestValue;
 
@@ -24,7 +25,6 @@ typedef struct sRequestHeader {
        uint16_t        ClientID;
        uint16_t        CallID; //!< \see eSyscalls
        uint16_t        NParams;
-       uint16_t        NReturn;
        
        tRequestValue   Params[];
 }      tRequestHeader;
@@ -53,5 +53,9 @@ enum eArgumentTypes {
        ARG_TYPE_STRING,
        ARG_TYPE_DATA
 };
+enum eArgumentFlags {
+       ARG_FLAG_RETURN = 0x40, // Pass back in the return message
+       ARG_FLAG_ZEROED = 0x80  // Not present in the message, just fill with zero
+};
 
 #endif

UCC git Repository :: git.ucc.asn.au