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