// Copyright (C) 1999 Open Source Telecom Corporation.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// As a special exception to the GNU General Public License, permission is
// granted for additional uses of the text contained in its release
// of APE.
//
// The exception is that, if you link the APE library with other files
// to produce an executable, this does not by itself cause the
// resulting executable to be covered by the GNU General Public License.
// Your use of that executable is in no way restricted on account of
// linking the APE library code into it.
//
// This exception does not however invalidate any other reasons why
// the executable file might be covered by the GNU General Public License.
//
// This exception applies only to the code released under the
// name APE. If you copy code from other releases into a copy of
// APE, as the General Public License permits, the exception does
// not apply to the code that you add in this way. To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for APE, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
#ifndef __APE_SOCKET_H__
#define __APE_SOCKET_H__
#ifndef __APE_THREAD_H__
#include <APE/thread.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
enum
{
SOCKET_COMPLETION_IMMEDIATE,
SOCKET_COMPLETION_DELAYED
};
enum
{
SOCKET_INITIAL,
SOCKET_AVAILABLE,
SOCKET_BOUND,
SOCKET_CONNECTED,
SOCKET_CONNECTING
};
class InetHostAddress;
class InetMaskAddress;
/**
* binary encoded internet host addresses are held in this special class
* object. This class represents the 'generic' internet address data type.
* Other InetAddress derived objects hold addresses which are used only
* for specific purposes, such as for network masks, broadcast addresses,
* etc.
*
* @author David Sugar <dyfet@oste.com>
* @short Internet Address binary data type.
*/
class InetAddress
{
protected:
struct in_addr ipaddr;
static MutexCounter counter;
public:
/**
* Create an Internet Address object with an empty (0.0.0.0)
* address.
*/
InetAddress();
/**
* Convert the system internet address data type (struct in_addr)
* into an APE InetAddress object.
*
* @param addr struct of system used binary internet address.
*/
InetAddress(struct in_addr);
/**
* Convert an null terminated ASCII host address string (example:
* "127.0.0.1") directly into an APE InetAddress object.
*
* @param address null terminated C string.
*/
InetAddress(const char *address);
/**
* Provide a string representation of the value (Internet Address)
* held in the InetAddress object.
*
* @return string representation of InetAddress.
*/
char *getHostname(void);
/**
* Provide a low level system usable struct in_addr object from
* the contents of InetAddress. This is needed for services such
* as bind() and connect().
*
* @return system binary coded internet address.
*/
inline struct in_addr getAddress(void)
{return ipaddr;};
};
/**
* Internet addresses used specifically as masking addresses (such as "
* 255.255.255.0") are held in the InetMaskAddress derived object. The
* seperate class is used so that C++ type casting can automatically
* determine when an InetAddress object is really a mask address object
* rather than simply using the base class. This also allows manipulative
* operators for address masking to operate only when presented with a
* Masked address as well as providing cleaner and safer source.
*
* @author David Sugar <dyfet@ostel.com>
* @short Internet Address Mask such as subnet masks.
*/
class InetMaskAddress : public InetAddress
{
public:
/**
* Create the mask from a null terminated ASCII string such as
* "255.255.255.128".
*
* @param mask null terminated ASCII mask string.
*/
InetMaskAddress(const char *mask);
/**
* Masks are usually used to coerce host addresses into a specific
* router or class domain. This can be done by taking the Inet
* Host Address object and "and"ing it with an address mask. This
* operation can be directly expressed in C++ through the & operator.
*
* @return a internet host address that has been masked.
* @param addr host address to be masked by subnet.
* @param mask inetnet mask address object to mask by.
*/
friend InetHostAddress operator&(InetHostAddress &addr, InetMaskAddress &mask);
};
/**
* This object is used to hold the actual and valid internet address of a
* specific host machine that will be accessed through a socket.
*
* @author David Sugar <dyfet@ostel.com>.
* @short Address of a specific Internet host machine.
*/
class InetHostAddress : public InetAddress
{
public:
/**
* Create a new host address for a specific internet host. The
* internet host can be specified in a null terminated ASCII
* string and include either the physical host address or the
* DNS name of a host machine. Hence, an InetHostAddress
* ("www.voxilla.org") can be directly declaired in this manner.
* If no host address is specified, the local host (127.0.0.1)
* is assumed.
*
* @param host dns or physical address of an Internet host.
*/
InetHostAddress(const char *host = NULL);
/**
* Convert a system socket binary address such as may be
* returned through the accept() call or getsockpeer() into
* an internet host address object.
*
* @param addr binary address of internet host.
*/
InetHostAddress(struct in_addr addr);
/**
* Convert a system socket binary address into an existing
* internet host address object through assignment by overloading
* the = operator.
*
* @param addr binary address of internet host.
*/
InetHostAddress &operator=(struct in_addr addr);
/**
* Compare two internet host addresses to see if they are equal
* (if they specify the physical address of the same internet host).
*/
bool operator==(InetHostAddress &a);
/**
* Compare two internet host addresses to see if they are not
* equal (if they each refer to unique and different physical
* ip addresses).
*/
bool operator!=(InetHostAddress &a);
/**
* Mask the internet host address object with a network mask address.
* This is commonly used to coerce an address by subnet.
*/
InetHostAddress &operator&=(InetMaskAddress &mask);
friend class InetMaskAddress;
friend InetHostAddress operator&(InetHostAddress &addr, InetMaskAddress &mask);
};
/**
* The broadcast address object is used to store the broadcast address for
* a specific subnet. This is commonly used for UDP broadcast operations.
*/
class BroadcastAddress : public InetAddress
{
public:
/**
* Specify the physical broadcast address to use and create a new
* broadcast address object based on a null terminated ASCII
* string.
*
* @param net null terminated ASCII network address.
*/
BroadcastAddress(const char *net = "255.255.255.255");
};
/**
* The Socket is used as the base for all Internet protocol services
* under APE. A socket is a system resource (or winsock descriptor)
* that occupies a specific port address (and may be bound to a specific
* network interface) on the local machine. The socket may also be
* directly connected to a specific socket on a remote internet host.
*/
class Socket
{
protected:
int state;
int so;
public:
virtual ~Socket();
/**
* An unconnected socket may be created directly on the local
* machine. Sockets can occupy both the internet domain (AF_INET)
* and UNIX socket domain (AF_UNIX) under unix. The socket type
* (SOCK_STREAM, SOCK_DGRAM) and protocol may also be specified.
* If the socket cannot be created, an exception is thrown.
*
* @param domain socket domain to use.
* @param type base type and protocol family of the socket.
* @param protocol specific protocol to apply.
*/
Socket(int domain, int type, int protocol = 0);
/**
* A socket object may be created from a file descriptor when that
* descriptor was created either through a socket() or accept()
* call. This constructor is mostly for internal use.
*
* @param fd file descriptor of an already existing socket.
*/
Socket(int fd);
/**
* A socket can also be constructed from an already existing
* Socket object. The socket file descriptor is dup()'d. This
* does not exist under win32.
*
* @param source of existing socket to clone.
*/
Socket(const Socket &source);
/**
* Sockets may also be duplicated by the assignment operator.
*/
Socket &operator=(const Socket &from);
/**
* Used to specify blocking mode for the socket. A socket
* can be made non-blocking by setting SOCKET_COMPLETION_DELAYED
* or set to block on all access with SOCKET_COMPLETION_IMMEDIATE.
* I do not believe this form of non-blocking socket I/O is supported
* in winsock, though it provides an alternate asynchronous set of
* socket services.
*
* @param mode specify socket I/O call blocking mode.
*/
void setCompletion(int mode);
/**
* Read an arbitrary byte data stream from the socket. This
* is made a virtual function so that derived classes can
* implement special data encoding for specific protocols such
* as in-stream MIME decoding, or to create timed streaming
* services.
*
* @return number of bytes read on success, -1 on error.
* @param addr pointer to store read data.
* @param len number of bytes to read.
*/
inline virtual int Read(void *addr, size_t len)
{return recv(so, (char *)addr, len, 0);};
/**
* Write an arbitrary byte data stream from the socket. This
* is made a virtual function so that derived classes can
* implement special data encoding for specific protocols such
* as in-stream MIME encoding, or to create timed streaming
* services.
*
* @return number of bytes written on success, -1 on error.
* @param addr pointer to write data from.
* @param len number of bytes to write.
*/
inline virtual int Write(void *addr, size_t len)
{return send(so, (char *)addr, len, 0);};
/**
* Write a null terminated string directly to a socket. This
* is made a virtual function so that derived classes can
* implement special data encoding for specific protocols such
* as in-stream MIME encoding, or to create timed streaming
* services.
*
* @return number of bytes written on success, -1 on failure.
* @param msg null terminated ASCII string to write.
*/
inline virtual int Write(char *msg)
{return send(so, msg, strlen(msg), 0);};
/**
* This allows one to peek at data waiting at the "head stream"
* of the socket. Peeking allows protocols to determine both if
* data is available, and, for some protocols, what kind of data
* to expect, to make processing more efficient.
*
* @return number of bytes available.
* @param addr to read socket head queue into.
* @param len number of bytes to try and read from the socket.
*/
inline virtual int Peek(void *addr, size_t len)
{return recv(so, (char *)addr, len, MSG_PEEK);};
/**
* This specific Peek method can be used to return the internet
* host address of the sender of the next packet to be read. For
* TCP servers, the Peek method can be used to determine the
* address of the next socket connection request and thereby
* determine if it should be accepted or not.
*
* @return address of sending host.
* @param port pointer to store port address of sending socket.
*/
InetHostAddress Peek(short *port = NULL);
friend inline InetHostAddress peek(Socket &s, short *port = NULL)
{return s.Peek(port);};
friend inline int read(Socket &s, void *addr, size_t len)
{return s.Read(addr, len);};
friend inline int write(Socket &s, void *addr, size_t len)
{return s.Write(addr, len);};
friend inline int write(Socket &s, char *msg)
{return s.Write(msg);};
friend inline int peek(Socket &s, void *addr, size_t len)
{return s.Peek(addr, len);}
};
/**
* UDP sockets implement the TCP SOCK_DGRAM UDP protocol. They can be
* used to pass unverified messages between hosts, or to broadcast a
* specific message to an entire subnet. Please note that Streaming of
* realtime data commonly use UDPSimplex or UDPDuplex rather than
* UDPSocket.
*
* @author David Sugar <dyfet@ostel.com>.
* @short Unreliable Datagram Protocol sockets.
*/
class Socket.html">UDPSocket : public Socket
{
public:
/**
* Create an unbound UDP socket, mostly for internal use.
*/
UDPSocket(void);
/**
* Create a UDP socket and bind it to a specific interface
* and port address so that other UDP sockets on remote
* machines (or the same host) may find and send UDP messages
* to it. On failure to bind, an exception is thrown.
*
* @param bind address to bind this socket to.
* @param port number to bind this socket to.
*/
UDPSocket(InetAddress &bind, short port);
/**
* Create a UDP socket that is connected to another UDP socket.
* While a UDP socket "connection" has no tangible resource unlike
* with TCP, it does prevent the socket from accepting UDP packets
* from any socket other than the one that it is connected to.
*
* @param host address to connect the local socket to.
* @param port number to connect the local socket to.
*/
UDPSocket(InetHostAddress &host, short port);
/**
* Bind a UDP socket for use in sending subnet broadcast messages.
* This enables the SO_BROADCAST attribute of the socket.
*
* @param cast address of subnet to broadcast messages on.
* @param port number to receive messages from other broadcasters.
*/
UDPSocket(BroadcastAddress &cast, short port);
/**
* Write a UDP message of arbitrary bytes. Each write genorates a
* unique UDP message of the specified length, rather than simply
* writing data to a stream. Hence, if one is writing a message
* composed of a header and data segment, all of which are meant to
* be sent as one UDP message, then one must do so in a single
* Write operation or through the use of writev.
*
* @return number of bytes sent on success, -1 on error.
* @param host internet address of destination socket.
* @param port number of destination socket.
* @param addr pointer to UDP message data.
* @param len number of bytes in UDP message.
*/
int Write(InetHostAddress &host, short port, void *addr, size_t len);
friend inline int write(UDPSocket &s, InetHostAddress &host, short port, void *addr, size_t len)
{return s.Write(host, port, addr, len);};
};
/**
* UDP simplex connections are used to impliment point-to-point UDP
* sessions and multi-point lan broadcasts between peer hosts under a
* single socket. Alternating port addresses are commonly used so that
* the transmitter does have to block while waiting on the receiver.
* DP Simplex connections can be used to create uni-directional realtime
* media sessions between hosts.
*
* @author David Sugar <dyfet@ostel.com>.
* @short Unreliable Datagram Peer Associations.
*/
class UDPSimplex : public Socket
{
private:
short peer;
public:
/**
* Create a UDP simplex, bind it to a specific interface
* and port address so that other UDP sockets on remote
* machines (or the same host) may find and send UDP messages
* to it, and associate it with a given port on a peer host.
* On failure to bind, an exception is thrown.
*
* @param bind address to bind this socket to.
* @param port number to bind this socket to.
* @param port number on peer host to associate with.
*/
UDPSimplex(InetAddress &bind, short port, short peer = 0);
/**
* Associate this socket with a specified peer host. The port
* number from the constructor will be used. All UDP packets
* will be sent to and received from the specified host.
*
* @return 0 on success, -1 on error.
* @param host address to connect socket to.
*/
int Connect(InetHostAddress &host);
/**
* Associate this socket with a subnet of peer hosts for
* subnet broadcasting. The server must be able to assert
* broadcast permission for the socket.
*
* @return 0 on success, -1 on error.
* @param subnet address to broadcast into.
*/
int Broadcast(BroadcastAddress &subnet);
/**
* Disassociate this socket from any host connection. No data
* should be read or written until a connection is established.
*/
int Disconnect(void);
/**
* Associate the socket with itself only. This can be used as
* a "disconnect" on systems which do not define AF_UNSPEC. This
* also means any data sent by the socket will be received by
* itself.
*/
int Loopback(void);
};
/**
* UDP duplex connections impliment a bi-directional point-to-point UDP
* session between two peer hosts. Two UDP sockets are typically used
* on alternating port addresses to assure that sender and receiver
* data does not collide or echo back. A UDP Duplex is commonly used
* for full duplex real-time streaming of UDP data between hosts.
*
* @author David Sugar <dyfet@ostel.com>.
* @short Unreliable Datagram Peer Associations.
*/
class UDPDuplex
{
private:
UDPSimplex *sender;
UDPSimplex *receiver;
public:
/**
* Create a UDP duplex as a pair of UDP simplex objects
* bound to alternating and interconnected port addresses.
*
* @param bind address to bind this socket to.
* @param port number to bind sender.
* @param port number to bind reciever.
*/
UDPDuplex(InetAddress &bind, short from, short to);
/**
* Disconnect and remove a UDP Duplex session.
*/
~UDPDuplex();
/**
* Associate the duplex with a specified peer host. Both
* the sender and receiver will be interconnected with
* the remote host.
*
* @return 0 on success, -1 on error.
* @param host address to connect socket to.
*/
int Connect(InetHostAddress &host);
/**
* Associate transmitter and receiver with a subnet
* for multi-peer subnet media streaming.
*
* @return 0 on success, -1 on error.
* @param subnet address to operate under.
*/
int Broadcast(BroadcastAddress &subnet);
/**
* Disassociate this duplex from any host connection. No data
* should be read or written until a connection is established.
*/
int Disconnect(void);
/**
* Associate the duplex with itself only. This can be used as
* a "disconnect" on systems which do not define AF_UNSPEC. This
* also means any data sent by the socket will be received by
* itself.
*/
int Loopback(void);
/**
* Examine next waiting UDP packet in the buffer without actually
* removing it from the socket head.
*
* @return number of bytes available.
* @param address to store packet to examine.
* @param length of packet to accept.
*/
int Peek(void *addr, size_t len)
{return receiver->Peek(addr, len);};
/**
* Read (receive) a UDP packet from the remote host using the
* simpex receiver.
*
* @return number of bytes read, or -1 on error.
* @param address to store packet received.
* @param maximum length of packet to accept.
*/
int Read(void *addr, size_t len)
{return receiver->Read(addr, len);};
/**
* Write (send) a UDP packet to the remote host using the
* simplex sender.
*
* @return number of bytes sent, or -1 on error.
* @param address of packet to send.
* @param length of packet to send.
*/
int Write(void *addr, size_t len)
{return sender->Write(addr, len);};
};
/**
* TCP sockets are used for stream based connected sessions between two
* sockets. Both error recovery and flow control operate transparently
* for a TCP socket connection.
*
* @author David Sugar <dyfet@tycho.com>
* @short reliable connected TCP stream sockets.
*/
class Socket.html">TCPSocket : public Socket
{
public:
/**
* A TCP "server" is created as a TCP socket that is bound
* to a hardware address and port number on the local machine
* and that has a backlog queue to listen for remote connection
* requests. If the server cannot be created, an exception is
* thrown.
*
* @param bind local ip address or interface to use.
* @param port number to bind socket under.
* @param backlog size of connection request queue.
*/
TCPSocket(InetAddress &bind, short port, int backlog);
/**
* Create and connect a TCP socket to a bound TCP "server"
* on a specified host bound to a specified port number. If
* the socket cannot be connected, an exception is thrown.
*
* @param host address of internet host to connect with.
* @param port number on the host to connect through.
*/
TCPSocket(InetHostAddress &host, short port);
/**
* Create a TCP socket that is an "accepted" client connection
* from a TCP socket that has been bound as a server. This new
* socket is directly connected to the remote socket that had
* made a connection "request" into the servers backlog queue
* and can be thought of as being the APE method of performing
* an "accept()" call.
*
* @param server socket to accept connection from.
*/
TCPSocket(TCPSocket &server);
/**
* Alternately create a TCP socket that is "accepted" from a
* casted pointer to a TCPSocket derived object acting as a
* bound TCP server. This new socket is directly connected to
* the remote socket that had made a connection "request" into
* the servers backlog queue.
*
* @param server pointer to accept connection from.
*/
TCPSocket(TCPSocket *server);
/**
* Create an unconnected TCP socket. Mostly for internal use.
*/
TCPSocket(void);
/**
* A method to call in a derived TCPSocket class that is acting
* as a server when a connection request is being accepted. The
* server can implement protocol specific rules to exclude the
* remote socket from being accepted by returning false. The
* Peek method can also be used for this purpose.
*
* @return true if client should be accepted.
* @param ia internet host address of the client.
* @param port number of the client.
*/
virtual bool OnAccept(InetHostAddress ia, short port)
{return true;};
/**
* Many TCP protocols involve the use of line oriented commands
* and data. The TCP readline method provides a very effecient
* means to read a single line of input from a TCP socket. This
* method does not use external buffering and is presumed safe
* from buffer overruns.
*
* @return number of bytes read on success, -1 on error.
* @param buf pointer to buffer.
* @len maximum number of bytes to read.
*/
int Readline(char *buf, size_t max);
/**
* Get the local socket address and port that the current socket
* has been bound to.
*
* @return internet address of host interface for this socket.
* @param port pointer to store the port number socket uses.
*/
InetHostAddress getHost(short *port = NULL);
/**
* Get the socket address of the remote socket that this socket
* is currently connected to.
*
* @return internet address of remote internet host.
* @param port pointer to store the port number of the remote socket.
*/
InetHostAddress getPeer(short *port = NULL);
friend inline int readline(TCPSocket &s, char *buf, size_t max)
{return s.Readline(buf, max);};
};
/**
* The TCP session is used to primarily to represent a client connection
* that can be managed on a seperate thread. The TCP session also supports
* a non-blocking connection scheme which prevents blocking during the
* constructor and moving the process of completing a connection into the
* thread that executes for the session.
*
* @author David Sugar <dyfet@ostel.com>
* @short Threaded socket with non-blocking constructor.
*/
class TCPSession : public TCPSocket, public Thread
{
protected:
/**
* Normally called during the thread Initial() method by default,
* this will wait for the socket connection to complete when
* connecting to a remote socket. One might wish to use
* setCompletion() to change the socket back to blocking I/O
* calls after the connection completes. To implement the
* session one must create a derived class which implements
* Run().
*
* @return 0 if successful, -1 if timed out.
* @param timeout to wait for completion in milliseconds.
*/
int WaitConnection(timeout_t timeout);
/**
* The initial method is used to esablish a connection when
* delayed completion is used. This assures the constructor
* terminates without having to wait for a connection request
* to complete.
*/
void Initial(void);
/**
* TCPSession derived objects can be freely created with "new"
* and safely terminate their "Run" method on their own by
* self-deleting when the thread terminates.
*/
void Final(void)
{delete this;};
public:
/**
* Create a TCP socket that will be connected to a remote TCP
* server and that will execute under it's own thread.
*
* @param start semaphore as per Thread startup.
* @param host internet address of remote TCP server.
* @param port number of remote server.
* @param pri execution priority relative to parent.
* @param stack allocation needed on some platforms.
*/
TCPSession(Semaphore *start, InetHostAddress &host, short port, int pri = 0, int stack = 0);
/**
* Create a TCP socket from a bound TCP server by accepting a pending
* connection from that server and execute a thread for the accepted
* connection.
*
* @param start semapore as per Thread startup.
* @param server tcp socket to accept a connection from.
* @param pri execution priority relative to parent.
* @param stack allocation needed on some platforms.
*/
TCPSession(Semaphore *start, TCPSocket &server, int pri = 0, int stack = 0);
/**
* Create a TCP socket from a pointer to a bound TCP server by
* accepting a pending connection from that server and execute a
* a thread for the accepted connection.
*
* @param server to accept connection from.
* @param start semaphore unless delayed start.
* @param pri execution priority relative to parent.
* @param stack allocation needed on some platforms.
*/
TCPSession(TCPSocket *server, Semaphore *start = NULL, int pri = 0, int stack = 0);
};
inline struct in_addr getaddress(InetAddress &ia)
{return ia.getAddress();};
#endif
Documentation generated by dyfet@home.sys on Thu Dec 16 09:54:26 EST 1999