--- /dev/null
+/*
+ * Copyright (c) 2000-2001,2003-2004,2011,2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+//
+// ip++ - C++ layer for IP socket and address management
+//
+// Key to comments:
+// HBO = host byte order, NBO = network byte order
+//
+// Rules for byte ordering: C++ objects store addresses and ports in NBO.
+// Struct in_addr arguments are in NBO. Integer type arguments are in HBO.
+// Stick with the conversion methods and you win. Cast around and you lose.
+//
+// @@@ Which namespace should we be in?
+//
+#ifndef _H_IPPLUSPLUS
+#define _H_IPPLUSPLUS
+
+#include "unix++.h"
+#include "timeflow.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <cstdio>
+#include <cstdarg>
+#include <map>
+
+using namespace UnixPlusPlus;
+
+
+namespace Security {
+namespace IPPlusPlus {
+
+class Host;
+
+
+//
+// For now, ports are simply a short unsigned integer type, in HBO.
+//
+typedef UInt16 IPPort;
+
+
+//
+// An IP host address.
+//
+class IPAddress : public in_addr {
+public:
+ IPAddress() { s_addr = htonl(INADDR_ANY); }
+ IPAddress(const struct in_addr &addr) { s_addr = addr.s_addr; }
+ explicit IPAddress(UInt32 addr) { s_addr = htonl(addr); }
+ IPAddress(const char *s); // ONLY dotted-quad form - use hosts.h for name resolution
+
+ operator UInt32 () const { return ntohl(s_addr); }
+ operator string () const; // "n.n.n.n" (no name resolution)
+
+public:
+ bool operator == (const IPAddress &other) const { return s_addr == other.s_addr; }
+ bool operator != (const IPAddress &other) const { return s_addr != other.s_addr; }
+ bool operator < (const IPAddress &other) const { return s_addr < other.s_addr; }
+
+ operator bool () const { return s_addr != htonl(INADDR_ANY); }
+ bool operator ! () const { return s_addr == htonl(INADDR_ANY); }
+
+public:
+ static const IPAddress &any;
+};
+
+
+//
+// An IP "socket address", i.e. a combined host address and port.
+//
+class IPSockAddress : public sockaddr_in {
+public:
+ IPSockAddress();
+ IPSockAddress(const struct sockaddr_in &sockaddr) { *(sockaddr_in *)this = sockaddr; }
+ IPSockAddress(const IPAddress &addr, IPPort port);
+
+ IPAddress address() const { return sin_addr; }
+ void address(IPAddress addr) { sin_addr = addr; }
+ IPPort port() const { return ntohs(sin_port); }
+ void port(IPPort p) { sin_port = htons(p); }
+
+ operator string () const; // "n.n.n.n:p" (no name resolution)
+
+ // automatically convert to struct sockaddr * for use in system calls
+ operator struct sockaddr * ()
+ { return reinterpret_cast<struct sockaddr *>(this); }
+ operator const struct sockaddr * () const
+ { return reinterpret_cast<const struct sockaddr *>(this); }
+
+ // conveniences
+ IPSockAddress defaults(const IPSockAddress &defaultAddr) const;
+ IPSockAddress defaults(const IPAddress &defaultAddr, IPPort defaultPort = 0) const;
+ IPSockAddress defaults(IPPort defaultPort) const;
+};
+
+
+//
+// UNIX Domain Socket addresses, for those who care.
+// An "UNAddress", such as it were, is simply a string.
+//
+class UNSockAddress : public sockaddr_un {
+public:
+ UNSockAddress();
+ UNSockAddress(const char *path);
+ UNSockAddress(const std::string &path);
+
+ string path() const;
+ operator string () const { return path(); }
+
+ // automatically convert to struct sockaddr * for use in system calls
+ operator struct sockaddr * ()
+ { return reinterpret_cast<struct sockaddr *>(this); }
+ operator const struct sockaddr * () const
+ { return reinterpret_cast<const struct sockaddr *>(this); }
+};
+
+
+//
+// An IP socket.
+// This inherits all functionality of a FileDesc, so I/O is fun and easy.
+// Socket is "passive"; it doesn't own any resources and does nothing on destruction.
+// On the upside, you can assign Sockets freely.
+// If you want self-managing sockets that clean up after themselves,
+// use the subclasses below.
+//
+class Socket : public FileDesc {
+public:
+ Socket() { }
+ explicit Socket(int domain, int type, int protocol = 0);
+ explicit Socket(int type);
+
+ Socket &operator = (int fd) { setFd(fd); return *this; }
+
+ // basic open (socket system call)
+ void open(int domain, int type, int protocol = 0);
+ void open(int type) { open(AF_INET, type, 0); }
+
+ // standard socket operations
+ void bind(const IPSockAddress &addr); // to this socket address
+ void bind(const IPAddress &addr = IPAddress::any, IPPort port = 0);
+ void bind(const UNSockAddress &addr); // to this UNIX domain socket
+ void listen(int backlog = 1);
+ void accept(Socket &s);
+ void accept(Socket &s, IPSockAddress &peer);
+ void accept(Socket &s, UNSockAddress &peer);
+ bool connect(const struct sockaddr *peer);
+ bool connect(const IPSockAddress &peer);
+ bool connect(const IPAddress &addr, IPPort port);
+ bool connect(const UNSockAddress &peer);
+ void connect(const Host &host, IPPort port); // any address of this host
+ void shutdown(int type);
+ enum { shutdownRead = 0, shutdownWrite = 1, shutdownBoth = 2 };
+
+ // get endpoint addresses
+ IPSockAddress localAddress() const;
+ IPSockAddress peerAddress() const;
+
+ // socket options
+ void setOption(const void *value, int length, int name, int level = SOL_SOCKET) const;
+ void getOption(void *value, socklen_t &length, int name, int level = SOL_SOCKET) const;
+
+ template <class T> void setOption(const T &value, int name, int level = SOL_SOCKET) const
+ { setOption(&value, sizeof(value), name, level); }
+
+ template <class T> T getOption(int name, int level = SOL_SOCKET) const
+ {
+ T value; socklen_t length = sizeof(value);
+ getOption(&value, length, name, level);
+ assert(length == sizeof(value));
+ return value;
+ }
+
+ // some specific useful options
+ int type() const { return getOption<int>(SO_TYPE); }
+ int error() const { return getOption<int>(SO_ERROR); }
+
+public:
+#if defined(SOMAXCONN)
+ static const int listenMaxQueue = SOMAXCONN;
+#else
+ static const int listenMaxQueue = 5; // the traditional BSD UNIX value
+#endif
+
+protected:
+ void prepare(int fdFlags, int domain, int type, int protocol = 0);
+};
+
+
+//
+// A TCPClientSocket is a self-connecting TCP socket that connects (actively) to a server.
+// Since TCP, once established, is symmetric, it can also be used for the server side
+// of a TCP pipe. You can think of it as the least complex embodiment of a TCP connection.
+//
+class TCPClientSocket : public Socket {
+ NOCOPY(TCPClientSocket)
+public:
+ TCPClientSocket() { }
+ ~TCPClientSocket(); // closes connection
+
+#if BUG_GCC
+ void open(int type, int protocol = 0) { Socket::open(type, protocol); }
+#else
+ using Socket::open;
+#endif
+
+ void open(const IPSockAddress &peer, int fdFlags = 0);
+ void open(const IPAddress &addr, IPPort port, int fdFlags = 0);
+ void open(const Host &host, IPPort port, int fdFlags = 0);
+
+ TCPClientSocket(const IPSockAddress &peer, int fdFlags = 0)
+ { open(peer, fdFlags); }
+ TCPClientSocket(const IPAddress &addr, IPPort port, int fdFlags = 0)
+ { open(addr, port, fdFlags); }
+ TCPClientSocket(const Host &host, IPPort port, int fdFlags = 0)
+ { open(host, port, fdFlags); }
+
+protected: // for serverSocket/clientSocket footsy play
+ void setFd(int fd) { Socket::setFd(fd); }
+
+private:
+ TCPClientSocket(int sockfd);
+};
+
+
+//
+// A TCPServerSocket is a self-initializing listener socket for incoming TCP requests
+// (usually to a server). Its function operator yields the next incoming connection request
+// as a TCPClientSocket (see above). For one-shot receivers, the receive() method will
+// create the client and close the listener atomically (which is sometimes faster).
+//
+class TCPServerSocket : public Socket {
+ NOCOPY(TCPServerSocket)
+public:
+ TCPServerSocket() { }
+ ~TCPServerSocket(); // closes listener; existing connections unaffected
+
+ void open(const IPSockAddress &local, int depth = 1);
+ void open(IPPort port = 0, int depth = 1)
+ { open(IPSockAddress(IPAddress::any, port), depth); }
+
+ TCPServerSocket(const IPSockAddress &local, int depth = 1) { open(local, depth); }
+ TCPServerSocket(IPPort port, int depth = 1) { open(port, depth); }
+
+ void operator () (TCPClientSocket &newClient); // retrieve next connection
+ void receive(TCPClientSocket &client); // accept once, then close listener
+};
+
+
+} // end namespace IPPlusPlus
+} // end namespace Security
+
+
+#endif //_H_IPPLUSPLUS