7491d74ac5622d0b1e54819a3e959c59e287e720
[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
21 #define USE_TCP 0
22 #define MAX_CLIENTS     16
23
24 // === TYPES ===
25 typedef struct {
26          int    ClientID;
27         SDL_Thread      *WorkerThread;
28         #if USE_TCP
29         #else
30         tRequestHeader  *CurrentRequest;
31         struct sockaddr_in      ClientAddr;
32         SDL_cond        *WaitFlag;
33         SDL_mutex       *Mutex;
34         #endif
35 }       tClient;
36
37 // === IMPORTS ===
38 extern tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength);
39
40 // === PROTOTYPES ===
41 tClient *Server_GetClient(int ClientID);
42  int    Server_WorkerThread(void *ClientPtr);
43  int    SyscallServer(void);
44
45 // === GLOBALS ===
46 #ifdef __WIN32__
47 WSADATA gWinsock;
48 SOCKET  gSocket = INVALID_SOCKET;
49 #else
50 # define INVALID_SOCKET -1
51  int    gSocket = INVALID_SOCKET;
52 #endif
53  int    giServer_NextClientID = 1;
54 tClient gaServer_Clients[MAX_CLIENTS];
55
56 // === CODE ===
57 tClient *Server_GetClient(int ClientID)
58 {
59         tClient *ret = NULL;
60          int    i;
61         
62         for( i = 0; i < MAX_CLIENTS; i ++ )
63         {
64                 if( gaServer_Clients[i].ClientID == ClientID ) {
65                         ret = &gaServer_Clients[i];
66                         break;
67                 }
68         }
69         
70         // Uh oh, no free slots
71         // TODO: Dynamic allocation
72         if( !ret )
73                 return NULL;
74         
75         if( ClientID == 0 )
76         {
77                 ret->ClientID = giServer_NextClientID ++;
78                 ret->CurrentRequest = NULL;
79                 
80                 if( !ret->WorkerThread ) {
81                         ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
82                         ret->WaitFlag = SDL_CreateCond();
83                         ret->Mutex = SDL_CreateMutex();
84                         SDL_mutexP( ret->Mutex );
85                 }
86         }
87         
88         return &gaServer_Clients[i];
89 }
90
91 int Server_WorkerThread(void *ClientPtr)
92 {
93         tClient *Client = ClientPtr;
94         tRequestHeader  *retHeader;
95          int    retSize = 0;
96          int    sentSize;
97         
98         #if USE_TCP
99         #else
100         for( ;; )
101         {
102                 // Wait for something to do
103                 while( !Client->CurrentRequest )        ;
104                 
105                 // Get the response
106                 retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
107                 
108                 if( !retHeader ) {
109                         // Return an error to the client
110                         printf("Error returned by SyscallRecieve\n");
111                 }
112                 
113                 // Return the data
114                 sentSize = sendto(gSocket, retHeader, retSize, 0,
115                         (struct sockaddr*)&Client->ClientAddr, sizeof(Client->ClientAddr)
116                         );
117                 if( sentSize != retSize ) {
118                         perror("Server_WorkerThread - send");
119                 }
120                 
121                 // Free allocated header
122                 free( retHeader );
123                 
124                 Client->CurrentRequest = 0;
125                 
126                 // Wait for something else
127                 SDL_CondWait(Client->WaitFlag, Client->Mutex);
128         }
129         #endif
130 }
131
132 int SyscallServer(void)
133 {
134         struct sockaddr_in      server;
135         
136         #ifdef __WIN32__
137         /* Open windows connection */
138         if (WSAStartup(0x0101, &gWinsock) != 0)
139         {
140                 fprintf(stderr, "Could not open Windows connection.\n");
141                 exit(0);
142         }
143         #endif
144         
145         #if USE_TCP
146         // Open TCP Connection
147         gSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
148         #else
149         // Open UDP Connection
150         gSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
151         #endif
152         if (gSocket == INVALID_SOCKET)
153         {
154                 fprintf(stderr, "Could not create socket.\n");
155                 #if __WIN32__
156                 WSACleanup();
157                 #endif
158                 exit(0);
159         }
160         
161         // Set server address
162         memset(&server, 0, sizeof(struct sockaddr_in));
163         server.sin_family = AF_INET;
164         server.sin_port = htons(SERVER_PORT);
165         server.sin_addr.s_addr = htonl(INADDR_ANY);
166         
167         // Bind
168         if( bind(gSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1 )
169         {
170                 fprintf(stderr, "Cannot bind address to socket.\n");
171                 perror("SyscallServer - bind");
172                 #if __WIN32__
173                 closesocket(gSocket);
174                 WSACleanup();
175                 #else
176                 close(gSocket);
177                 #endif
178                 exit(0);
179         }
180         
181         #if USE_TCP
182         listen(gSocket, 5);
183         #endif
184         
185         Log_Notice("Syscall", "Listening on 0.0.0.0:%i\n", SERVER_PORT);
186         
187         // Wait for something to do :)
188         for( ;; )
189         {
190                 #if USE_TCP
191                 struct sockaddr_in      client;
192                 uint    clientSize = sizeof(client);
193                  int    clientSock = accept(gSocket, (struct sockaddr*)&client, &clientSize);
194                 if( clientSock < 0 ) {
195                         perror("SyscallServer - accept");
196                         break ;
197                 }
198                 
199                 printf("Client connection %x:%i",
200                         ntohl(client.sin_addr), ntohs(client.sin_port)
201                         );
202                 
203                 #else
204                 char    data[BUFSIZ];
205                 tRequestHeader  *req = (void*)data;
206                 struct sockaddr_in      addr;
207                 uint    clientSize = sizeof(addr);
208                  int    length = recvfrom(gSocket, data, BUFSIZ, 0, (struct sockaddr*)&addr, &clientSize);
209                 tClient *client;
210                 
211                 if( length == -1 ) {
212                         perror("SyscallServer - recv");
213                         break;
214                 }
215                 
216                 // Hand off to a worker thread
217                 // - TODO: Actually have worker threads
218                 printf("%i bytes from %x:%i\n", length,
219                         ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
220                 
221                 client = Server_GetClient(req->ClientID);
222                 if( req->ClientID == 0 )
223                 {
224                         memcpy(&client->ClientAddr, &addr, sizeof(addr));
225                 }
226                 else if( memcmp(&client->ClientAddr, &addr, sizeof(addr)) != 0 )
227                 {
228                         printf("ClientID %i used by %x:%i\n",
229                                 client->ClientID, ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
230                         printf(" actually owned by %x:%i\n",
231                                 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
232                         continue;
233                 }
234                 
235                 if( client->CurrentRequest ) {
236                         printf("Worker thread for %x:%i is busy\n",
237                                 ntohl(client->ClientAddr.sin_addr.s_addr), ntohs(client->ClientAddr.sin_port));
238                         continue;
239                 }
240                 
241                 client->CurrentRequest = req;
242                 SDL_CondSignal(client->WaitFlag);
243                 #endif
244         }
245         
246         return -1;
247 }

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