]>
git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/ip++.cpp
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // ip++ - C++ layer for IP socket and address management
22 // [Also see comments in header file.]
26 #include <Security/debugging.h>
27 #include <arpa/inet.h>
32 namespace IPPlusPlus
{
35 typedef unsigned char Byte
; // occasionally useful
41 static const struct in_addr in_addr_any
= { INADDR_ANY
};
43 const IPAddress
&IPAddress::any
= *static_cast<const IPAddress
*>(&in_addr_any
);
45 const IPAddress
&IPAddress::any
= static_cast<const IPAddress
&>(in_addr_any
);
48 IPAddress::IPAddress(const char *s
)
50 if (!inet_aton(s
, this))
51 UnixError::throwMe(EINVAL
);
54 IPAddress::operator string() const
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]);
68 IPSockAddress::IPSockAddress()
73 IPSockAddress::IPSockAddress(const IPAddress
&addr
, IPPort port
)
77 sin_port
= htons(port
);
80 IPSockAddress::operator string () const
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());
88 IPSockAddress
IPSockAddress::defaults(const IPSockAddress
&defaultAddr
) const
90 return defaults(defaultAddr
.address(), defaultAddr
.port());
93 IPSockAddress
IPSockAddress::defaults(const IPAddress
&defaultAddr
, IPPort defaultPort
) const
96 address() ? address() : defaultAddr
,
97 port() ? port() : defaultPort
101 IPSockAddress
IPSockAddress::defaults(IPPort defaultPort
) const
103 return IPSockAddress(address(), port() ? port() : defaultPort
);
110 UNSockAddress::UNSockAddress()
112 sun_family
= AF_UNIX
;
115 UNSockAddress::UNSockAddress(const char *path
)
117 sun_family
= AF_UNIX
;
118 size_t length
= strlen(path
);
119 if (length
>= sizeof(sun_path
)) // won't fit into struct sockaddr_un
120 UnixError::throwMe(EINVAL
);
121 memcpy(sun_path
, path
, length
+ 1);
124 UNSockAddress::UNSockAddress(const string
&path
)
126 sun_family
= AF_UNIX
;
127 if (path
.length() >= sizeof(sun_path
)) // won't fit into struct sockaddr_un
128 UnixError::throwMe(EINVAL
);
129 memcpy(sun_path
, path
.c_str(), path
.length() + 1);
133 string
UNSockAddress::path() const
142 Socket::Socket(int type
)
147 Socket::Socket(int domain
, int type
, int protocol
)
149 open(domain
, type
, protocol
);
152 void Socket::open(int domain
, int type
, int protocol
)
154 checkSetFd(::socket(domain
, type
, protocol
));
156 secdebug("sockio", "socket(%d,%d) -> %d", type
, protocol
, fd());
159 void Socket::prepare(int fdFlags
, int domain
, int type
, int protocol
)
161 // if file descriptor is closed, open it - otherwise take what's there
163 open(domain
, type
, protocol
);
165 // if flags were passed in, set them on the file descriptor now
171 void Socket::bind(const IPAddress
&addr
, IPPort port
)
173 bind(IPSockAddress(addr
, port
));
176 void Socket::bind(const IPSockAddress
&local
)
178 checkError(::bind(fd(), local
, sizeof(local
)));
179 secdebug("sockio", "%d bind to %s", fd(), string(local
).c_str());
182 void Socket::bind(const UNSockAddress
&local
)
184 checkError(::bind(fd(), local
, sizeof(local
)));
185 secdebug("sockio", "%d bind to %s", fd(), string(local
).c_str());
189 void Socket::listen(int backlog
)
191 checkError(::listen(fd(), backlog
));
195 void Socket::accept(Socket
&s
)
197 IPSockAddress dummy
; // ignored
198 return accept(s
, dummy
);
201 void Socket::accept(Socket
&s
, IPSockAddress
&peer
)
203 int length
= sizeof(IPSockAddress
);
204 s
.checkSetFd(::accept(fd(), peer
, &length
));
205 assert(length
== sizeof(IPSockAddress
));
208 void Socket::accept(Socket
&s
, UNSockAddress
&peer
)
210 int length
= sizeof(UNSockAddress
);
211 s
.checkSetFd(::accept(fd(), peer
, &length
));
212 assert(length
== sizeof(UNSockAddress
));
216 bool Socket::connect(const IPSockAddress
&peer
)
218 if (::connect(fd(), peer
, sizeof(peer
))) {
221 secdebug("sockio", "%d connecting to %s", fd(), string(peer
).c_str());
224 if (int err
= error()) // connect failed
225 UnixError::throwMe(err
);
227 secdebug("sockio", "%d still trying to connect", fd());
230 if (flags() & O_NONBLOCK
) {
231 secdebug("sockio", "%d now connected", fd());
234 UnixError::throwMe();
237 UnixError::throwMe();
240 secdebug("sockio", "%d connect to %s", fd(), string(peer
).c_str());
245 bool Socket::connect(const IPAddress
&addr
, IPPort port
)
247 return connect(IPSockAddress(addr
, port
));
250 bool Socket::connect(const UNSockAddress
&peer
)
252 // no nice async support here: local operation (but keep the niceties)
253 checkError(::connect(fd(), peer
, sizeof(peer
)));
254 secdebug("sockio", "%d connect to %s", fd(), string(peer
).c_str());
258 // void Socket::connect(const Host &host, ...): see below.
261 void Socket::shutdown(int how
)
263 assert(how
>= 0 && how
<= 2);
264 checkError(::shutdown(fd(), how
));
268 IPSockAddress
Socket::localAddress() const
271 int length
= sizeof(addr
);
272 checkError(::getsockname(fd(), addr
, &length
));
273 assert(length
== sizeof(addr
));
277 IPSockAddress
Socket::peerAddress() const
280 int length
= sizeof(addr
);
281 checkError(::getpeername(fd(), addr
, &length
));
282 assert(length
== sizeof(addr
));
286 void Socket::getOption(void *value
, int &length
, int name
, int level
/*= SOL_SOCKET*/) const
288 UnixError::check(::getsockopt(fd(), level
, name
, value
, &length
));
291 void Socket::setOption(const void *value
, int length
, int name
, int level
/*= SOL_SOCKET*/) const
293 UnixError::check(::setsockopt(fd(), level
, name
, value
, length
));
298 // Connect to a Host object.
299 // This version of connect performs nontrivial work and makes interesting decisions.
301 void Socket::connect(const Host
&host
, IPPort port
)
303 //@@@ use two-step stutter algorithm?
304 //@@@ randomize order?
305 //@@@ keep worked-recently information?
306 //@@@ what about nonblocking operation?
307 set
<IPAddress
> addrs
= host
.addresses();
308 for (set
<IPAddress
>::const_iterator it
= addrs
.begin(); it
!= addrs
.end(); it
++) {
309 const IPSockAddress
address(*it
, port
);
310 if (::connect(fd(), address
, sizeof(IPSockAddress
)) == 0) {
311 secdebug("sockio", "%d connect to %s", fd(), string(address
).c_str());
315 // no joy on any of the candidate addresses. Throw last error
316 //@@@ clean up errno?
317 UnixError::throwMe();
323 // Note that these will TCP*Socket::open() will *use* its existing file descriptor,
324 // on the theory that the caller may have prepared it specially (e.g. to make it nonblocking).
326 void TCPClientSocket::open(const IPSockAddress
&peer
, int fdFlags
)
328 prepare(fdFlags
, AF_INET
, SOCK_STREAM
);
332 void TCPClientSocket::open(const IPAddress
&addr
, IPPort port
, int fdFlags
)
334 prepare(fdFlags
, AF_INET
, SOCK_STREAM
);
338 void TCPClientSocket::open(const Host
&host
, IPPort port
, int fdFlags
)
340 prepare(fdFlags
, AF_INET
, SOCK_STREAM
);
344 TCPClientSocket::~TCPClientSocket()
350 void TCPServerSocket::open(const IPSockAddress
&addr
, int depth
)
352 prepare(0, AF_INET
, SOCK_STREAM
);
357 void TCPServerSocket::operator () (TCPClientSocket
&newClient
)
362 void TCPServerSocket::receive(TCPClientSocket
&newClient
)
368 TCPServerSocket::~TCPServerSocket()
374 } // end namespace IPPlusPlus
375 } // end namespace Security