diff options
Diffstat (limited to 'indra/llmessage/lltransfermanager.cpp')
-rw-r--r-- | indra/llmessage/lltransfermanager.cpp | 2802 |
1 files changed, 1401 insertions, 1401 deletions
diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp index bad12101e5..f5351c6b58 100644 --- a/indra/llmessage/lltransfermanager.cpp +++ b/indra/llmessage/lltransfermanager.cpp @@ -1,1401 +1,1401 @@ -/** - * @file lltransfermanager.cpp - * @brief Improved transfer mechanism for moving data through the - * message system. - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "lltransfermanager.h" - -#include "llerror.h" -#include "message.h" -#include "lldatapacker.h" - -#include "lltransfersourcefile.h" -#include "lltransfersourceasset.h" -#include "lltransfertargetfile.h" -#include "lltransfertargetvfile.h" - -const S32 MAX_PACKET_DATA_SIZE = 2048; -const S32 MAX_PARAMS_SIZE = 1024; - -LLTransferManager gTransferManager; -LLTransferSource::stype_scfunc_map LLTransferSource::sSourceCreateMap; - -// -// LLTransferManager implementation -// - -LLTransferManager::LLTransferManager() : - mValid(false) -{ - S32 i; - for (i = 0; i < LLTTT_NUM_TYPES; i++) - { - mTransferBitsIn[i] = 0; - mTransferBitsOut[i] = 0; - } -} - - -LLTransferManager::~LLTransferManager() -{ - // LLTransferManager should have been cleaned up by message system shutdown process - llassert(!mValid); - if (mValid) - { - // Usually happens if OS tries to kill viewer - cleanup(); - } -} - - -void LLTransferManager::init() -{ - if (mValid) - { - LL_ERRS() << "Double initializing LLTransferManager!" << LL_ENDL; - } - mValid = true; - - // Register message system handlers - gMessageSystem->setHandlerFunc("TransferRequest", processTransferRequest, NULL); - gMessageSystem->setHandlerFunc("TransferInfo", processTransferInfo, NULL); - gMessageSystem->setHandlerFunc("TransferPacket", processTransferPacket, NULL); - gMessageSystem->setHandlerFunc("TransferAbort", processTransferAbort, NULL); -} - - -void LLTransferManager::cleanup() -{ - mValid = false; - - host_tc_map::iterator iter; - for (iter = mTransferConnections.begin(); iter != mTransferConnections.end(); iter++) - { - delete iter->second; - } - mTransferConnections.clear(); -} - - -void LLTransferManager::updateTransfers() -{ - host_tc_map::iterator iter,cur; - - iter = mTransferConnections.begin(); - - while (iter !=mTransferConnections.end()) - { - cur = iter; - iter++; - cur->second->updateTransfers(); - } -} - - -void LLTransferManager::cleanupConnection(const LLHost &host) -{ - host_tc_map::iterator iter; - iter = mTransferConnections.find(host); - if (iter == mTransferConnections.end()) - { - // This can happen legitimately if we've never done a transfer, and we're - // cleaning up a circuit. - //LL_WARNS() << "Cleaning up nonexistent transfer connection to " << host << LL_ENDL; - return; - } - LLTransferConnection *connp = iter->second; - delete connp; - mTransferConnections.erase(iter); -} - - -LLTransferConnection *LLTransferManager::getTransferConnection(const LLHost &host) -{ - host_tc_map::iterator iter; - iter = mTransferConnections.find(host); - if (iter == mTransferConnections.end()) - { - mTransferConnections[host] = new LLTransferConnection(host); - return mTransferConnections[host]; - } - - return iter->second; -} - - -LLTransferSourceChannel *LLTransferManager::getSourceChannel(const LLHost &host, const LLTransferChannelType type) -{ - LLTransferConnection *tcp = getTransferConnection(host); - if (!tcp) - { - return NULL; - } - return tcp->getSourceChannel(type); -} - - - -LLTransferTargetChannel *LLTransferManager::getTargetChannel(const LLHost &host, const LLTransferChannelType type) -{ - LLTransferConnection *tcp = getTransferConnection(host); - if (!tcp) - { - return NULL; - } - return tcp->getTargetChannel(type); -} - -// virtual -LLTransferSourceParams::~LLTransferSourceParams() -{ } - - -LLTransferSource *LLTransferManager::findTransferSource(const LLUUID &transfer_id) -{ - // This linear traversal could screw us later if we do lots of - // searches for sources. However, this ONLY happens right now - // in asset transfer callbacks, so this should be relatively quick. - host_tc_map::iterator iter; - for (iter = mTransferConnections.begin(); iter != mTransferConnections.end(); iter++) - { - LLTransferConnection *tcp = iter->second; - LLTransferConnection::tsc_iter sc_iter; - for (sc_iter = tcp->mTransferSourceChannels.begin(); sc_iter != tcp->mTransferSourceChannels.end(); sc_iter++) - { - LLTransferSourceChannel *scp = *sc_iter; - LLTransferSource *sourcep = scp->findTransferSource(transfer_id); - if (sourcep) - { - return sourcep; - } - } - } - - return NULL; -} - -// -// Message handlers -// - -//static -void LLTransferManager::processTransferRequest(LLMessageSystem *msgp, void **) -{ - //LL_INFOS() << "LLTransferManager::processTransferRequest" << LL_ENDL; - - LLUUID transfer_id; - LLTransferSourceType source_type; - LLTransferChannelType channel_type; - F32 priority; - - msgp->getUUID("TransferInfo", "TransferID", transfer_id); - msgp->getS32("TransferInfo", "SourceType", (S32 &)source_type); - msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type); - msgp->getF32("TransferInfo", "Priority", priority); - - LLTransferSourceChannel *tscp = gTransferManager.getSourceChannel(msgp->getSender(), channel_type); - - if (!tscp) - { - LL_WARNS() << "Source channel not found" << LL_ENDL; - return; - } - - if (tscp->findTransferSource(transfer_id)) - { - LL_WARNS() << "Duplicate request for transfer " << transfer_id << ", aborting!" << LL_ENDL; - return; - } - - S32 size = msgp->getSize("TransferInfo", "Params"); - if(size > MAX_PARAMS_SIZE) - { - LL_WARNS() << "LLTransferManager::processTransferRequest params too big." - << LL_ENDL; - return; - } - - //LL_INFOS() << transfer_id << ":" << source_type << ":" << channel_type << ":" << priority << LL_ENDL; - LLTransferSource* tsp = LLTransferSource::createSource( - source_type, - transfer_id, - priority); - if(!tsp) - { - LL_WARNS() << "LLTransferManager::processTransferRequest couldn't create" - << " transfer source!" << LL_ENDL; - return; - } - U8 tmp[MAX_PARAMS_SIZE]; - msgp->getBinaryData("TransferInfo", "Params", tmp, size); - - LLDataPackerBinaryBuffer dpb(tmp, MAX_PARAMS_SIZE); - bool unpack_ok = tsp->unpackParams(dpb); - if (!unpack_ok) - { - // This should only happen if the data is corrupt or - // incorrectly packed. - // *NOTE: We may want to call abortTransfer(). - LL_WARNS() << "LLTransferManager::processTransferRequest: bad parameters." - << LL_ENDL; - delete tsp; - return; - } - - tscp->addTransferSource(tsp); - tsp->initTransfer(); -} - - -//static -void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) -{ - //LL_INFOS() << "LLTransferManager::processTransferInfo" << LL_ENDL; - - LLUUID transfer_id; - LLTransferTargetType target_type; - LLTransferChannelType channel_type; - LLTSCode status; - S32 size; - - msgp->getUUID("TransferInfo", "TransferID", transfer_id); - msgp->getS32("TransferInfo", "TargetType", (S32 &)target_type); - msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type); - msgp->getS32("TransferInfo", "Status", (S32 &)status); - msgp->getS32("TransferInfo", "Size", size); - - //LL_INFOS() << transfer_id << ":" << target_type<< ":" << channel_type << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type); - if (!ttcp) - { - LL_WARNS() << "Target channel not found" << LL_ENDL; - // Should send a message to abort the transfer. - return; - } - - LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id); - if (!ttp) - { - LL_WARNS() << "TransferInfo for unknown transfer! Not able to handle this yet!" << LL_ENDL; - // This could happen if we're doing a push transfer, although to avoid confusion, - // maybe it should be a different message. - return; - } - - if (status != LLTS_OK) - { - LL_WARNS() << transfer_id << ": Non-ok status, cleaning up" << LL_ENDL; - ttp->completionCallback(status); - // Clean up the transfer. - ttcp->deleteTransfer(ttp); - return; - } - - // unpack the params - S32 params_size = msgp->getSize("TransferInfo", "Params"); - if(params_size > MAX_PARAMS_SIZE) - { - LL_WARNS() << "LLTransferManager::processTransferInfo params too big." - << LL_ENDL; - return; - } - else if(params_size > 0) - { - U8 tmp[MAX_PARAMS_SIZE]; - msgp->getBinaryData("TransferInfo", "Params", tmp, params_size); - LLDataPackerBinaryBuffer dpb(tmp, MAX_PARAMS_SIZE); - if (!ttp->unpackParams(dpb)) - { - // This should only happen if the data is corrupt or - // incorrectly packed. - LL_WARNS() << "LLTransferManager::processTransferRequest: bad params." - << LL_ENDL; - ttp->abortTransfer(); - ttcp->deleteTransfer(ttp); - return; - } - } - - //LL_INFOS() << "Receiving " << transfer_id << ", size " << size << " bytes" << LL_ENDL; - ttp->setSize(size); - ttp->setGotInfo(true); - - // OK, at this point we to handle any delayed transfer packets (which could happen - // if this packet was lost) - - // This is a lame cut and paste of code down below. If we change the logic down there, - // we HAVE to change the logic up here. - - while (1) - { - S32 packet_id = 0; - U8 tmp_data[MAX_PACKET_DATA_SIZE]; - // See if we've got any delayed packets - packet_id = ttp->getNextPacketID(); - if (ttp->mDelayedPacketMap.find(packet_id) != ttp->mDelayedPacketMap.end()) - { - // Perhaps this stuff should be inside a method in LLTransferPacket? - // I'm too lazy to do it now, though. -// LL_INFOS() << "Playing back delayed packet " << packet_id << LL_ENDL; - LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id]; - - // This is somewhat inefficient, but avoids us having to duplicate - // code between the off-the-wire and delayed paths. - packet_id = packetp->mPacketID; - size = packetp->mSize; - if (size) - { - if ((packetp->mDatap != NULL) && (size<(S32)sizeof(tmp_data))) - { - memcpy(tmp_data, packetp->mDatap, size); /*Flawfinder: ignore*/ - } - } - status = packetp->mStatus; - ttp->mDelayedPacketMap.erase(packet_id); - delete packetp; - } - else - { - // No matching delayed packet, we're done. - break; - } - - LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size); - if (ret_code == LLTS_OK) - { - ttp->setLastPacketID(packet_id); - } - - if (status != LLTS_OK) - { - if (status != LLTS_DONE) - { - LL_WARNS() << "LLTransferManager::processTransferInfo Error in playback!" << LL_ENDL; - } - else - { - LL_INFOS() << "LLTransferManager::processTransferInfo replay FINISHED for " << transfer_id << LL_ENDL; - } - // This transfer is done, either via error or not. - ttp->completionCallback(status); - ttcp->deleteTransfer(ttp); - return; - } - } -} - - -//static -void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) -{ - //LL_INFOS() << "LLTransferManager::processTransferPacket" << LL_ENDL; - - LLUUID transfer_id; - LLTransferChannelType channel_type; - S32 packet_id; - LLTSCode status; - S32 size; - msgp->getUUID("TransferData", "TransferID", transfer_id); - msgp->getS32("TransferData", "ChannelType", (S32 &)channel_type); - msgp->getS32("TransferData", "Packet", packet_id); - msgp->getS32("TransferData", "Status", (S32 &)status); - - // Find the transfer associated with this packet. - //LL_INFOS() << transfer_id << ":" << channel_type << LL_ENDL; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type); - if (!ttcp) - { - LL_WARNS() << "Target channel not found" << LL_ENDL; - return; - } - - LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id); - if (!ttp) - { - LL_WARNS() << "Didn't find matching transfer for " << transfer_id - << " processing packet " << packet_id - << " from " << msgp->getSender() << LL_ENDL; - return; - } - - size = msgp->getSize("TransferData", "Data"); - - S32 msg_bytes = 0; - if (msgp->getReceiveCompressedSize()) - { - msg_bytes = msgp->getReceiveCompressedSize(); - } - else - { - msg_bytes = msgp->getReceiveSize(); - } - gTransferManager.addTransferBitsIn(ttcp->mChannelType, msg_bytes*8); - - if ((size < 0) || (size > MAX_PACKET_DATA_SIZE)) - { - LL_WARNS() << "Invalid transfer packet size " << size << LL_ENDL; - return; - } - - U8 tmp_data[MAX_PACKET_DATA_SIZE]; - if (size > 0) - { - // Only pull the data out if the size is > 0 - msgp->getBinaryData("TransferData", "Data", tmp_data, size); - } - - if ((!ttp->gotInfo()) || (ttp->getNextPacketID() != packet_id)) - { - // Put this on a list of packets to be delivered later. - if(!ttp->addDelayedPacket(packet_id, status, tmp_data, size)) - { - // Whoops - failed to add a delayed packet for some reason. - LL_WARNS() << "Too many delayed packets processing transfer " - << transfer_id << " from " << msgp->getSender() << LL_ENDL; - ttp->abortTransfer(); - ttcp->deleteTransfer(ttp); - return; - } -#if 0 - // Spammy! - const S32 LL_TRANSFER_WARN_GAP = 10; - if(!ttp->gotInfo()) - { - LL_WARNS() << "Got data packet before information in transfer " - << transfer_id << " from " << msgp->getSender() - << ", got " << packet_id << LL_ENDL; - } - else if((packet_id - ttp->getNextPacketID()) > LL_TRANSFER_WARN_GAP) - { - LL_WARNS() << "Out of order packet in transfer " << transfer_id - << " from " << msgp->getSender() << ", got " << packet_id - << " expecting " << ttp->getNextPacketID() << LL_ENDL; - } -#endif - return; - } - - // Loop through this until we're done with all delayed packets - - // - // NOTE: THERE IS A CUT AND PASTE OF THIS CODE IN THE TRANSFERINFO HANDLER - // SO WE CAN PLAY BACK DELAYED PACKETS THERE!!!!!!!!!!!!!!!!!!!!!!!!! - // - bool done = false; - while (!done) - { - LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size); - if (ret_code == LLTS_OK) - { - ttp->setLastPacketID(packet_id); - } - - if (status != LLTS_OK) - { - if (status != LLTS_DONE) - { - LL_WARNS() << "LLTransferManager::processTransferPacket Error in transfer!" << LL_ENDL; - } - else - { -// LL_INFOS() << "LLTransferManager::processTransferPacket done for " << transfer_id << LL_ENDL; - } - // This transfer is done, either via error or not. - ttp->completionCallback(status); - ttcp->deleteTransfer(ttp); - return; - } - - // See if we've got any delayed packets - packet_id = ttp->getNextPacketID(); - if (ttp->mDelayedPacketMap.find(packet_id) != ttp->mDelayedPacketMap.end()) - { - // Perhaps this stuff should be inside a method in LLTransferPacket? - // I'm too lazy to do it now, though. -// LL_INFOS() << "Playing back delayed packet " << packet_id << LL_ENDL; - LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id]; - - // This is somewhat inefficient, but avoids us having to duplicate - // code between the off-the-wire and delayed paths. - packet_id = packetp->mPacketID; - size = packetp->mSize; - if (size) - { - if ((packetp->mDatap != NULL) && (size<(S32)sizeof(tmp_data))) - { - memcpy(tmp_data, packetp->mDatap, size); /*Flawfinder: ignore*/ - } - } - status = packetp->mStatus; - ttp->mDelayedPacketMap.erase(packet_id); - delete packetp; - } - else - { - // No matching delayed packet, abort it. - done = true; - } - } -} - - -//static -void LLTransferManager::processTransferAbort(LLMessageSystem *msgp, void **) -{ - //LL_INFOS() << "LLTransferManager::processTransferPacket" << LL_ENDL; - - LLUUID transfer_id; - LLTransferChannelType channel_type; - msgp->getUUID("TransferInfo", "TransferID", transfer_id); - msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type); - - // See if it's a target that we're trying to abort - // Find the transfer associated with this packet. - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type); - if (ttcp) - { - LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id); - if (ttp) - { - ttp->abortTransfer(); - ttcp->deleteTransfer(ttp); - return; - } - } - - // Hmm, not a target. Maybe it's a source. - LLTransferSourceChannel *tscp = gTransferManager.getSourceChannel(msgp->getSender(), channel_type); - if (tscp) - { - LLTransferSource *tsp = tscp->findTransferSource(transfer_id); - if (tsp) - { - tsp->abortTransfer(); - tscp->deleteTransfer(tsp); - return; - } - } - - LL_WARNS() << "Couldn't find transfer " << transfer_id << " to abort!" << LL_ENDL; -} - - -//static -void LLTransferManager::reliablePacketCallback(void **user_data, S32 result) -{ - LLUUID *transfer_idp = (LLUUID *)user_data; - if (result && - transfer_idp != NULL) - { - LLTransferSource *tsp = gTransferManager.findTransferSource(*transfer_idp); - if (tsp) - { - LL_WARNS() << "Aborting reliable transfer " << *transfer_idp << " due to failed reliable resends!" << LL_ENDL; - LLTransferSourceChannel *tscp = tsp->mChannelp; - tsp->abortTransfer(); - tscp->deleteTransfer(tsp); - } - else - { - LL_WARNS() << "Aborting reliable transfer " << *transfer_idp << " but can't find the LLTransferSource object" << LL_ENDL; - } - } - delete transfer_idp; -} - -// -// LLTransferConnection implementation -// - -LLTransferConnection::LLTransferConnection(const LLHost &host) -{ - mHost = host; -} - -LLTransferConnection::~LLTransferConnection() -{ - tsc_iter itersc; - for (itersc = mTransferSourceChannels.begin(); itersc != mTransferSourceChannels.end(); itersc++) - { - delete *itersc; - } - mTransferSourceChannels.clear(); - - ttc_iter itertc; - for (itertc = mTransferTargetChannels.begin(); itertc != mTransferTargetChannels.end(); itertc++) - { - delete *itertc; - } - mTransferTargetChannels.clear(); -} - - -void LLTransferConnection::updateTransfers() -{ - // Do stuff for source transfers (basically, send data out). - tsc_iter iter, cur; - iter = mTransferSourceChannels.begin(); - - while (iter !=mTransferSourceChannels.end()) - { - cur = iter; - iter++; - (*cur)->updateTransfers(); - } - - // Do stuff for target transfers - // Primarily, we should be aborting transfers that are irredeemably broken - // (large packet gaps that don't appear to be getting filled in, most likely) - // Probably should NOT be doing timeouts for other things, as new priority scheme - // means that a high priority transfer COULD block a transfer for a long time. -} - - -LLTransferSourceChannel *LLTransferConnection::getSourceChannel(const LLTransferChannelType channel_type) -{ - tsc_iter iter; - for (iter = mTransferSourceChannels.begin(); iter != mTransferSourceChannels.end(); iter++) - { - if ((*iter)->getChannelType() == channel_type) - { - return *iter; - } - } - - LLTransferSourceChannel *tscp = new LLTransferSourceChannel(channel_type, mHost); - mTransferSourceChannels.push_back(tscp); - return tscp; -} - - -LLTransferTargetChannel *LLTransferConnection::getTargetChannel(const LLTransferChannelType channel_type) -{ - ttc_iter iter; - for (iter = mTransferTargetChannels.begin(); iter != mTransferTargetChannels.end(); iter++) - { - if ((*iter)->getChannelType() == channel_type) - { - return *iter; - } - } - - LLTransferTargetChannel *ttcp = new LLTransferTargetChannel(channel_type, mHost); - mTransferTargetChannels.push_back(ttcp); - return ttcp; -} - - -// -// LLTransferSourceChannel implementation -// - -const S32 DEFAULT_PACKET_SIZE = 1000; - - -LLTransferSourceChannel::LLTransferSourceChannel(const LLTransferChannelType channel_type, const LLHost &host) : - mChannelType(channel_type), - mHost(host), - mTransferSources(LLTransferSource::sSetPriority, LLTransferSource::sGetPriority), - mThrottleID(TC_ASSET) -{ -} - - -LLTransferSourceChannel::~LLTransferSourceChannel() -{ - LLPriQueueMap<LLTransferSource*>::pqm_iter iter = - mTransferSources.mMap.begin(); - LLPriQueueMap<LLTransferSource*>::pqm_iter end = - mTransferSources.mMap.end(); - for (; iter != end; ++iter) - { - // Just kill off all of the transfers - (*iter).second->abortTransfer(); - delete iter->second; - } - mTransferSources.mMap.clear(); -} - -void LLTransferSourceChannel::updatePriority(LLTransferSource *tsp, const F32 priority) -{ - mTransferSources.reprioritize(priority, tsp); -} - -void LLTransferSourceChannel::updateTransfers() -{ - // Actually, this should do the following: - // Decide if we can actually send data. - // If so, update priorities so we know who gets to send it. - // Send data from the sources, while updating until we've sent our throttle allocation. - - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(getHost()); - if (!cdp) - { - return; - } - - if (cdp->isBlocked()) - { - // *NOTE: We need to make sure that the throttle bits - // available gets reset. - - // We DON'T want to send any packets if they're blocked, they'll just end up - // piling up on the other end. - //LL_WARNS() << "Blocking transfers due to blocked circuit for " << getHost() << LL_ENDL; - return; - } - - const S32 throttle_id = mThrottleID; - - LLThrottleGroup &tg = cdp->getThrottleGroup(); - - if (tg.checkOverflow(throttle_id, 0.f)) - { - return; - } - - LLPriQueueMap<LLTransferSource *>::pqm_iter iter, next; - - bool done = false; - for (iter = mTransferSources.mMap.begin(); (iter != mTransferSources.mMap.end()) && !done;) - { - //LL_INFOS() << "LLTransferSourceChannel::updateTransfers()" << LL_ENDL; - // Do stuff. - next = iter; - next++; - - LLTransferSource *tsp = iter->second; - U8 *datap = NULL; - S32 data_size = 0; - bool delete_data = false; - S32 packet_id = 0; - S32 sent_bytes = 0; - LLTSCode status = LLTS_OK; - - // Get the packetID for the next packet that we're transferring. - packet_id = tsp->getNextPacketID(); - status = tsp->dataCallback(packet_id, DEFAULT_PACKET_SIZE, &datap, data_size, delete_data); - - if (status == LLTS_SKIP) - { - // We don't have any data, but we're not done, just go on. - // This will presumably be used for streaming or async transfers that - // are stalled waiting for data from another source. - iter=next; - continue; - } - - LLUUID *cb_uuid = new LLUUID(tsp->getID()); - LLUUID transaction_id = tsp->getID(); - - // Send the data now, even if it's an error. - // The status code will tell the other end what to do. - gMessageSystem->newMessage("TransferPacket"); - gMessageSystem->nextBlock("TransferData"); - gMessageSystem->addUUID("TransferID", tsp->getID()); - gMessageSystem->addS32("ChannelType", getChannelType()); - gMessageSystem->addS32("Packet", packet_id); // HACK! Need to put in a REAL packet id - gMessageSystem->addS32("Status", status); - gMessageSystem->addBinaryData("Data", datap, data_size); - sent_bytes = gMessageSystem->getCurrentSendTotal(); - gMessageSystem->sendReliable(getHost(), LL_DEFAULT_RELIABLE_RETRIES, true, F32Seconds(0.f), - LLTransferManager::reliablePacketCallback, (void**)cb_uuid); - - // Do bookkeeping for the throttle - done = tg.throttleOverflow(throttle_id, sent_bytes*8.f); - gTransferManager.addTransferBitsOut(mChannelType, sent_bytes*8); - - // Clean up our temporary data. - if (delete_data) - { - delete[] datap; - datap = NULL; - } - - if (findTransferSource(transaction_id) == NULL) - { - //Warning! In the case of an aborted transfer, the sendReliable call above calls - //AbortTransfer which in turn calls deleteTransfer which means that somewhere way - //down the chain our current iter can get invalidated resulting in an infrequent - //sim crash. This check gets us to a valid transfer source in this event. - iter=next; - continue; - } - - // Update the packet counter - tsp->setLastPacketID(packet_id); - - switch (status) - { - case LLTS_OK: - // We're OK, don't need to do anything. Keep sending data. - break; - case LLTS_ERROR: - LL_WARNS() << "Error in transfer dataCallback!" << LL_ENDL; - // fall through - case LLTS_DONE: - // We need to clean up this transfer source. - //LL_INFOS() << "LLTransferSourceChannel::updateTransfers() " << tsp->getID() << " done" << LL_ENDL; - tsp->completionCallback(status); - delete tsp; - - mTransferSources.mMap.erase(iter); - iter = next; - break; - default: - LL_ERRS() << "Unknown transfer error code!" << LL_ENDL; - } - - // At this point, we should do priority adjustment (since some transfers like - // streaming transfers will adjust priority based on how much they've sent and time, - // but I'm not going to bother yet. - djs. - } -} - - -void LLTransferSourceChannel::addTransferSource(LLTransferSource *sourcep) -{ - sourcep->mChannelp = this; - mTransferSources.push(sourcep->getPriority(), sourcep); -} - - -LLTransferSource *LLTransferSourceChannel::findTransferSource(const LLUUID &transfer_id) -{ - LLPriQueueMap<LLTransferSource *>::pqm_iter iter; - for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++) - { - LLTransferSource *tsp = iter->second; - if (tsp->getID() == transfer_id) - { - return tsp; - } - } - return NULL; -} - - -void LLTransferSourceChannel::deleteTransfer(LLTransferSource *tsp) -{ - if (tsp) - { - LLPriQueueMap<LLTransferSource *>::pqm_iter iter; - for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++) - { - if (iter->second == tsp) - { - delete tsp; - mTransferSources.mMap.erase(iter); - return; - } - } - - LL_WARNS() << "Unable to find transfer source id " - << tsp->getID() - << " to delete!" - << LL_ENDL; - } -} - - -// -// LLTransferTargetChannel implementation -// - -LLTransferTargetChannel::LLTransferTargetChannel(const LLTransferChannelType channel_type, const LLHost &host) : - mChannelType(channel_type), - mHost(host) -{ -} - -LLTransferTargetChannel::~LLTransferTargetChannel() -{ - tt_iter iter; - for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++) - { - // Abort all of the current transfers - (*iter)->abortTransfer(); - delete *iter; - } - mTransferTargets.clear(); -} - - -void LLTransferTargetChannel::requestTransfer( - const LLTransferSourceParams& source_params, - const LLTransferTargetParams& target_params, - const F32 priority) -{ - LLUUID id; - id.generate(); - LLTransferTarget* ttp = LLTransferTarget::createTarget( - target_params.getType(), - id, - source_params.getType()); - if (!ttp) - { - LL_WARNS() << "LLTransferManager::requestTransfer aborting due to target creation failure!" << LL_ENDL; - return; - } - - ttp->applyParams(target_params); - addTransferTarget(ttp); - - sendTransferRequest(ttp, source_params, priority); -} - - -void LLTransferTargetChannel::sendTransferRequest(LLTransferTarget *targetp, - const LLTransferSourceParams ¶ms, - const F32 priority) -{ - // - // Pack the message with data which explains how to get the source, and - // send it off to the source for this channel. - // - llassert(targetp); - llassert(targetp->getChannel() == this); - - gMessageSystem->newMessage("TransferRequest"); - gMessageSystem->nextBlock("TransferInfo"); - gMessageSystem->addUUID("TransferID", targetp->getID()); - gMessageSystem->addS32("SourceType", params.getType()); - gMessageSystem->addS32("ChannelType", getChannelType()); - gMessageSystem->addF32("Priority", priority); - - U8 tmp[MAX_PARAMS_SIZE]; - LLDataPackerBinaryBuffer dp(tmp, MAX_PARAMS_SIZE); - params.packParams(dp); - S32 len = dp.getCurrentSize(); - gMessageSystem->addBinaryData("Params", tmp, len); - - gMessageSystem->sendReliable(mHost); -} - - -void LLTransferTargetChannel::addTransferTarget(LLTransferTarget *targetp) -{ - targetp->mChannelp = this; - mTransferTargets.push_back(targetp); -} - - -LLTransferTarget *LLTransferTargetChannel::findTransferTarget(const LLUUID &transfer_id) -{ - tt_iter iter; - for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++) - { - LLTransferTarget *ttp = *iter; - if (ttp->getID() == transfer_id) - { - return ttp; - } - } - return NULL; -} - - -void LLTransferTargetChannel::deleteTransfer(LLTransferTarget *ttp) -{ - if (ttp) - { - tt_iter iter; - for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++) - { - if (*iter == ttp) - { - delete ttp; - mTransferTargets.erase(iter); - return; - } - } - - LL_WARNS() << "Unable to find transfer target id " - << ttp->getID() - << " to delete!" - << LL_ENDL; - } -} - - -// -// LLTransferSource implementation -// - -LLTransferSource::LLTransferSource(const LLTransferSourceType type, - const LLUUID &transfer_id, - const F32 priority) : - mType(type), - mID(transfer_id), - mChannelp(NULL), - mPriority(priority), - mSize(0), - mLastPacketID(-1) -{ - setPriority(priority); -} - - -LLTransferSource::~LLTransferSource() -{ - // No actual cleanup of the transfer is done here, this is purely for - // memory cleanup. The completionCallback is guaranteed to get called - // before this happens. -} - - -void LLTransferSource::sendTransferStatus(LLTSCode status) -{ - gMessageSystem->newMessage("TransferInfo"); - gMessageSystem->nextBlock("TransferInfo"); - gMessageSystem->addUUID("TransferID", getID()); - gMessageSystem->addS32("TargetType", LLTTT_UNKNOWN); - gMessageSystem->addS32("ChannelType", mChannelp->getChannelType()); - gMessageSystem->addS32("Status", status); - gMessageSystem->addS32("Size", mSize); - U8 tmp[MAX_PARAMS_SIZE]; - LLDataPackerBinaryBuffer dp(tmp, MAX_PARAMS_SIZE); - packParams(dp); - S32 len = dp.getCurrentSize(); - gMessageSystem->addBinaryData("Params", tmp, len); - gMessageSystem->sendReliable(mChannelp->getHost()); - - // Abort if there was as asset system issue. - if (status != LLTS_OK) - { - completionCallback(status); - mChannelp->deleteTransfer(this); - } -} - - -// This should never be called directly, the transfer manager is responsible for -// aborting the transfer from the channel. I might want to rethink this in the -// future, though. -void LLTransferSource::abortTransfer() -{ - // Send a message down, call the completion callback - LL_INFOS() << "LLTransferSource::Aborting transfer " << getID() << " to " << mChannelp->getHost() << LL_ENDL; - gMessageSystem->newMessage("TransferAbort"); - gMessageSystem->nextBlock("TransferInfo"); - gMessageSystem->addUUID("TransferID", getID()); - gMessageSystem->addS32("ChannelType", mChannelp->getChannelType()); - gMessageSystem->sendReliable(mChannelp->getHost()); - - completionCallback(LLTS_ABORT); -} - - -//static -void LLTransferSource::registerSourceType(const LLTransferSourceType stype, LLTransferSourceCreateFunc func) -{ - if (sSourceCreateMap.count(stype)) - { - // Disallow changing what class handles a source type - // Unclear when you would want to do this, and whether it would work. - LL_ERRS() << "Reregistering source type " << stype << LL_ENDL; - } - else - { - sSourceCreateMap[stype] = func; - } -} - -//static -LLTransferSource *LLTransferSource::createSource(const LLTransferSourceType stype, - const LLUUID &id, - const F32 priority) -{ - switch (stype) - { - // *NOTE: The source file transfer mechanism is highly insecure and could - // lead to easy exploitation of a server process. - // I have removed all uses of it from the codebase. Phoenix. - // - //case LLTST_FILE: - // return new LLTransferSourceFile(id, priority); - case LLTST_ASSET: - return new LLTransferSourceAsset(id, priority); - default: - { - if (!sSourceCreateMap.count(stype)) - { - // Use the callback to create the source type if it's not there. - LL_WARNS() << "Unknown transfer source type: " << stype << LL_ENDL; - return NULL; - } - return (sSourceCreateMap[stype])(id, priority); - } - } -} - - -// static -void LLTransferSource::sSetPriority(LLTransferSource *&tsp, const F32 priority) -{ - tsp->setPriority(priority); -} - - -// static -F32 LLTransferSource::sGetPriority(LLTransferSource *&tsp) -{ - return tsp->getPriority(); -} - - -// -// LLTransferPacket implementation -// - -LLTransferPacket::LLTransferPacket(const S32 packet_id, const LLTSCode status, const U8 *datap, const S32 size) : - mPacketID(packet_id), - mStatus(status), - mDatap(NULL), - mSize(size) -{ - if (size == 0) - { - return; - } - - mDatap = new U8[size]; - if (mDatap != NULL) - { - memcpy(mDatap, datap, size); /*Flawfinder: ignore*/ - } -} - -LLTransferPacket::~LLTransferPacket() -{ - delete[] mDatap; -} - -// -// LLTransferTarget implementation -// - -LLTransferTarget::LLTransferTarget( - LLTransferTargetType type, - const LLUUID& transfer_id, - LLTransferSourceType source_type) : - mType(type), - mSourceType(source_type), - mID(transfer_id), - mChannelp(NULL), - mGotInfo(false), - mSize(0), - mLastPacketID(-1) -{ -} - -LLTransferTarget::~LLTransferTarget() -{ - // No actual cleanup of the transfer is done here, this is purely for - // memory cleanup. The completionCallback is guaranteed to get called - // before this happens. - tpm_iter iter; - for (iter = mDelayedPacketMap.begin(); iter != mDelayedPacketMap.end(); iter++) - { - delete iter->second; - } - mDelayedPacketMap.clear(); -} - -// This should never be called directly, the transfer manager is responsible for -// aborting the transfer from the channel. I might want to rethink this in the -// future, though. -void LLTransferTarget::abortTransfer() -{ - // Send a message up, call the completion callback - LL_INFOS() << "LLTransferTarget::Aborting transfer " << getID() << " from " << mChannelp->getHost() << LL_ENDL; - gMessageSystem->newMessage("TransferAbort"); - gMessageSystem->nextBlock("TransferInfo"); - gMessageSystem->addUUID("TransferID", getID()); - gMessageSystem->addS32("ChannelType", mChannelp->getChannelType()); - gMessageSystem->sendReliable(mChannelp->getHost()); - - completionCallback(LLTS_ABORT); -} - -bool LLTransferTarget::addDelayedPacket( - const S32 packet_id, - const LLTSCode status, - U8* datap, - const S32 size) -{ - const transfer_packet_map::size_type LL_MAX_DELAYED_PACKETS = 100; - if(mDelayedPacketMap.size() > LL_MAX_DELAYED_PACKETS) - { - // too many delayed packets - return false; - } - - LLTransferPacket* tpp = new LLTransferPacket( - packet_id, - status, - datap, - size); - -#ifdef _DEBUG - transfer_packet_map::iterator iter = mDelayedPacketMap.find(packet_id); - if (iter != mDelayedPacketMap.end()) - { - if (!(iter->second->mSize == size) && !(iter->second->mDatap == datap)) - { - LL_ERRS() << "Packet ALREADY in delayed packet map!" << LL_ENDL; - } - } -#endif - - mDelayedPacketMap[packet_id] = tpp; - return true; -} - - -LLTransferTarget* LLTransferTarget::createTarget( - LLTransferTargetType type, - const LLUUID& id, - LLTransferSourceType source_type) -{ - switch (type) - { - case LLTTT_FILE: - return new LLTransferTargetFile(id, source_type); - case LLTTT_VFILE: - return new LLTransferTargetVFile(id, source_type); - default: - LL_WARNS() << "Unknown transfer target type: " << type << LL_ENDL; - return NULL; - } -} - - -LLTransferSourceParamsInvItem::LLTransferSourceParamsInvItem() : LLTransferSourceParams(LLTST_SIM_INV_ITEM), mAssetType(LLAssetType::AT_NONE) -{ -} - - -void LLTransferSourceParamsInvItem::setAgentSession(const LLUUID &agent_id, const LLUUID &session_id) -{ - mAgentID = agent_id; - mSessionID = session_id; -} - - -void LLTransferSourceParamsInvItem::setInvItem(const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id) -{ - mOwnerID = owner_id; - mTaskID = task_id; - mItemID = item_id; -} - - -void LLTransferSourceParamsInvItem::setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type) -{ - mAssetID = asset_id; - mAssetType = asset_type; -} - - -void LLTransferSourceParamsInvItem::packParams(LLDataPacker &dp) const -{ - LL_DEBUGS() << "LLTransferSourceParamsInvItem::packParams()" << LL_ENDL; - dp.packUUID(mAgentID, "AgentID"); - dp.packUUID(mSessionID, "SessionID"); - dp.packUUID(mOwnerID, "OwnerID"); - dp.packUUID(mTaskID, "TaskID"); - dp.packUUID(mItemID, "ItemID"); - dp.packUUID(mAssetID, "AssetID"); - dp.packS32(mAssetType, "AssetType"); -} - - -bool LLTransferSourceParamsInvItem::unpackParams(LLDataPacker &dp) -{ - S32 tmp_at; - - dp.unpackUUID(mAgentID, "AgentID"); - dp.unpackUUID(mSessionID, "SessionID"); - dp.unpackUUID(mOwnerID, "OwnerID"); - dp.unpackUUID(mTaskID, "TaskID"); - dp.unpackUUID(mItemID, "ItemID"); - dp.unpackUUID(mAssetID, "AssetID"); - dp.unpackS32(tmp_at, "AssetType"); - - mAssetType = (LLAssetType::EType)tmp_at; - - return true; -} - -LLTransferSourceParamsEstate::LLTransferSourceParamsEstate() : - LLTransferSourceParams(LLTST_SIM_ESTATE), - mEstateAssetType(ET_NONE), - mAssetType(LLAssetType::AT_NONE) -{ -} - -void LLTransferSourceParamsEstate::setAgentSession(const LLUUID &agent_id, const LLUUID &session_id) -{ - mAgentID = agent_id; - mSessionID = session_id; -} - -void LLTransferSourceParamsEstate::setEstateAssetType(const EstateAssetType etype) -{ - mEstateAssetType = etype; -} - -void LLTransferSourceParamsEstate::setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type) -{ - mAssetID = asset_id; - mAssetType = asset_type; -} - -void LLTransferSourceParamsEstate::packParams(LLDataPacker &dp) const -{ - dp.packUUID(mAgentID, "AgentID"); - // *NOTE: We do not want to pass the session id from the server to - // the client, but I am not sure if anyone expects this value to - // be set on the client. - dp.packUUID(mSessionID, "SessionID"); - dp.packS32(mEstateAssetType, "EstateAssetType"); -} - - -bool LLTransferSourceParamsEstate::unpackParams(LLDataPacker &dp) -{ - S32 tmp_et; - - dp.unpackUUID(mAgentID, "AgentID"); - dp.unpackUUID(mSessionID, "SessionID"); - dp.unpackS32(tmp_et, "EstateAssetType"); - - mEstateAssetType = (EstateAssetType)tmp_et; - - return true; -} +/**
+ * @file lltransfermanager.cpp
+ * @brief Improved transfer mechanism for moving data through the
+ * message system.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "lltransfermanager.h"
+
+#include "llerror.h"
+#include "message.h"
+#include "lldatapacker.h"
+
+#include "lltransfersourcefile.h"
+#include "lltransfersourceasset.h"
+#include "lltransfertargetfile.h"
+#include "lltransfertargetvfile.h"
+
+const S32 MAX_PACKET_DATA_SIZE = 2048;
+const S32 MAX_PARAMS_SIZE = 1024;
+
+LLTransferManager gTransferManager;
+LLTransferSource::stype_scfunc_map LLTransferSource::sSourceCreateMap;
+
+//
+// LLTransferManager implementation
+//
+
+LLTransferManager::LLTransferManager() :
+ mValid(false)
+{
+ S32 i;
+ for (i = 0; i < LLTTT_NUM_TYPES; i++)
+ {
+ mTransferBitsIn[i] = 0;
+ mTransferBitsOut[i] = 0;
+ }
+}
+
+
+LLTransferManager::~LLTransferManager()
+{
+ // LLTransferManager should have been cleaned up by message system shutdown process
+ llassert(!mValid);
+ if (mValid)
+ {
+ // Usually happens if OS tries to kill viewer
+ cleanup();
+ }
+}
+
+
+void LLTransferManager::init()
+{
+ if (mValid)
+ {
+ LL_ERRS() << "Double initializing LLTransferManager!" << LL_ENDL;
+ }
+ mValid = true;
+
+ // Register message system handlers
+ gMessageSystem->setHandlerFunc("TransferRequest", processTransferRequest, NULL);
+ gMessageSystem->setHandlerFunc("TransferInfo", processTransferInfo, NULL);
+ gMessageSystem->setHandlerFunc("TransferPacket", processTransferPacket, NULL);
+ gMessageSystem->setHandlerFunc("TransferAbort", processTransferAbort, NULL);
+}
+
+
+void LLTransferManager::cleanup()
+{
+ mValid = false;
+
+ host_tc_map::iterator iter;
+ for (iter = mTransferConnections.begin(); iter != mTransferConnections.end(); iter++)
+ {
+ delete iter->second;
+ }
+ mTransferConnections.clear();
+}
+
+
+void LLTransferManager::updateTransfers()
+{
+ host_tc_map::iterator iter,cur;
+
+ iter = mTransferConnections.begin();
+
+ while (iter !=mTransferConnections.end())
+ {
+ cur = iter;
+ iter++;
+ cur->second->updateTransfers();
+ }
+}
+
+
+void LLTransferManager::cleanupConnection(const LLHost &host)
+{
+ host_tc_map::iterator iter;
+ iter = mTransferConnections.find(host);
+ if (iter == mTransferConnections.end())
+ {
+ // This can happen legitimately if we've never done a transfer, and we're
+ // cleaning up a circuit.
+ //LL_WARNS() << "Cleaning up nonexistent transfer connection to " << host << LL_ENDL;
+ return;
+ }
+ LLTransferConnection *connp = iter->second;
+ delete connp;
+ mTransferConnections.erase(iter);
+}
+
+
+LLTransferConnection *LLTransferManager::getTransferConnection(const LLHost &host)
+{
+ host_tc_map::iterator iter;
+ iter = mTransferConnections.find(host);
+ if (iter == mTransferConnections.end())
+ {
+ mTransferConnections[host] = new LLTransferConnection(host);
+ return mTransferConnections[host];
+ }
+
+ return iter->second;
+}
+
+
+LLTransferSourceChannel *LLTransferManager::getSourceChannel(const LLHost &host, const LLTransferChannelType type)
+{
+ LLTransferConnection *tcp = getTransferConnection(host);
+ if (!tcp)
+ {
+ return NULL;
+ }
+ return tcp->getSourceChannel(type);
+}
+
+
+
+LLTransferTargetChannel *LLTransferManager::getTargetChannel(const LLHost &host, const LLTransferChannelType type)
+{
+ LLTransferConnection *tcp = getTransferConnection(host);
+ if (!tcp)
+ {
+ return NULL;
+ }
+ return tcp->getTargetChannel(type);
+}
+
+// virtual
+LLTransferSourceParams::~LLTransferSourceParams()
+{ }
+
+
+LLTransferSource *LLTransferManager::findTransferSource(const LLUUID &transfer_id)
+{
+ // This linear traversal could screw us later if we do lots of
+ // searches for sources. However, this ONLY happens right now
+ // in asset transfer callbacks, so this should be relatively quick.
+ host_tc_map::iterator iter;
+ for (iter = mTransferConnections.begin(); iter != mTransferConnections.end(); iter++)
+ {
+ LLTransferConnection *tcp = iter->second;
+ LLTransferConnection::tsc_iter sc_iter;
+ for (sc_iter = tcp->mTransferSourceChannels.begin(); sc_iter != tcp->mTransferSourceChannels.end(); sc_iter++)
+ {
+ LLTransferSourceChannel *scp = *sc_iter;
+ LLTransferSource *sourcep = scp->findTransferSource(transfer_id);
+ if (sourcep)
+ {
+ return sourcep;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+//
+// Message handlers
+//
+
+//static
+void LLTransferManager::processTransferRequest(LLMessageSystem *msgp, void **)
+{
+ //LL_INFOS() << "LLTransferManager::processTransferRequest" << LL_ENDL;
+
+ LLUUID transfer_id;
+ LLTransferSourceType source_type;
+ LLTransferChannelType channel_type;
+ F32 priority;
+
+ msgp->getUUID("TransferInfo", "TransferID", transfer_id);
+ msgp->getS32("TransferInfo", "SourceType", (S32 &)source_type);
+ msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type);
+ msgp->getF32("TransferInfo", "Priority", priority);
+
+ LLTransferSourceChannel *tscp = gTransferManager.getSourceChannel(msgp->getSender(), channel_type);
+
+ if (!tscp)
+ {
+ LL_WARNS() << "Source channel not found" << LL_ENDL;
+ return;
+ }
+
+ if (tscp->findTransferSource(transfer_id))
+ {
+ LL_WARNS() << "Duplicate request for transfer " << transfer_id << ", aborting!" << LL_ENDL;
+ return;
+ }
+
+ S32 size = msgp->getSize("TransferInfo", "Params");
+ if(size > MAX_PARAMS_SIZE)
+ {
+ LL_WARNS() << "LLTransferManager::processTransferRequest params too big."
+ << LL_ENDL;
+ return;
+ }
+
+ //LL_INFOS() << transfer_id << ":" << source_type << ":" << channel_type << ":" << priority << LL_ENDL;
+ LLTransferSource* tsp = LLTransferSource::createSource(
+ source_type,
+ transfer_id,
+ priority);
+ if(!tsp)
+ {
+ LL_WARNS() << "LLTransferManager::processTransferRequest couldn't create"
+ << " transfer source!" << LL_ENDL;
+ return;
+ }
+ U8 tmp[MAX_PARAMS_SIZE];
+ msgp->getBinaryData("TransferInfo", "Params", tmp, size);
+
+ LLDataPackerBinaryBuffer dpb(tmp, MAX_PARAMS_SIZE);
+ bool unpack_ok = tsp->unpackParams(dpb);
+ if (!unpack_ok)
+ {
+ // This should only happen if the data is corrupt or
+ // incorrectly packed.
+ // *NOTE: We may want to call abortTransfer().
+ LL_WARNS() << "LLTransferManager::processTransferRequest: bad parameters."
+ << LL_ENDL;
+ delete tsp;
+ return;
+ }
+
+ tscp->addTransferSource(tsp);
+ tsp->initTransfer();
+}
+
+
+//static
+void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **)
+{
+ //LL_INFOS() << "LLTransferManager::processTransferInfo" << LL_ENDL;
+
+ LLUUID transfer_id;
+ LLTransferTargetType target_type;
+ LLTransferChannelType channel_type;
+ LLTSCode status;
+ S32 size;
+
+ msgp->getUUID("TransferInfo", "TransferID", transfer_id);
+ msgp->getS32("TransferInfo", "TargetType", (S32 &)target_type);
+ msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type);
+ msgp->getS32("TransferInfo", "Status", (S32 &)status);
+ msgp->getS32("TransferInfo", "Size", size);
+
+ //LL_INFOS() << transfer_id << ":" << target_type<< ":" << channel_type << LL_ENDL;
+ LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type);
+ if (!ttcp)
+ {
+ LL_WARNS() << "Target channel not found" << LL_ENDL;
+ // Should send a message to abort the transfer.
+ return;
+ }
+
+ LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id);
+ if (!ttp)
+ {
+ LL_WARNS() << "TransferInfo for unknown transfer! Not able to handle this yet!" << LL_ENDL;
+ // This could happen if we're doing a push transfer, although to avoid confusion,
+ // maybe it should be a different message.
+ return;
+ }
+
+ if (status != LLTS_OK)
+ {
+ LL_WARNS() << transfer_id << ": Non-ok status, cleaning up" << LL_ENDL;
+ ttp->completionCallback(status);
+ // Clean up the transfer.
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+
+ // unpack the params
+ S32 params_size = msgp->getSize("TransferInfo", "Params");
+ if(params_size > MAX_PARAMS_SIZE)
+ {
+ LL_WARNS() << "LLTransferManager::processTransferInfo params too big."
+ << LL_ENDL;
+ return;
+ }
+ else if(params_size > 0)
+ {
+ U8 tmp[MAX_PARAMS_SIZE];
+ msgp->getBinaryData("TransferInfo", "Params", tmp, params_size);
+ LLDataPackerBinaryBuffer dpb(tmp, MAX_PARAMS_SIZE);
+ if (!ttp->unpackParams(dpb))
+ {
+ // This should only happen if the data is corrupt or
+ // incorrectly packed.
+ LL_WARNS() << "LLTransferManager::processTransferRequest: bad params."
+ << LL_ENDL;
+ ttp->abortTransfer();
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+ }
+
+ //LL_INFOS() << "Receiving " << transfer_id << ", size " << size << " bytes" << LL_ENDL;
+ ttp->setSize(size);
+ ttp->setGotInfo(true);
+
+ // OK, at this point we to handle any delayed transfer packets (which could happen
+ // if this packet was lost)
+
+ // This is a lame cut and paste of code down below. If we change the logic down there,
+ // we HAVE to change the logic up here.
+
+ while (1)
+ {
+ S32 packet_id = 0;
+ U8 tmp_data[MAX_PACKET_DATA_SIZE];
+ // See if we've got any delayed packets
+ packet_id = ttp->getNextPacketID();
+ if (ttp->mDelayedPacketMap.find(packet_id) != ttp->mDelayedPacketMap.end())
+ {
+ // Perhaps this stuff should be inside a method in LLTransferPacket?
+ // I'm too lazy to do it now, though.
+// LL_INFOS() << "Playing back delayed packet " << packet_id << LL_ENDL;
+ LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id];
+
+ // This is somewhat inefficient, but avoids us having to duplicate
+ // code between the off-the-wire and delayed paths.
+ packet_id = packetp->mPacketID;
+ size = packetp->mSize;
+ if (size)
+ {
+ if ((packetp->mDatap != NULL) && (size<(S32)sizeof(tmp_data)))
+ {
+ memcpy(tmp_data, packetp->mDatap, size); /*Flawfinder: ignore*/
+ }
+ }
+ status = packetp->mStatus;
+ ttp->mDelayedPacketMap.erase(packet_id);
+ delete packetp;
+ }
+ else
+ {
+ // No matching delayed packet, we're done.
+ break;
+ }
+
+ LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size);
+ if (ret_code == LLTS_OK)
+ {
+ ttp->setLastPacketID(packet_id);
+ }
+
+ if (status != LLTS_OK)
+ {
+ if (status != LLTS_DONE)
+ {
+ LL_WARNS() << "LLTransferManager::processTransferInfo Error in playback!" << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << "LLTransferManager::processTransferInfo replay FINISHED for " << transfer_id << LL_ENDL;
+ }
+ // This transfer is done, either via error or not.
+ ttp->completionCallback(status);
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+ }
+}
+
+
+//static
+void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **)
+{
+ //LL_INFOS() << "LLTransferManager::processTransferPacket" << LL_ENDL;
+
+ LLUUID transfer_id;
+ LLTransferChannelType channel_type;
+ S32 packet_id;
+ LLTSCode status;
+ S32 size;
+ msgp->getUUID("TransferData", "TransferID", transfer_id);
+ msgp->getS32("TransferData", "ChannelType", (S32 &)channel_type);
+ msgp->getS32("TransferData", "Packet", packet_id);
+ msgp->getS32("TransferData", "Status", (S32 &)status);
+
+ // Find the transfer associated with this packet.
+ //LL_INFOS() << transfer_id << ":" << channel_type << LL_ENDL;
+ LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type);
+ if (!ttcp)
+ {
+ LL_WARNS() << "Target channel not found" << LL_ENDL;
+ return;
+ }
+
+ LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id);
+ if (!ttp)
+ {
+ LL_WARNS() << "Didn't find matching transfer for " << transfer_id
+ << " processing packet " << packet_id
+ << " from " << msgp->getSender() << LL_ENDL;
+ return;
+ }
+
+ size = msgp->getSize("TransferData", "Data");
+
+ S32 msg_bytes = 0;
+ if (msgp->getReceiveCompressedSize())
+ {
+ msg_bytes = msgp->getReceiveCompressedSize();
+ }
+ else
+ {
+ msg_bytes = msgp->getReceiveSize();
+ }
+ gTransferManager.addTransferBitsIn(ttcp->mChannelType, msg_bytes*8);
+
+ if ((size < 0) || (size > MAX_PACKET_DATA_SIZE))
+ {
+ LL_WARNS() << "Invalid transfer packet size " << size << LL_ENDL;
+ return;
+ }
+
+ U8 tmp_data[MAX_PACKET_DATA_SIZE];
+ if (size > 0)
+ {
+ // Only pull the data out if the size is > 0
+ msgp->getBinaryData("TransferData", "Data", tmp_data, size);
+ }
+
+ if ((!ttp->gotInfo()) || (ttp->getNextPacketID() != packet_id))
+ {
+ // Put this on a list of packets to be delivered later.
+ if(!ttp->addDelayedPacket(packet_id, status, tmp_data, size))
+ {
+ // Whoops - failed to add a delayed packet for some reason.
+ LL_WARNS() << "Too many delayed packets processing transfer "
+ << transfer_id << " from " << msgp->getSender() << LL_ENDL;
+ ttp->abortTransfer();
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+#if 0
+ // Spammy!
+ const S32 LL_TRANSFER_WARN_GAP = 10;
+ if(!ttp->gotInfo())
+ {
+ LL_WARNS() << "Got data packet before information in transfer "
+ << transfer_id << " from " << msgp->getSender()
+ << ", got " << packet_id << LL_ENDL;
+ }
+ else if((packet_id - ttp->getNextPacketID()) > LL_TRANSFER_WARN_GAP)
+ {
+ LL_WARNS() << "Out of order packet in transfer " << transfer_id
+ << " from " << msgp->getSender() << ", got " << packet_id
+ << " expecting " << ttp->getNextPacketID() << LL_ENDL;
+ }
+#endif
+ return;
+ }
+
+ // Loop through this until we're done with all delayed packets
+
+ //
+ // NOTE: THERE IS A CUT AND PASTE OF THIS CODE IN THE TRANSFERINFO HANDLER
+ // SO WE CAN PLAY BACK DELAYED PACKETS THERE!!!!!!!!!!!!!!!!!!!!!!!!!
+ //
+ bool done = false;
+ while (!done)
+ {
+ LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size);
+ if (ret_code == LLTS_OK)
+ {
+ ttp->setLastPacketID(packet_id);
+ }
+
+ if (status != LLTS_OK)
+ {
+ if (status != LLTS_DONE)
+ {
+ LL_WARNS() << "LLTransferManager::processTransferPacket Error in transfer!" << LL_ENDL;
+ }
+ else
+ {
+// LL_INFOS() << "LLTransferManager::processTransferPacket done for " << transfer_id << LL_ENDL;
+ }
+ // This transfer is done, either via error or not.
+ ttp->completionCallback(status);
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+
+ // See if we've got any delayed packets
+ packet_id = ttp->getNextPacketID();
+ if (ttp->mDelayedPacketMap.find(packet_id) != ttp->mDelayedPacketMap.end())
+ {
+ // Perhaps this stuff should be inside a method in LLTransferPacket?
+ // I'm too lazy to do it now, though.
+// LL_INFOS() << "Playing back delayed packet " << packet_id << LL_ENDL;
+ LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id];
+
+ // This is somewhat inefficient, but avoids us having to duplicate
+ // code between the off-the-wire and delayed paths.
+ packet_id = packetp->mPacketID;
+ size = packetp->mSize;
+ if (size)
+ {
+ if ((packetp->mDatap != NULL) && (size<(S32)sizeof(tmp_data)))
+ {
+ memcpy(tmp_data, packetp->mDatap, size); /*Flawfinder: ignore*/
+ }
+ }
+ status = packetp->mStatus;
+ ttp->mDelayedPacketMap.erase(packet_id);
+ delete packetp;
+ }
+ else
+ {
+ // No matching delayed packet, abort it.
+ done = true;
+ }
+ }
+}
+
+
+//static
+void LLTransferManager::processTransferAbort(LLMessageSystem *msgp, void **)
+{
+ //LL_INFOS() << "LLTransferManager::processTransferPacket" << LL_ENDL;
+
+ LLUUID transfer_id;
+ LLTransferChannelType channel_type;
+ msgp->getUUID("TransferInfo", "TransferID", transfer_id);
+ msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type);
+
+ // See if it's a target that we're trying to abort
+ // Find the transfer associated with this packet.
+ LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type);
+ if (ttcp)
+ {
+ LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id);
+ if (ttp)
+ {
+ ttp->abortTransfer();
+ ttcp->deleteTransfer(ttp);
+ return;
+ }
+ }
+
+ // Hmm, not a target. Maybe it's a source.
+ LLTransferSourceChannel *tscp = gTransferManager.getSourceChannel(msgp->getSender(), channel_type);
+ if (tscp)
+ {
+ LLTransferSource *tsp = tscp->findTransferSource(transfer_id);
+ if (tsp)
+ {
+ tsp->abortTransfer();
+ tscp->deleteTransfer(tsp);
+ return;
+ }
+ }
+
+ LL_WARNS() << "Couldn't find transfer " << transfer_id << " to abort!" << LL_ENDL;
+}
+
+
+//static
+void LLTransferManager::reliablePacketCallback(void **user_data, S32 result)
+{
+ LLUUID *transfer_idp = (LLUUID *)user_data;
+ if (result &&
+ transfer_idp != NULL)
+ {
+ LLTransferSource *tsp = gTransferManager.findTransferSource(*transfer_idp);
+ if (tsp)
+ {
+ LL_WARNS() << "Aborting reliable transfer " << *transfer_idp << " due to failed reliable resends!" << LL_ENDL;
+ LLTransferSourceChannel *tscp = tsp->mChannelp;
+ tsp->abortTransfer();
+ tscp->deleteTransfer(tsp);
+ }
+ else
+ {
+ LL_WARNS() << "Aborting reliable transfer " << *transfer_idp << " but can't find the LLTransferSource object" << LL_ENDL;
+ }
+ }
+ delete transfer_idp;
+}
+
+//
+// LLTransferConnection implementation
+//
+
+LLTransferConnection::LLTransferConnection(const LLHost &host)
+{
+ mHost = host;
+}
+
+LLTransferConnection::~LLTransferConnection()
+{
+ tsc_iter itersc;
+ for (itersc = mTransferSourceChannels.begin(); itersc != mTransferSourceChannels.end(); itersc++)
+ {
+ delete *itersc;
+ }
+ mTransferSourceChannels.clear();
+
+ ttc_iter itertc;
+ for (itertc = mTransferTargetChannels.begin(); itertc != mTransferTargetChannels.end(); itertc++)
+ {
+ delete *itertc;
+ }
+ mTransferTargetChannels.clear();
+}
+
+
+void LLTransferConnection::updateTransfers()
+{
+ // Do stuff for source transfers (basically, send data out).
+ tsc_iter iter, cur;
+ iter = mTransferSourceChannels.begin();
+
+ while (iter !=mTransferSourceChannels.end())
+ {
+ cur = iter;
+ iter++;
+ (*cur)->updateTransfers();
+ }
+
+ // Do stuff for target transfers
+ // Primarily, we should be aborting transfers that are irredeemably broken
+ // (large packet gaps that don't appear to be getting filled in, most likely)
+ // Probably should NOT be doing timeouts for other things, as new priority scheme
+ // means that a high priority transfer COULD block a transfer for a long time.
+}
+
+
+LLTransferSourceChannel *LLTransferConnection::getSourceChannel(const LLTransferChannelType channel_type)
+{
+ tsc_iter iter;
+ for (iter = mTransferSourceChannels.begin(); iter != mTransferSourceChannels.end(); iter++)
+ {
+ if ((*iter)->getChannelType() == channel_type)
+ {
+ return *iter;
+ }
+ }
+
+ LLTransferSourceChannel *tscp = new LLTransferSourceChannel(channel_type, mHost);
+ mTransferSourceChannels.push_back(tscp);
+ return tscp;
+}
+
+
+LLTransferTargetChannel *LLTransferConnection::getTargetChannel(const LLTransferChannelType channel_type)
+{
+ ttc_iter iter;
+ for (iter = mTransferTargetChannels.begin(); iter != mTransferTargetChannels.end(); iter++)
+ {
+ if ((*iter)->getChannelType() == channel_type)
+ {
+ return *iter;
+ }
+ }
+
+ LLTransferTargetChannel *ttcp = new LLTransferTargetChannel(channel_type, mHost);
+ mTransferTargetChannels.push_back(ttcp);
+ return ttcp;
+}
+
+
+//
+// LLTransferSourceChannel implementation
+//
+
+const S32 DEFAULT_PACKET_SIZE = 1000;
+
+
+LLTransferSourceChannel::LLTransferSourceChannel(const LLTransferChannelType channel_type, const LLHost &host) :
+ mChannelType(channel_type),
+ mHost(host),
+ mTransferSources(LLTransferSource::sSetPriority, LLTransferSource::sGetPriority),
+ mThrottleID(TC_ASSET)
+{
+}
+
+
+LLTransferSourceChannel::~LLTransferSourceChannel()
+{
+ LLPriQueueMap<LLTransferSource*>::pqm_iter iter =
+ mTransferSources.mMap.begin();
+ LLPriQueueMap<LLTransferSource*>::pqm_iter end =
+ mTransferSources.mMap.end();
+ for (; iter != end; ++iter)
+ {
+ // Just kill off all of the transfers
+ (*iter).second->abortTransfer();
+ delete iter->second;
+ }
+ mTransferSources.mMap.clear();
+}
+
+void LLTransferSourceChannel::updatePriority(LLTransferSource *tsp, const F32 priority)
+{
+ mTransferSources.reprioritize(priority, tsp);
+}
+
+void LLTransferSourceChannel::updateTransfers()
+{
+ // Actually, this should do the following:
+ // Decide if we can actually send data.
+ // If so, update priorities so we know who gets to send it.
+ // Send data from the sources, while updating until we've sent our throttle allocation.
+
+ LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(getHost());
+ if (!cdp)
+ {
+ return;
+ }
+
+ if (cdp->isBlocked())
+ {
+ // *NOTE: We need to make sure that the throttle bits
+ // available gets reset.
+
+ // We DON'T want to send any packets if they're blocked, they'll just end up
+ // piling up on the other end.
+ //LL_WARNS() << "Blocking transfers due to blocked circuit for " << getHost() << LL_ENDL;
+ return;
+ }
+
+ const S32 throttle_id = mThrottleID;
+
+ LLThrottleGroup &tg = cdp->getThrottleGroup();
+
+ if (tg.checkOverflow(throttle_id, 0.f))
+ {
+ return;
+ }
+
+ LLPriQueueMap<LLTransferSource *>::pqm_iter iter, next;
+
+ bool done = false;
+ for (iter = mTransferSources.mMap.begin(); (iter != mTransferSources.mMap.end()) && !done;)
+ {
+ //LL_INFOS() << "LLTransferSourceChannel::updateTransfers()" << LL_ENDL;
+ // Do stuff.
+ next = iter;
+ next++;
+
+ LLTransferSource *tsp = iter->second;
+ U8 *datap = NULL;
+ S32 data_size = 0;
+ bool delete_data = false;
+ S32 packet_id = 0;
+ S32 sent_bytes = 0;
+ LLTSCode status = LLTS_OK;
+
+ // Get the packetID for the next packet that we're transferring.
+ packet_id = tsp->getNextPacketID();
+ status = tsp->dataCallback(packet_id, DEFAULT_PACKET_SIZE, &datap, data_size, delete_data);
+
+ if (status == LLTS_SKIP)
+ {
+ // We don't have any data, but we're not done, just go on.
+ // This will presumably be used for streaming or async transfers that
+ // are stalled waiting for data from another source.
+ iter=next;
+ continue;
+ }
+
+ LLUUID *cb_uuid = new LLUUID(tsp->getID());
+ LLUUID transaction_id = tsp->getID();
+
+ // Send the data now, even if it's an error.
+ // The status code will tell the other end what to do.
+ gMessageSystem->newMessage("TransferPacket");
+ gMessageSystem->nextBlock("TransferData");
+ gMessageSystem->addUUID("TransferID", tsp->getID());
+ gMessageSystem->addS32("ChannelType", getChannelType());
+ gMessageSystem->addS32("Packet", packet_id); // HACK! Need to put in a REAL packet id
+ gMessageSystem->addS32("Status", status);
+ gMessageSystem->addBinaryData("Data", datap, data_size);
+ sent_bytes = gMessageSystem->getCurrentSendTotal();
+ gMessageSystem->sendReliable(getHost(), LL_DEFAULT_RELIABLE_RETRIES, true, F32Seconds(0.f),
+ LLTransferManager::reliablePacketCallback, (void**)cb_uuid);
+
+ // Do bookkeeping for the throttle
+ done = tg.throttleOverflow(throttle_id, sent_bytes*8.f);
+ gTransferManager.addTransferBitsOut(mChannelType, sent_bytes*8);
+
+ // Clean up our temporary data.
+ if (delete_data)
+ {
+ delete[] datap;
+ datap = NULL;
+ }
+
+ if (findTransferSource(transaction_id) == NULL)
+ {
+ //Warning! In the case of an aborted transfer, the sendReliable call above calls
+ //AbortTransfer which in turn calls deleteTransfer which means that somewhere way
+ //down the chain our current iter can get invalidated resulting in an infrequent
+ //sim crash. This check gets us to a valid transfer source in this event.
+ iter=next;
+ continue;
+ }
+
+ // Update the packet counter
+ tsp->setLastPacketID(packet_id);
+
+ switch (status)
+ {
+ case LLTS_OK:
+ // We're OK, don't need to do anything. Keep sending data.
+ break;
+ case LLTS_ERROR:
+ LL_WARNS() << "Error in transfer dataCallback!" << LL_ENDL;
+ // fall through
+ case LLTS_DONE:
+ // We need to clean up this transfer source.
+ //LL_INFOS() << "LLTransferSourceChannel::updateTransfers() " << tsp->getID() << " done" << LL_ENDL;
+ tsp->completionCallback(status);
+ delete tsp;
+
+ mTransferSources.mMap.erase(iter);
+ iter = next;
+ break;
+ default:
+ LL_ERRS() << "Unknown transfer error code!" << LL_ENDL;
+ }
+
+ // At this point, we should do priority adjustment (since some transfers like
+ // streaming transfers will adjust priority based on how much they've sent and time,
+ // but I'm not going to bother yet. - djs.
+ }
+}
+
+
+void LLTransferSourceChannel::addTransferSource(LLTransferSource *sourcep)
+{
+ sourcep->mChannelp = this;
+ mTransferSources.push(sourcep->getPriority(), sourcep);
+}
+
+
+LLTransferSource *LLTransferSourceChannel::findTransferSource(const LLUUID &transfer_id)
+{
+ LLPriQueueMap<LLTransferSource *>::pqm_iter iter;
+ for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++)
+ {
+ LLTransferSource *tsp = iter->second;
+ if (tsp->getID() == transfer_id)
+ {
+ return tsp;
+ }
+ }
+ return NULL;
+}
+
+
+void LLTransferSourceChannel::deleteTransfer(LLTransferSource *tsp)
+{
+ if (tsp)
+ {
+ LLPriQueueMap<LLTransferSource *>::pqm_iter iter;
+ for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++)
+ {
+ if (iter->second == tsp)
+ {
+ delete tsp;
+ mTransferSources.mMap.erase(iter);
+ return;
+ }
+ }
+
+ LL_WARNS() << "Unable to find transfer source id "
+ << tsp->getID()
+ << " to delete!"
+ << LL_ENDL;
+ }
+}
+
+
+//
+// LLTransferTargetChannel implementation
+//
+
+LLTransferTargetChannel::LLTransferTargetChannel(const LLTransferChannelType channel_type, const LLHost &host) :
+ mChannelType(channel_type),
+ mHost(host)
+{
+}
+
+LLTransferTargetChannel::~LLTransferTargetChannel()
+{
+ tt_iter iter;
+ for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++)
+ {
+ // Abort all of the current transfers
+ (*iter)->abortTransfer();
+ delete *iter;
+ }
+ mTransferTargets.clear();
+}
+
+
+void LLTransferTargetChannel::requestTransfer(
+ const LLTransferSourceParams& source_params,
+ const LLTransferTargetParams& target_params,
+ const F32 priority)
+{
+ LLUUID id;
+ id.generate();
+ LLTransferTarget* ttp = LLTransferTarget::createTarget(
+ target_params.getType(),
+ id,
+ source_params.getType());
+ if (!ttp)
+ {
+ LL_WARNS() << "LLTransferManager::requestTransfer aborting due to target creation failure!" << LL_ENDL;
+ return;
+ }
+
+ ttp->applyParams(target_params);
+ addTransferTarget(ttp);
+
+ sendTransferRequest(ttp, source_params, priority);
+}
+
+
+void LLTransferTargetChannel::sendTransferRequest(LLTransferTarget *targetp,
+ const LLTransferSourceParams ¶ms,
+ const F32 priority)
+{
+ //
+ // Pack the message with data which explains how to get the source, and
+ // send it off to the source for this channel.
+ //
+ llassert(targetp);
+ llassert(targetp->getChannel() == this);
+
+ gMessageSystem->newMessage("TransferRequest");
+ gMessageSystem->nextBlock("TransferInfo");
+ gMessageSystem->addUUID("TransferID", targetp->getID());
+ gMessageSystem->addS32("SourceType", params.getType());
+ gMessageSystem->addS32("ChannelType", getChannelType());
+ gMessageSystem->addF32("Priority", priority);
+
+ U8 tmp[MAX_PARAMS_SIZE];
+ LLDataPackerBinaryBuffer dp(tmp, MAX_PARAMS_SIZE);
+ params.packParams(dp);
+ S32 len = dp.getCurrentSize();
+ gMessageSystem->addBinaryData("Params", tmp, len);
+
+ gMessageSystem->sendReliable(mHost);
+}
+
+
+void LLTransferTargetChannel::addTransferTarget(LLTransferTarget *targetp)
+{
+ targetp->mChannelp = this;
+ mTransferTargets.push_back(targetp);
+}
+
+
+LLTransferTarget *LLTransferTargetChannel::findTransferTarget(const LLUUID &transfer_id)
+{
+ tt_iter iter;
+ for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++)
+ {
+ LLTransferTarget *ttp = *iter;
+ if (ttp->getID() == transfer_id)
+ {
+ return ttp;
+ }
+ }
+ return NULL;
+}
+
+
+void LLTransferTargetChannel::deleteTransfer(LLTransferTarget *ttp)
+{
+ if (ttp)
+ {
+ tt_iter iter;
+ for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++)
+ {
+ if (*iter == ttp)
+ {
+ delete ttp;
+ mTransferTargets.erase(iter);
+ return;
+ }
+ }
+
+ LL_WARNS() << "Unable to find transfer target id "
+ << ttp->getID()
+ << " to delete!"
+ << LL_ENDL;
+ }
+}
+
+
+//
+// LLTransferSource implementation
+//
+
+LLTransferSource::LLTransferSource(const LLTransferSourceType type,
+ const LLUUID &transfer_id,
+ const F32 priority) :
+ mType(type),
+ mID(transfer_id),
+ mChannelp(NULL),
+ mPriority(priority),
+ mSize(0),
+ mLastPacketID(-1)
+{
+ setPriority(priority);
+}
+
+
+LLTransferSource::~LLTransferSource()
+{
+ // No actual cleanup of the transfer is done here, this is purely for
+ // memory cleanup. The completionCallback is guaranteed to get called
+ // before this happens.
+}
+
+
+void LLTransferSource::sendTransferStatus(LLTSCode status)
+{
+ gMessageSystem->newMessage("TransferInfo");
+ gMessageSystem->nextBlock("TransferInfo");
+ gMessageSystem->addUUID("TransferID", getID());
+ gMessageSystem->addS32("TargetType", LLTTT_UNKNOWN);
+ gMessageSystem->addS32("ChannelType", mChannelp->getChannelType());
+ gMessageSystem->addS32("Status", status);
+ gMessageSystem->addS32("Size", mSize);
+ U8 tmp[MAX_PARAMS_SIZE];
+ LLDataPackerBinaryBuffer dp(tmp, MAX_PARAMS_SIZE);
+ packParams(dp);
+ S32 len = dp.getCurrentSize();
+ gMessageSystem->addBinaryData("Params", tmp, len);
+ gMessageSystem->sendReliable(mChannelp->getHost());
+
+ // Abort if there was as asset system issue.
+ if (status != LLTS_OK)
+ {
+ completionCallback(status);
+ mChannelp->deleteTransfer(this);
+ }
+}
+
+
+// This should never be called directly, the transfer manager is responsible for
+// aborting the transfer from the channel. I might want to rethink this in the
+// future, though.
+void LLTransferSource::abortTransfer()
+{
+ // Send a message down, call the completion callback
+ LL_INFOS() << "LLTransferSource::Aborting transfer " << getID() << " to " << mChannelp->getHost() << LL_ENDL;
+ gMessageSystem->newMessage("TransferAbort");
+ gMessageSystem->nextBlock("TransferInfo");
+ gMessageSystem->addUUID("TransferID", getID());
+ gMessageSystem->addS32("ChannelType", mChannelp->getChannelType());
+ gMessageSystem->sendReliable(mChannelp->getHost());
+
+ completionCallback(LLTS_ABORT);
+}
+
+
+//static
+void LLTransferSource::registerSourceType(const LLTransferSourceType stype, LLTransferSourceCreateFunc func)
+{
+ if (sSourceCreateMap.count(stype))
+ {
+ // Disallow changing what class handles a source type
+ // Unclear when you would want to do this, and whether it would work.
+ LL_ERRS() << "Reregistering source type " << stype << LL_ENDL;
+ }
+ else
+ {
+ sSourceCreateMap[stype] = func;
+ }
+}
+
+//static
+LLTransferSource *LLTransferSource::createSource(const LLTransferSourceType stype,
+ const LLUUID &id,
+ const F32 priority)
+{
+ switch (stype)
+ {
+ // *NOTE: The source file transfer mechanism is highly insecure and could
+ // lead to easy exploitation of a server process.
+ // I have removed all uses of it from the codebase. Phoenix.
+ //
+ //case LLTST_FILE:
+ // return new LLTransferSourceFile(id, priority);
+ case LLTST_ASSET:
+ return new LLTransferSourceAsset(id, priority);
+ default:
+ {
+ if (!sSourceCreateMap.count(stype))
+ {
+ // Use the callback to create the source type if it's not there.
+ LL_WARNS() << "Unknown transfer source type: " << stype << LL_ENDL;
+ return NULL;
+ }
+ return (sSourceCreateMap[stype])(id, priority);
+ }
+ }
+}
+
+
+// static
+void LLTransferSource::sSetPriority(LLTransferSource *&tsp, const F32 priority)
+{
+ tsp->setPriority(priority);
+}
+
+
+// static
+F32 LLTransferSource::sGetPriority(LLTransferSource *&tsp)
+{
+ return tsp->getPriority();
+}
+
+
+//
+// LLTransferPacket implementation
+//
+
+LLTransferPacket::LLTransferPacket(const S32 packet_id, const LLTSCode status, const U8 *datap, const S32 size) :
+ mPacketID(packet_id),
+ mStatus(status),
+ mDatap(NULL),
+ mSize(size)
+{
+ if (size == 0)
+ {
+ return;
+ }
+
+ mDatap = new U8[size];
+ if (mDatap != NULL)
+ {
+ memcpy(mDatap, datap, size); /*Flawfinder: ignore*/
+ }
+}
+
+LLTransferPacket::~LLTransferPacket()
+{
+ delete[] mDatap;
+}
+
+//
+// LLTransferTarget implementation
+//
+
+LLTransferTarget::LLTransferTarget(
+ LLTransferTargetType type,
+ const LLUUID& transfer_id,
+ LLTransferSourceType source_type) :
+ mType(type),
+ mSourceType(source_type),
+ mID(transfer_id),
+ mChannelp(NULL),
+ mGotInfo(false),
+ mSize(0),
+ mLastPacketID(-1)
+{
+}
+
+LLTransferTarget::~LLTransferTarget()
+{
+ // No actual cleanup of the transfer is done here, this is purely for
+ // memory cleanup. The completionCallback is guaranteed to get called
+ // before this happens.
+ tpm_iter iter;
+ for (iter = mDelayedPacketMap.begin(); iter != mDelayedPacketMap.end(); iter++)
+ {
+ delete iter->second;
+ }
+ mDelayedPacketMap.clear();
+}
+
+// This should never be called directly, the transfer manager is responsible for
+// aborting the transfer from the channel. I might want to rethink this in the
+// future, though.
+void LLTransferTarget::abortTransfer()
+{
+ // Send a message up, call the completion callback
+ LL_INFOS() << "LLTransferTarget::Aborting transfer " << getID() << " from " << mChannelp->getHost() << LL_ENDL;
+ gMessageSystem->newMessage("TransferAbort");
+ gMessageSystem->nextBlock("TransferInfo");
+ gMessageSystem->addUUID("TransferID", getID());
+ gMessageSystem->addS32("ChannelType", mChannelp->getChannelType());
+ gMessageSystem->sendReliable(mChannelp->getHost());
+
+ completionCallback(LLTS_ABORT);
+}
+
+bool LLTransferTarget::addDelayedPacket(
+ const S32 packet_id,
+ const LLTSCode status,
+ U8* datap,
+ const S32 size)
+{
+ const transfer_packet_map::size_type LL_MAX_DELAYED_PACKETS = 100;
+ if(mDelayedPacketMap.size() > LL_MAX_DELAYED_PACKETS)
+ {
+ // too many delayed packets
+ return false;
+ }
+
+ LLTransferPacket* tpp = new LLTransferPacket(
+ packet_id,
+ status,
+ datap,
+ size);
+
+#ifdef _DEBUG
+ transfer_packet_map::iterator iter = mDelayedPacketMap.find(packet_id);
+ if (iter != mDelayedPacketMap.end())
+ {
+ if (!(iter->second->mSize == size) && !(iter->second->mDatap == datap))
+ {
+ LL_ERRS() << "Packet ALREADY in delayed packet map!" << LL_ENDL;
+ }
+ }
+#endif
+
+ mDelayedPacketMap[packet_id] = tpp;
+ return true;
+}
+
+
+LLTransferTarget* LLTransferTarget::createTarget(
+ LLTransferTargetType type,
+ const LLUUID& id,
+ LLTransferSourceType source_type)
+{
+ switch (type)
+ {
+ case LLTTT_FILE:
+ return new LLTransferTargetFile(id, source_type);
+ case LLTTT_VFILE:
+ return new LLTransferTargetVFile(id, source_type);
+ default:
+ LL_WARNS() << "Unknown transfer target type: " << type << LL_ENDL;
+ return NULL;
+ }
+}
+
+
+LLTransferSourceParamsInvItem::LLTransferSourceParamsInvItem() : LLTransferSourceParams(LLTST_SIM_INV_ITEM), mAssetType(LLAssetType::AT_NONE)
+{
+}
+
+
+void LLTransferSourceParamsInvItem::setAgentSession(const LLUUID &agent_id, const LLUUID &session_id)
+{
+ mAgentID = agent_id;
+ mSessionID = session_id;
+}
+
+
+void LLTransferSourceParamsInvItem::setInvItem(const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id)
+{
+ mOwnerID = owner_id;
+ mTaskID = task_id;
+ mItemID = item_id;
+}
+
+
+void LLTransferSourceParamsInvItem::setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type)
+{
+ mAssetID = asset_id;
+ mAssetType = asset_type;
+}
+
+
+void LLTransferSourceParamsInvItem::packParams(LLDataPacker &dp) const
+{
+ LL_DEBUGS() << "LLTransferSourceParamsInvItem::packParams()" << LL_ENDL;
+ dp.packUUID(mAgentID, "AgentID");
+ dp.packUUID(mSessionID, "SessionID");
+ dp.packUUID(mOwnerID, "OwnerID");
+ dp.packUUID(mTaskID, "TaskID");
+ dp.packUUID(mItemID, "ItemID");
+ dp.packUUID(mAssetID, "AssetID");
+ dp.packS32(mAssetType, "AssetType");
+}
+
+
+bool LLTransferSourceParamsInvItem::unpackParams(LLDataPacker &dp)
+{
+ S32 tmp_at;
+
+ dp.unpackUUID(mAgentID, "AgentID");
+ dp.unpackUUID(mSessionID, "SessionID");
+ dp.unpackUUID(mOwnerID, "OwnerID");
+ dp.unpackUUID(mTaskID, "TaskID");
+ dp.unpackUUID(mItemID, "ItemID");
+ dp.unpackUUID(mAssetID, "AssetID");
+ dp.unpackS32(tmp_at, "AssetType");
+
+ mAssetType = (LLAssetType::EType)tmp_at;
+
+ return true;
+}
+
+LLTransferSourceParamsEstate::LLTransferSourceParamsEstate() :
+ LLTransferSourceParams(LLTST_SIM_ESTATE),
+ mEstateAssetType(ET_NONE),
+ mAssetType(LLAssetType::AT_NONE)
+{
+}
+
+void LLTransferSourceParamsEstate::setAgentSession(const LLUUID &agent_id, const LLUUID &session_id)
+{
+ mAgentID = agent_id;
+ mSessionID = session_id;
+}
+
+void LLTransferSourceParamsEstate::setEstateAssetType(const EstateAssetType etype)
+{
+ mEstateAssetType = etype;
+}
+
+void LLTransferSourceParamsEstate::setAsset(const LLUUID &asset_id, const LLAssetType::EType asset_type)
+{
+ mAssetID = asset_id;
+ mAssetType = asset_type;
+}
+
+void LLTransferSourceParamsEstate::packParams(LLDataPacker &dp) const
+{
+ dp.packUUID(mAgentID, "AgentID");
+ // *NOTE: We do not want to pass the session id from the server to
+ // the client, but I am not sure if anyone expects this value to
+ // be set on the client.
+ dp.packUUID(mSessionID, "SessionID");
+ dp.packS32(mEstateAssetType, "EstateAssetType");
+}
+
+
+bool LLTransferSourceParamsEstate::unpackParams(LLDataPacker &dp)
+{
+ S32 tmp_et;
+
+ dp.unpackUUID(mAgentID, "AgentID");
+ dp.unpackUUID(mSessionID, "SessionID");
+ dp.unpackS32(tmp_et, "EstateAssetType");
+
+ mEstateAssetType = (EstateAssetType)tmp_et;
+
+ return true;
+}
|