]>
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 Socket::Socket(int type
, int protocol
)
112 open(type
, protocol
);
115 void Socket::open(int type
, int protocol
)
117 checkSetFd(::socket(AF_INET
, type
, protocol
));
119 debug("sockio", "socket(%d,%d) -> %d", type
, protocol
, fd());
122 void Socket::prepare(int fdFlags
, int type
, int protocol
)
124 // if file descriptor is closed, open it - otherwise take what's there
126 open(type
, protocol
);
128 // if flags were passed in, set them on the file descriptor now
134 void Socket::bind(const IPAddress
&addr
, IPPort port
)
136 bind(IPSockAddress(addr
, port
));
139 void Socket::bind(const IPSockAddress
&local
)
141 checkError(::bind(fd(), local
, sizeof(local
)));
142 IFDEBUG(debug("sockio", "%d bind to %s", fd(), string(local
).c_str()));
146 void Socket::listen(int backlog
)
148 checkError(::listen(fd(), backlog
));
152 void Socket::accept(Socket
&s
)
154 IPSockAddress dummy
; // ignored
155 return accept(s
, dummy
);
158 void Socket::accept(Socket
&s
, IPSockAddress
&peer
)
160 int length
= sizeof(IPSockAddress
);
161 s
.checkSetFd(::accept(fd(), peer
, &length
));
162 assert(length
== sizeof(IPSockAddress
));
166 bool Socket::connect(const IPSockAddress
&peer
)
168 if (::connect(fd(), peer
, sizeof(peer
))) {
171 IFDEBUG(debug("sockio", "%d connecting to %s", fd(), string(peer
).c_str()));
174 if (int err
= error()) // connect failed
175 UnixError::throwMe(err
);
177 IFDEBUG(debug("sockio", "%d still trying to connect", fd()));
180 if (flags() & O_NONBLOCK
) {
181 debug("sockio", "%d now connected", fd());
184 UnixError::throwMe();
187 UnixError::throwMe();
190 IFDEBUG(debug("sockio", "%d connect to %s", fd(), string(peer
).c_str()));
195 bool Socket::connect(const IPAddress
&addr
, IPPort port
)
197 return connect(IPSockAddress(addr
, port
));
200 // void Socket::connect(const Host &host, ...): see below.
203 void Socket::shutdown(int how
)
205 assert(how
>= 0 && how
<= 2);
206 checkError(::shutdown(fd(), how
));
210 IPSockAddress
Socket::localAddress() const
213 int length
= sizeof(addr
);
214 checkError(::getsockname(fd(), addr
, &length
));
215 assert(length
== sizeof(addr
));
219 IPSockAddress
Socket::peerAddress() const
222 int length
= sizeof(addr
);
223 checkError(::getpeername(fd(), addr
, &length
));
224 assert(length
== sizeof(addr
));
228 void Socket::getOption(void *value
, int &length
, int name
, int level
= SOL_SOCKET
) const
230 UnixError::check(::getsockopt(fd(), level
, name
, value
, &length
));
233 void Socket::setOption(const void *value
, int length
, int name
, int level
= SOL_SOCKET
) const
235 UnixError::check(::setsockopt(fd(), level
, name
, value
, length
));
240 // Connect to a Host object.
241 // This version of connect performs nontrivial work and makes interesting decisions.
243 void Socket::connect(const Host
&host
, IPPort port
)
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()));
257 // no joy on any of the candidate addresses. Throw last error
258 //@@@ clean up errno?
259 UnixError::throwMe();
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).
268 void TCPClientSocket::open(const IPSockAddress
&peer
, int fdFlags
)
270 prepare(fdFlags
, SOCK_STREAM
);
274 void TCPClientSocket::open(const IPAddress
&addr
, IPPort port
, int fdFlags
)
276 prepare(fdFlags
, SOCK_STREAM
);
280 void TCPClientSocket::open(const Host
&host
, IPPort port
, int fdFlags
)
282 prepare(fdFlags
, SOCK_STREAM
);
286 TCPClientSocket::~TCPClientSocket()
292 void TCPServerSocket::open(const IPSockAddress
&addr
, int depth
)
294 prepare(0, SOCK_STREAM
);
299 void TCPServerSocket::operator () (TCPClientSocket
&newClient
)
304 void TCPServerSocket::receive(TCPClientSocket
&newClient
)
310 TCPServerSocket::~TCPServerSocket()
316 } // end namespace IPPlusPlus
317 } // end namespace Security