#include <OSGConfig.h>

using namespace osg;

/*! \page PageBaseSocket Socket

Socket baseclass. The Socket class wraps a socket descriptor. This
class has no additional state variables. It is only h handle to the
underlaying descriptor. Class createion and destruction has no
influence to any descriptor. Use open to assign a descriptor and
close to remove it from the system. If this class is copied, then
there are to classes which uses the same descriptor. This is
ok until you call close for one of this classes.
One purpose of this implementation is to hide the differences between
Windows and Unix sockets. Calls to this class should behave equally
on all systems. As a result, some methods will not work as an 
experienced Windows ore Unix programmer maight expect. Please refere
to the function docu to get details about this.

Stream sockets

A stream socket is an endpoint for a reliable point to point
communication. The following example code shows, how to establish a
stream socket connection.

<PRE>
// server code
StreamSocket socket,client;
socket.open();
socket.bind(SocketAddress(SocketAddress::ANY,12345));
client=socket.accept();
client.send(buffer,100);
client.close();
socket.close();

// client code
StreamSocket server;
server.open();
server.connect(SocketAddress("localhost",12345));
server.recv(buffer,100);
server.close();
</PRE>

The method bind() assigns the socket to a given port and network
device. If the network device is ANY, then the socket will accept
connections from all network interfaces. If the port number is zero,
then a free port is assigned. In the above example, the socket will
accept incoming connections at each interface on the port
12345. StreamSocket::accept() waits for a incoming connection. For
each incoming connection a new socket object will be created. With
send and recv data can be transferred over the connection. By default
all calls will block until the operation has finished.

Datagram sockets

Datagram sockets are not connection orientated. There is no connect or
accept methods for datagram sockets. You have to provide a destination
address for each send and will get a source address for each recv
call. There is no guarantee that packages will arrive and there is no
guarantee for the order in which the package will arrive. The followin
code shows how to wait for incoming packages at port 22222. 

<PRE>
SocketAddress client;
DgramSocket socket;
socket.open();
socket.bind(SocketAddress(SocketAddress::ANY,22222))
socket.recvFrom(buffer,100,client);
socket.close();
</PRE>

This is the code to send the package. This is a simple example. If the
package gets lost for example because the server is not started, then
this code wont work. If your application relays on reliable data
transmission, then StreamSockets should be used. 

<PRE>
DgramSocket sock;
SocketAddress server;
socket.open();
socket.sendTo("hallo",100,SocketAddress("localhost",22222));
socket.close();
</PRE>

Exceptions:

All socket methods will throw exceptions if the desired function could
not be finished. All socket related exceptions are derived from the
SocketException class. All socket calls should be enclosed in
try/catch blocks. For example, if you want to check if a connect
operation was successful then you should use the following code.

<PRE>
try
{
    server..connect(SocketAddress("localhost",12345));
}
catch(SocketException &e)
{
    SFATAL << "Unable to connect to server:" << e.what() << endl;
}
</PRE>

Each exceptions contains the system error text that causes the error
situation. This text can be accessed by SocketException::what(). The
text is given as an std:string object.
 
Broadcast Messages

Broadcast packages are a special case of datagram packages. Broadcast
packages are send to each host in a network. For broadcasting packages
a special address type is used. For example with the address
SocketAddress(SocketAddress::BROADCAST,2345) packages will be send to each
host on port number 2345. Equal to normal datagram sockets, broadcast
packages are transmitted not reliable. 

Multicast Messages

With multicast it is possible to send packages to more then one
destination. In contrast to broadcast the package is not send to all
hosts but only to those hosts that have joined a multicast group. A
multicast group is specified with special IP addresses
(224.xxx.xxx.xxx). To write a package to the multicast group
224.22.33.33 at port 4444 you could use

<PRE>
socket.sendTo(buffer,100,SocketAddress("224.22.33.44",4444) 
</PRE>

The receive has to join this group. The following examples shows how
to join and leave multicast groups. It is possible to join more then
one group.

<PRE>
socket.bind(SocketAddress(SocketAddress::ANY,4444));
socket.join(SocketAddress("224.22.33.44"));
socket.join(SocketAddress("224.0.0.52"));
socket.join(SocketAddress("224.0.0.53"));
socket.leave(SocketAddress("224.0.0.52"));
</PRE>

With multicast groups you also have to bind your socket to a network
device and port. In the example above only those packages are received
that are send to port 4444. With multicast it often happens, that you
have more then one member of a multicast group on a single host. If
you try to call bind for the same port multiple times, then you will
get socket exceptions. To be able to assign more then one process to
the same port you have to call  socket.setReusePort(true) before the
call to bind.

It is possible set the network device that is used to send 
multicast packages. By default the system uses the first device
that is capable to send multicast packages.

<PRE>
socket.setInterface(SocketAddress("192.168.10.1"));
</PRE>

Nonblocking IO

In many applications it is not possible or not wanted to block
execution until an accept() or recv() call has finished. Each socket
has methods to ask if it is possible to read or write data without
blocking. The followin examples shows how to wait for data without
blocking.

<UL>
<LI>socket.waitReadable(0): Don't wait, returns true if data is
available otherwise it returns false.
<LI>socket.waitReadable(0.5): If data arrives in the next .5 seconds
then true is returned. Otherwise false is returned.
<LI>socket.waitReadable(-1): Wait until data is available and then
return true. This function call is equal to a blocking read.
<LI>socket.waitWritable(10): If the socket is able to send data in the
next 10 seconds, then true is returned. Otherwise false. 
</UL>

With this simple interface it is possible to wait a specified time for
incoming or outgoing data. But it is only possible to wait for exactly one
socket. If it is necessary to wait for more then one socket then the
Selection class could be used.  A selection specifies for each socket
for what kind of event the system should wait. 

<PRE>
SocketSelection s;
s.setRead(socket1);
s.setRead(socket2);
s.select(.1);
if(s.isSetRead(sock1)) 
   socket 1 is readable
if(s.isSetRead(sock2)) 
   socket 1 is readable
</PRE>

A call of selection.select(seconds) waits the given number of seconds for the events set with setRead() or serWrite(). It returns after the first occurrence of an event.  If no events occur in the given periode then 0 is returned. Otherwise the number of readable and writable sockets is returned. The method select() modifies the selection object. You have to call setRead() and setWrite() for each time, you want to call select(). If the SocketSelection is constant, then you can use an other version of select. With s.select(seconds,rs) s will not be modified. The result will be set into the SocketSelection rs. You have to call rs.isReadable(sock) instead of s.isReadable(sock).

IO-Buffers

If data should be read from more then one socket, then the performance could be improved by not reading from the first socket that provides data but from that socket with the most data in the input buffer. With socket.getAvailable() the number of bytes in the input buffer could be retrieved. In addition the Socket class provides the functions setWriteBufferSize and setReadBufferSize set the size of input and output buffers. Current sizes can be retrieved with getReadBufferSize and getWriteBufferSize.

*/
