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 // HACK: Should have these in a header
42 extern void Log_Debug(const char *Subsys, const char *Message, ...);
43 extern void Log_Notice(const char *Subsys, const char *Message, ...);
46 tClient *Server_GetClient(int ClientID);
47 int Server_WorkerThread(void *ClientPtr);
48 int SyscallServer(void);
53 SOCKET gSocket = INVALID_SOCKET;
55 # define INVALID_SOCKET -1
56 int gSocket = INVALID_SOCKET;
58 tClient gaServer_Clients[MAX_CLIENTS];
61 int Server_GetClientID(void)
64 Uint32 thisId = SDL_ThreadID();
66 for( i = 0; i < MAX_CLIENTS; i ++ )
68 if( SDL_GetThreadID(gaServer_Clients[i].WorkerThread) == thisId )
69 return gaServer_Clients[i].ClientID;
72 fprintf(stderr, "ERROR: Server_GetClientID - Thread is not allocated\n");
77 tClient *Server_GetClient(int ClientID)
82 // Allocate an ID if needed
84 ClientID = Threads_CreateRootProcess();
86 for( i = 0; i < MAX_CLIENTS; i ++ )
88 if( gaServer_Clients[i].ClientID == ClientID ) {
89 return &gaServer_Clients[i];
91 if(!ret && gaServer_Clients[i].ClientID == 0)
92 ret = &gaServer_Clients[i];
95 // Uh oh, no free slots
96 // TODO: Dynamic allocation
100 // Allocate a thread for the process
101 ret->ClientID = ClientID;
102 ret->CurrentRequest = NULL;
104 if( !ret->WorkerThread ) {
105 ret->WaitFlag = SDL_CreateCond();
106 ret->Mutex = SDL_CreateMutex();
107 SDL_mutexP( ret->Mutex );
108 ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
114 int Server_WorkerThread(void *ClientPtr)
116 tClient *Client = ClientPtr;
117 tRequestHeader *retHeader;
118 tRequestHeader errorHeader;
121 int cur_client_id = 0;
127 // Wait for something to do
128 while( Client->CurrentRequest == NULL )
129 SDL_CondWait(Client->WaitFlag, Client->Mutex);
131 if(Client->ClientID != cur_client_id) {
132 Threads_SetThread( Client->ClientID );
133 cur_client_id = Client->ClientID;
136 Log_Debug("AcessSrv", "Worker %i takes %p",
137 Client->ClientID, Client->CurrentRequest);
140 retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
143 // Return an error to the client
144 printf("ERROR: SyscallRecieve failed\n");
145 errorHeader.CallID = Client->CurrentRequest->CallID;
146 errorHeader.NParams = 0;
147 retHeader = &errorHeader;
148 retSize = sizeof(errorHeader);
152 retHeader->ClientID = Client->ClientID;
154 // Mark the thread as ready for another job
155 Client->CurrentRequest = 0;
157 Log_Debug("AcessSrv", "Sending %i to %x:%i (Client %i)",
158 retSize, ntohl(Client->ClientAddr.sin_addr.s_addr),
159 ntohs(Client->ClientAddr.sin_port),
164 sentSize = sendto(gSocket, retHeader, retSize, 0,
165 (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
167 if( sentSize != retSize ) {
168 perror("Server_WorkerThread - send");
171 // Free allocated header
172 if( retHeader != &errorHeader )
178 int SyscallServer(void)
180 struct sockaddr_in server;
183 /* Open windows connection */
184 if (WSAStartup(0x0101, &gWinsock) != 0)
186 fprintf(stderr, "Could not open Windows connection.\n");
192 // Open TCP Connection
193 gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
195 // Open UDP Connection
196 gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
198 if (gSocket == INVALID_SOCKET)
200 fprintf(stderr, "Could not create socket.\n");
207 // Set server address
208 memset(&server, 0, sizeof(struct sockaddr_in));
209 server.sin_family = AF_INET;
210 server.sin_port = htons(SERVER_PORT);
211 server.sin_addr.s_addr = htonl(INADDR_ANY);
214 if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
216 fprintf(stderr, "Cannot bind address to socket.\n");
217 perror("SyscallServer - bind");
219 closesocket(gSocket);
231 Log_Notice("AcessSrv", "Listening on 0.0.0.0:%i", SERVER_PORT);
233 // Wait for something to do :)
237 struct sockaddr_in client;
238 uint clientSize = sizeof(client);
239 int clientSock = accept(gSocket, (struct sockaddr*)&client, &clientSize);
240 if( clientSock < 0 ) {
241 perror("SyscallServer - accept");
245 Log("Client connection %x:%i\n",
246 ntohl(client.sin_addr), ntohs(client.sin_port)
251 tRequestHeader *req = (void*)data;
252 struct sockaddr_in addr;
253 uint clientSize = sizeof(addr);
257 length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
260 perror("SyscallServer - recv");
264 // Hand off to a worker thread
265 // - TODO: Actually have worker threads
266 printf("%i bytes from %x:%i\n", length,
267 ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
269 client = Server_GetClient(req->ClientID);
270 // NOTE: Hack - Should check if all zero
271 if( req->ClientID == 0 || client->ClientAddr.sin_port == 0 )
273 memcpy(&client->ClientAddr, &addr, sizeof(addr));
275 else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
277 printf("ClientID %i used by %x:%i\n",
278 client->ClientID, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
279 printf(" actually owned by %x:%i\n",
280 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
284 if( client->CurrentRequest ) {
285 printf("Worker thread for %x:%i is busy\n",
286 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
290 Log_Debug("AcessSrv", "Message from Client %i (%p)",
291 client->ClientID, client);
293 client->CurrentRequest = req;
294 SDL_CondSignal(client->WaitFlag);