3 * - Acess kernel emulation on another OS using SDL and UDP
16 # include <sys/socket.h>
17 # include <netinet/in.h>
18 # include <arpa/inet.h> // inet_ntop
20 #include "../syscalls.h"
25 #define MAX_CLIENTS 16
30 SDL_Thread *WorkerThread;
34 tRequestHeader *CurrentRequest;
35 struct sockaddr_in ClientAddr;
42 extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength);
43 extern int Threads_CreateRootProcess(void);
44 extern void Threads_SetThread(int TID);
45 // HACK: Should have these in a header
46 extern void Log_Debug(const char *Subsys, const char *Message, ...);
47 extern void Log_Notice(const char *Subsys, const char *Message, ...);
48 extern void Log_Warning(const char *Subsys, const char *Message, ...);
51 tClient *Server_GetClient(int ClientID);
52 int Server_WorkerThread(void *ClientPtr);
53 int SyscallServer(void);
54 int Server_ListenThread(void *Unused);
59 SOCKET gSocket = INVALID_SOCKET;
61 # define INVALID_SOCKET -1
62 int gSocket = INVALID_SOCKET;
64 tClient gaServer_Clients[MAX_CLIENTS];
65 SDL_Thread *gpServer_ListenThread;
68 int Server_GetClientID(void)
71 Uint32 thisId = SDL_ThreadID();
73 for( i = 0; i < MAX_CLIENTS; i ++ )
75 if( SDL_GetThreadID(gaServer_Clients[i].WorkerThread) == thisId )
76 return gaServer_Clients[i].ClientID;
79 fprintf(stderr, "ERROR: Server_GetClientID - Thread is not allocated\n");
84 tClient *Server_GetClient(int ClientID)
89 // Allocate an ID if needed
91 ClientID = Threads_CreateRootProcess();
93 for( i = 0; i < MAX_CLIENTS; i ++ )
95 if( gaServer_Clients[i].ClientID == ClientID ) {
96 return &gaServer_Clients[i];
98 if(!ret && gaServer_Clients[i].ClientID == 0)
99 ret = &gaServer_Clients[i];
102 // Uh oh, no free slots
103 // TODO: Dynamic allocation
107 // Allocate a thread for the process
108 ret->ClientID = ClientID;
112 ret->CurrentRequest = NULL;
115 if( !ret->WorkerThread ) {
118 ret->WaitFlag = SDL_CreateCond();
119 ret->Mutex = SDL_CreateMutex();
120 SDL_mutexP( ret->Mutex );
122 Log_Debug("Server", "Creating worker for %p", ret);
123 ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
129 int Server_WorkerThread(void *ClientPtr)
131 tClient *Client = ClientPtr;
133 Log_Debug("Server", "Worker %p", ClientPtr);
137 while( *((volatile typeof(Client->Socket)*)&Client->Socket) == 0 )
139 Threads_SetThread( Client->ClientID );
141 while( Client->ClientID != -1 )
144 int nfd = Client->Socket+1;
146 FD_SET(Client->Socket, &fds);
148 int rv = select(nfd, &fds, NULL, NULL, NULL); // TODO: Timeouts?
153 Log_Debug("Server", "%p: rv=%i", Client, rv);
155 if( FD_ISSET(Client->Socket, &fds) )
157 const int ciMaxParamCount = 6;
158 char lbuf[sizeof(tRequestHeader) + ciMaxParamCount*sizeof(tRequestValue)];
159 tRequestHeader *hdr = (void*)lbuf;
160 size_t len = recv(Client->Socket, hdr, sizeof(*hdr), 0);
161 Log_Debug("Server", "%i bytes of header", len);
162 if( len == 0 ) break;
164 perror("recv header");
165 // Log_Warning("Server", "recv() error - %s", strerror(errno));
168 if( len != sizeof(*hdr) ) {
170 Log_Warning("Server", "FD%i bad sized (%i != exp %i)",
171 Client->Socket, len, sizeof(*hdr));
175 if( hdr->NParams > ciMaxParamCount ) {
177 Log_Warning("Server", "FD%i too many params (%i > max %i)",
178 Client->Socket, hdr->NParams, ciMaxParamCount);
182 if( hdr->NParams > 0 )
184 len = recv(Client->Socket, hdr->Params, hdr->NParams*sizeof(tRequestValue), 0);
185 Log_Debug("Server", "%i bytes of params", len);
186 if( len != hdr->NParams*sizeof(tRequestValue) ) {
188 perror("recv params");
189 Log_Warning("Sever", "Recieving params failed");
195 Log_Debug("Server", "No params?");
199 size_t hdrsize = sizeof(tRequestHeader) + hdr->NParams*sizeof(tRequestValue);
200 size_t bufsize = hdrsize;
202 for( i = 0; i < hdr->NParams; i ++ )
204 if( hdr->Params[i].Flags & ARG_FLAG_ZEROED )
207 bufsize += hdr->Params[i].Length;
211 // Allocate full buffer
212 hdr = malloc(bufsize);
213 memcpy(hdr, lbuf, hdrsize);
214 if( bufsize > hdrsize )
216 size_t rem = bufsize - hdrsize;
217 char *ptr = (void*)( hdr->Params + hdr->NParams );
220 len = recv(Client->Socket, ptr, rem, 0);
221 Log_Debug("Server", "%i bytes of data", len);
225 Log_Warning("Sever", "Recieving data failed");
236 Log_Debug("Server", "no data");
239 tRequestHeader *retHeader;
240 retHeader = SyscallRecieve(hdr, &retlen);
242 // Some sort of error
243 Log_Warning("Server", "SyscallRecieve failed?");
247 send(Client->Socket, retHeader, retlen, 0);
254 tRequestHeader *retHeader;
255 tRequestHeader errorHeader;
258 int cur_client_id = 0;
259 while( Client->ClientID != -1 )
261 // Wait for something to do
262 if( Client->CurrentRequest == NULL )
263 SDL_CondWait(Client->WaitFlag, Client->Mutex);
264 if( Client->CurrentRequest == NULL )
267 // Log_Debug("AcessSrv", "Worker got message %p", Client->CurrentRequest);
269 if(Client->ClientID != cur_client_id) {
270 // Log_Debug("AcessSrv", "Client thread ID changed from %i to %i",
271 // cur_client_id, Client->ClientID);
272 Threads_SetThread( Client->ClientID );
273 cur_client_id = Client->ClientID;
278 int callid = Client->CurrentRequest->CallID;
279 Log_Debug("AcessSrv", "Client %i request %i %s",
280 Client->ClientID, callid,
281 callid < N_SYSCALLS ? casSYSCALL_NAMES[callid] : "UNK"
286 retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
289 // Return an error to the client
290 printf("ERROR: SyscallRecieve failed\n");
291 errorHeader.CallID = Client->CurrentRequest->CallID;
292 errorHeader.NParams = 0;
293 retHeader = &errorHeader;
294 retSize = sizeof(errorHeader);
298 retHeader->ClientID = Client->ClientID;
300 // Mark the thread as ready for another job
301 free(Client->CurrentRequest);
302 Client->CurrentRequest = 0;
304 // Log_Debug("AcessSrv", "Sending %i to %x:%i (Client %i)",
305 // retSize, ntohl(Client->ClientAddr.sin_addr.s_addr),
306 // ntohs(Client->ClientAddr.sin_port),
311 sentSize = sendto(gSocket, retHeader, retSize, 0,
312 (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
314 if( sentSize != retSize ) {
315 perror("Server_WorkerThread - send");
318 // Free allocated header
319 if( retHeader != &errorHeader )
323 Log_Notice("Server", "Terminated Worker %p", ClientPtr);
327 int SyscallServer(void)
329 struct sockaddr_in server;
332 /* Open windows connection */
333 if (WSAStartup(0x0101, &gWinsock) != 0)
335 fprintf(stderr, "Could not open Windows connection.\n");
341 // Open TCP Connection
342 gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
344 // Open UDP Connection
345 gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
347 if (gSocket == INVALID_SOCKET)
349 fprintf(stderr, "Could not create socket.\n");
356 // Set server address
357 memset(&server, 0, sizeof(struct sockaddr_in));
358 server.sin_family = AF_INET;
359 server.sin_port = htons(SERVER_PORT);
360 server.sin_addr.s_addr = htonl(INADDR_ANY);
363 if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
365 fprintf(stderr, "Cannot bind address to socket.\n");
366 perror("SyscallServer - bind");
368 closesocket(gSocket);
380 Log_Notice("AcessSrv", "Listening on 0.0.0.0:%i", SERVER_PORT);
381 gpServer_ListenThread = SDL_CreateThread( Server_ListenThread, NULL );
385 int Server_Shutdown(void)
388 for( int i = 0; i < MAX_CLIENTS; i ++ )
390 if( gaServer_Clients[i].ClientID == 0 )
392 Threads_PostEvent( Threads_GetThread(gaServer_Clients[i].ClientID), 0 );
393 gaServer_Clients[i].ClientID = -1;
395 close(gaServer_Clients[i].Socket);
397 SDL_CondSignal(gaServer_Clients[i].WaitFlag);
403 int Server_ListenThread(void *Unused)
405 // Wait for something to do :)
409 struct sockaddr_in clientaddr;
410 socklen_t clientSize = sizeof(clientaddr);
411 int clientSock = accept(gSocket, (struct sockaddr*)&clientaddr, &clientSize);
412 if( clientSock < 0 ) {
413 perror("SyscallServer - accept");
417 char addrstr[4*8+8+1];
418 inet_ntop(clientaddr.sin_family, &clientaddr.sin_addr, addrstr, sizeof(addrstr));
419 Log_Debug("Server", "Client connection %s:%i", addrstr, ntohs(clientaddr.sin_port));
423 tRequestAuthHdr authhdr;
424 len = recv(clientSock, &authhdr, sizeof(authhdr), 0);
425 if( len != sizeof(authhdr) ) {
426 // Some form of error?
427 Log_Warning("Server", "Client auth block bad size (%i != exp %i)",
428 len, sizeof(authhdr));
433 Log_Debug("Server", "Client assumed PID %i", authhdr.pid);
436 if( authhdr.pid == 0 ) {
437 // Allocate PID and client structure/thread
438 client = Server_GetClient(0);
439 client->Socket = clientSock;
440 authhdr.pid = client->ClientID;
443 // Get client structure and make sure it's unused
444 // - Auth token / verifcation?
445 client = Server_GetClient(authhdr.pid);
447 Log_Warning("Server", "Can't allocate a client struct for %s:%i",
448 addrstr, clientaddr.sin_port);
452 if( client->Socket != 0 ) {
453 Log_Warning("Server", "Client (%i)%p owned by FD%i but %s:%i tried to use it",
454 authhdr.pid, client, addrstr, clientaddr.sin_port);
459 client->Socket = clientSock;
462 Log_Debug("Server", "Client given PID %i - info %p", authhdr.pid, client);
464 len = send(clientSock, &authhdr, sizeof(authhdr), 0);
465 if( len != sizeof(authhdr) ) {
466 // Ok, this is an error
467 perror("Sending auth reply");
470 // All done, client thread should be watching now
474 tRequestHeader *req = (void*)data;
475 struct sockaddr_in addr;
476 uint clientSize = sizeof(addr);
480 length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
483 perror("SyscallServer - recv");
487 // Hand off to a worker thread
488 // - TODO: Actually have worker threads
489 // Log_Debug("Server", "%i bytes from %x:%i", length,
490 // ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
492 client = Server_GetClient(req->ClientID);
493 // NOTE: Hack - Should check if all zero
494 if( req->ClientID == 0 || client->ClientAddr.sin_port == 0 )
496 memcpy(&client->ClientAddr, &addr, sizeof(addr));
498 else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
500 printf("ClientID %i used by %x:%i\n",
501 client->ClientID, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
502 printf(" actually owned by %x:%i\n",
503 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
507 if( client->CurrentRequest ) {
508 printf("Worker thread for %x:%i is busy\n",
509 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
513 // Log_Debug("AcessSrv", "Message from Client %i (%p)",
514 // client->ClientID, client);
516 // Make a copy of the request data
517 req = malloc(length);
518 memcpy(req, data, length);
519 client->CurrentRequest = req;
520 SDL_CondSignal(client->WaitFlag);