3 * - Acess kernel emulation on another OS using SDL and UDP
16 # include <sys/socket.h>
17 # include <netinet/in.h>
19 #include "../syscalls.h"
23 #define MAX_CLIENTS 16
28 SDL_Thread *WorkerThread;
31 tRequestHeader *CurrentRequest;
32 struct sockaddr_in ClientAddr;
39 extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength);
40 extern int Threads_CreateRootProcess(void);
41 extern void Threads_SetThread(int TID);
42 // HACK: Should have these in a header
43 extern void Log_Debug(const char *Subsys, const char *Message, ...);
44 extern void Log_Notice(const char *Subsys, const char *Message, ...);
47 tClient *Server_GetClient(int ClientID);
48 int Server_WorkerThread(void *ClientPtr);
49 int SyscallServer(void);
50 int Server_ListenThread(void *Unused);
55 SOCKET gSocket = INVALID_SOCKET;
57 # define INVALID_SOCKET -1
58 int gSocket = INVALID_SOCKET;
60 tClient gaServer_Clients[MAX_CLIENTS];
61 SDL_Thread *gpServer_ListenThread;
64 int Server_GetClientID(void)
67 Uint32 thisId = SDL_ThreadID();
69 for( i = 0; i < MAX_CLIENTS; i ++ )
71 if( SDL_GetThreadID(gaServer_Clients[i].WorkerThread) == thisId )
72 return gaServer_Clients[i].ClientID;
75 fprintf(stderr, "ERROR: Server_GetClientID - Thread is not allocated\n");
80 tClient *Server_GetClient(int ClientID)
85 // Allocate an ID if needed
87 ClientID = Threads_CreateRootProcess();
89 for( i = 0; i < MAX_CLIENTS; i ++ )
91 if( gaServer_Clients[i].ClientID == ClientID ) {
92 return &gaServer_Clients[i];
94 if(!ret && gaServer_Clients[i].ClientID == 0)
95 ret = &gaServer_Clients[i];
98 // Uh oh, no free slots
99 // TODO: Dynamic allocation
103 // Allocate a thread for the process
104 ret->ClientID = ClientID;
105 ret->CurrentRequest = NULL;
107 if( !ret->WorkerThread ) {
108 ret->WaitFlag = SDL_CreateCond();
109 ret->Mutex = SDL_CreateMutex();
110 SDL_mutexP( ret->Mutex );
111 ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
117 int Server_WorkerThread(void *ClientPtr)
119 tClient *Client = ClientPtr;
120 tRequestHeader *retHeader;
121 tRequestHeader errorHeader;
124 int cur_client_id = 0;
130 // Wait for something to do
131 while( Client->CurrentRequest == NULL )
132 SDL_CondWait(Client->WaitFlag, Client->Mutex);
134 // Log_Debug("AcessSrv", "Worker got message %p", Client->CurrentRequest);
136 if(Client->ClientID != cur_client_id) {
137 // Log_Debug("AcessSrv", "Client thread ID changed from %i to %i",
138 // cur_client_id, Client->ClientID);
139 Threads_SetThread( Client->ClientID );
140 cur_client_id = Client->ClientID;
145 int callid = Client->CurrentRequest->CallID;
146 Log_Debug("AcessSrv", "Client %i request %i %s",
147 Client->ClientID, callid,
148 callid < N_SYSCALLS ? casSYSCALL_NAMES[callid] : "UNK"
153 retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
156 // Return an error to the client
157 printf("ERROR: SyscallRecieve failed\n");
158 errorHeader.CallID = Client->CurrentRequest->CallID;
159 errorHeader.NParams = 0;
160 retHeader = &errorHeader;
161 retSize = sizeof(errorHeader);
165 retHeader->ClientID = Client->ClientID;
167 // Mark the thread as ready for another job
168 free(Client->CurrentRequest);
169 Client->CurrentRequest = 0;
171 // Log_Debug("AcessSrv", "Sending %i to %x:%i (Client %i)",
172 // retSize, ntohl(Client->ClientAddr.sin_addr.s_addr),
173 // ntohs(Client->ClientAddr.sin_port),
178 sentSize = sendto(gSocket, retHeader, retSize, 0,
179 (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
181 if( sentSize != retSize ) {
182 perror("Server_WorkerThread - send");
185 // Free allocated header
186 if( retHeader != &errorHeader )
192 int SyscallServer(void)
194 struct sockaddr_in server;
197 /* Open windows connection */
198 if (WSAStartup(0x0101, &gWinsock) != 0)
200 fprintf(stderr, "Could not open Windows connection.\n");
206 // Open TCP Connection
207 gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
209 // Open UDP Connection
210 gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
212 if (gSocket == INVALID_SOCKET)
214 fprintf(stderr, "Could not create socket.\n");
221 // Set server address
222 memset(&server, 0, sizeof(struct sockaddr_in));
223 server.sin_family = AF_INET;
224 server.sin_port = htons(SERVER_PORT);
225 server.sin_addr.s_addr = htonl(INADDR_ANY);
228 if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
230 fprintf(stderr, "Cannot bind address to socket.\n");
231 perror("SyscallServer - bind");
233 closesocket(gSocket);
245 Log_Notice("AcessSrv", "Listening on 0.0.0.0:%i", SERVER_PORT);
246 gpServer_ListenThread = SDL_CreateThread( Server_ListenThread, NULL );
250 int Server_ListenThread(void *Unused)
252 // Wait for something to do :)
256 struct sockaddr_in client;
257 uint clientSize = sizeof(client);
258 int clientSock = accept(gSocket, (struct sockaddr*)&client, &clientSize);
259 if( clientSock < 0 ) {
260 perror("SyscallServer - accept");
264 Log("Client connection %x:%i\n",
265 ntohl(client.sin_addr), ntohs(client.sin_port)
270 tRequestHeader *req = (void*)data;
271 struct sockaddr_in addr;
272 uint clientSize = sizeof(addr);
276 length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
279 perror("SyscallServer - recv");
283 // Hand off to a worker thread
284 // - TODO: Actually have worker threads
285 // Log_Debug("Server", "%i bytes from %x:%i", length,
286 // ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
288 client = Server_GetClient(req->ClientID);
289 // NOTE: Hack - Should check if all zero
290 if( req->ClientID == 0 || client->ClientAddr.sin_port == 0 )
292 memcpy(&client->ClientAddr, &addr, sizeof(addr));
294 else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
296 printf("ClientID %i used by %x:%i\n",
297 client->ClientID, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
298 printf(" actually owned by %x:%i\n",
299 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
303 if( client->CurrentRequest ) {
304 printf("Worker thread for %x:%i is busy\n",
305 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
309 // Log_Debug("AcessSrv", "Message from Client %i (%p)",
310 // client->ClientID, client);
312 // Make a copy of the request data
313 req = malloc(length);
314 memcpy(req, data, length);
315 client->CurrentRequest = req;
316 SDL_CondSignal(client->WaitFlag);