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. //llwarns << "Blocking transfers due to blocked circuit for " << getHost() << llendl; 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;) { //llinfos << "LLTransferSourceChannel::updateTransfers()" << llendl; // 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, 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: llwarns << "Error in transfer dataCallback!" << llendl; // fall through case LLTS_DONE: // We need to clean up this transfer source. //llinfos << "LLTransferSourceChannel::updateTransfers() " << tsp->getID() << " done" << llendl; tsp->completionCallback(status); delete tsp; mTransferSources.mMap.erase(iter); iter = next; break; default: llerrs << "Unknown transfer error code!" << llendl; } // 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. } }