]> git.mxchange.org Git - simgear.git/blob - simgear/io/raw_socket.cxx
Compile with MSVC10
[simgear.git] / simgear / io / raw_socket.cxx
1 /*
2      simgear::Socket, adapted from PLIB Socket by James Turner
3      Copyright (C) 2010  James Turner
4      
5      PLIB - A Suite of Portable Game Libraries
6      Copyright (C) 1998,2002  Steve Baker
7  
8      This library is free software; you can redistribute it and/or
9      modify it under the terms of the GNU Library General Public
10      License as published by the Free Software Foundation; either
11      version 2 of the License, or (at your option) any later version.
12  
13      This library is distributed in the hope that it will be useful,
14      but WITHOUT ANY WARRANTY; without even the implied warranty of
15      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16      Library General Public License for more details.
17  
18      You should have received a copy of the GNU Library General Public
19      License along with this library; if not, write to the Free Software
20      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #  include <simgear_config.h>
25 #endif
26
27 #include <simgear/compiler.h>
28
29 #include "sg_socket.hxx"
30
31 #if defined(_WIN32) && !defined(__CYGWIN__)
32 # define WINSOCK // use winsock convetions, otherwise standard POSIX
33 #endif
34
35 #include <cstdlib>
36 #include <ctime>
37 #include <cstring>
38 #include <cassert>
39 #include <cstdio> // for snprintf
40
41 #if defined(WINSOCK)
42 #  include <winsock.h>
43 #  include <stdarg.h>
44 #else
45 #  include <sys/types.h>
46 #  include <sys/socket.h>
47 #  include <netinet/in.h>
48 #  include <arpa/inet.h>
49 #  include <sys/time.h>  
50 #  include <unistd.h>
51 #  include <netdb.h>
52 #  include <fcntl.h>
53 #endif
54
55 #if defined(_MSC_VER) && !defined(socklen_t)
56 #define socklen_t int
57 #endif
58
59 #include <simgear/debug/logstream.hxx>
60 #include <simgear/structure/exception.hxx>
61
62 namespace simgear
63 {
64                                                                                        
65 IPAddress::IPAddress ( const char* host, int port )
66 {
67   set ( host, port ) ;
68 }
69
70
71 void IPAddress::set ( const char* host, int port )
72 {
73   memset(this, 0, sizeof(IPAddress));
74
75   sin_family = AF_INET ;
76   sin_port = htons (port);
77
78   /* Convert a string specifying a host name or one of a few symbolic
79   ** names to a numeric IP address.  This usually calls gethostbyname()
80   ** to do the work; the names "" and "<broadcast>" are special.
81   */
82
83   if (!host || host[0] == '\0') {
84     sin_addr = INADDR_ANY;
85     return;
86   }
87   
88   if (strcmp(host, "<broadcast>") == 0) {
89     sin_addr = INADDR_BROADCAST;
90     return;
91   }
92   
93   sin_addr = inet_addr ( host ) ;
94   if (sin_addr != INADDR_NONE) {
95     return;
96   }
97 // finally, try gethostbyname
98     struct hostent *hp = gethostbyname ( host ) ;
99     if (!hp) {
100       SG_LOG(SG_IO, SG_WARN, "gethostbyname failed for " << host);
101       sin_addr = INADDR_ANY ;
102       return;
103     }
104     
105     memcpy ( (char *) &sin_addr, hp->h_addr, hp->h_length ) ;
106 }
107
108
109 /* Create a string object representing an IP address.
110    This is always a string of the form 'dd.dd.dd.dd' (with variable
111    size numbers). */
112
113 const char* IPAddress::getHost () const
114 {
115 #if 0
116   const char* buf = inet_ntoa ( sin_addr ) ;
117 #else
118   static char buf [32];
119         long x = ntohl(sin_addr);
120         sprintf(buf, "%d.%d.%d.%d",
121                 (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
122                 (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff );
123 #endif
124   return buf;
125 }
126
127 unsigned int IPAddress::getIP () const 
128
129         return sin_addr; 
130 }
131
132 unsigned int IPAddress::getPort() const
133 {
134   return ntohs(sin_port);
135 }
136
137 unsigned int IPAddress::getFamily () const 
138
139         return sin_family; 
140 }
141
142 const char* IPAddress::getLocalHost ()
143 {
144   //gethostbyname(gethostname())
145
146   char buf[256];
147   memset(buf, 0, sizeof(buf));
148   gethostname(buf, sizeof(buf)-1);
149   const hostent *hp = gethostbyname(buf);
150
151   if (hp && *hp->h_addr_list)
152   {
153     in_addr     addr = *((in_addr*)*hp->h_addr_list);
154     const char* host = inet_ntoa(addr);
155
156     if ( host )
157       return host ;
158   }
159
160   return "127.0.0.1" ;
161 }
162
163
164 bool IPAddress::getBroadcast () const
165 {
166   return sin_addr == INADDR_BROADCAST;
167 }
168
169
170 Socket::Socket ()
171 {
172   handle = -1 ;
173 }
174
175
176 Socket::~Socket ()
177 {
178   close () ;
179 }
180
181
182 void Socket::setHandle (int _handle)
183 {
184   close () ;
185   handle = _handle ;
186 }
187
188
189 bool Socket::open ( bool stream )
190 {
191   close () ;
192   handle = ::socket ( AF_INET, (stream? SOCK_STREAM: SOCK_DGRAM), 0 ) ;
193   return (handle != -1);
194 }
195
196
197 void Socket::setBlocking ( bool blocking )
198 {
199   assert ( handle != -1 ) ;
200
201 #if defined(WINSOCK)
202     u_long nblocking = blocking? 0: 1;
203   ::ioctlsocket(handle, FIONBIO, &nblocking);
204 #else
205
206   int delay_flag = ::fcntl (handle, F_GETFL, 0);
207
208   if (blocking)
209     delay_flag &= (~O_NDELAY);
210   else
211     delay_flag |= O_NDELAY;
212
213   ::fcntl (handle, F_SETFL, delay_flag);
214 #endif
215 }
216
217
218 void Socket::setBroadcast ( bool broadcast )
219 {
220   assert ( handle != -1 ) ;
221   int result;
222   if ( broadcast ) {
223       int one = 1;
224 #if defined(_WIN32) || defined(__CYGWIN__)
225       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one) );
226 #else
227       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one) );
228 #endif
229   } else {
230       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, NULL, 0 );
231   }
232   
233   if ( result < 0 ) {
234       throw sg_exception("Socket::setBroadcast failed");
235   }
236 }
237
238
239 int Socket::bind ( const char* host, int port )
240 {
241   assert ( handle != -1 ) ;
242   IPAddress addr ( host, port ) ;
243   return ::bind(handle,(const sockaddr*)&addr,sizeof(IPAddress));
244 }
245
246
247 int Socket::listen ( int backlog )
248 {
249   assert ( handle != -1 ) ;
250   return ::listen(handle,backlog);
251 }
252
253
254 int Socket::accept ( IPAddress* addr )
255 {
256   assert ( handle != -1 ) ;
257
258   if ( addr == NULL )
259   {
260     return ::accept(handle,NULL,NULL);
261   }
262   else
263   {
264     socklen_t addr_len = (socklen_t) sizeof(IPAddress) ;
265     return ::accept(handle,(sockaddr*)addr,&addr_len);
266   }
267 }
268
269
270 int Socket::connect ( const char* host, int port )
271 {
272   assert ( handle != -1 ) ;
273   IPAddress addr ( host, port ) ;
274   if ( addr.getBroadcast() ) {
275       setBroadcast( true );
276   }
277   return ::connect(handle,(const sockaddr*)&addr,sizeof(IPAddress));
278 }
279
280
281 int Socket::send (const void * buffer, int size, int flags)
282 {
283   assert ( handle != -1 ) ;
284   return ::send (handle, (const char*)buffer, size, flags);
285 }
286
287
288 int Socket::sendto ( const void * buffer, int size,
289                         int flags, const IPAddress* to )
290 {
291   assert ( handle != -1 ) ;
292   return ::sendto(handle,(const char*)buffer,size,flags,
293                          (const sockaddr*)to,sizeof(IPAddress));
294 }
295
296
297 int Socket::recv (void * buffer, int size, int flags)
298 {
299   assert ( handle != -1 ) ;
300   return ::recv (handle, (char*)buffer, size, flags);
301 }
302
303
304 int Socket::recvfrom ( void * buffer, int size,
305                           int flags, IPAddress* from )
306 {
307   assert ( handle != -1 ) ;
308   socklen_t fromlen = (socklen_t) sizeof(IPAddress) ;
309   return ::recvfrom(handle,(char*)buffer,size,flags,(sockaddr*)from,&fromlen);
310 }
311
312
313 void Socket::close (void)
314 {
315   if ( handle != -1 )
316   {
317 #if defined(WINSOCK)
318     ::closesocket( handle );
319 #else
320     ::close( handle );
321 #endif
322     handle = -1 ;
323   }
324 }
325
326
327 bool Socket::isNonBlockingError ()
328 {
329 #if defined(WINSOCK)
330   int wsa_errno = WSAGetLastError();
331   if ( wsa_errno != 0 )
332   {
333     WSASetLastError(0);
334         SG_LOG(SG_IO, SG_WARN, "isNonBlockingError: WSAGetLastError():" << wsa_errno);
335     switch (wsa_errno) {
336     case WSAEWOULDBLOCK: // always == NET_EAGAIN?
337     case WSAEALREADY:
338     case WSAEINPROGRESS:
339       return true;
340     }
341   }
342   return false;
343 #else
344   switch (errno) {
345   case EWOULDBLOCK: // always == NET_EAGAIN?
346   case EALREADY:
347   case EINPROGRESS:
348     return true;
349   }
350   return false;
351
352 #endif
353 }
354
355
356 //////////////////////////////////////////////////////////////////////
357 //
358 //      modified version by os
359 //
360 //////////////////////////////////////////////////////////////////////
361 int Socket::select ( Socket** reads, Socket** writes, int timeout )
362 {
363   fd_set r,w;
364   int   retval;
365   
366   FD_ZERO (&r);
367   FD_ZERO (&w);
368
369   int i, k ;
370   int num = 0 ;
371
372   if ( reads )
373   {
374     for ( i=0; reads[i]; i++ )
375     {
376       int fd = reads[i]->getHandle();
377       FD_SET (fd, &r);
378       num++;
379     }
380   }
381
382   if ( writes )
383   {
384     for ( i=0; writes[i]; i++ )
385     {
386       int fd = writes[i]->getHandle();
387       FD_SET (fd, &w);
388       num++;
389     }
390   }
391
392   if (!num)
393     return num ;
394
395   /* Set up the timeout */
396   struct timeval tv ;
397   tv.tv_sec = timeout/1000;
398   tv.tv_usec = (timeout%1000)*1000;
399
400   // It bothers me that select()'s first argument does not appear to
401   // work as advertised... [it hangs like this if called with
402   // anything less than FD_SETSIZE, which seems wasteful?]
403   
404   // Note: we ignore the 'exception' fd_set - I have never had a
405   // need to use it.  The name is somewhat misleading - the only
406   // thing I have ever seen it used for is to detect urgent data -
407   // which is an unportable feature anyway.
408
409   retval = ::select (FD_SETSIZE, &r, &w, 0, &tv);
410
411   //remove sockets that had no activity
412
413   num = 0 ;
414
415   if ( reads )
416   {
417     for ( k=i=0; reads[i]; i++ )
418     {
419       int fd = reads[i]->getHandle();
420       if ( FD_ISSET (fd, &r) )
421       {
422         reads[k++] = reads[i];
423         num++;
424       }
425     }
426     reads[k] = NULL ;
427   }
428
429   if ( writes )
430   {
431     for ( k=i=0; writes[i]; i++ )
432     {
433       int fd = writes[i]->getHandle();
434       if ( FD_ISSET (fd, &w) )
435       {
436         writes[k++] = writes[i];
437         num++;
438       }
439     }
440     writes[k] = NULL ;
441   }
442
443   if (retval == 0) // timeout
444     return (-2);
445   if (retval == -1)// error
446     return (-1);
447
448   return num ;
449 }
450
451
452 /* Init/Exit functions */
453
454 static void netExit ( void )
455 {
456 #if defined(WINSOCK)
457         /* Clean up windows networking */
458         if ( WSACleanup() == SOCKET_ERROR ) {
459                 if ( WSAGetLastError() == WSAEINPROGRESS ) {
460                         WSACancelBlockingCall();
461                         WSACleanup();
462                 }
463         }
464 #endif
465 }
466
467 int Socket::initSockets()
468 {
469   assert ( sizeof(sockaddr_in) == sizeof(IPAddress) ) ;
470
471 #if defined(WINSOCK)
472         /* Start up the windows networking */
473         WORD version_wanted = MAKEWORD(1,1);
474         WSADATA wsaData;
475
476         if ( WSAStartup(version_wanted, &wsaData) != 0 ) {
477                 throw sg_exception("WinSock initialization failed");
478         }
479 #endif
480
481   atexit( netExit ) ;
482         return(0);
483 }
484
485
486 } // of namespace simgear
487