]> git.mxchange.org Git - simgear.git/blob - simgear/io/sg_netChannel.cxx
SGPath: fix creating paths with permission checker.
[simgear.git] / simgear / io / sg_netChannel.cxx
1 /*
2   Copied from PLIB into SimGear
3   
4      PLIB - A Suite of Portable Game Libraries
5      Copyright (C) 1998,2002  Steve Baker
6  
7      This library is free software; you can redistribute it and/or
8      modify it under the terms of the GNU Library General Public
9      License as published by the Free Software Foundation; either
10      version 2 of the License, or (at your option) any later version.
11  
12      This library is distributed in the hope that it will be useful,
13      but WITHOUT ANY WARRANTY; without even the implied warranty of
14      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15      Library General Public License for more details.
16  
17      You should have received a copy of the GNU Library General Public
18      License along with this library; if not, write to the Free Software
19      Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
20  
21      For further information visit http://plib.sourceforge.net
22
23      $Id: netChannel.cxx 1906 2004-03-22 19:44:50Z sjbaker $
24 */
25
26 // TODO:
27 // have all socket-related functions assert that the socket has not
28 // been closed.  [a read event may close it, and a write event may try
29 // to write or something...]
30 // Maybe assert valid handle, too?
31
32 #include "sg_netChannel.hxx"
33
34 #include <memory>
35 #include <cassert>
36 #include <cstring>
37 #include <errno.h>
38
39 #include <simgear/debug/logstream.hxx>
40
41
42 namespace simgear  {
43
44 NetChannel::NetChannel ()
45 {
46   closed = true ;
47   connected = false ;
48   resolving_host  = false;
49   accepting = false ;
50   write_blocked = false ;
51   should_delete = false ;
52   poller = NULL;
53 }
54   
55 NetChannel::~NetChannel ()
56 {
57   close();
58   if (poller) {
59       poller->removeChannel(this);
60   }
61 }
62   
63 void
64 NetChannel::setHandle (int handle, bool is_connected)
65 {
66   close () ;
67   Socket::setHandle ( handle ) ;
68   connected = is_connected ;
69   closed = false ;
70 }
71
72 bool
73 NetChannel::open (void)
74 {
75   close();
76   if (Socket::open(true)) {
77     closed = false ;
78     setBlocking ( false ) ;
79     return true ;
80   }
81   return false ;
82 }
83
84 int
85 NetChannel::listen ( int backlog )
86 {
87   accepting = true ;
88   return Socket::listen ( backlog ) ;
89 }
90
91 int
92 NetChannel::connect ( const char* h, int p )
93 {
94   host = h;
95   port = p;
96   resolving_host = true;
97   return handleResolve();
98 }
99
100 int
101 NetChannel::send (const void * buffer, int size, int flags)
102 {
103   int result = Socket::send (buffer, size, flags);
104   
105   if (result == (int)size) {
106     // everything was sent
107     write_blocked = false ;
108     return result;
109   } else if (result >= 0) {
110     // not all of it was sent, but no error
111     write_blocked = true ;
112     return result;
113   } else if (isNonBlockingError ()) {
114     write_blocked = true ;
115     return 0;
116   } else {
117     this->handleError (result);
118     close();
119     return -1;
120   }
121   
122 }
123
124 int
125 NetChannel::recv (void * buffer, int size, int flags)
126 {
127   int result = Socket::recv (buffer, size, flags);
128   
129   if (result > 0) {
130     return result;
131   } else if (result == 0) {
132     close();
133     return 0;
134   } else if (isNonBlockingError ()) {
135     return 0;
136   } else {
137     this->handleError (result);
138     close();
139     return -1;
140   }
141 }
142
143 void
144 NetChannel::close (void)
145 {
146   if ( !closed )
147   {
148     this->handleClose();
149   
150     closed = true ;
151     connected = false ;
152     accepting = false ;
153     write_blocked = false ;
154   }
155
156   Socket::close () ;
157 }
158
159 void
160 NetChannel::handleReadEvent (void)
161 {
162   if (accepting) {
163     if (!connected) {
164       connected = true ;
165     }
166     this->handleAccept();
167   } else if (!connected) {
168     connected = true ;
169     this->handleRead();
170   } else {
171     this->handleRead();
172   }
173 }
174
175 void
176 NetChannel::handleWriteEvent (void)
177 {
178   if (!connected) {
179     connected = true ;
180   }
181   write_blocked = false ;
182   this->handleWrite();
183 }
184
185 int
186 NetChannel::handleResolve()
187 {
188     IPAddress addr;
189     if (!IPAddress::lookupNonblocking(host.c_str(), addr)) {
190         return 0; // not looked up yet, wait longer
191     }
192     
193     if (!addr.isValid()) {
194         SG_LOG(SG_IO, SG_WARN, "Network: host lookup failed:" << host);
195         handleError (ENOENT);
196         close();
197         return -1;
198     }
199     
200     resolving_host = false;
201     addr.setPort(port);
202     int result = Socket::connect ( &addr ) ;
203     if (result == 0) {
204         connected = true ;
205         return 0;
206     } else if (isNonBlockingError ()) {
207         return 0;
208     } else {
209         // some other error condition
210         handleError (result);
211         close();
212         return -1;
213     }
214 }
215
216 void NetChannel::handleRead (void) {
217   SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read");
218 }
219
220 void NetChannel::handleWrite (void) {
221   SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled write");
222 }
223
224 void NetChannel::handleAccept (void) {
225   SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled accept");
226 }
227
228 void NetChannel::handleError (int error)
229 {
230     // warn about address lookup failures seperately, don't warn again.
231     // (and we (ab-)use ENOENT to mean 'name not found'.
232     if (error != ENOENT) {
233         SG_LOG(SG_IO, SG_WARN,"Network:" << getHandle() << ": errno: " << strerror(errno) <<"(" << errno << ")");
234     }
235 }
236
237 void
238 NetChannelPoller::addChannel(NetChannel* channel)
239 {
240     assert(channel);
241     assert(channel->poller == NULL);
242         
243     channel->poller = this;
244     channels.push_back(channel);
245 }
246
247 void
248 NetChannelPoller::removeChannel(NetChannel* channel)
249 {
250     assert(channel);
251     assert(channel->poller == this);
252     channel->poller = NULL;
253     
254     ChannelList::iterator it = channels.begin();
255     for (; it != channels.end(); ++it) {
256         if (*it == channel) {
257             channels.erase(it);
258             return;
259         }
260     }
261 }
262
263 bool
264 NetChannelPoller::poll(unsigned int timeout)
265 {
266     if (channels.empty()) {
267         return false;
268     }
269     
270     enum { MAX_SOCKETS = 256 } ;
271     Socket* reads [ MAX_SOCKETS+1 ] ;
272     Socket* writes [ MAX_SOCKETS+1 ] ;
273     int nreads = 0 ;
274     int nwrites = 0 ;
275     int nopen = 0 ;
276     
277     ChannelList::iterator it = channels.begin();
278     while( it != channels.end() )
279     {
280         NetChannel* ch = *it;
281         if ( ch -> should_delete )
282         {
283             // avoid the channel trying to remove itself from us, or we get
284             // bug http://code.google.com/p/flightgear-bugs/issues/detail?id=1144
285             ch->poller = NULL;
286             delete ch;
287             it = channels.erase(it);
288             continue;
289         }
290
291         ++it; // we've copied the pointer into ch
292         if ( ch->closed ) { 
293             continue;
294         }
295
296         if (ch -> resolving_host )
297         {
298             ch -> handleResolve();
299             continue;
300         }
301       
302         nopen++ ;
303         if (ch -> readable()) {
304           assert(nreads<MAX_SOCKETS);
305           reads[nreads++] = ch ;
306         }
307         if (ch -> writable()) {
308           assert(nwrites<MAX_SOCKETS);
309           writes[nwrites++] = ch ;
310         }
311     } // of array-filling pass
312     
313     reads[nreads] = NULL ;
314     writes[nwrites] = NULL ;
315
316     if (!nopen)
317       return false ;
318     if (!nreads && !nwrites)
319       return true ; //hmmm- should we shutdown?
320
321     Socket::select (reads, writes, timeout) ;
322
323     for ( int i=0; reads[i]; i++ )
324     {
325       NetChannel* ch = (NetChannel*)reads[i];
326       if ( ! ch -> closed )
327         ch -> handleReadEvent();
328     }
329
330     for ( int i=0; writes[i]; i++ )
331     {
332       NetChannel* ch = (NetChannel*)writes[i];
333       if ( ! ch -> closed )
334         ch -> handleWriteEvent();
335     }
336
337     return true ;
338 }
339
340 void
341 NetChannelPoller::loop (unsigned int timeout)
342 {
343   while ( poll (timeout) ) ;
344 }
345
346
347 } // of namespace simgear