]> git.saurik.com Git - apple/security.git/blame - cdsa/cdsa_utilities/ip++.cpp
Security-54.1.9.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / ip++.cpp
CommitLineData
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// [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
31namespace Security {
32namespace IPPlusPlus {
33
34
35typedef unsigned char Byte; // occasionally useful
36
37
38//
39// IPAddress
40//
41static const struct in_addr in_addr_any = { INADDR_ANY };
42#if BUG_GCC
43const IPAddress &IPAddress::any = *static_cast<const IPAddress *>(&in_addr_any);
44#else
45const IPAddress &IPAddress::any = static_cast<const IPAddress &>(in_addr_any);
46#endif
47
48IPAddress::IPAddress(const char *s)
49{
50 if (!inet_aton(s, this))
51 UnixError::throwMe(EINVAL);
52}
53
54IPAddress::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//
68IPSockAddress::IPSockAddress()
69{
70 sin_family = AF_INET;
71}
72
73IPSockAddress::IPSockAddress(const IPAddress &addr, IPPort port)
74{
75 sin_family = AF_INET;
76 sin_addr = addr;
77 sin_port = htons(port);
78}
79
80IPSockAddress::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
88IPSockAddress IPSockAddress::defaults(const IPSockAddress &defaultAddr) const
89{
90 return defaults(defaultAddr.address(), defaultAddr.port());
91}
92
93IPSockAddress IPSockAddress::defaults(const IPAddress &defaultAddr, IPPort defaultPort) const
94{
95 return IPSockAddress(
96 address() ? address() : defaultAddr,
97 port() ? port() : defaultPort
98 );
99}
100
101IPSockAddress IPSockAddress::defaults(IPPort defaultPort) const
102{
103 return IPSockAddress(address(), port() ? port() : defaultPort);
104}
105
106
107//
108// Sockets
109//
110Socket::Socket(int type, int protocol)
111{
112 open(type, protocol);
113}
114
115void 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
122void 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
134void Socket::bind(const IPAddress &addr, IPPort port)
135{
136 bind(IPSockAddress(addr, port));
137}
138
139void 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
146void Socket::listen(int backlog)
147{
148 checkError(::listen(fd(), backlog));
149}
150
151
152void Socket::accept(Socket &s)
153{
154 IPSockAddress dummy; // ignored
155 return accept(s, dummy);
156}
157
158void 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
166bool 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
195bool 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
203void Socket::shutdown(int how)
204{
205 assert(how >= 0 && how <= 2);
206 checkError(::shutdown(fd(), how));
207}
208
209
210IPSockAddress 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
219IPSockAddress 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
228void 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
233void 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//
243void 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//
268void TCPClientSocket::open(const IPSockAddress &peer, int fdFlags)
269{
270 prepare(fdFlags, SOCK_STREAM);
271 connect(peer);
272}
273
274void TCPClientSocket::open(const IPAddress &addr, IPPort port, int fdFlags)
275{
276 prepare(fdFlags, SOCK_STREAM);
277 connect(addr, port);
278}
279
280void TCPClientSocket::open(const Host &host, IPPort port, int fdFlags)
281{
282 prepare(fdFlags, SOCK_STREAM);
283 connect(host, port);
284}
285
286TCPClientSocket::~TCPClientSocket()
287{
288 close();
289}
290
291
292void TCPServerSocket::open(const IPSockAddress &addr, int depth)
293{
294 prepare(0, SOCK_STREAM);
295 bind(addr);
296 listen(depth);
297}
298
299void TCPServerSocket::operator () (TCPClientSocket &newClient)
300{
301 accept(newClient);
302}
303
304void TCPServerSocket::receive(TCPClientSocket &newClient)
305{
306 accept(newClient);
307 close();
308}
309
310TCPServerSocket::~TCPServerSocket()
311{
312 close();
313}
314
315
316} // end namespace IPPlusPlus
317} // end namespace Security