Source: socket.h


Annotated List
Files
Globals
Hierarchy
Index
// 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 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 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);
	/**
	 * 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);
	void Initial(void);

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);
};

inline struct in_addr getaddress(InetAddress &ia)
	{return ia.getAddress();};

#endif

Generated by: dyfet@home.sys on Wed Dec 1 16:09:46 199.