/* * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the * specific language governing rights and limitations under the License. */ // // manager - network protocol core manager class // #include "netmanager.h" #include "protocol.h" #include "transfer.h" #include "netconnection.h" #include "neterror.h" namespace Security { namespace Network { Manager::Manager() : mActiveTransfers(0), mRetainConnections(true), mObserver(NULL) { } Manager::~Manager() { //@@@ cleanup, s'il vous plait: //@@@ abort transfers and destroy them //@@@ notify any observers //@@@ destroy protocol objects } // // Add a new Transfer to this Manager. // This does not start it; it'll just sit around until started. // void Manager::add(Transfer *xfer) { assert(xfer->state() == Transfer::cold); mTransfers.insert(xfer); xfer->mState = Transfer::warm; } // // Remove a Transfer from this Manager. // You can remove a pre-active Transfer, or one that has finished or failed. // You can't remove an active Transfer - abort it first. // void Manager::remove(Transfer *xfer) { assert(mTransfers.find(xfer) != mTransfers.end()); // is ours assert(xfer->state() != Transfer::active); mTransfers.erase(xfer); } // // Start a Transfer. It must already have been added, and must be in a pre-active state. // void Manager::start(Transfer *xfer) { assert(mTransfers.find(xfer) != mTransfers.end()); // is ours assert(xfer->state() == Transfer::warm); try { xfer->start(); xfer->mState = Transfer::active; xfer->observe(Observer::transferStarting); mActiveTransfers++; debug("netmanager", "%ld active transfers", mActiveTransfers); } catch (...) { xfer->mState = Transfer::failed; debug("netmanager", "Transfer %p failed to start", xfer); throw; } } // // Abort a Transfer. // If it is active, try to make it stop as soon as it's safe. This may return while // the Transfer's state is still active; it will eventually switch to failed unless it // happened to succeed before we got to it (in which case it'll be finished). // You can't abort a Transfer that isn't active. //@@@ Phasing problem? Perhaps aborting non-active Transfers should be //@@@ allowed (and ignored or flagged). // void Manager::abort(Transfer *xfer) { assert(mTransfers.find(xfer) != mTransfers.end()); // is ours switch (xfer->state()) { case Transfer::active: try { debug("netmanager", "xfer %p request abort", xfer); xfer->abort(); } catch (...) { debug("netmanager", "xfer %p failed to abort; forcing the issue", xfer); xfer->Transfer::abort(); } break; case Transfer::finished: case Transfer::failed: // no longer running; ignore cancel request debug("netmanager", "xfer %p abort ignored (already done)", xfer); break; default: assert(false); // mustn't call in this state } } // // Do bookkeeping for a Transfer that wants to be done. // This method can only be called from a Transfer that belongs // to this Manager and was started. // void Manager::done(Transfer *xfer) { assert(mTransfers.find(xfer) != mTransfers.end()); // is ours assert(xfer->state() == Transfer::finished || xfer->state() == Transfer::failed); assert(mActiveTransfers > 0); mActiveTransfers--; debug("netmanager", "%ld active transfers", mActiveTransfers); } // // Manage engine clients on behalf of active Transfers. //@@@ Currently the API doesn't specify which Transfer these belong to. //@@@ Perhaps it should. // void Manager::addIO(TransferEngine::Client *client) { mEngine.add(client); } void Manager::removeIO(TransferEngine::Client *client) { mEngine.remove(client); } // // Manage Connections on behalf of Transfers (and perhaps Protocols) // void Manager::retainConnection(Connection *connection) { if (mRetainConnections) mConnections.retain(connection); else closeConnection(connection); } void Manager::closeConnection(Connection *connection) { mConnections.remove(connection); mMorgue.insert(connection); } // // Try to find a live retained Connection for a HostTarget and return it. // Connection *Manager::pickConnection(const HostTarget &host) { while (Connection *connection = mConnections.get(host)) { if (connection->validate()) { connection->restarting(true); // mark restarting return connection; // good to go } // if validate returned false, the connection has self-destructed (so ignore it) debug("netmanager", "%p connection %p failed to validate", this, connection); } return NULL; // no joy, caller must make a new one } // // Handle the global Connection cache // void Manager::reuseConnections(bool retain) { mRetainConnections = retain; } void Manager::flushConnections() { mConnections.purge(); } // // Timer management // void Manager::setTimer(Timer *timer, Time::Absolute when) { mTimers.schedule(timer, when); } void Manager::clearTimer(Timer *timer) { if (timer->scheduled()) mTimers.unschedule(timer); } void Manager::runTimers() { while (Timer *top = static_cast(mTimers.pop(Time::now()))) { debug("netmanager", "%p timer %p executing at %.3f", this, top, Time::now().internalForm()); try { top->action(); debug("machsrvtime", "%p timer %p done", this, top); } catch (...) { debug("machsrvtime", "%p server timer %p failed with exception", this, top); } } } // // Perform a (small) incremental operations step. // void Manager::step() { prepare(); if (!mEngine.isEmpty()) { debug("mgrstep", "operations step"); mEngine(); } } // // Run in this thread until a particular time (or until no more Transfers are active). // void Manager::run(Time::Absolute stopTime) { debug("netmanager", "starting run with %ld active transfers", mActiveTransfers); while (mActiveTransfers > 0) { prepare(); Time::Absolute limit = mTimers.empty() ? stopTime : min(stopTime, mTimers.next()); mEngine(limit - Time::now()); if (Time::now() > stopTime) break; } debug("netmanager", "ending run"); } void Manager::run() { run(Time::heatDeath()); } // // Internal stepper // void Manager::prepare() { // clear the morgue if (!mMorgue.empty()) { debug("netmanager", "clearing morgue of %ld connections", mMorgue.size()); for (set::iterator it = mMorgue.begin(); it != mMorgue.end(); it++) delete *it; mMorgue.erase(mMorgue.begin(), mMorgue.end()); } // run pending timers runTimers(); } } // end namespace Network } // end namespace Security