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