]> git.saurik.com Git - apple/security.git/blob - Network/netconnection.cpp
Security-28.tar.gz
[apple/security.git] / Network / netconnection.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 //
20 // connection - a (potentially) persistent access path to a (possibly :-) remote entity
21 //
22 #include "netconnection.h"
23 #include "protocol.h"
24 #include "netmanager.h"
25 #include "transfer.h"
26
27
28 namespace Security {
29 namespace Network {
30
31
32 //
33 // Create a Connection object for a particular Protocol and HostTarget.
34 // Note that these two arguments are potentially unrelated; in general,
35 // you can't assume that &proto == &host.protocol().
36 //
37 Connection::Connection(Protocol &proto, const HostTarget &host)
38 : protocol(proto), hostTarget(host), mTransfer(NULL), mRetainMe(false), mRestarting(false)
39 {
40 debug("netconn",
41 "connection %p created for %s", this, hostTarget.urlForm().c_str());
42 }
43
44
45 //
46 // Destroy a Connection, assuming it's idle.
47 //
48 Connection::~Connection()
49 {
50 assert(!isDocked());
51 debug("netconn", "connection %p destroyed", this);
52 }
53
54
55 //
56 // Dock the Connection to a Transfer.
57 //
58 void Connection::dock(Transfer *xfer)
59 {
60 assert(!isDocked());
61 assert(!xfer->isDocked());
62 mTransfer = xfer;
63 xfer->mConnection = this;
64 debug("netconn", "connection %p docked xfer %p", this, xfer);
65 }
66
67
68 //
69 // Undock the Connection from its currently docked Transfer.
70 // The mRetainMe flag determines what happens next: we either
71 // submit ourselves to our Manager for retention, or for cleanup.
72 //
73 void Connection::undock()
74 {
75 // paranoia first
76 assert(isDocked());
77 assert(mTransfer->mConnection == this);
78
79 // will we be kept?
80 bool retain = mRetainMe && mTransfer->shareConnections();
81
82 // physically sever our relationship with the Transfer
83 debug("netconn", "connection %p undocking xfer %p", this, mTransfer);
84 mTransfer->mConnection = NULL;
85 mTransfer = NULL;
86
87 // submit ourselves to the manager for retention
88 if (retain)
89 protocol.manager.retainConnection(this);
90 else
91 protocol.manager.closeConnection(this);
92 }
93
94
95 //
96 // Forwarders for finish/fail
97 //
98 void Connection::finish()
99 {
100 assert(isDocked());
101 mTransfer->finish();
102 }
103
104 void Connection::fail()
105 {
106 if (isDocked()) {
107 // fail the transfer we're docked to, which will undock us and dispose of us
108 mTransfer->fail();
109 } else {
110 // we failed while in limbo. Self-dispose
111 retain(false);
112 protocol.manager.closeConnection(this);
113 }
114 }
115
116
117 //
118 // Drop the current Connection and re-execute start()
119 //
120 void Connection::restart()
121 {
122 if (mRestarting) {
123 Transfer *transfer = mTransfer;
124 debug("netconn", "%p restarting xfer %p", this, transfer);
125
126 // throw outselves out
127 retain(false);
128 undock();
129
130 // restart the transfer
131 transfer->start();
132 } else {
133 // restart request on Connection that's not marked restarting.
134 // Presumably a real error, and we assume error indications have already
135 // been set (in the Transfer) by the caller as desired.
136 fail();
137 }
138 }
139
140
141 //
142 // The default implementation of validate() does nothing and succeeds.
143 //
144 bool Connection::validate()
145 {
146 return true;
147 }
148
149
150 //
151 // The file descriptor of a TCPConnection is itself (as a TCPClientSocket)
152 //
153 int TCPConnection::fileDesc() const
154 {
155 return *this;
156 }
157
158
159 //
160 // The TCPConnection destructor will remove any remaining I/O hook
161 //
162 TCPConnection::~TCPConnection()
163 {
164 close();
165 }
166
167 void TCPConnection::close()
168 {
169 if (isOpen()) {
170 protocol.manager.removeIO(this);
171 TCPClientSocket::close();
172 }
173 }
174
175
176 //
177 // Asynchronous connect processing for TCPClient subclasses.
178 // The full call sets up data and initiates the first connect attempt; the second
179 // form needs to be called on failure notification to (re)try other addresses.
180 //
181 void TCPConnection::connect(const Host &host, IPPort port)
182 {
183 mAddressCandidates = host.addresses();
184 mPort = port;
185 nextCandidate();
186 protocol.manager.addIO(this);
187 mode(connecting);
188 }
189
190 void TCPConnection::connect()
191 {
192 if (mAddressCandidates.empty()) {
193 // out of candidates. This connection attempt is failing
194 UnixError::throwMe(EHOSTUNREACH);
195 }
196
197 close();
198 nextCandidate();
199 protocol.manager.addIO(this);
200 mode(connecting);
201 }
202
203 void TCPConnection::nextCandidate()
204 {
205 // pull the next address from the candidate set
206 std::set<IPAddress>::iterator it = mAddressCandidates.begin();
207 IPAddress addr = *it;
208 mAddressCandidates.erase(it);
209
210 open(addr, mPort, O_NONBLOCK);
211 }
212
213
214 } // end namespace Network
215 } // end namespace Security