1/* 2 * Copyright (c) 2000-2001,2003-2004 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// ip++ - C++ layer for IP socket and address management 27// 28// Key to comments: 29// HBO = host byte order, NBO = network byte order 30// 31// Rules for byte ordering: C++ objects store addresses and ports in NBO. 32// Struct in_addr arguments are in NBO. Integer type arguments are in HBO. 33// Stick with the conversion methods and you win. Cast around and you lose. 34// 35// @@@ Which namespace should we be in? 36// 37#ifndef _H_IPPLUSPLUS 38#define _H_IPPLUSPLUS 39 40#include "unix++.h" 41#include "timeflow.h" 42#include <sys/types.h> 43#include <sys/ioctl.h> 44#include <sys/un.h> 45#include <sys/socket.h> 46#include <netinet/in.h> 47#include <fcntl.h> 48#include <cstdio> 49#include <cstdarg> 50#include <map> 51 52using namespace UnixPlusPlus; 53 54 55namespace Security { 56namespace IPPlusPlus { 57 58class Host; 59 60 61// 62// For now, ports are simply a short unsigned integer type, in HBO. 63// 64typedef UInt16 IPPort; 65 66 67// 68// An IP host address. 69// 70class IPAddress : public in_addr { 71public: 72 IPAddress() { s_addr = htonl(INADDR_ANY); } 73 IPAddress(const struct in_addr &addr) { s_addr = addr.s_addr; } 74 explicit IPAddress(UInt32 addr) { s_addr = htonl(addr); } 75 IPAddress(const char *s); // ONLY dotted-quad form - use hosts.h for name resolution 76 77 operator UInt32 () const { return ntohl(s_addr); } 78 operator string () const; // "n.n.n.n" (no name resolution) 79 80public: 81 bool operator == (const IPAddress &other) const { return s_addr == other.s_addr; } 82 bool operator != (const IPAddress &other) const { return s_addr != other.s_addr; } 83 bool operator < (const IPAddress &other) const { return s_addr < other.s_addr; } 84 85 operator bool () const { return s_addr != htonl(INADDR_ANY); } 86 bool operator ! () const { return s_addr == htonl(INADDR_ANY); } 87 88public: 89 static const IPAddress &any; 90}; 91 92 93// 94// An IP "socket address", i.e. a combined host address and port. 95// 96class IPSockAddress : public sockaddr_in { 97public: 98 IPSockAddress(); 99 IPSockAddress(const struct sockaddr_in &sockaddr) { *(sockaddr_in *)this = sockaddr; } 100 IPSockAddress(const IPAddress &addr, IPPort port); 101 102 IPAddress address() const { return sin_addr; } 103 void address(IPAddress addr) { sin_addr = addr; } 104 IPPort port() const { return ntohs(sin_port); } 105 void port(IPPort p) { sin_port = htons(p); } 106 107 operator string () const; // "n.n.n.n:p" (no name resolution) 108 109 // automatically convert to struct sockaddr * for use in system calls 110 operator struct sockaddr * () 111 { return reinterpret_cast<struct sockaddr *>(this); } 112 operator const struct sockaddr * () const 113 { return reinterpret_cast<const struct sockaddr *>(this); } 114 115 // conveniences 116 IPSockAddress defaults(const IPSockAddress &defaultAddr) const; 117 IPSockAddress defaults(const IPAddress &defaultAddr, IPPort defaultPort = 0) const; 118 IPSockAddress defaults(IPPort defaultPort) const; 119}; 120 121 122// 123// UNIX Domain Socket addresses, for those who care. 124// An "UNAddress", such as it were, is simply a string. 125// 126class UNSockAddress : public sockaddr_un { 127public: 128 UNSockAddress(); 129 UNSockAddress(const char *path); 130 UNSockAddress(const std::string &path); 131 132 string path() const; 133 operator string () const { return path(); } 134 135 // automatically convert to struct sockaddr * for use in system calls 136 operator struct sockaddr * () 137 { return reinterpret_cast<struct sockaddr *>(this); } 138 operator const struct sockaddr * () const 139 { return reinterpret_cast<const struct sockaddr *>(this); } 140}; 141 142 143// 144// An IP socket. 145// This inherits all functionality of a FileDesc, so I/O is fun and easy. 146// Socket is "passive"; it doesn't own any resources and does nothing on destruction. 147// On the upside, you can assign Sockets freely. 148// If you want self-managing sockets that clean up after themselves, 149// use the subclasses below. 150// 151class Socket : public FileDesc { 152public: 153 Socket() { } 154 explicit Socket(int domain, int type, int protocol = 0); 155 explicit Socket(int type); 156 157 Socket &operator = (int fd) { setFd(fd); return *this; } 158 159 // basic open (socket system call) 160 void open(int domain, int type, int protocol = 0); 161 void open(int type) { open(AF_INET, type, 0); } 162 163 // standard socket operations 164 void bind(const IPSockAddress &addr); // to this socket address 165 void bind(const IPAddress &addr = IPAddress::any, IPPort port = 0); 166 void bind(const UNSockAddress &addr); // to this UNIX domain socket 167 void listen(int backlog = 1); 168 void accept(Socket &s); 169 void accept(Socket &s, IPSockAddress &peer); 170 void accept(Socket &s, UNSockAddress &peer); 171 bool connect(const struct sockaddr *peer); 172 bool connect(const IPSockAddress &peer); 173 bool connect(const IPAddress &addr, IPPort port); 174 bool connect(const UNSockAddress &peer); 175 void connect(const Host &host, IPPort port); // any address of this host 176 void shutdown(int type); 177 enum { shutdownRead = 0, shutdownWrite = 1, shutdownBoth = 2 }; 178 179 // get endpoint addresses 180 IPSockAddress localAddress() const; 181 IPSockAddress peerAddress() const; 182 183 // socket options 184 void setOption(const void *value, int length, int name, int level = SOL_SOCKET) const; 185 void getOption(void *value, socklen_t &length, int name, int level = SOL_SOCKET) const; 186 187 template <class T> void setOption(const T &value, int name, int level = SOL_SOCKET) const 188 { setOption(&value, sizeof(value), name, level); } 189 190 template <class T> T getOption(int name, int level = SOL_SOCKET) const 191 { 192 T value; socklen_t length = sizeof(value); 193 getOption(&value, length, name, level); 194 assert(length == sizeof(value)); 195 return value; 196 } 197 198 // some specific useful options 199 int type() const { return getOption<int>(SO_TYPE); } 200 int error() const { return getOption<int>(SO_ERROR); } 201 202public: 203#if defined(SOMAXCONN) 204 static const int listenMaxQueue = SOMAXCONN; 205#else 206 static const int listenMaxQueue = 5; // the traditional BSD UNIX value 207#endif 208 209protected: 210 void prepare(int fdFlags, int domain, int type, int protocol = 0); 211}; 212 213 214// 215// A TCPClientSocket is a self-connecting TCP socket that connects (actively) to a server. 216// Since TCP, once established, is symmetric, it can also be used for the server side 217// of a TCP pipe. You can think of it as the least complex embodiment of a TCP connection. 218// 219class TCPClientSocket : public Socket { 220 NOCOPY(TCPClientSocket) 221public: 222 TCPClientSocket() { } 223 ~TCPClientSocket(); // closes connection 224 225#if BUG_GCC 226 void open(int type, int protocol = 0) { Socket::open(type, protocol); } 227#else 228 using Socket::open; 229#endif 230 231 void open(const IPSockAddress &peer, int fdFlags = 0); 232 void open(const IPAddress &addr, IPPort port, int fdFlags = 0); 233 void open(const Host &host, IPPort port, int fdFlags = 0); 234 235 TCPClientSocket(const IPSockAddress &peer, int fdFlags = 0) 236 { open(peer, fdFlags); } 237 TCPClientSocket(const IPAddress &addr, IPPort port, int fdFlags = 0) 238 { open(addr, port, fdFlags); } 239 TCPClientSocket(const Host &host, IPPort port, int fdFlags = 0) 240 { open(host, port, fdFlags); } 241 242protected: // for serverSocket/clientSocket footsy play 243 void setFd(int fd) { Socket::setFd(fd); } 244 245private: 246 TCPClientSocket(int sockfd); 247}; 248 249 250// 251// A TCPServerSocket is a self-initializing listener socket for incoming TCP requests 252// (usually to a server). Its function operator yields the next incoming connection request 253// as a TCPClientSocket (see above). For one-shot receivers, the receive() method will 254// create the client and close the listener atomically (which is sometimes faster). 255// 256class TCPServerSocket : public Socket { 257 NOCOPY(TCPServerSocket) 258public: 259 TCPServerSocket() { } 260 ~TCPServerSocket(); // closes listener; existing connections unaffected 261 262 void open(const IPSockAddress &local, int depth = 1); 263 void open(IPPort port = 0, int depth = 1) 264 { open(IPSockAddress(IPAddress::any, port), depth); } 265 266 TCPServerSocket(const IPSockAddress &local, int depth = 1) { open(local, depth); } 267 TCPServerSocket(IPPort port, int depth = 1) { open(port, depth); } 268 269 void operator () (TCPClientSocket &newClient); // retrieve next connection 270 void receive(TCPClientSocket &client); // accept once, then close listener 271}; 272 273 274} // end namespace IPPlusPlus 275} // end namespace Security 276 277 278#endif //_H_IPPLUSPLUS 279