ecere: Initial Emscripten support
[sdk] / ecere / src / net / network.ec
1 #define _Noreturn
2
3 namespace net;
4
5 #ifndef ECERE_NONET
6
7 #if defined(__WIN32__)
8
9 #define WIN32_LEAN_AND_MEAN
10 #define String _String
11 #include <winsock.h>
12 #undef String
13 static WSADATA wsaData;
14
15 #elif defined(__unix__) || defined(__APPLE__)
16 default:
17 #define set _set
18 #define uint _uint
19 #include <sys/time.h>
20 #include <unistd.h>
21
22 #include <netinet/in.h>
23 #include <netdb.h>
24 #include <sys/select.h>
25 #include <sys/socket.h>
26 #include <sys/wait.h>
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <arpa/inet.h>
30 #undef set
31 #undef uint
32 typedef int SOCKET;
33 typedef struct hostent HOSTENT;
34 typedef struct sockaddr SOCKADDR;
35 typedef struct sockaddr_in SOCKADDR_IN;
36 typedef struct in_addr IN_ADDR;
37 #define closesocket(s) close(s)
38 private:
39 #endif
40
41 import "GuiApplication"
42 import "Service"
43 import "Socket"
44
45 private struct NetworkData
46 {
47    // Connections to the outside world
48    OldList sockets;
49    // Local services
50    OldList services;
51    // Ongoing Connections
52    OldList connectSockets;
53    // Socket Sets
54    fd_set readSet, writeSet, exceptSet;
55    fd_set selectRS, selectWS, selectES;
56
57    int ns;
58
59    // Synchronization Elements
60    Thread networkThread;
61    Semaphore socketsSemaphore;
62    Semaphore selectSemaphore;
63    bool networkEvent;
64    bool connectEvent;
65    bool networkInitialized;
66    bool networkTerminated;
67    uint errorLevel, lastErrorCode;
68    bool leftOverBytes;
69    Mutex processMutex;
70    Mutex mutex;
71    int64 mainThreadID;
72    OldList mtSemaphores;
73 };
74
75 #include <errno.h>
76
77 NetworkData network;
78
79 static class NetworkThread : Thread
80 {
81    uint Main()
82    {
83       network.mutex.Wait();
84       while(!network.networkTerminated)
85       {
86          int ns = network.ns;
87
88          if(ns)
89          {
90             struct timeval tv = { 0, 0 }; // TESTING 0 INSTEAD OF (int)(1000000 / 18.2) };
91
92             network.selectRS = network.readSet, network.selectWS = network.writeSet, network.selectES = network.exceptSet;
93
94             network.mutex.Release();
95    #ifdef DEBUG_SOCKETS
96             Log("[N] Waiting for network event...\n");
97    #endif
98             if(select(ns, &network.selectRS, &network.selectWS, &network.selectES, &tv))
99             {
100                network.mutex.Wait();
101                network.networkEvent = true;
102    #ifdef DEBUG_SOCKETS
103                Log("[N] Signaling Network event\n");
104    #endif
105                guiApp.SignalEvent();
106    #ifdef DEBUG_SOCKETS
107                Log("[N] Waiting for select semaphore in Network Thread...\n");
108    #endif
109                network.mutex.Release();
110                network.selectSemaphore.Wait();
111                network.mutex.Wait();
112             }
113             else
114             {
115                ecere::sys::Sleep(1 / 18.2f);
116                network.mutex.Wait();
117             }
118          }
119          else
120          {
121             network.mutex.Release();
122             network.socketsSemaphore.Wait();
123             network.mutex.Wait();
124          }
125
126       }
127       network.mutex.Release();
128       return 0;
129    }
130 }
131
132 void Network_DetermineMaxSocket()
133 {
134    Service service;
135    Socket socket;
136
137    network.mutex.Wait();
138    network.ns = 0;
139    for(socket = network.sockets.first; socket; socket = socket.next)
140       if(!socket.processAlone && !socket.destroyed && socket.s >= network.ns)
141          network.ns = (int)(socket.s + 1);
142    for(socket = network.connectSockets.first; socket; socket = socket.next)
143       if(!socket.destroyed && socket.s >= network.ns)
144          network.ns = (int)(socket.s + 1);
145
146    for(service = network.services.first; service; service = service.next)
147    {
148       if(!service.destroyed && !service.processAlone)
149       {
150          if(service.s >= network.ns)
151             network.ns = (int)(service.s + 1);
152       }
153       for(socket = service.sockets.first; socket; socket = socket.next)
154          if(!socket.destroyed && !socket.processAlone && socket.s >= network.ns)
155             network.ns = (int)(socket.s + 1);
156    }
157    network.mutex.Release();
158 }
159
160 // --- Network System ---
161 #endif
162
163 bool Network_Initialize()
164 {
165 #ifndef ECERE_NONET
166    if(!network.networkInitialized)
167    {
168 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
169       network.networkInitialized = true;
170       network.networkTerminated = false;
171 #if defined(__WIN32__)
172       WSAStartup(0x0002, &wsaData);
173 #endif
174
175       network.services.Clear();
176
177       network.services.offset = (uint)(uintptr)&((Service)0).prev;
178       network.sockets.Clear();
179
180       network.sockets.offset = (uint)(uintptr)&((Socket)0).prev;
181
182       network.connectSockets.Clear();
183       network.connectSockets.offset = (uint)(uintptr)&((Socket)0).prev;
184
185       FD_ZERO(&network.readSet);
186       FD_ZERO(&network.writeSet);
187       FD_ZERO(&network.exceptSet);
188
189       network.socketsSemaphore = Semaphore { };
190       network.selectSemaphore = Semaphore { };
191       network.networkThread = NetworkThread { };
192       incref network.networkThread;
193
194       network.errorLevel = 2;
195
196       network.processMutex = Mutex { };
197       network.mutex = Mutex { };
198
199       network.mainThreadID = GetCurrentThreadID();
200
201       network.networkThread.Create();
202 #endif
203    }
204    return true;
205 #else
206    return false;
207 #endif
208 }
209
210 void Network_Terminate()
211 {
212 #ifndef ECERE_NONET
213
214    if(network.networkInitialized)
215    {
216 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
217       Service service;
218       Socket socket;
219
220       guiApp.PauseNetworkEvents();
221       network.networkTerminated = true;
222
223       delete network.processMutex;
224       delete network.mutex;
225
226       for(socket = network.connectSockets.first; socket; socket = socket.next)
227       {
228          socket.connectThread.Wait();
229          delete socket.connectThread;
230       }
231
232       network.socketsSemaphore.Release();
233       network.selectSemaphore.Release();
234
235       network.networkThread.Wait();
236       delete network.networkThread;
237
238       // Cleanup External network.sockets
239       while((socket = network.sockets.first))
240       {
241          incref socket;
242          //network.sockets.Remove(socket); //THIS IS ALREADY DONE IN Socket::Free
243          socket.Free(true);
244          if(socket._refCount > 1) socket._refCount--;
245          delete socket;
246       }
247       while((socket = network.connectSockets.first))
248       {
249          //network.connectSockets.Remove(socket); //THIS IS ALREADY DONE IN Socket::Free
250          socket.Free(true);
251          delete socket;
252       }
253
254       // Cleanup network.services
255       while((service = network.services.first))
256          service.Stop();
257
258       network.ns = 0;
259
260 #if defined(__WIN32__)
261       WSACleanup();
262 #endif
263
264       delete network.selectSemaphore;
265       delete network.socketsSemaphore;
266 #endif
267 #ifdef DEBUG_SOCKETS
268       Log("[P] Network System Terminated\n");
269 #endif
270       network.networkInitialized = false;
271    }
272 #endif
273 }
274
275 #ifndef ECERE_NONET
276
277 public bool GetAddressFromName(const char * hostName, char * inetAddress)
278 {
279    HOSTENT * host;
280
281    if(!Network_Initialize())
282       return false;
283
284    host = gethostbyname(hostName);
285    if(host)
286    {
287       strcpy(inetAddress, inet_ntoa(*((IN_ADDR *)host->h_addr)));
288       return true;
289    }
290    return false;
291 }
292
293 public bool GetNameFromAddress(const char * inetAddress, char * hostName)
294 {
295    struct in_addr in;
296    HOSTENT * host;
297
298    if(!Network_Initialize())
299       return false;
300
301    in.s_addr = inet_addr(inetAddress);
302    host = gethostbyaddr((char *)&in, 4, PF_INET);
303    if(host)
304    {
305       strcpy(hostName, host->h_name);
306       return true;
307    }
308    return false;
309 }
310
311 public bool GetHostName(char * hostName, int size)
312 {
313    if(!Network_Initialize())
314       return false;
315
316    return !gethostname(hostName,size);
317 }
318
319 #endif