]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/ip++.cpp
2 * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // ip++ - C++ layer for IP socket and address management
28 // [Also see comments in header file.]
32 #include <security_utilities/debugging.h>
33 #include <arpa/inet.h>
38 namespace IPPlusPlus
{
41 typedef unsigned char Byte
; // occasionally useful
47 static const struct in_addr in_addr_any
= { INADDR_ANY
};
49 const IPAddress
&IPAddress::any
= *static_cast<const IPAddress
*>(&in_addr_any
);
51 const IPAddress
&IPAddress::any
= static_cast<const IPAddress
&>(in_addr_any
);
54 IPAddress::IPAddress(const char *s
)
56 if (!inet_aton(s
, this))
57 UnixError::throwMe(EINVAL
);
60 IPAddress::operator string() const
62 // This code is esentially equivalent to inet_ntoa, which we can't use for thread safety.
63 // Note: contents in NBO = always high-endian, thus this cast works everywhere.
64 const Byte
*p
= reinterpret_cast<const Byte
*>(this);
65 char buffer
[(3+1)*4]; // nnn.nnn.nnn.nnn\0
66 snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d", p
[0], p
[1], p
[2], p
[3]);
74 IPSockAddress::IPSockAddress()
79 IPSockAddress::IPSockAddress(const IPAddress
&addr
, IPPort port
)
83 sin_port
= htons(port
);
86 IPSockAddress::operator string () const
88 char buffer
[4*(3+1)+5+1]; // nnn.nnn.nnn.nnn:ppppp
89 snprintf(buffer
, sizeof(buffer
), "%s:%d", string(address()).c_str(), port());
94 IPSockAddress
IPSockAddress::defaults(const IPSockAddress
&defaultAddr
) const
96 return defaults(defaultAddr
.address(), defaultAddr
.port());
99 IPSockAddress
IPSockAddress::defaults(const IPAddress
&defaultAddr
, IPPort defaultPort
) const
101 return IPSockAddress(
102 address() ? address() : defaultAddr
,
103 port() ? port() : defaultPort
107 IPSockAddress
IPSockAddress::defaults(IPPort defaultPort
) const
109 return IPSockAddress(address(), port() ? port() : defaultPort
);
116 UNSockAddress::UNSockAddress()
118 sun_family
= AF_UNIX
;
121 UNSockAddress::UNSockAddress(const char *path
)
123 sun_family
= AF_UNIX
;
124 size_t length
= strlen(path
);
125 if (length
>= sizeof(sun_path
)) // won't fit into struct sockaddr_un
126 UnixError::throwMe(EINVAL
);
127 memcpy(sun_path
, path
, length
+ 1);
130 UNSockAddress::UNSockAddress(const string
&path
)
132 sun_family
= AF_UNIX
;
133 if (path
.length() >= sizeof(sun_path
)) // won't fit into struct sockaddr_un
134 UnixError::throwMe(EINVAL
);
135 memcpy(sun_path
, path
.c_str(), path
.length() + 1);
139 string
UNSockAddress::path() const
148 Socket::Socket(int type
)
153 Socket::Socket(int domain
, int type
, int protocol
)
155 open(domain
, type
, protocol
);
158 void Socket::open(int domain
, int type
, int protocol
)
160 checkSetFd(::socket(domain
, type
, protocol
));
162 secdebug("sockio", "socket(%d,%d) -> %d", type
, protocol
, fd());
165 void Socket::prepare(int fdFlags
, int domain
, int type
, int protocol
)
167 // if file descriptor is closed, open it - otherwise take what's there
169 open(domain
, type
, protocol
);
171 // if flags were passed in, set them on the file descriptor now
177 void Socket::bind(const IPAddress
&addr
, IPPort port
)
179 bind(IPSockAddress(addr
, port
));
182 void Socket::bind(const IPSockAddress
&local
)
184 checkError(::bind(fd(), local
, sizeof(local
)));
185 secdebug("sockio", "%d bind to %s", fd(), string(local
).c_str());
188 void Socket::bind(const UNSockAddress
&local
)
190 checkError(::bind(fd(), local
, sizeof(local
)));
191 secdebug("sockio", "%d bind to %s", fd(), string(local
).c_str());
195 void Socket::listen(int backlog
)
197 checkError(::listen(fd(), backlog
));
201 void Socket::accept(Socket
&s
)
203 IPSockAddress dummy
; // ignored
204 return accept(s
, dummy
);
207 void Socket::accept(Socket
&s
, IPSockAddress
&peer
)
209 socklen_t length
= sizeof(IPSockAddress
);
210 s
.checkSetFd(::accept(fd(), peer
, &length
));
211 assert(length
== sizeof(IPSockAddress
));
214 void Socket::accept(Socket
&s
, UNSockAddress
&peer
)
216 socklen_t length
= sizeof(UNSockAddress
);
217 s
.checkSetFd(::accept(fd(), peer
, &length
));
218 assert(length
== sizeof(UNSockAddress
));
222 bool Socket::connect(const IPSockAddress
&peer
)
224 if (::connect(fd(), peer
, sizeof(peer
))) {
227 secdebug("sockio", "%d connecting to %s", fd(), string(peer
).c_str());
230 if (int err
= error()) // connect failed
231 UnixError::throwMe(err
);
233 secdebug("sockio", "%d still trying to connect", fd());
236 if (flags() & O_NONBLOCK
) {
237 secdebug("sockio", "%d now connected", fd());
240 UnixError::throwMe();
243 UnixError::throwMe();
246 secdebug("sockio", "%d connect to %s", fd(), string(peer
).c_str());
251 bool Socket::connect(const IPAddress
&addr
, IPPort port
)
253 return connect(IPSockAddress(addr
, port
));
256 bool Socket::connect(const UNSockAddress
&peer
)
258 // no nice async support here: local operation (but keep the niceties)
259 checkError(::connect(fd(), peer
, sizeof(peer
)));
260 secdebug("sockio", "%d connect to %s", fd(), string(peer
).c_str());
264 // void Socket::connect(const Host &host, ...): see below.
267 void Socket::shutdown(int how
)
269 assert(how
>= 0 && how
<= 2);
270 checkError(::shutdown(fd(), how
));
274 IPSockAddress
Socket::localAddress() const
277 socklen_t length
= sizeof(addr
);
278 checkError(::getsockname(fd(), addr
, &length
));
279 assert(length
== sizeof(addr
));
283 IPSockAddress
Socket::peerAddress() const
286 socklen_t length
= sizeof(addr
);
287 checkError(::getpeername(fd(), addr
, &length
));
288 assert(length
== sizeof(addr
));
292 void Socket::getOption(void *value
, socklen_t
&length
, int name
, int level
/*= SOL_SOCKET*/) const
294 UnixError::check(::getsockopt(fd(), level
, name
, value
, &length
));
297 void Socket::setOption(const void *value
, int length
, int name
, int level
/*= SOL_SOCKET*/) const
299 UnixError::check(::setsockopt(fd(), level
, name
, value
, length
));
304 // Connect to a Host object.
305 // This version of connect performs nontrivial work and makes interesting decisions.
307 void Socket::connect(const Host
&host
, IPPort port
)
309 //@@@ use two-step stutter algorithm?
310 //@@@ randomize order?
311 //@@@ keep worked-recently information?
312 //@@@ what about nonblocking operation?
313 set
<IPAddress
> addrs
= host
.addresses();
314 for (set
<IPAddress
>::const_iterator it
= addrs
.begin(); it
!= addrs
.end(); it
++) {
315 const IPSockAddress
address(*it
, port
);
316 if (::connect(fd(), address
, sizeof(IPSockAddress
)) == 0) {
317 secdebug("sockio", "%d connect to %s", fd(), string(address
).c_str());
321 // no joy on any of the candidate addresses. Throw last error
322 //@@@ clean up errno?
323 UnixError::throwMe();
329 // Note that these will TCP*Socket::open() will *use* its existing file descriptor,
330 // on the theory that the caller may have prepared it specially (e.g. to make it nonblocking).
332 void TCPClientSocket::open(const IPSockAddress
&peer
, int fdFlags
)
334 prepare(fdFlags
, AF_INET
, SOCK_STREAM
);
338 void TCPClientSocket::open(const IPAddress
&addr
, IPPort port
, int fdFlags
)
340 prepare(fdFlags
, AF_INET
, SOCK_STREAM
);
344 void TCPClientSocket::open(const Host
&host
, IPPort port
, int fdFlags
)
346 prepare(fdFlags
, AF_INET
, SOCK_STREAM
);
350 TCPClientSocket::~TCPClientSocket()
356 void TCPServerSocket::open(const IPSockAddress
&addr
, int depth
)
358 prepare(0, AF_INET
, SOCK_STREAM
);
363 void TCPServerSocket::operator () (TCPClientSocket
&newClient
)
368 void TCPServerSocket::receive(TCPClientSocket
&newClient
)
374 TCPServerSocket::~TCPServerSocket()
380 } // end namespace IPPlusPlus
381 } // end namespace Security