]> git.saurik.com Git - apple/security.git/blame - Network/netmanager.cpp
Security-54.1.9.tar.gz
[apple/security.git] / Network / netmanager.cpp
CommitLineData
bac41a7b
A
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
29namespace Security {
30namespace Network {
31
32
33Manager::Manager() : mActiveTransfers(0), mRetainConnections(true), mObserver(NULL)
34{
35}
36
37Manager::~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//
50void 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//
63void 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//
74void 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//
101void 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//
130void 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//
145void Manager::addIO(TransferEngine::Client *client)
146{
147 mEngine.add(client);
148}
149
150void 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//
159void Manager::retainConnection(Connection *connection)
160{
161 if (mRetainConnections)
162 mConnections.retain(connection);
163 else
164 closeConnection(connection);
165}
166
167void 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//
177Connection *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//
195void Manager::reuseConnections(bool retain)
196{
197 mRetainConnections = retain;
198}
199
200
201void Manager::flushConnections()
202{
203 mConnections.purge();
204}
205
206
207//
208// Timer management
209//
210void Manager::setTimer(Timer *timer, Time::Absolute when)
211{
212 mTimers.schedule(timer, when);
213}
214
215void Manager::clearTimer(Timer *timer)
216{
217 if (timer->scheduled())
218 mTimers.unschedule(timer);
219}
220
221
222void 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//
241void 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//
254void 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
268void Manager::run()
269{
270 run(Time::heatDeath());
271}
272
273
274//
275// Internal stepper
276//
277void 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