]> git.saurik.com Git - apple/security.git/blob - Network/netmanager.cpp
Security-28.tar.gz
[apple/security.git] / Network / netmanager.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 // manager - network protocol core manager class
21 //
22 #include "netmanager.h"
23 #include "protocol.h"
24 #include "transfer.h"
25 #include "netconnection.h"
26 #include "neterror.h"
27
28
29 namespace Security {
30 namespace Network {
31
32
33 Manager::Manager() : mActiveTransfers(0), mRetainConnections(true), mObserver(NULL)
34 {
35 }
36
37 Manager::~Manager()
38 {
39 //@@@ cleanup, s'il vous plait:
40 //@@@ abort transfers and destroy them
41 //@@@ notify any observers
42 //@@@ destroy protocol objects
43 }
44
45
46 //
47 // Add a new Transfer to this Manager.
48 // This does not start it; it'll just sit around until started.
49 //
50 void Manager::add(Transfer *xfer)
51 {
52 assert(xfer->state() == Transfer::cold);
53 mTransfers.insert(xfer);
54 xfer->mState = Transfer::warm;
55 }
56
57
58 //
59 // Remove a Transfer from this Manager.
60 // You can remove a pre-active Transfer, or one that has finished or failed.
61 // You can't remove an active Transfer - abort it first.
62 //
63 void Manager::remove(Transfer *xfer)
64 {
65 assert(mTransfers.find(xfer) != mTransfers.end()); // is ours
66 assert(xfer->state() != Transfer::active);
67 mTransfers.erase(xfer);
68 }
69
70
71 //
72 // Start a Transfer. It must already have been added, and must be in a pre-active state.
73 //
74 void Manager::start(Transfer *xfer)
75 {
76 assert(mTransfers.find(xfer) != mTransfers.end()); // is ours
77 assert(xfer->state() == Transfer::warm);
78 try {
79 xfer->start();
80 xfer->mState = Transfer::active;
81 xfer->observe(Observer::transferStarting);
82 mActiveTransfers++;
83 debug("netmanager", "%ld active transfers", mActiveTransfers);
84 } catch (...) {
85 xfer->mState = Transfer::failed;
86 debug("netmanager", "Transfer %p failed to start", xfer);
87 throw;
88 }
89 }
90
91
92 //
93 // Abort a Transfer.
94 // If it is active, try to make it stop as soon as it's safe. This may return while
95 // the Transfer's state is still active; it will eventually switch to failed unless it
96 // happened to succeed before we got to it (in which case it'll be finished).
97 // You can't abort a Transfer that isn't active.
98 //@@@ Phasing problem? Perhaps aborting non-active Transfers should be
99 //@@@ allowed (and ignored or flagged).
100 //
101 void Manager::abort(Transfer *xfer)
102 {
103 assert(mTransfers.find(xfer) != mTransfers.end()); // is ours
104 switch (xfer->state()) {
105 case Transfer::active:
106 try {
107 debug("netmanager", "xfer %p request abort", xfer);
108 xfer->abort();
109 } catch (...) {
110 debug("netmanager", "xfer %p failed to abort; forcing the issue", xfer);
111 xfer->Transfer::abort();
112 }
113 break;
114 case Transfer::finished:
115 case Transfer::failed:
116 // no longer running; ignore cancel request
117 debug("netmanager", "xfer %p abort ignored (already done)", xfer);
118 break;
119 default:
120 assert(false); // mustn't call in this state
121 }
122 }
123
124
125 //
126 // Do bookkeeping for a Transfer that wants to be done.
127 // This method can only be called from a Transfer that belongs
128 // to this Manager and was started.
129 //
130 void Manager::done(Transfer *xfer)
131 {
132 assert(mTransfers.find(xfer) != mTransfers.end()); // is ours
133 assert(xfer->state() == Transfer::finished || xfer->state() == Transfer::failed);
134 assert(mActiveTransfers > 0);
135 mActiveTransfers--;
136 debug("netmanager", "%ld active transfers", mActiveTransfers);
137 }
138
139
140 //
141 // Manage engine clients on behalf of active Transfers.
142 //@@@ Currently the API doesn't specify which Transfer these belong to.
143 //@@@ Perhaps it should.
144 //
145 void Manager::addIO(TransferEngine::Client *client)
146 {
147 mEngine.add(client);
148 }
149
150 void Manager::removeIO(TransferEngine::Client *client)
151 {
152 mEngine.remove(client);
153 }
154
155
156 //
157 // Manage Connections on behalf of Transfers (and perhaps Protocols)
158 //
159 void Manager::retainConnection(Connection *connection)
160 {
161 if (mRetainConnections)
162 mConnections.retain(connection);
163 else
164 closeConnection(connection);
165 }
166
167 void Manager::closeConnection(Connection *connection)
168 {
169 mConnections.remove(connection);
170 mMorgue.insert(connection);
171 }
172
173
174 //
175 // Try to find a live retained Connection for a HostTarget and return it.
176 //
177 Connection *Manager::pickConnection(const HostTarget &host)
178 {
179 while (Connection *connection = mConnections.get(host)) {
180 if (connection->validate()) {
181 connection->restarting(true); // mark restarting
182 return connection; // good to go
183 }
184 // if validate returned false, the connection has self-destructed (so ignore it)
185 debug("netmanager", "%p connection %p failed to validate",
186 this, connection);
187 }
188 return NULL; // no joy, caller must make a new one
189 }
190
191
192 //
193 // Handle the global Connection cache
194 //
195 void Manager::reuseConnections(bool retain)
196 {
197 mRetainConnections = retain;
198 }
199
200
201 void Manager::flushConnections()
202 {
203 mConnections.purge();
204 }
205
206
207 //
208 // Timer management
209 //
210 void Manager::setTimer(Timer *timer, Time::Absolute when)
211 {
212 mTimers.schedule(timer, when);
213 }
214
215 void Manager::clearTimer(Timer *timer)
216 {
217 if (timer->scheduled())
218 mTimers.unschedule(timer);
219 }
220
221
222 void Manager::runTimers()
223 {
224 while (Timer *top = static_cast<Timer *>(mTimers.pop(Time::now()))) {
225 debug("netmanager", "%p timer %p executing at %.3f",
226 this, top, Time::now().internalForm());
227 try {
228 top->action();
229 debug("machsrvtime", "%p timer %p done", this, top);
230 } catch (...) {
231 debug("machsrvtime",
232 "%p server timer %p failed with exception", this, top);
233 }
234 }
235 }
236
237
238 //
239 // Perform a (small) incremental operations step.
240 //
241 void Manager::step()
242 {
243 prepare();
244 if (!mEngine.isEmpty()) {
245 debug("mgrstep", "operations step");
246 mEngine();
247 }
248 }
249
250
251 //
252 // Run in this thread until a particular time (or until no more Transfers are active).
253 //
254 void Manager::run(Time::Absolute stopTime)
255 {
256 debug("netmanager",
257 "starting run with %ld active transfers", mActiveTransfers);
258 while (mActiveTransfers > 0) {
259 prepare();
260 Time::Absolute limit = mTimers.empty() ? stopTime : min(stopTime, mTimers.next());
261 mEngine(limit - Time::now());
262 if (Time::now() > stopTime)
263 break;
264 }
265 debug("netmanager", "ending run");
266 }
267
268 void Manager::run()
269 {
270 run(Time::heatDeath());
271 }
272
273
274 //
275 // Internal stepper
276 //
277 void Manager::prepare()
278 {
279 // clear the morgue
280 if (!mMorgue.empty()) {
281 debug("netmanager",
282 "clearing morgue of %ld connections", mMorgue.size());
283 for (set<Connection *>::iterator it = mMorgue.begin(); it != mMorgue.end(); it++)
284 delete *it;
285 mMorgue.erase(mMorgue.begin(), mMorgue.end());
286 }
287
288 // run pending timers
289 runTimers();
290 }
291
292
293 } // end namespace Network
294 } // end namespace Security