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