3 * - Acess kernel emulation on another OS using SDL and UDP
13 # define _WIN32_WINNT 0x0501
15 # include <winsock2.h>
16 # include <ws2tcpip.h>
17 # define close(fd) closesocket(fd)
18 typedef int socklen_t;
21 # include <sys/socket.h>
22 # include <netinet/in.h>
23 # include <netdb.h> // getaddrinfo
25 #define DONT_INCLUDE_SYSCALL_NAMES
26 #include "../syscalls.h"
27 #include <logdebug.h> // acess but std
31 #define MAX_CLIENTS 16
36 SDL_Thread *WorkerThread;
37 tRequestHeader *CurrentRequest;
43 struct sockaddr_in ClientAddr;
48 // TODO: Move these to headers
49 extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, size_t *ReturnLength);
50 extern int Threads_CreateRootProcess(void);
51 extern void Threads_SetThread(int TID, void *ClientPtr);
52 extern void *Threads_GetThread(int TID);
53 extern void Threads_PostEvent(void *Thread, uint32_t Event);
54 extern void Threads_int_Terminate(void *Thread);
57 tClient *Server_GetClient(int ClientID);
58 int Server_WorkerThread(void *ClientPtr);
59 int SyscallServer(void);
60 int Server_ListenThread(void *Unused);
65 SOCKET gSocket = INVALID_SOCKET;
67 # define INVALID_SOCKET -1
68 int gSocket = INVALID_SOCKET;
70 tClient gaServer_Clients[MAX_CLIENTS];
71 SDL_Thread *gpServer_ListenThread;
74 int Server_GetClientID(void)
76 Uint32 thisId = SDL_ThreadID();
78 for( int i = 0; i < MAX_CLIENTS; i ++ )
80 if( SDL_GetThreadID(gaServer_Clients[i].WorkerThread) == thisId )
81 return gaServer_Clients[i].ClientID;
84 fprintf(stderr, "ERROR: Server_GetClientID - Thread is not allocated\n");
89 tClient *Server_GetClient(int ClientID)
93 // Allocate an ID if needed
95 ClientID = Threads_CreateRootProcess();
97 for( int i = 0; i < MAX_CLIENTS; i ++ )
99 if( gaServer_Clients[i].ClientID == ClientID ) {
100 return &gaServer_Clients[i];
102 if(!ret && gaServer_Clients[i].ClientID == 0)
103 ret = &gaServer_Clients[i];
106 // Uh oh, no free slots
107 // TODO: Dynamic allocation
109 Log_Error("Server", "Ran out of static client slots (%i)", MAX_CLIENTS);
113 // Allocate a thread for the process
114 ret->ClientID = ClientID;
115 ret->CurrentRequest = NULL;
120 if( !ret->WorkerThread ) {
121 Log_Debug("Server", "Creating worker for %p", ret);
122 ret->WaitFlag = SDL_CreateCond();
123 ret->Mutex = SDL_CreateMutex();
124 SDL_mutexP( ret->Mutex );
125 ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
131 int Server_WorkerThread(void *ClientPtr)
133 tClient *Client = ClientPtr;
135 Log_Debug("Server", "Worker %p active", ClientPtr);
137 tRequestHeader errorHeader;
139 int cur_client_id = 0;
140 while( Client->ClientID != 0 )
142 // Wait for something to do
143 if( Client->CurrentRequest == NULL )
144 SDL_CondWait(Client->WaitFlag, Client->Mutex);
145 if( Client->CurrentRequest == NULL )
148 if(Client->ClientID != cur_client_id) {
149 Threads_SetThread( Client->ClientID, Client );
150 cur_client_id = Client->ClientID;
154 tRequestHeader *retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
157 // Return an error to the client
158 printf("ERROR: SyscallRecieve failed\n");
159 errorHeader.CallID = Client->CurrentRequest->CallID;
160 errorHeader.NParams = 0;
161 retHeader = &errorHeader;
162 retSize = sizeof(errorHeader);
166 retHeader->ClientID = Client->ClientID;
168 // Mark the thread as ready for another job
169 free(Client->CurrentRequest);
170 Client->CurrentRequest = 0;
172 // If the thread is being terminated, don't send reply
173 if( Client->ClientID > 0 )
177 size_t sentSize = send(Client->Socket, retHeader, retSize, 0);
179 size_t sentSize = sendto(gSocket, retHeader, retSize, 0,
180 (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
183 if( sentSize != retSize ) {
184 perror("Server_WorkerThread - send");
188 // Free allocated header
189 if( retHeader != &errorHeader )
192 Log_Notice("Server", "Terminated Worker %p", ClientPtr);
196 int SyscallServer(void)
198 struct sockaddr_in server;
201 /* Open windows connection */
202 if (WSAStartup(0x0101, &gWinsock) != 0)
204 fprintf(stderr, "Could not open Windows connection.\n");
210 // Open TCP Connection
211 gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
213 // Open UDP Connection
214 gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
216 if (gSocket == INVALID_SOCKET)
218 fprintf(stderr, "Could not create socket.\n");
225 // Set server address
226 memset(&server, 0, sizeof(struct sockaddr_in));
227 server.sin_family = AF_INET;
228 server.sin_port = htons(SERVER_PORT);
229 server.sin_addr.s_addr = htonl(INADDR_ANY);
234 setsockopt(gSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
239 if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
241 fprintf(stderr, "Cannot bind address to socket.\n");
242 perror("SyscallServer - bind");
244 closesocket(gSocket);
256 Log_Notice("AcessSrv", "Listening on 0.0.0.0:%i", SERVER_PORT);
257 gpServer_ListenThread = SDL_CreateThread( Server_ListenThread, NULL );
261 int Server_Shutdown(void)
264 for( int i = 0; i < MAX_CLIENTS; i ++ )
266 if( gaServer_Clients[i].ClientID == 0 )
268 Threads_PostEvent( Threads_GetThread(gaServer_Clients[i].ClientID), 0 );
269 gaServer_Clients[i].ClientID = -1;
271 close(gaServer_Clients[i].Socket);
273 SDL_CondSignal(gaServer_Clients[i].WaitFlag);
280 int Server_int_HandleRx(tClient *Client)
282 const int ciMaxParamCount = 6;
283 char lbuf[sizeof(tRequestHeader) + ciMaxParamCount*sizeof(tRequestValue)];
284 tRequestHeader *hdr = (void*)lbuf;
285 size_t len = recv(Client->Socket, (void*)hdr, sizeof(*hdr), 0);
287 Log_Notice("Server", "Zero RX on %i (worker %p)", Client->Socket, Client);
291 perror("recv header");
294 if( len != sizeof(*hdr) ) {
296 Log_Warning("Server", "FD%i bad sized (%i != exp %i)",
297 Client->Socket, len, sizeof(*hdr));
301 if( hdr->NParams > ciMaxParamCount ) {
303 Log_Warning("Server", "FD%i too many params (%i > max %i)",
304 Client->Socket, hdr->NParams, ciMaxParamCount);
308 if( hdr->NParams > 0 )
310 len = recv(Client->Socket, (void*)hdr->Params, hdr->NParams*sizeof(tRequestValue), 0);
311 if( len != hdr->NParams*sizeof(tRequestValue) ) {
313 perror("recv params");
314 Log_Warning("Sever", "Recieving params failed");
320 //Log_Debug("Server", "No params?");
324 size_t hdrsize = sizeof(tRequestHeader) + hdr->NParams*sizeof(tRequestValue);
325 size_t bufsize = hdrsize;
326 for( int i = 0; i < hdr->NParams; i ++ )
328 if( hdr->Params[i].Flags & ARG_FLAG_ZEROED )
331 bufsize += hdr->Params[i].Length;
335 // Allocate full buffer
336 hdr = malloc(bufsize);
337 memcpy(hdr, lbuf, hdrsize);
338 if( bufsize > hdrsize )
340 size_t rem = bufsize - hdrsize;
341 char *ptr = (void*)( hdr->Params + hdr->NParams );
344 len = recv(Client->Socket, ptr, rem, 0);
348 Log_Warning("Sever", "Recieving data failed");
360 //Log_Debug("Server", "no data");
363 // Dispatch to worker
364 if( Client->CurrentRequest ) {
365 printf("Worker thread for client ID %i is busy\n", Client->ClientID);
370 Log_Debug("Server", "Message from Client %i (%p)", Client->ClientID, Client);
371 Client->CurrentRequest = hdr;
372 SDL_CondSignal(Client->WaitFlag);
377 int Server_int_HandshakeClient(int Socket, struct sockaddr_in *addr, socklen_t addr_size)
379 ENTER("iSocket paddr iaddr_size",
380 Socket, addr, addr_size);
381 unsigned short port = ntohs(addr->sin_port);
382 char addrstr[4*8+8+1];
383 getnameinfo((struct sockaddr*)addr, addr_size, addrstr, sizeof(addrstr), NULL, 0, NI_NUMERICHOST);
384 Log_Debug("Server", "Client connection %s:%i", addrstr, port);
387 tRequestAuthHdr authhdr;
388 size_t len = recv(Socket, &authhdr, sizeof(authhdr), 0);
389 if( len != sizeof(authhdr) ) {
390 // Some form of error?
391 Log_Warning("Server", "Client auth block bad size (%i != exp %i)",
392 len, sizeof(authhdr));
397 LOG("authhdr.pid = %i", authhdr.pid);
398 tClient *client = Server_GetClient(authhdr.pid);
399 if( authhdr.pid == 0 ) {
400 // Allocate PID and client structure/thread
401 client->Socket = Socket;
402 authhdr.pid = client->ClientID;
405 Log_Debug("Server", "Client assumed PID %i", authhdr.pid);
407 // Get client structure and make sure it's unused
408 // - Auth token / verifcation?
410 Log_Warning("Server", "Can't allocate a client struct for %s:%i",
415 if( client->Socket != 0 ) {
416 Log_Warning("Server", "Client (%i)%p owned by FD%i but %s:%i tried to use it",
417 authhdr.pid, client, addrstr, port);
422 client->Socket = Socket;
425 LOG("Sending auth reply");
426 len = send(Socket, (void*)&authhdr, sizeof(authhdr), 0);
427 if( len != sizeof(authhdr) ) {
428 // Ok, this is an error
429 perror("Sending auth reply");
434 // All done, client thread should be watching now
440 void Server_int_RemoveClient(tClient *Client)
442 // Trigger the thread to kill itself
443 Threads_int_Terminate( Threads_GetThread(Client->ClientID) );
444 Client->ClientID = 0;
445 close(Client->Socket);
450 int Server_ListenThread(void *Unused)
452 // Wait for something to do :)
459 FD_SET(gSocket, &fds);
461 for( int i = 0; i < MAX_CLIENTS; i ++ ) {
462 tClient *client = &gaServer_Clients[i];
463 if( client->ClientID == 0 )
465 FD_SET(client->Socket, &fds);
466 if(client->Socket > maxfd)
467 maxfd = client->Socket;
470 int rv = select(maxfd+1, &fds, NULL, NULL, NULL);
471 Log_Debug("Server", "Select rv = %i", rv);
477 // Incoming connection
478 if( FD_ISSET(gSocket, &fds) )
480 struct sockaddr_in clientaddr;
481 socklen_t clientSize = sizeof(clientaddr);
482 int clientSock = accept(gSocket, (struct sockaddr*)&clientaddr, &clientSize);
483 if( clientSock < 0 ) {
484 perror("SyscallServer - accept");
487 if( Server_int_HandshakeClient(clientSock, &clientaddr, clientSize) ) {
488 Log_Warning("Server", "Client handshake failed :(");
493 for( int i = 0; i < MAX_CLIENTS; i ++ )
495 tClient *client = &gaServer_Clients[i];
496 if( client->ClientID == 0 )
498 //Debug("Server_ListenThread: Idx %i ID %i FD %i",
499 // i, client->ClientID, client->Socket);
500 if( !FD_ISSET(client->Socket, &fds) )
503 if( Server_int_HandleRx( client ) )
505 Log_Warning("Server", "Client %p dropped, TODO: clean up", client);
506 Server_int_RemoveClient(client);
512 tRequestHeader *req = (void*)data;
513 struct sockaddr_in addr;
514 uint clientSize = sizeof(addr);
517 length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
520 perror("SyscallServer - recv");
525 // Log_Debug("Server", "%i bytes from %x:%i", length,
526 // ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
528 tClient *client = Server_GetClient(req->ClientID);
529 // NOTE: I should really check if the sin_addr is zero, but meh
530 // Shouldn't matter much
531 if( req->ClientID == 0 || client->ClientAddr.sin_port == 0 )
533 memcpy(&client->ClientAddr, &addr, sizeof(addr));
535 else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
537 printf("ClientID %i used by %x:%i\n",
538 client->ClientID, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
539 printf(" actually owned by %x:%i\n",
540 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
544 // Log_Debug("AcessSrv", "Message from Client %i (%p)",
545 // client->ClientID, client);
546 if( client->CurrentRequest ) {
547 printf("Worker thread for %x:%i is busy\n",
548 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
552 // Duplicate the data currently on the stack, and dispatch to worker
553 req = malloc(length);
554 memcpy(req, data, length);
555 client->CurrentRequest = req;
556 SDL_CondSignal(client->WaitFlag);