ecere/net/Service: Avoiding problems when trying to start a Service already started
[sdk] / ecere / src / net / Service.ec
1 #define __statement __extension__   // To compile for Android/X86 (Need to add support to eC)
2                                     // Also had to add __extension__ to __swap16md macro in endian.h
3 namespace net;
4
5 #ifndef ECERE_NONET
6
7 #if defined(__WIN32__)
8 #define SOCKLEN_TYPE int
9 #define WIN32_LEAN_AND_MEAN
10 #define String _String
11 #include <winsock.h>
12 #undef String
13
14 #elif defined(__unix__) || defined(__APPLE__)
15 default:
16 #define SOCKLEN_TYPE socklen_t
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/socket.h>
25 #include <sys/wait.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <arpa/inet.h>
29 #undef set
30 #undef uint
31 private:
32
33 typedef int SOCKET;
34 typedef struct hostent HOSTENT;
35 typedef struct sockaddr SOCKADDR;
36 typedef struct sockaddr_in SOCKADDR_IN;
37 typedef struct in_addr IN_ADDR;
38 #define closesocket(s) close(s)
39
40 #endif
41
42 import "network"
43
44 public class Service
45 {
46 public:
47    property int port { set { port = value; } get { return port; } };
48    property Socket firstClient { get { return sockets.first; } };
49    property bool processAlone { get { return processAlone; } set { processAlone = value; } };
50
51    virtual void OnAccept();
52
53    s = -1;
54
55    // --- Services ---
56
57    bool Start()
58    {
59    #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
60       SOCKET s;
61
62       if(this.s != -1)
63          return false; // Already started
64
65    #ifdef DEBUG_SOCKETS
66       Log("[P] [NStartService]\n");
67    #endif
68
69       s = socket(AF_INET,SOCK_STREAM,0);
70       if(s != -1)
71       {
72          SOCKADDR_IN a;
73          bool val = true;
74
75          a.sin_family=AF_INET;
76          a.sin_port=htons((uint16)port);
77          a.sin_addr.s_addr=INADDR_ANY;
78    #ifdef DEBUG_SOCKETS
79          Log("Service Socket: %x\n", s);
80    #endif
81
82          setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
83          if(!bind(s,(SOCKADDR *)&a, sizeof(a)))
84          {
85             if(!listen(s,5))
86             {
87                network.mutex.Wait();
88                network.services.Add(this);
89                this.s = s;
90
91                destroyed = false;
92                sockets.Clear();
93
94                // Fix up the links/offsets here...
95                sockets.offset = (uint)(uintptr)&((Socket)0).prev;
96
97                FD_SET(s, &network.readSet);
98                FD_SET(s, &network.exceptSet);
99                if(s >= network.ns)
100                {
101                   network.ns = (int)(s+1);
102                   network.socketsSemaphore.Release();
103                }
104                network.mutex.Release();
105                return true;
106             }
107          }
108          closesocket(s);
109       }
110    #endif
111       return false;
112    }
113
114    bool Stop(void)
115    {
116    #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
117       SOCKET s = this.s;
118       Socket socket;
119
120    #ifdef DEBUG_SOCKETS
121       Log("[P] [NStopService]\n");
122    #endif
123
124       network.mutex.Wait();
125       while((socket = sockets.first))
126       {
127          socket.Free(false);
128          delete socket;
129       }
130       network.mutex.Release();
131
132       if(s != -1)
133       {
134          network.mutex.Wait();
135          this.s = -1;
136          network.services.Remove(this);
137          FD_CLR(s, &network.readSet);
138          FD_CLR(s, &network.exceptSet);
139          network.mutex.Release();
140          closesocket(s);
141       }
142
143       Network_DetermineMaxSocket();
144       return true;
145    #endif
146       return false;
147    }
148
149    bool Process()
150    {
151       bool gotEvent = false;
152       if(s != -1)
153       {
154          fd_set rs, ws, es;
155          int selectResult;
156          struct timeval tvTO = {0, 200000};
157
158          FD_ZERO(&rs);
159          FD_ZERO(&ws);
160          FD_ZERO(&es);
161          FD_SET(s, &rs);
162          //FD_SET(s, &ws);
163          FD_SET(s, &es);
164
165          selectResult = select((int)(s+1), &rs, &ws, &es, &tvTO);
166          if(selectResult > 0)
167          {
168             if(FD_ISSET(s, &rs))
169             {
170                accepted = false;
171                OnAccept();
172                if(!accepted)
173                {
174                   SOCKET s;
175                   SOCKADDR_IN a;
176                   SOCKLEN_TYPE addrLen = sizeof(a);
177                   s = accept(this.s,(SOCKADDR *)&a,&addrLen);
178                   closesocket(s);
179                }
180                gotEvent |= true;
181             }
182          }
183       }
184       return gotEvent;
185    }
186
187 private:
188
189    Service()
190    {
191       Network_Initialize();
192    }
193
194    ~Service()
195    {
196       Stop();
197    }
198
199    int port;
200    Service prev, next;
201
202    SOCKET s;
203    OldList sockets;
204    bool destroyed;
205    bool accepted;
206    bool processAlone;
207 }
208 #endif