fixed: gcc8 compile issues
[opensg.git] / Source / Base / Network / Socket / OSGSocket.cpp
blob36b7552264ae2e25d46ff41d15c46fb07a0d6c1a
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
40 // Includes
41 //---------------------------------------------------------------------------
43 #if defined(__sun)
44 #define BSD_COMP
45 #endif
48 #include <sys/types.h>
49 #ifdef WIN32
50 #include <windows.h>
51 #include <io.h>
52 #else
53 #include <sys/socket.h>
54 #include <netinet/in.h>
55 #include <netinet/tcp.h>
56 #include <arpa/inet.h>
57 #include <netdb.h>
58 #include <unistd.h>
59 #include <fcntl.h>
60 #include <sys/ioctl.h>
61 #endif
62 #include <cerrno>
63 #include <cstdio>
64 #include <cmath>
65 #include <map>
66 #include "OSGSocketAddress.h"
67 #include "OSGSocket.h"
68 #include "OSGSocketSelection.h"
69 #include "OSGNetworkMessage.h"
70 #include "OSGTime.h"
71 #include "OSGBaseFunctions.h"
73 OSG_USING_NAMESPACE
75 /*! \class OSG::Socket
76 \brief Abstract network socket handler
78 Socket base class. The Socket class wraps a socket descriptor. This
79 class has no additional state variables. It is only a handle to the
80 underlying descriptor. Class creation and destruction has no
81 influence on the descriptor. Use open to assign a descriptor and
82 close to remove it from the system. If this class is copied, then
83 there are to classes which share the same descriptor. This is
84 acceptable until you call close for one of these classes, then any other class
85 sharing the same descriptor becomes practically unusable.
86 One purpose of this implementation is to hide the differences between
87 Windows and Unix sockets. Calls to this class should behave equally
88 on all systems. As a result, some methods will not work the way an
89 experienced Windows ore Unix programmer might expect. Please refer
90 to the function documentation for details about this.
94 int Socket::initialized=0;
96 /*-------------------------------------------------------------------------*/
97 /* constructor destructor */
99 /*! Create a new Socket class. A valid socket descriptor will be assigned
100 by calling open on a derived Socket class e.g. StreamSocket or
101 DgramSocket. On Windows WSAStartup is called by the first socket
102 created.
104 Socket::Socket(void):
105 _sd(-1)
107 if(!initialized)
109 initialized=1;
110 #ifdef WIN32
111 WSADATA wsaData;
113 WORD wVersionRequested = MAKEWORD( 2, 2 );
114 if(WSAStartup( wVersionRequested, &wsaData )!=0)
116 throw SocketError("WSAStartup()");
118 #endif
122 /*! Copy constructor
124 Socket::Socket(const Socket &source):
125 _sd(source._sd)
129 /*! Destructor. The Socket class is only a descriptor to the socket.
130 Upon destruction of this class, the socket remains open.
132 Socket::~Socket()
136 /*-------------------------------------------------------------------------*/
137 /* open, close, connect */
139 /*! Close the assigned socket.
141 void Socket::close(void)
143 #ifdef WIN32
144 ::closesocket(_sd);
145 #else
146 ::close(_sd);
147 #endif
150 /*! Bind a socket to a given SocketAddress. It is possible to bind a
151 Socket to a special network interface ore to all availabel interfaces.
153 \param[in] address The address to bind to.
155 \code
156 sock.bind(AnySocketAddress(23344)); // Bind Socket to port 23344
157 sock.bind(Address("123.223.112.33",0); // Bind to the given adapter
158 sock.bind(AnySocketAddress(0)); // Bind to a free port
159 port = sock.getAddress().getPort(); // Get bound port
160 \endcode
162 void Socket::bind(const SocketAddress &address)
164 SocketAddress result=address;
166 if( ::bind(_sd,
167 result.getSockAddr(),
168 result.getSockAddrSize()) < 0)
170 if(getError() ==
171 #if defined WIN32
172 WSAEADDRINUSE
173 #else
174 EADDRINUSE
175 #endif
178 throw SocketInUse("bind()");
180 else
182 throw SocketError("bind()");
187 /*! Set queue length for incomming connection requests.
189 \param[in] maxPending Maximum number of simultaneous connection requests.
191 void Socket::listen(int maxPending)
193 if(::listen(_sd, maxPending) < 0)
195 throw SocketError("listen()");
199 /*! Connect to the given address. After connect, all send data will be
200 transfered to the address.
202 \param[in] address Address to connect to.
204 void Socket::connect(const SocketAddress &address)
206 if( ::connect(_sd,
207 address.getSockAddr(),
208 address.getSockAddrSize()) )
210 throw SocketError("connect()");
214 /*-------------------------------------------------------------------------*/
215 /* read, write nnect */
217 /*! Read \a size bytes into the buffer \a buf. This function waits until there
218 are size bytes available.
219 On Dgram sockets data might be lost, if size is smaller then the
220 incomming package. This situation will not be treated as an error.
222 \param[in,out] buf Buffer that is large enough to hold \a size bytes.
223 \param[in] size Number of bytes to receive.
225 \see recvAvailable recvFrom
227 int Socket::recv(void *buf, int size)
229 int readSize;
230 int pos = 0;
232 while(size)
234 readSize = ::recv(_sd, static_cast<char *>(buf) + pos, size, 0);
235 if(readSize < 0)
237 #if defined WIN32
238 if(getError() == WSAECONNRESET)
240 throw SocketConnReset("recv");
242 if(getError() == WSAEMSGSIZE)
244 readSize = size;
246 else
247 #endif
248 throw SocketError("recv()");
250 if(readSize == 0)
252 return 0;
254 size -= readSize;
255 pos += readSize;
257 return pos;
260 /*! Read at most \a size bytes of availbale data into the buffer \a buf.
261 This function does not wait until enough bytes are available.
263 \param[in,out] buf Buffer that is large enough to hold \a size bytes.
264 \param[in] size Maximum number of bytes to receive.
266 \see recv
268 int Socket::recvAvailable(void *buf, int size)
270 int len;
272 #ifndef WIN32
275 #endif
276 len = ::recv(_sd, static_cast<char *>(buf), size, 0);
277 #ifndef WIN32
279 while(len < 0 && errno == EAGAIN);
280 #endif
282 if(len == -1)
284 #if defined WIN32
285 switch(getError())
287 case WSAECONNRESET:
288 throw SocketConnReset("recvAvailable()");
289 break;
290 case WSAEMSGSIZE:
291 len=size;
292 break;
293 default:
294 throw SocketError("recv()");
296 #else
297 throw SocketError("recv()");
298 #endif
300 return len;
303 /*! Like recv, but buffer and size are taken from the NetworkMessage.
305 \param[in,out] msg NetworkMessage describing the buffer and size to receive.
307 \see recv
309 int Socket::recv(NetworkMessage &msg)
311 NetworkMessage::Header hdr;
312 peek(&hdr, sizeof(hdr));
313 msg.setSize(osgNetToHost<UInt32>(hdr.size));
314 return recv(msg.getBuffer(), msg.getSize());
317 /*! Read \a size bytes into the buffer \a buf. This function waits until there
318 are size bytes available. The read bytes will not be removed from the
319 receive buffer and a subsequent call to recv or recvAvailable will
320 read the same data.
321 On Dgram sockets data might be lost, if size is smaller then the
322 incomming package. This situation will not be treated as an error.
324 \param[in,out] buf Buffer that is large enough to hold \a size bytes.
325 \param[in] size Number of bytes to receive.
327 \see recv recvAvailable
329 int Socket::peek(void *buf, int size)
331 int readSize;
332 int pos = 0;
334 while(size)
336 readSize = ::recv(_sd, static_cast<char *>(buf) + pos, size, MSG_PEEK);
337 if(readSize < 0)
339 #if defined WIN32
340 if(getError() == WSAECONNRESET)
342 throw SocketConnReset("peek");
344 if(getError() == WSAEMSGSIZE)
346 readSize = size;
348 else
349 #endif
350 throw SocketError("peek");
352 if(readSize == 0)
354 return 0;
356 size -= readSize;
357 pos += readSize;
359 return pos;
362 /*! Write size bytes to the socket. This method might block, if the
363 output buffer is full.
365 \param[in] buf Pointer to a buffer with the data to send.
366 \param[in] size Number of bytes to send.
367 \return Number of bytes sent.
369 int Socket::send(const void *buf, int size)
371 int writeSize;
372 int pos = 0;
374 while(size)
376 #if defined(WIN32) && defined(MSG_NOSIGNAL)
377 writeSize = ::send(_sd, static_cast<const char *>(buf) + pos,
378 size, MSG_NOSIGNAL );
379 #else
380 writeSize = ::send(_sd, static_cast<const char *>(buf) + pos,
381 size, 0 );
382 #endif
383 if(writeSize == -1)
385 throw SocketError("send()");
387 if(writeSize == 0)
389 return 0;
391 size -= writeSize;
392 pos += writeSize;
394 return pos;
397 /*! Like send, but buffer and size is taken from the NetworkMessage
399 \param[in] msg NetworkMessage with buffer and size to send.
401 \see send
403 int Socket::send(NetworkMessage &msg)
405 NetworkMessage::Header &hdr = msg.getHeader();
406 hdr.size = osgHostToNet<UInt32>(msg.getSize());
407 return send(msg.getBuffer(), msg.getSize());
410 /*-------------------------------------------------------------------------*/
411 /* socket state access */
413 /*! Enable or disable reuse port behavior. If reuse port is true, then
414 more then one process or thread is able to bind to the same port.
415 This makes sense for multicast or broadcast sockets. For StreamSockets
416 this feature can be used to avoid the <EM>Socket in use</EM> message
417 on not properly closed ports.
419 \param[in] value True to enable port reuse, false to disable it.
422 void Socket::setReusePort(bool value)
424 int v = static_cast<int>(value);
425 #ifdef SO_REUSEPORT
426 ::setsockopt(_sd, SOL_SOCKET, SO_REUSEPORT,
427 reinterpret_cast<SocketOptT*>(&v), sizeof(v));
428 #endif
429 ::setsockopt(_sd, SOL_SOCKET, SO_REUSEADDR,
430 reinterpret_cast<SocketOptT*>(&v), sizeof(v));
433 /*! By default all recv, send, accept calls will block until the operation
434 is finished. This behavior can be switched off by setting blocking to
435 false. This will lead to a more difficult programming. An easier
436 way to get non blocking behavior is to use SocketSelections or
437 waitReadable, waitWritable. These methods provide a timeout
438 for waiting.
440 \param[in] value True to enable blocking mode, false to disable it.
442 \see Socket::waitReadable Socket::waitWritable SocketSelection
444 void Socket::setBlocking(bool value)
446 #ifndef WIN32
447 int val = 0;
449 if(value == false)
450 val = O_NDELAY;
451 if(fcntl(_sd, F_GETFL, &val) < 0)
453 throw SocketError("fcntl()");
455 val |= O_NDELAY;
456 if(value)
458 val ^= O_NDELAY;
460 if(fcntl(_sd, F_SETFL, val) < 0)
462 throw SocketError("fcntl()");
464 #else
465 u_long ulVal = !value;
466 if(ioctlsocket(_sd, FIONBIO, &ulVal) != 0)
468 throw SocketError("ioctlsocket()");
470 #endif
473 /*! Get the SocketAddress this Socket is bound to.
475 \return The bound address of this Socket.
477 \see SocketAddress
479 SocketAddress Socket::getAddress()
481 SocketAddress result;
482 SocketLenT len;
484 len=result.getSockAddrSize();
485 if( ::getsockname(_sd,result.getSockAddr(),&len) < 0)
487 throw SocketError("getsockname()");
489 return result;
492 /*! Set the internal read buffer size.
494 \param[in] size Number of bytes to use as internal read buffer.
496 \see Socket::getReadBufferSize
498 void Socket::setReadBufferSize(int size)
500 ::setsockopt(_sd, SOL_SOCKET, SO_RCVBUF,
501 reinterpret_cast<SocketOptT*>(&size), sizeof(size));
504 /*! Set the internal write buffer size.
506 \param[in] size Number of bytes to use as internal write buffer.
508 \see Socket::getWriteBufferSize
510 void Socket::setWriteBufferSize(int size)
512 ::setsockopt(_sd, SOL_SOCKET, SO_SNDBUF,
513 reinterpret_cast<SocketOptT*>(&size), sizeof(size));
516 /*! Get internal read buffer size.
518 \return Number of bytes used for the internal read buffer.
520 \see Socket::setReadBufferSize
522 int Socket::getReadBufferSize()
524 int v;
525 SocketLenT len = sizeof(v);
526 ::getsockopt(_sd, SOL_SOCKET, SO_RCVBUF,
527 reinterpret_cast<SocketOptT*>(&v), &len);
528 return v;
531 /*! Get internal write buffer size.
533 \return Number of bytes used for the internal write buffer.
535 \see Socket::setWriteBufferSize
537 int Socket::getWriteBufferSize()
539 int v;
540 SocketLenT len = sizeof(v);
541 ::getsockopt(_sd, SOL_SOCKET, SO_SNDBUF,
542 reinterpret_cast<SocketOptT*>(&v), &len);
543 return v;
546 /*! Get number of bytes in the internal read buffer.
548 \return Number of bytes in the internal read buffer.
550 int Socket::getAvailable(void)
552 #ifndef WIN32
553 int value;
554 if(::ioctl(_sd, FIONREAD, &value) < 0)
556 throw SocketError("ioctl()");
558 return value;
559 #else
560 u_long ulVal;
561 if(ioctlsocket(_sd, FIONREAD, &ulVal) != 0)
563 throw SocketError("ioctlsocket()");
565 return static_cast<int>(ulVal);
566 #endif
569 /*! Wait until recv or accept will not block, but no longer than the given
570 duration.
572 \param[in] duration Maximum wait time in seconds.
573 \return True if data is available.
575 bool Socket::waitReadable(double duration)
577 SocketSelection selection;
578 selection.setRead(*this);
579 if(selection.select(duration) == 1)
580 return true;
581 else
582 return false;
585 /*! Wait until send will not block, but no longer than the given duration.
587 \param[in] duration Maximum wait time in seconds.
588 \return True if next send will not block.
590 bool Socket::waitWritable(double duration)
592 SocketSelection selection;
593 selection.setWrite(*this);
594 if(selection.select(duration)==1)
595 return true;
596 else
597 return false;
600 /*! Assign another socket to this one. This results in both sockets sharing
601 a descriptor.
603 \warning Be very careful when sharing descriptors, to only open or close
604 them once and not use them after they where closed in one instance.
606 const Socket & Socket::operator =(const Socket &source)
608 _sd = source._sd;
609 return *this;
612 /*-------------------------------------------------------------------------*/
613 /* error information */
615 /*! Get the last occured error.
617 int Socket::getError(void)
619 #ifdef WIN32
620 return WSAGetLastError();
621 #else
622 return errno;
623 #endif
626 /*! Get last host error.
628 int Socket::getHostError(void)
630 #ifdef WIN32
631 return WSAGetLastError();
632 #else
633 return h_errno;
634 #endif
637 /*! Get last occured error as string.
639 std::string Socket::getErrorStr(void)
641 const char *err = NULL;
643 #ifdef WIN32
644 switch(getError())
646 case WSAEINTR: err= "WSAEINTR"; break;
647 case WSAEBADF: err= "WSAEBADF"; break;
648 case WSAEFAULT: err= "WSAEFAULT"; break;
649 case WSAEINVAL: err= "WSAEINVAL"; break;
650 case WSAEMFILE: err= "WSAEMFILE"; break;
651 case WSAEWOULDBLOCK: err= "WSAEWOULDBLOCK"; break;
652 case WSAEINPROGRESS: err= "WSAEINPROGRESS"; break;
653 case WSAEALREADY: err= "WSAEALREADY"; break;
654 case WSAENOTSOCK: err= "WSAENOTSOCK"; break;
655 case WSAEDESTADDRREQ: err= "WSAEDESTADDRREQ"; break;
656 case WSAEMSGSIZE: err= "WSAEMSGSIZE"; break;
657 case WSAEPROTOTYPE: err= "WSAEPROTOTYPE"; break;
658 case WSAENOPROTOOPT: err= "WSAENOPROTOOPT"; break;
659 case WSAEPROTONOSUPPORT: err= "WSAEPROTONOSUPPORT"; break;
660 case WSAESOCKTNOSUPPORT: err= "WSAESOCKTNOSUPPORT"; break;
661 case WSAEOPNOTSUPP: err= "WSAEOPNOTSUPP"; break;
662 case WSAEPFNOSUPPORT: err= "WSAEPFNOSUPPORT"; break;
663 case WSAEAFNOSUPPORT: err= "WSAEAFNOSUPPORT"; break;
664 case WSAEADDRINUSE: err= "WSAEADDRINUSE"; break;
665 case WSAEADDRNOTAVAIL: err= "WSAEADDRNOTAVAIL"; break;
666 case WSAENETDOWN: err= "WSAENETDOWN"; break;
667 case WSAENETUNREACH: err= "WSAENETUNREACH"; break;
668 case WSAENETRESET: err= "WSAENETRESET"; break;
669 case WSAECONNABORTED: err= "WSAECONNABORTED"; break;
670 case WSAECONNRESET: err= "WSAECONNRESET"; break;
671 case WSAENOBUFS: err= "WSAENOBUFS"; break;
672 case WSAEISCONN: err= "WSAEISCONN"; break;
673 case WSAENOTCONN: err= "WSAENOTCONN"; break;
674 case WSAESHUTDOWN: err= "WSAESHUTDOWN"; break;
675 case WSAETOOMANYREFS: err= "WSAETOOMANYREFS"; break;
676 case WSAETIMEDOUT: err= "WSAETIMEDOUT"; break;
677 case WSAECONNREFUSED: err= "WSAECONNREFUSED"; break;
678 case WSAELOOP: err= "WSAELOOP"; break;
679 case WSAENAMETOOLONG: err= "WSAENAMETOOLONG"; break;
680 case WSAEHOSTDOWN: err= "WSAEHOSTDOWN"; break;
681 case WSAEHOSTUNREACH: err= "WSAEHOSTUNREACH"; break;
682 case WSASYSNOTREADY: err= "WSASYSNOTREADY"; break;
683 case WSAVERNOTSUPPORTED: err= "WSAVERNOTSUPPORTED"; break;
684 case WSANOTINITIALISED: err= "WSANOTINITIALISED"; break;
685 case WSAHOST_NOT_FOUND: err= "WSAHOST_NOT_FOUND"; break;
686 case WSATRY_AGAIN: err= "WSATRY_AGAIN"; break;
687 case WSANO_RECOVERY: err= "WSANO_RECOVERY"; break;
688 case WSANO_DATA: err= "WSANO_DATA"; break;
690 #else
691 err = strerror(getError());
692 #endif
693 if(err)
694 return std::string(err);
695 else
696 return std::string("Unknown error");
699 /*! Get last occured host error as string
701 std::string Socket::getHostErrorStr(void)
703 const char *err;
704 #if defined(WIN32) || defined(__hpux)
705 err = strerror(getHostError());
706 #else
707 err = hstrerror(getHostError());
708 #endif
709 if(err)
710 return std::string(err);
711 else
712 return std::string("Unknown error");