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