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"
22 #define MAX_CLIENTS 16
27 SDL_Thread *WorkerThread;
30 tRequestHeader *CurrentRequest;
31 struct sockaddr_in ClientAddr;
38 extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength);
41 tClient *Server_GetClient(int ClientID);
42 int Server_WorkerThread(void *ClientPtr);
43 int SyscallServer(void);
48 SOCKET gSocket = INVALID_SOCKET;
50 # define INVALID_SOCKET -1
51 int gSocket = INVALID_SOCKET;
53 int giServer_NextClientID = 1;
54 tClient gaServer_Clients[MAX_CLIENTS];
57 int Server_GetClientID(void)
60 Uint32 thisId = SDL_ThreadID();
62 for( i = 0; i < MAX_CLIENTS; i ++ )
64 if( SDL_GetThreadID(gaServer_Clients[i].WorkerThread) == thisId )
65 return gaServer_Clients[i].ClientID;
68 fprintf(stderr, "ERROR: Server_GetClientID - Thread is not allocated\n");
73 tClient *Server_GetClient(int ClientID)
78 for( i = 0; i < MAX_CLIENTS; i ++ )
80 if( gaServer_Clients[i].ClientID == ClientID ) {
81 ret = &gaServer_Clients[i];
86 // Uh oh, no free slots
87 // TODO: Dynamic allocation
93 ret->ClientID = giServer_NextClientID ++;
94 ret->CurrentRequest = NULL;
96 if( !ret->WorkerThread ) {
97 ret->WaitFlag = SDL_CreateCond();
98 ret->Mutex = SDL_CreateMutex();
99 SDL_mutexP( ret->Mutex );
100 ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
104 return &gaServer_Clients[i];
107 int Server_WorkerThread(void *ClientPtr)
109 tClient *Client = ClientPtr;
110 tRequestHeader *retHeader;
111 tRequestHeader errorHeader;
119 // Wait for something to do
120 while( Client->CurrentRequest == NULL )
121 SDL_CondWait(Client->WaitFlag, Client->Mutex);
123 printf("Worker for %i, Job: %p\n", Client->ClientID, Client->CurrentRequest);
126 retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
129 // Return an error to the client
130 printf("Error returned by SyscallRecieve\n");
131 errorHeader.CallID = Client->CurrentRequest->CallID;
132 errorHeader.NParams = 0;
133 retHeader = &errorHeader;
134 retSize = sizeof(errorHeader);
138 retHeader->ClientID = Client->ClientID;
140 // Mark the thread as ready for another job
141 Client->CurrentRequest = 0;
143 printf("Sending %i to %x:%i\n",
144 retSize, ntohl(Client->ClientAddr.sin_addr.s_addr),
145 ntohs(Client->ClientAddr.sin_port)
149 sentSize = sendto(gSocket, retHeader, retSize, 0,
150 (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
152 if( sentSize != retSize ) {
153 perror("Server_WorkerThread - send");
156 // Free allocated header
157 if( retHeader != &errorHeader )
163 int SyscallServer(void)
165 struct sockaddr_in server;
168 /* Open windows connection */
169 if (WSAStartup(0x0101, &gWinsock) != 0)
171 fprintf(stderr, "Could not open Windows connection.\n");
177 // Open TCP Connection
178 gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
180 // Open UDP Connection
181 gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
183 if (gSocket == INVALID_SOCKET)
185 fprintf(stderr, "Could not create socket.\n");
192 // Set server address
193 memset(&server, 0, sizeof(struct sockaddr_in));
194 server.sin_family = AF_INET;
195 server.sin_port = htons(SERVER_PORT);
196 server.sin_addr.s_addr = htonl(INADDR_ANY);
199 if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
201 fprintf(stderr, "Cannot bind address to socket.\n");
202 perror("SyscallServer - bind");
204 closesocket(gSocket);
216 Log_Notice("Syscall", "Listening on 0.0.0.0:%i\n", SERVER_PORT);
218 // Wait for something to do :)
222 struct sockaddr_in client;
223 uint clientSize = sizeof(client);
224 int clientSock = accept(gSocket, (struct sockaddr*)&client, &clientSize);
225 if( clientSock < 0 ) {
226 perror("SyscallServer - accept");
230 printf("Client connection %x:%i",
231 ntohl(client.sin_addr), ntohs(client.sin_port)
236 tRequestHeader *req = (void*)data;
237 struct sockaddr_in addr;
238 uint clientSize = sizeof(addr);
239 int length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
243 perror("SyscallServer - recv");
247 // Hand off to a worker thread
248 // - TODO: Actually have worker threads
249 printf("%i bytes from %x:%i\n", length,
250 ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
252 client = Server_GetClient(req->ClientID);
253 if( req->ClientID == 0 )
255 memcpy(&client->ClientAddr, &addr, sizeof(addr));
257 else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
259 printf("ClientID %i used by %x:%i\n",
260 client->ClientID, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
261 printf(" actually owned by %x:%i\n",
262 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
266 if( client->CurrentRequest ) {
267 printf("Worker thread for %x:%i is busy\n",
268 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
272 printf("client = %p, ClientID = %i\n", client, client->ClientID);
274 client->CurrentRequest = req;
275 SDL_CondSignal(client->WaitFlag);