]> git.mxchange.org Git - simgear.git/blob - simgear/io/sg_netChannel.cxx
Build fixes for net classes in Simgear.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 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
38 #include <simgear/debug/logstream.hxx>
39
40 namespace simgear  {
41
42 static NetChannel* channels = 0 ;
43
44 NetChannel::NetChannel ()
45 {
46   closed = true ;
47   connected = false ;
48   accepting = false ;
49   write_blocked = false ;
50   should_delete = false ;
51
52   next_channel = channels ;
53   channels = this ;
54 }
55   
56 NetChannel::~NetChannel ()
57 {
58   close();
59
60   NetChannel* prev = NULL ;
61
62   for ( NetChannel* ch = channels; ch != NULL;
63                     ch = ch -> next_channel )
64   {
65     if (ch == this)
66     {
67       ch = ch -> next_channel ;
68       if ( prev != NULL )
69         prev -> next_channel = ch ;
70       else
71         channels = ch ;
72       next_channel = 0 ;
73       break;
74     }
75     prev = ch ;
76   }
77 }
78   
79 void
80 NetChannel::setHandle (int handle, bool is_connected)
81 {
82   close () ;
83   Socket::setHandle ( handle ) ;
84   connected = is_connected ;
85   //if ( connected ) this->handleConnect();
86   closed = false ;
87 }
88
89 bool
90 NetChannel::open (void)
91 {
92   close();
93   if (Socket::open(true)) {
94     closed = false ;
95     setBlocking ( false ) ;
96     return true ;
97   }
98   return false ;
99 }
100
101 int
102 NetChannel::listen ( int backlog )
103 {
104   accepting = true ;
105   return Socket::listen ( backlog ) ;
106 }
107
108 int
109 NetChannel::connect ( const char* host, int port )
110 {
111   int result = Socket::connect ( host, port ) ;
112   if (result == 0) {
113     connected = true ;
114     //this->handleConnect();
115     return 0;
116   } else if (isNonBlockingError ()) {
117     return 0;
118   } else {
119     // some other error condition
120     this->handleError (result);
121     close();
122     return -1;
123   }
124 }
125
126 int
127 NetChannel::send (const void * buffer, int size, int flags)
128 {
129   int result = Socket::send (buffer, size, flags);
130   
131   if (result == (int)size) {
132     // everything was sent
133     write_blocked = false ;
134     return result;
135   } else if (result >= 0) {
136     // not all of it was sent, but no error
137     write_blocked = true ;
138     return result;
139   } else if (isNonBlockingError ()) {
140     write_blocked = true ;
141     return 0;
142   } else {
143     this->handleError (result);
144     close();
145     return -1;
146   }
147   
148 }
149
150 int
151 NetChannel::recv (void * buffer, int size, int flags)
152 {
153   int result = Socket::recv (buffer, size, flags);
154   
155   if (result > 0) {
156     return result;
157   } else if (result == 0) {
158     close();
159     return 0;
160   } else if (isNonBlockingError ()) {
161     return 0;
162   } else {
163     this->handleError (result);
164     close();
165     return -1;
166   }
167 }
168
169 void
170 NetChannel::close (void)
171 {
172   if ( !closed )
173   {
174     this->handleClose();
175   
176     closed = true ;
177     connected = false ;
178     accepting = false ;
179     write_blocked = false ;
180   }
181
182   Socket::close () ;
183 }
184
185 void
186 NetChannel::handleReadEvent (void)
187 {
188   if (accepting) {
189     if (!connected) {
190       connected = true ;
191       //this->handleConnect();
192     }
193     this->handleAccept();
194   } else if (!connected) {
195     connected = true ;
196     //this->handleConnect();
197     this->handleRead();
198   } else {
199     this->handleRead();
200   }
201 }
202
203 void
204 NetChannel::handleWriteEvent (void)
205 {
206   if (!connected) {
207     connected = true ;
208     //this->handleConnect();
209   }
210   write_blocked = false ;
211   this->handleWrite();
212 }
213
214 bool
215 NetChannel::poll (unsigned int timeout)
216 {
217   if (!channels)
218     return false ;
219   
220   enum { MAX_SOCKETS = 256 } ;
221   Socket* reads [ MAX_SOCKETS+1 ] ;
222   Socket* writes [ MAX_SOCKETS+1 ] ;
223   Socket* deletes [ MAX_SOCKETS+1 ] ;
224   int nreads = 0 ;
225   int nwrites = 0 ;
226   int ndeletes = 0 ;
227   int nopen = 0 ;
228   NetChannel* ch;
229   for (  ch = channels; ch != NULL; ch = ch -> next_channel )
230   {
231     if ( ch -> should_delete )
232     {
233       assert(ndeletes<MAX_SOCKETS);
234       deletes[ndeletes++] = ch ;
235     }
236     else if ( ! ch -> closed )
237     {
238       nopen++ ;
239       if (ch -> readable()) {
240         assert(nreads<MAX_SOCKETS);
241         reads[nreads++] = ch ;
242       }
243       if (ch -> writable()) {
244         assert(nwrites<MAX_SOCKETS);
245         writes[nwrites++] = ch ;
246       }
247     }
248   }
249   reads[nreads] = NULL ;
250   writes[nwrites] = NULL ;
251   deletes[ndeletes] = NULL ;
252
253   int i ;
254   for ( i=0; deletes[i]; i++ )
255   {
256     ch = (NetChannel*)deletes[i];
257     delete ch ;
258   }
259
260   if (!nopen)
261     return false ;
262   if (!nreads && !nwrites)
263     return true ; //hmmm- should we shutdown?
264
265   Socket::select (reads, writes, timeout) ;
266
267   for ( i=0; reads[i]; i++ )
268   {
269     ch = (NetChannel*)reads[i];
270     if ( ! ch -> closed )
271       ch -> handleReadEvent();
272   }
273
274   for ( i=0; writes[i]; i++ )
275   {
276     ch = (NetChannel*)writes[i];
277     if ( ! ch -> closed )
278       ch -> handleWriteEvent();
279   }
280
281   return true ;
282 }
283
284 void
285 NetChannel::loop (unsigned int timeout)
286 {
287   while ( poll (timeout) ) ;
288 }
289
290
291 void NetChannel::handleRead (void) {
292   SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read");
293 }
294
295 void NetChannel::handleWrite (void) {
296   SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled write");
297 }
298
299 void NetChannel::handleAccept (void) {
300   SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled accept");
301 }
302
303 void NetChannel::handleError (int error) {
304   SG_LOG(SG_IO, SG_WARN,"Network:" << getHandle() << ": errno: " << strerror(errno) <<"(" << errno << ")");
305 }
306
307 } // of namespace simgear