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"
24 #define MAX_CLIENTS 16
29 SDL_Thread *WorkerThread;
33 tRequestHeader *CurrentRequest;
34 struct sockaddr_in ClientAddr;
41 extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength);
42 extern int Threads_CreateRootProcess(void);
43 extern void Threads_SetThread(int TID);
44 // HACK: Should have these in a header
45 extern void Log_Debug(const char *Subsys, const char *Message, ...);
46 extern void Log_Notice(const char *Subsys, const char *Message, ...);
47 extern void Log_Warning(const char *Subsys, const char *Message, ...);
50 tClient *Server_GetClient(int ClientID);
51 int Server_WorkerThread(void *ClientPtr);
52 int SyscallServer(void);
53 int Server_ListenThread(void *Unused);
58 SOCKET gSocket = INVALID_SOCKET;
60 # define INVALID_SOCKET -1
61 int gSocket = INVALID_SOCKET;
63 tClient gaServer_Clients[MAX_CLIENTS];
64 SDL_Thread *gpServer_ListenThread;
67 int Server_GetClientID(void)
70 Uint32 thisId = SDL_ThreadID();
72 for( i = 0; i < MAX_CLIENTS; i ++ )
74 if( SDL_GetThreadID(gaServer_Clients[i].WorkerThread) == thisId )
75 return gaServer_Clients[i].ClientID;
78 fprintf(stderr, "ERROR: Server_GetClientID - Thread is not allocated\n");
83 tClient *Server_GetClient(int ClientID)
88 // Allocate an ID if needed
90 ClientID = Threads_CreateRootProcess();
92 for( i = 0; i < MAX_CLIENTS; i ++ )
94 if( gaServer_Clients[i].ClientID == ClientID ) {
95 return &gaServer_Clients[i];
97 if(!ret && gaServer_Clients[i].ClientID == 0)
98 ret = &gaServer_Clients[i];
101 // Uh oh, no free slots
102 // TODO: Dynamic allocation
106 // Allocate a thread for the process
107 ret->ClientID = ClientID;
111 ret->CurrentRequest = NULL;
114 if( !ret->WorkerThread ) {
117 ret->WaitFlag = SDL_CreateCond();
118 ret->Mutex = SDL_CreateMutex();
119 SDL_mutexP( ret->Mutex );
121 ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
127 int Server_WorkerThread(void *ClientPtr)
129 tClient *Client = ClientPtr;
135 int nfd = Client->Socket;
137 FD_SET(Client->Socket, &fds);
139 select(nfd, &fds, NULL, NULL, NULL); // TODO: Timeouts?
141 if( FD_ISSET(Client->Socket, &fds) )
143 const int ciMaxParamCount = 6;
144 char lbuf[sizeof(tRequestHeader) + ciMaxParamCount*sizeof(tRequestValue)];
145 tRequestHeader *hdr = (void*)lbuf;
146 size_t len = recv(Client->Socket, hdr, sizeof(*hdr), 0);
147 if( len != sizeof(hdr) ) {
151 if( hdr->NParams > ciMaxParamCount ) {
155 len = recv(Client->Socket, hdr->Params, hdr->NParams*sizeof(tRequestValue), 0);
156 if( len != hdr->NParams*sizeof(tRequestValue) ) {
161 size_t hdrsize = sizeof(tRequestHeader) + hdr->NParams*sizeof(tRequestValue);
162 size_t bufsize = hdrsize;
164 for( i = 0; i < hdr->NParams; i ++ )
166 if( hdr->Params[i].Flags & ARG_FLAG_ZEROED )
169 bufsize += hdr->Params[i].Length;
173 // Allocate full buffer
174 hdr = malloc(bufsize);
175 memcpy(hdr, lbuf, hdrsize);
176 len = recv(Client->Socket, hdr->Params + hdr->NParams, bufsize - hdrsize, 0);
177 if( len != bufsize - hdrsize ) {
182 tRequestHeader *retHeader;
183 retHeader = SyscallRecieve(hdr, &retlen);
185 // Some sort of error
188 send(Client->Socket, retHeader, retlen, 0);
195 tRequestHeader *retHeader;
196 tRequestHeader errorHeader;
199 int cur_client_id = 0;
202 // Wait for something to do
203 while( Client->CurrentRequest == NULL )
204 SDL_CondWait(Client->WaitFlag, Client->Mutex);
206 // Log_Debug("AcessSrv", "Worker got message %p", Client->CurrentRequest);
208 if(Client->ClientID != cur_client_id) {
209 // Log_Debug("AcessSrv", "Client thread ID changed from %i to %i",
210 // cur_client_id, Client->ClientID);
211 Threads_SetThread( Client->ClientID );
212 cur_client_id = Client->ClientID;
217 int callid = Client->CurrentRequest->CallID;
218 Log_Debug("AcessSrv", "Client %i request %i %s",
219 Client->ClientID, callid,
220 callid < N_SYSCALLS ? casSYSCALL_NAMES[callid] : "UNK"
225 retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
228 // Return an error to the client
229 printf("ERROR: SyscallRecieve failed\n");
230 errorHeader.CallID = Client->CurrentRequest->CallID;
231 errorHeader.NParams = 0;
232 retHeader = &errorHeader;
233 retSize = sizeof(errorHeader);
237 retHeader->ClientID = Client->ClientID;
239 // Mark the thread as ready for another job
240 free(Client->CurrentRequest);
241 Client->CurrentRequest = 0;
243 // Log_Debug("AcessSrv", "Sending %i to %x:%i (Client %i)",
244 // retSize, ntohl(Client->ClientAddr.sin_addr.s_addr),
245 // ntohs(Client->ClientAddr.sin_port),
250 sentSize = sendto(gSocket, retHeader, retSize, 0,
251 (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
253 if( sentSize != retSize ) {
254 perror("Server_WorkerThread - send");
257 // Free allocated header
258 if( retHeader != &errorHeader )
264 int SyscallServer(void)
266 struct sockaddr_in server;
269 /* Open windows connection */
270 if (WSAStartup(0x0101, &gWinsock) != 0)
272 fprintf(stderr, "Could not open Windows connection.\n");
278 // Open TCP Connection
279 gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
281 // Open UDP Connection
282 gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
284 if (gSocket == INVALID_SOCKET)
286 fprintf(stderr, "Could not create socket.\n");
293 // Set server address
294 memset(&server, 0, sizeof(struct sockaddr_in));
295 server.sin_family = AF_INET;
296 server.sin_port = htons(SERVER_PORT);
297 server.sin_addr.s_addr = htonl(INADDR_ANY);
300 if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
302 fprintf(stderr, "Cannot bind address to socket.\n");
303 perror("SyscallServer - bind");
305 closesocket(gSocket);
317 Log_Notice("AcessSrv", "Listening on 0.0.0.0:%i", SERVER_PORT);
318 gpServer_ListenThread = SDL_CreateThread( Server_ListenThread, NULL );
322 int Server_ListenThread(void *Unused)
324 // Wait for something to do :)
328 struct sockaddr_in clientaddr;
329 socklen_t clientSize = sizeof(clientaddr);
330 int clientSock = accept(gSocket, (struct sockaddr*)&clientaddr, &clientSize);
331 if( clientSock < 0 ) {
332 perror("SyscallServer - accept");
336 char addrstr[4*8+8+1];
337 inet_ntop(clientaddr.sin_family, &clientaddr.sin_addr, addrstr, sizeof(addrstr));
338 Log_Debug("Server", "Client connection %s:%i\n", addrstr, ntohs(clientaddr.sin_port));
342 tRequestAuthHdr authhdr;
343 len = recv(clientSock, &authhdr, sizeof(authhdr), 0);
344 if( len != sizeof(authhdr) ) {
345 // Some form of error?
349 if( authhdr.pid == 0 ) {
350 // Allocate PID and client structure/thread
351 client = Server_GetClient(0);
352 client->Socket = clientSock;
353 authhdr.pid = client->ClientID;
356 // Get client structure and make sure it's unused
357 // - Auth token / verifcation?
358 client = Server_GetClient(authhdr.pid);
359 if( client->Socket != 0 ) {
360 Log_Warning("Server", "Client (%i)%p owned by FD%i but %s:%i tried to use it",
361 authhdr.pid, client, addrstr, clientaddr.sin_port);
365 client->Socket = clientSock;
369 len = send(clientSock, &authhdr, sizeof(authhdr), 0);
370 if( len != sizeof(authhdr) ) {
371 // Ok, this is an error
372 perror("Sending auth reply");
375 // All done, client thread should be watching now
379 tRequestHeader *req = (void*)data;
380 struct sockaddr_in addr;
381 uint clientSize = sizeof(addr);
385 length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
388 perror("SyscallServer - recv");
392 // Hand off to a worker thread
393 // - TODO: Actually have worker threads
394 // Log_Debug("Server", "%i bytes from %x:%i", length,
395 // ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
397 client = Server_GetClient(req->ClientID);
398 // NOTE: Hack - Should check if all zero
399 if( req->ClientID == 0 || client->ClientAddr.sin_port == 0 )
401 memcpy(&client->ClientAddr, &addr, sizeof(addr));
403 else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
405 printf("ClientID %i used by %x:%i\n",
406 client->ClientID, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
407 printf(" actually owned by %x:%i\n",
408 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
412 if( client->CurrentRequest ) {
413 printf("Worker thread for %x:%i is busy\n",
414 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
418 // Log_Debug("AcessSrv", "Message from Client %i (%p)",
419 // client->ClientID, client);
421 // Make a copy of the request data
422 req = malloc(length);
423 memcpy(req, data, length);
424 client->CurrentRequest = req;
425 SDL_CondSignal(client->WaitFlag);