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