|
|
// 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. |