1/*
2 * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// ip++ - C++ layer for IP socket and address management
27//
28// [Also see comments in header file.]
29//
30#include "ip++.h"
31#include "hosts.h"
32#include <security_utilities/debugging.h>
33#include <arpa/inet.h>
34#include <netdb.h>
35
36
37namespace Security {
38namespace IPPlusPlus {
39
40
41typedef unsigned char Byte;		// occasionally useful
42
43
44//
45// IPAddress
46//
47static const struct in_addr in_addr_any = { INADDR_ANY };
48#if BUG_GCC
49const IPAddress &IPAddress::any = *static_cast<const IPAddress *>(&in_addr_any);
50#else
51const IPAddress &IPAddress::any = static_cast<const IPAddress &>(in_addr_any);
52#endif
53
54IPAddress::IPAddress(const char *s)
55{
56    if (!inet_aton(s, this))
57        UnixError::throwMe(EINVAL);
58}
59
60IPAddress::operator string() const
61{
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]);
67    return buffer;
68}
69
70
71//
72// IPSockAddress
73//
74IPSockAddress::IPSockAddress()
75{
76    sin_family = AF_INET;
77}
78
79IPSockAddress::IPSockAddress(const IPAddress &addr, IPPort port)
80{
81    sin_family = AF_INET;
82    sin_addr = addr;
83    sin_port = htons(port);
84}
85
86IPSockAddress::operator string () const
87{
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());
90    return buffer;
91}
92
93
94IPSockAddress IPSockAddress::defaults(const IPSockAddress &defaultAddr) const
95{
96    return defaults(defaultAddr.address(), defaultAddr.port());
97}
98
99IPSockAddress IPSockAddress::defaults(const IPAddress &defaultAddr, IPPort defaultPort) const
100{
101    return IPSockAddress(
102        address() ? address() : defaultAddr,
103        port() ? port() : defaultPort
104    );
105}
106
107IPSockAddress IPSockAddress::defaults(IPPort defaultPort) const
108{
109    return IPSockAddress(address(), port() ? port() : defaultPort);
110}
111
112
113//
114// UNSockAddress
115//
116UNSockAddress::UNSockAddress()
117{
118	sun_family = AF_UNIX;
119}
120
121UNSockAddress::UNSockAddress(const char *path)
122{
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);
128}
129
130UNSockAddress::UNSockAddress(const string &path)
131{
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);
136}
137
138
139string UNSockAddress::path() const
140{
141	return sun_path;
142}
143
144
145//
146// Sockets
147//
148Socket::Socket(int type)
149{
150    open(type);
151}
152
153Socket::Socket(int domain, int type, int protocol)
154{
155	open(domain, type, protocol);
156}
157
158void Socket::open(int domain, int type, int protocol)
159{
160    checkSetFd(::socket(domain, type, protocol));
161    mAtEnd = false;
162    secdebug("sockio", "socket(%d,%d) -> %d", type, protocol, fd());
163}
164
165void Socket::prepare(int fdFlags, int domain, int type, int protocol)
166{
167    // if file descriptor is closed, open it - otherwise take what's there
168    if (!isOpen())
169        open(domain, type, protocol);
170
171    // if flags were passed in, set them on the file descriptor now
172    if (fdFlags)
173        setFlag(fdFlags);
174}
175
176
177void Socket::bind(const IPAddress &addr, IPPort port)
178{
179    bind(IPSockAddress(addr, port));
180}
181
182void Socket::bind(const IPSockAddress &local)
183{
184    checkError(::bind(fd(), local, sizeof(local)));
185    secdebug("sockio", "%d bind to %s", fd(), string(local).c_str());
186}
187
188void Socket::bind(const UNSockAddress &local)
189{
190    checkError(::bind(fd(), local, sizeof(local)));
191    secdebug("sockio", "%d bind to %s", fd(), string(local).c_str());
192}
193
194
195void Socket::listen(int backlog)
196{
197    checkError(::listen(fd(), backlog));
198}
199
200
201void Socket::accept(Socket &s)
202{
203    IPSockAddress dummy;	// ignored
204    return accept(s, dummy);
205}
206
207void Socket::accept(Socket &s, IPSockAddress &peer)
208{
209    socklen_t length = sizeof(IPSockAddress);
210    s.checkSetFd(::accept(fd(), peer, &length));
211    assert(length == sizeof(IPSockAddress));
212}
213
214void Socket::accept(Socket &s, UNSockAddress &peer)
215{
216    socklen_t length = sizeof(UNSockAddress);
217    s.checkSetFd(::accept(fd(), peer, &length));
218    assert(length == sizeof(UNSockAddress));
219}
220
221
222bool Socket::connect(const IPSockAddress &peer)
223{
224    if (::connect(fd(), peer, sizeof(peer))) {
225        switch (errno) {
226        case EINPROGRESS:
227            secdebug("sockio", "%d connecting to %s", fd(), string(peer).c_str());
228            return false;
229        case EALREADY:
230            if (int err = error())		// connect failed
231                UnixError::throwMe(err);
232            // just keep trying
233            secdebug("sockio", "%d still trying to connect", fd());
234            return false;
235        case EISCONN:
236            if (flags() & O_NONBLOCK) {
237                secdebug("sockio", "%d now connected", fd());
238                return true;
239            } else {
240                UnixError::throwMe();
241            }
242        default:
243            UnixError::throwMe();
244        }
245    } else {
246        secdebug("sockio", "%d connect to %s", fd(), string(peer).c_str());
247        return true;
248    }
249}
250
251bool Socket::connect(const IPAddress &addr, IPPort port)
252{
253    return connect(IPSockAddress(addr, port));
254}
255
256bool Socket::connect(const UNSockAddress &peer)
257{
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());
261	return true;
262}
263
264// void Socket::connect(const Host &host, ...): see below.
265
266
267void Socket::shutdown(int how)
268{
269    assert(how >= 0 && how <= 2);
270    checkError(::shutdown(fd(), how));
271}
272
273
274IPSockAddress Socket::localAddress() const
275{
276    IPSockAddress addr;
277    socklen_t length = sizeof(addr);
278    checkError(::getsockname(fd(), addr, &length));
279    assert(length == sizeof(addr));
280    return addr;
281}
282
283IPSockAddress Socket::peerAddress() const
284{
285    IPSockAddress addr;
286    socklen_t length = sizeof(addr);
287    checkError(::getpeername(fd(), addr, &length));
288    assert(length == sizeof(addr));
289    return addr;
290}
291
292void Socket::getOption(void *value, socklen_t &length, int name, int level /*= SOL_SOCKET*/) const
293{
294    UnixError::check(::getsockopt(fd(), level, name, value, &length));
295}
296
297void Socket::setOption(const void *value, int length, int name, int level /*= SOL_SOCKET*/) const
298{
299    UnixError::check(::setsockopt(fd(), level, name, value, length));
300}
301
302
303//
304// Connect to a Host object.
305// This version of connect performs nontrivial work and makes interesting decisions.
306//
307void Socket::connect(const Host &host, IPPort port)
308{
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());
318            return;
319        }
320    }
321    // no joy on any of the candidate addresses. Throw last error
322    //@@@ clean up errno?
323    UnixError::throwMe();
324}
325
326
327//
328// TCP*Sockets.
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).
331//
332void TCPClientSocket::open(const IPSockAddress &peer, int fdFlags)
333{
334    prepare(fdFlags, AF_INET, SOCK_STREAM);
335    connect(peer);
336}
337
338void TCPClientSocket::open(const IPAddress &addr, IPPort port, int fdFlags)
339{
340    prepare(fdFlags, AF_INET, SOCK_STREAM);
341    connect(addr, port);
342}
343
344void TCPClientSocket::open(const Host &host, IPPort port, int fdFlags)
345{
346    prepare(fdFlags, AF_INET, SOCK_STREAM);
347    connect(host, port);
348}
349
350TCPClientSocket::~TCPClientSocket()
351{
352    close();
353}
354
355
356void TCPServerSocket::open(const IPSockAddress &addr, int depth)
357{
358    prepare(0, AF_INET, SOCK_STREAM);
359    bind(addr);
360    listen(depth);
361}
362
363void TCPServerSocket::operator () (TCPClientSocket &newClient)
364{
365    accept(newClient);
366}
367
368void TCPServerSocket::receive(TCPClientSocket &newClient)
369{
370    accept(newClient);
371    close();
372}
373
374TCPServerSocket::~TCPServerSocket()
375{
376    close();
377}
378
379
380}	// end namespace IPPlusPlus
381}	// end namespace Security
382