3 * - Acess kernel emulation on another OS using SDL and UDP
12 # define _WIN32_WINNT 0x0501
14 # include <winsock2.h>
15 # include <ws2tcpip.h>
16 # define close(fd) closesocket(fd)
17 typedef int socklen_t;
20 # include <sys/socket.h>
21 # include <netinet/in.h>
22 # include <netdb.h> // getaddrinfo
24 #define DONT_INCLUDE_SYSCALL_NAMES
25 #include "../syscalls.h"
26 #include <logdebug.h> // acess but std
30 #define MAX_CLIENTS 16
35 SDL_Thread *WorkerThread;
39 tRequestHeader *CurrentRequest;
40 struct sockaddr_in ClientAddr;
47 extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength);
48 extern int Threads_CreateRootProcess(void);
49 extern void Threads_SetThread(int TID);
50 extern void *Threads_GetThread(int TID);
51 extern void Threads_PostEvent(void *Thread, uint32_t Event);
54 tClient *Server_GetClient(int ClientID);
55 int Server_WorkerThread(void *ClientPtr);
56 int SyscallServer(void);
57 int Server_ListenThread(void *Unused);
62 SOCKET gSocket = INVALID_SOCKET;
64 # define INVALID_SOCKET -1
65 int gSocket = INVALID_SOCKET;
67 tClient gaServer_Clients[MAX_CLIENTS];
68 SDL_Thread *gpServer_ListenThread;
71 int Server_GetClientID(void)
74 Uint32 thisId = SDL_ThreadID();
76 for( i = 0; i < MAX_CLIENTS; i ++ )
78 if( SDL_GetThreadID(gaServer_Clients[i].WorkerThread) == thisId )
79 return gaServer_Clients[i].ClientID;
82 fprintf(stderr, "ERROR: Server_GetClientID - Thread is not allocated\n");
87 tClient *Server_GetClient(int ClientID)
92 // Allocate an ID if needed
94 ClientID = Threads_CreateRootProcess();
96 for( i = 0; i < MAX_CLIENTS; i ++ )
98 if( gaServer_Clients[i].ClientID == ClientID ) {
99 return &gaServer_Clients[i];
101 if(!ret && gaServer_Clients[i].ClientID == 0)
102 ret = &gaServer_Clients[i];
105 // Uh oh, no free slots
106 // TODO: Dynamic allocation
110 // Allocate a thread for the process
111 ret->ClientID = ClientID;
115 ret->CurrentRequest = NULL;
118 if( !ret->WorkerThread ) {
121 ret->WaitFlag = SDL_CreateCond();
122 ret->Mutex = SDL_CreateMutex();
123 SDL_mutexP( ret->Mutex );
125 Log_Debug("Server", "Creating worker for %p", ret);
126 ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
132 int Server_WorkerThread(void *ClientPtr)
134 tClient *Client = ClientPtr;
136 Log_Debug("Server", "Worker %p", ClientPtr);
139 while( *((volatile typeof(Client->Socket)*)&Client->Socket) == 0 )
141 Threads_SetThread( Client->ClientID );
143 while( Client->ClientID != -1 )
146 int nfd = Client->Socket+1;
148 FD_SET(Client->Socket, &fds);
150 int rv = select(nfd, &fds, NULL, NULL, NULL); // TODO: Timeouts?
155 // Log_Debug("Server", "%p: rv=%i", Client, rv);
157 if( FD_ISSET(Client->Socket, &fds) )
159 const int ciMaxParamCount = 6;
160 char lbuf[sizeof(tRequestHeader) + ciMaxParamCount*sizeof(tRequestValue)];
161 tRequestHeader *hdr = (void*)lbuf;
162 size_t len = recv(Client->Socket, (void*)hdr, sizeof(*hdr), 0);
163 // Log_Debug("Server", "%i bytes of header", len);
165 Log_Notice("Server", "Zero RX on %i (worker %p)", Client->Socket, Client);
169 perror("recv header");
170 // Log_Warning("Server", "recv() error - %s", strerror(errno));
173 if( len != sizeof(*hdr) ) {
175 Log_Warning("Server", "FD%i bad sized (%i != exp %i)",
176 Client->Socket, len, sizeof(*hdr));
180 if( hdr->NParams > ciMaxParamCount ) {
182 Log_Warning("Server", "FD%i too many params (%i > max %i)",
183 Client->Socket, hdr->NParams, ciMaxParamCount);
187 if( hdr->NParams > 0 )
189 len = recv(Client->Socket, (void*)hdr->Params, hdr->NParams*sizeof(tRequestValue), 0);
190 // Log_Debug("Server", "%i bytes of params", len);
191 if( len != hdr->NParams*sizeof(tRequestValue) ) {
193 perror("recv params");
194 Log_Warning("Sever", "Recieving params failed");
200 // Log_Debug("Server", "No params?");
204 size_t hdrsize = sizeof(tRequestHeader) + hdr->NParams*sizeof(tRequestValue);
205 size_t bufsize = hdrsize;
207 for( i = 0; i < hdr->NParams; i ++ )
209 if( hdr->Params[i].Flags & ARG_FLAG_ZEROED )
212 bufsize += hdr->Params[i].Length;
216 // Allocate full buffer
217 hdr = malloc(bufsize);
218 memcpy(hdr, lbuf, hdrsize);
219 if( bufsize > hdrsize )
221 size_t rem = bufsize - hdrsize;
222 char *ptr = (void*)( hdr->Params + hdr->NParams );
225 len = recv(Client->Socket, ptr, rem, 0);
226 // Log_Debug("Server", "%i bytes of data", len);
230 Log_Warning("Sever", "Recieving data failed");
241 // Log_Debug("Server", "no data");
244 tRequestHeader *retHeader;
245 retHeader = SyscallRecieve(hdr, &retlen);
247 // Some sort of error
248 Log_Warning("Server", "SyscallRecieve failed?");
252 send(Client->Socket, (void*)retHeader, retlen, 0);
259 tRequestHeader *retHeader;
260 tRequestHeader errorHeader;
263 int cur_client_id = 0;
264 while( Client->ClientID != -1 )
266 // Wait for something to do
267 if( Client->CurrentRequest == NULL )
268 SDL_CondWait(Client->WaitFlag, Client->Mutex);
269 if( Client->CurrentRequest == NULL )
272 // Log_Debug("AcessSrv", "Worker got message %p", Client->CurrentRequest);
274 if(Client->ClientID != cur_client_id) {
275 // Log_Debug("AcessSrv", "Client thread ID changed from %i to %i",
276 // cur_client_id, Client->ClientID);
277 Threads_SetThread( Client->ClientID );
278 cur_client_id = Client->ClientID;
283 int callid = Client->CurrentRequest->CallID;
284 Log_Debug("AcessSrv", "Client %i request %i %s",
285 Client->ClientID, callid,
286 callid < N_SYSCALLS ? casSYSCALL_NAMES[callid] : "UNK"
291 retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
294 // Return an error to the client
295 printf("ERROR: SyscallRecieve failed\n");
296 errorHeader.CallID = Client->CurrentRequest->CallID;
297 errorHeader.NParams = 0;
298 retHeader = &errorHeader;
299 retSize = sizeof(errorHeader);
303 retHeader->ClientID = Client->ClientID;
305 // Mark the thread as ready for another job
306 free(Client->CurrentRequest);
307 Client->CurrentRequest = 0;
309 // Log_Debug("AcessSrv", "Sending %i to %x:%i (Client %i)",
310 // retSize, ntohl(Client->ClientAddr.sin_addr.s_addr),
311 // ntohs(Client->ClientAddr.sin_port),
316 sentSize = sendto(gSocket, retHeader, retSize, 0,
317 (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
319 if( sentSize != retSize ) {
320 perror("Server_WorkerThread - send");
323 // Free allocated header
324 if( retHeader != &errorHeader )
328 Log_Notice("Server", "Terminated Worker %p", ClientPtr);
332 int SyscallServer(void)
334 struct sockaddr_in server;
337 /* Open windows connection */
338 if (WSAStartup(0x0101, &gWinsock) != 0)
340 fprintf(stderr, "Could not open Windows connection.\n");
346 // Open TCP Connection
347 gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
349 // Open UDP Connection
350 gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
352 if (gSocket == INVALID_SOCKET)
354 fprintf(stderr, "Could not create socket.\n");
361 // Set server address
362 memset(&server, 0, sizeof(struct sockaddr_in));
363 server.sin_family = AF_INET;
364 server.sin_port = htons(SERVER_PORT);
365 server.sin_addr.s_addr = htonl(INADDR_ANY);
368 if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
370 fprintf(stderr, "Cannot bind address to socket.\n");
371 perror("SyscallServer - bind");
373 closesocket(gSocket);
385 Log_Notice("AcessSrv", "Listening on 0.0.0.0:%i", SERVER_PORT);
386 gpServer_ListenThread = SDL_CreateThread( Server_ListenThread, NULL );
390 int Server_Shutdown(void)
393 for( int i = 0; i < MAX_CLIENTS; i ++ )
395 if( gaServer_Clients[i].ClientID == 0 )
397 Threads_PostEvent( Threads_GetThread(gaServer_Clients[i].ClientID), 0 );
398 gaServer_Clients[i].ClientID = -1;
400 close(gaServer_Clients[i].Socket);
402 SDL_CondSignal(gaServer_Clients[i].WaitFlag);
408 int Server_ListenThread(void *Unused)
410 // Wait for something to do :)
414 struct sockaddr_in clientaddr;
415 socklen_t clientSize = sizeof(clientaddr);
416 int clientSock = accept(gSocket, (struct sockaddr*)&clientaddr, &clientSize);
417 if( clientSock < 0 ) {
418 perror("SyscallServer - accept");
422 char addrstr[4*8+8+1];
423 getnameinfo((struct sockaddr*)&clientaddr, sizeof(clientaddr),
424 addrstr, sizeof(addrstr), NULL, 0, NI_NUMERICHOST);
425 Log_Debug("Server", "Client connection %s:%i", addrstr, ntohs(clientaddr.sin_port));
429 tRequestAuthHdr authhdr;
430 len = recv(clientSock, (void*)&authhdr, sizeof(authhdr), 0);
431 if( len != sizeof(authhdr) ) {
432 // Some form of error?
433 Log_Warning("Server", "Client auth block bad size (%i != exp %i)",
434 len, sizeof(authhdr));
439 Log_Debug("Server", "Client assumed PID %i", authhdr.pid);
442 if( authhdr.pid == 0 ) {
443 // Allocate PID and client structure/thread
444 client = Server_GetClient(0);
445 client->Socket = clientSock;
446 authhdr.pid = client->ClientID;
449 // Get client structure and make sure it's unused
450 // - Auth token / verifcation?
451 client = Server_GetClient(authhdr.pid);
453 Log_Warning("Server", "Can't allocate a client struct for %s:%i",
454 addrstr, clientaddr.sin_port);
458 if( client->Socket != 0 ) {
459 Log_Warning("Server", "Client (%i)%p owned by FD%i but %s:%i tried to use it",
460 authhdr.pid, client, addrstr, clientaddr.sin_port);
465 client->Socket = clientSock;
468 Log_Debug("Server", "Client given PID %i - info %p", authhdr.pid, client);
470 len = send(clientSock, (void*)&authhdr, sizeof(authhdr), 0);
471 if( len != sizeof(authhdr) ) {
472 // Ok, this is an error
473 perror("Sending auth reply");
476 // All done, client thread should be watching now
480 tRequestHeader *req = (void*)data;
481 struct sockaddr_in addr;
482 uint clientSize = sizeof(addr);
486 length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
489 perror("SyscallServer - recv");
493 // Hand off to a worker thread
494 // - TODO: Actually have worker threads
495 // Log_Debug("Server", "%i bytes from %x:%i", length,
496 // ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
498 client = Server_GetClient(req->ClientID);
499 // NOTE: Hack - Should check if all zero
500 if( req->ClientID == 0 || client->ClientAddr.sin_port == 0 )
502 memcpy(&client->ClientAddr, &addr, sizeof(addr));
504 else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
506 printf("ClientID %i used by %x:%i\n",
507 client->ClientID, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
508 printf(" actually owned by %x:%i\n",
509 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
513 if( client->CurrentRequest ) {
514 printf("Worker thread for %x:%i is busy\n",
515 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
519 // Log_Debug("AcessSrv", "Message from Client %i (%p)",
520 // client->ClientID, client);
522 // Make a copy of the request data
523 req = malloc(length);
524 memcpy(req, data, length);
525 client->CurrentRequest = req;
526 SDL_CondSignal(client->WaitFlag);