]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/ip++.cpp
030b678f686738546985192207d0582c338bc963
   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     secinfo("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     secinfo("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     secinfo("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             secinfo("sockio", "%d connecting to %s", fd(), string(peer
).c_str()); 
 230             if (int err 
= error())              // connect failed 
 231                 UnixError::throwMe(err
); 
 233             secinfo("sockio", "%d still trying to connect", fd()); 
 236             if (flags() & O_NONBLOCK
) { 
 237                 secinfo("sockio", "%d now connected", fd()); 
 240                 UnixError::throwMe(); 
 243             UnixError::throwMe(); 
 246         secinfo("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         secinfo("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             secinfo("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