]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/ip++.cpp
Security-54.1.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / ip++.cpp
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 // [Also see comments in header file.]
23 //
24 #include "ip++.h"
25 #include "hosts.h"
26 #include <Security/debugging.h>
27 #include <arpa/inet.h>
28 #include <netdb.h>
29
30
31 namespace Security {
32 namespace IPPlusPlus {
33
34
35 typedef unsigned char Byte; // occasionally useful
36
37
38 //
39 // IPAddress
40 //
41 static const struct in_addr in_addr_any = { INADDR_ANY };
42 #if BUG_GCC
43 const IPAddress &IPAddress::any = *static_cast<const IPAddress *>(&in_addr_any);
44 #else
45 const IPAddress &IPAddress::any = static_cast<const IPAddress &>(in_addr_any);
46 #endif
47
48 IPAddress::IPAddress(const char *s)
49 {
50 if (!inet_aton(s, this))
51 UnixError::throwMe(EINVAL);
52 }
53
54 IPAddress::operator string() const
55 {
56 // This code is esentially equivalent to inet_ntoa, which we can't use for thread safety.
57 // Note: contents in NBO = always high-endian, thus this cast works everywhere.
58 const Byte *p = reinterpret_cast<const Byte *>(this);
59 char buffer[(3+1)*4]; // nnn.nnn.nnn.nnn\0
60 snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
61 return buffer;
62 }
63
64
65 //
66 // IPSockAddress
67 //
68 IPSockAddress::IPSockAddress()
69 {
70 sin_family = AF_INET;
71 }
72
73 IPSockAddress::IPSockAddress(const IPAddress &addr, IPPort port)
74 {
75 sin_family = AF_INET;
76 sin_addr = addr;
77 sin_port = htons(port);
78 }
79
80 IPSockAddress::operator string () const
81 {
82 char buffer[4*(3+1)+5+1]; // nnn.nnn.nnn.nnn:ppppp
83 snprintf(buffer, sizeof(buffer), "%s:%d", string(address()).c_str(), port());
84 return buffer;
85 }
86
87
88 IPSockAddress IPSockAddress::defaults(const IPSockAddress &defaultAddr) const
89 {
90 return defaults(defaultAddr.address(), defaultAddr.port());
91 }
92
93 IPSockAddress IPSockAddress::defaults(const IPAddress &defaultAddr, IPPort defaultPort) const
94 {
95 return IPSockAddress(
96 address() ? address() : defaultAddr,
97 port() ? port() : defaultPort
98 );
99 }
100
101 IPSockAddress IPSockAddress::defaults(IPPort defaultPort) const
102 {
103 return IPSockAddress(address(), port() ? port() : defaultPort);
104 }
105
106
107 //
108 // Sockets
109 //
110 Socket::Socket(int type, int protocol)
111 {
112 open(type, protocol);
113 }
114
115 void Socket::open(int type, int protocol)
116 {
117 checkSetFd(::socket(AF_INET, type, protocol));
118 mAtEnd = false;
119 debug("sockio", "socket(%d,%d) -> %d", type, protocol, fd());
120 }
121
122 void Socket::prepare(int fdFlags, int type, int protocol)
123 {
124 // if file descriptor is closed, open it - otherwise take what's there
125 if (!isOpen())
126 open(type, protocol);
127
128 // if flags were passed in, set them on the file descriptor now
129 if (fdFlags)
130 setFlag(fdFlags);
131 }
132
133
134 void Socket::bind(const IPAddress &addr, IPPort port)
135 {
136 bind(IPSockAddress(addr, port));
137 }
138
139 void Socket::bind(const IPSockAddress &local)
140 {
141 checkError(::bind(fd(), local, sizeof(local)));
142 IFDEBUG(debug("sockio", "%d bind to %s", fd(), string(local).c_str()));
143 }
144
145
146 void Socket::listen(int backlog)
147 {
148 checkError(::listen(fd(), backlog));
149 }
150
151
152 void Socket::accept(Socket &s)
153 {
154 IPSockAddress dummy; // ignored
155 return accept(s, dummy);
156 }
157
158 void Socket::accept(Socket &s, IPSockAddress &peer)
159 {
160 int length = sizeof(IPSockAddress);
161 s.checkSetFd(::accept(fd(), peer, &length));
162 assert(length == sizeof(IPSockAddress));
163 }
164
165
166 bool Socket::connect(const IPSockAddress &peer)
167 {
168 if (::connect(fd(), peer, sizeof(peer))) {
169 switch (errno) {
170 case EINPROGRESS:
171 IFDEBUG(debug("sockio", "%d connecting to %s", fd(), string(peer).c_str()));
172 return false;
173 case EALREADY:
174 if (int err = error()) // connect failed
175 UnixError::throwMe(err);
176 // just keep trying
177 IFDEBUG(debug("sockio", "%d still trying to connect", fd()));
178 return false;
179 case EISCONN:
180 if (flags() & O_NONBLOCK) {
181 debug("sockio", "%d now connected", fd());
182 return true;
183 } else {
184 UnixError::throwMe();
185 }
186 default:
187 UnixError::throwMe();
188 }
189 } else {
190 IFDEBUG(debug("sockio", "%d connect to %s", fd(), string(peer).c_str()));
191 return true;
192 }
193 }
194
195 bool Socket::connect(const IPAddress &addr, IPPort port)
196 {
197 return connect(IPSockAddress(addr, port));
198 }
199
200 // void Socket::connect(const Host &host, ...): see below.
201
202
203 void Socket::shutdown(int how)
204 {
205 assert(how >= 0 && how <= 2);
206 checkError(::shutdown(fd(), how));
207 }
208
209
210 IPSockAddress Socket::localAddress() const
211 {
212 IPSockAddress addr;
213 int length = sizeof(addr);
214 checkError(::getsockname(fd(), addr, &length));
215 assert(length == sizeof(addr));
216 return addr;
217 }
218
219 IPSockAddress Socket::peerAddress() const
220 {
221 IPSockAddress addr;
222 int length = sizeof(addr);
223 checkError(::getpeername(fd(), addr, &length));
224 assert(length == sizeof(addr));
225 return addr;
226 }
227
228 void Socket::getOption(void *value, int &length, int name, int level = SOL_SOCKET) const
229 {
230 UnixError::check(::getsockopt(fd(), level, name, value, &length));
231 }
232
233 void Socket::setOption(const void *value, int length, int name, int level = SOL_SOCKET) const
234 {
235 UnixError::check(::setsockopt(fd(), level, name, value, length));
236 }
237
238
239 //
240 // Connect to a Host object.
241 // This version of connect performs nontrivial work and makes interesting decisions.
242 //
243 void Socket::connect(const Host &host, IPPort port)
244 {
245 //@@@ use two-step stutter algorithm?
246 //@@@ randomize order?
247 //@@@ keep worked-recently information?
248 //@@@ what about nonblocking operation?
249 set<IPAddress> addrs = host.addresses();
250 for (set<IPAddress>::const_iterator it = addrs.begin(); it != addrs.end(); it++) {
251 const IPSockAddress address(*it, port);
252 if (::connect(fd(), address, sizeof(IPSockAddress)) == 0) {
253 IFDEBUG(debug("sockio", "%d connect to %s", fd(), string(address).c_str()));
254 return;
255 }
256 }
257 // no joy on any of the candidate addresses. Throw last error
258 //@@@ clean up errno?
259 UnixError::throwMe();
260 }
261
262
263 //
264 // TCP*Sockets.
265 // Note that these will TCP*Socket::open() will *use* its existing file descriptor,
266 // on the theory that the caller may have prepared it specially (e.g. to make it nonblocking).
267 //
268 void TCPClientSocket::open(const IPSockAddress &peer, int fdFlags)
269 {
270 prepare(fdFlags, SOCK_STREAM);
271 connect(peer);
272 }
273
274 void TCPClientSocket::open(const IPAddress &addr, IPPort port, int fdFlags)
275 {
276 prepare(fdFlags, SOCK_STREAM);
277 connect(addr, port);
278 }
279
280 void TCPClientSocket::open(const Host &host, IPPort port, int fdFlags)
281 {
282 prepare(fdFlags, SOCK_STREAM);
283 connect(host, port);
284 }
285
286 TCPClientSocket::~TCPClientSocket()
287 {
288 close();
289 }
290
291
292 void TCPServerSocket::open(const IPSockAddress &addr, int depth)
293 {
294 prepare(0, SOCK_STREAM);
295 bind(addr);
296 listen(depth);
297 }
298
299 void TCPServerSocket::operator () (TCPClientSocket &newClient)
300 {
301 accept(newClient);
302 }
303
304 void TCPServerSocket::receive(TCPClientSocket &newClient)
305 {
306 accept(newClient);
307 close();
308 }
309
310 TCPServerSocket::~TCPServerSocket()
311 {
312 close();
313 }
314
315
316 } // end namespace IPPlusPlus
317 } // end namespace Security