AcessNative - Cleaning up debug
[tpg/acess2.git] / AcessNative / acesskernel_src / server.c
1 /*
2  * Acess2 Native Kernel
3  * - Acess kernel emulation on another OS using SDL and UDP
4  *
5  * Syscall Server
6  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <SDL/SDL.h>
11 #ifdef __WIN32__
12 # include <windows.h>
13 # include <winsock.h>
14 #else
15 # include <unistd.h>
16 # include <sys/socket.h>
17 # include <netinet/in.h>
18 #endif
19 #include "../syscalls.h"
20 //#include <debug.h>
21
22 #define USE_TCP 0
23 #define MAX_CLIENTS     16
24
25 // === TYPES ===
26 typedef struct {
27          int    ClientID;
28         SDL_Thread      *WorkerThread;
29         #if USE_TCP
30         #else
31         tRequestHeader  *CurrentRequest;
32         struct sockaddr_in      ClientAddr;
33         SDL_cond        *WaitFlag;
34         SDL_mutex       *Mutex;
35         #endif
36 }       tClient;
37
38 // === IMPORTS ===
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, ...);
45
46 // === PROTOTYPES ===
47 tClient *Server_GetClient(int ClientID);
48  int    Server_WorkerThread(void *ClientPtr);
49  int    SyscallServer(void);
50  int    Server_ListenThread(void *Unused);
51
52 // === GLOBALS ===
53 #ifdef __WIN32__
54 WSADATA gWinsock;
55 SOCKET  gSocket = INVALID_SOCKET;
56 #else
57 # define INVALID_SOCKET -1
58  int    gSocket = INVALID_SOCKET;
59 #endif
60 tClient gaServer_Clients[MAX_CLIENTS];
61 SDL_Thread      *gpServer_ListenThread;
62
63 // === CODE ===
64 int Server_GetClientID(void)
65 {
66          int    i;
67         Uint32  thisId = SDL_ThreadID();
68         
69         for( i = 0; i < MAX_CLIENTS; i ++ )
70         {
71                 if( SDL_GetThreadID(gaServer_Clients[i].WorkerThread) == thisId )
72                         return gaServer_Clients[i].ClientID;
73         }
74         
75         fprintf(stderr, "ERROR: Server_GetClientID - Thread is not allocated\n");
76         
77         return 0;
78 }
79
80 tClient *Server_GetClient(int ClientID)
81 {
82         tClient *ret = NULL;
83          int    i;
84         
85         // Allocate an ID if needed
86         if(ClientID == 0)
87                 ClientID = Threads_CreateRootProcess();
88         
89         for( i = 0; i < MAX_CLIENTS; i ++ )
90         {
91                 if( gaServer_Clients[i].ClientID == ClientID ) {
92                         return &gaServer_Clients[i];
93                 }
94                 if(!ret && gaServer_Clients[i].ClientID == 0)
95                         ret = &gaServer_Clients[i];
96         }
97         
98         // Uh oh, no free slots
99         // TODO: Dynamic allocation
100         if( !ret )
101                 return NULL;
102         
103         // Allocate a thread for the process
104         ret->ClientID = ClientID;
105         ret->CurrentRequest = NULL;
106                 
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 );
112         }
113         
114         return ret;
115 }
116
117 int Server_WorkerThread(void *ClientPtr)
118 {
119         tClient *Client = ClientPtr;
120         tRequestHeader  *retHeader;
121         tRequestHeader  errorHeader;
122          int    retSize = 0;
123          int    sentSize;
124          int    cur_client_id = 0;
125         
126         #if USE_TCP
127         #else
128         for( ;; )
129         {
130                 // Wait for something to do
131                 while( Client->CurrentRequest == NULL )
132                         SDL_CondWait(Client->WaitFlag, Client->Mutex);
133                 
134 //              Log_Debug("AcessSrv", "Worker got message %p", Client->CurrentRequest);
135                 
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;
141                 }
142                 
143                 // Debug
144                 {
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"
149                                 );
150                 }
151                 
152                 // Get the response
153                 retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
154
155                 if( !retHeader ) {
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);
162                 }
163                 
164                 // Set ID
165                 retHeader->ClientID = Client->ClientID;
166                 
167                 // Mark the thread as ready for another job
168                 free(Client->CurrentRequest);
169                 Client->CurrentRequest = 0;
170                 
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),
174 //                      Client->ClientID
175 //                      );
176                 
177                 // Return the data
178                 sentSize = sendto(gSocket, retHeader, retSize, 0,
179                         (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
180                         );
181                 if( sentSize != retSize ) {
182                         perror("Server_WorkerThread - send");
183                 }
184                 
185                 // Free allocated header
186                 if( retHeader != &errorHeader )
187                         free( retHeader );
188         }
189         #endif
190 }
191
192 int SyscallServer(void)
193 {
194         struct sockaddr_in      server;
195         
196         #ifdef __WIN32__
197         /* Open windows connection */
198         if (WSAStartup(0x0101, &gWinsock) != 0)
199         {
200                 fprintf(stderr, "Could not open Windows connection.\n");
201                 exit(0);
202         }
203         #endif
204         
205         #if USE_TCP
206         // Open TCP Connection
207         gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
208         #else
209         // Open UDP Connection
210         gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
211         #endif
212         if (gSocket == INVALID_SOCKET)
213         {
214                 fprintf(stderr, "Could not create socket.\n");
215                 #if __WIN32__
216                 WSACleanup();
217                 #endif
218                 exit(0);
219         }
220         
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);
226         
227         // Bind
228         if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
229         {
230                 fprintf(stderr, "Cannot bind address to socket.\n");
231                 perror("SyscallServer - bind");
232                 #if __WIN32__
233                 closesocket(gSocket);
234                 WSACleanup();
235                 #else
236                 close(gSocket);
237                 #endif
238                 exit(0);
239         }
240         
241         #if USE_TCP
242         listen(gSocket, 5);
243         #endif
244         
245         Log_Notice("AcessSrv", "Listening on 0.0.0.0:%i", SERVER_PORT);
246         gpServer_ListenThread = SDL_CreateThread( Server_ListenThread, NULL );
247         return 0;
248 }
249
250 int Server_ListenThread(void *Unused)
251 {       
252         // Wait for something to do :)
253         for( ;; )
254         {
255                 #if USE_TCP
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");
261                         break ;
262                 }
263                 
264                 Log("Client connection %x:%i\n",
265                         ntohl(client.sin_addr), ntohs(client.sin_port)
266                         );
267                 
268                 #else
269                 char    data[BUFSIZ];
270                 tRequestHeader  *req = (void*)data;
271                 struct sockaddr_in      addr;
272                 uint    clientSize = sizeof(addr);
273                  int    length;
274                 tClient *client;
275                 
276                 length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
277                 
278                 if( length == -1 ) {
279                         perror("SyscallServer - recv");
280                         break;
281                 }
282                 
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));
287                 
288                 client = Server_GetClient(req->ClientID);
289                 // NOTE: Hack - Should check if all zero
290                 if( req->ClientID == 0 || client->ClientAddr.sin_port == 0 )
291                 {
292                         memcpy(&client->ClientAddr, &addr, sizeof(addr));
293                 }
294                 else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
295                 {
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));
300                         continue;
301                 }
302                 
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));
306                         continue;
307                 }
308                 
309 //              Log_Debug("AcessSrv", "Message from Client %i (%p)",
310 //                      client->ClientID, client);
311
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);
317                 #endif
318         }
319         return -1;
320 }

UCC git Repository :: git.ucc.asn.au