Annotation of /linden_release/linden/indra/llmessage/llxfer.cpp
Parent Directory
|
Revision Log
Revision 57 - (view) (download)
| 1 : | mjm | 57 | /** |
| 2 : | * @file llxfer.cpp | ||
| 3 : | * @brief implementation of LLXfer class for a single xfer. | ||
| 4 : | * | ||
| 5 : | * $LicenseInfo:firstyear=2001&license=viewergpl$ | ||
| 6 : | * | ||
| 7 : | * Copyright (c) 2001-2008, Linden Research, Inc. | ||
| 8 : | * | ||
| 9 : | * Second Life Viewer Source Code | ||
| 10 : | * The source code in this file ("Source Code") is provided by Linden Lab | ||
| 11 : | * to you under the terms of the GNU General Public License, version 2.0 | ||
| 12 : | * ("GPL"), unless you have obtained a separate licensing agreement | ||
| 13 : | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
| 14 : | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
| 15 : | * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 | ||
| 16 : | * | ||
| 17 : | * There are special exceptions to the terms and conditions of the GPL as | ||
| 18 : | * it is applied to this Source Code. View the full text of the exception | ||
| 19 : | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
| 20 : | * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception | ||
| 21 : | * | ||
| 22 : | * By copying, modifying or distributing this software, you acknowledge | ||
| 23 : | * that you have read and understood your obligations described above, | ||
| 24 : | * and agree to abide by those obligations. | ||
| 25 : | * | ||
| 26 : | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
| 27 : | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
| 28 : | * COMPLETENESS OR PERFORMANCE. | ||
| 29 : | * $/LicenseInfo$ | ||
| 30 : | */ | ||
| 31 : | |||
| 32 : | #include "linden_common.h" | ||
| 33 : | |||
| 34 : | #include "llxfer.h" | ||
| 35 : | #include "lluuid.h" | ||
| 36 : | #include "llerror.h" | ||
| 37 : | #include "llmath.h" | ||
| 38 : | #include "u64.h" | ||
| 39 : | |||
| 40 : | //number of bytes sent in each message | ||
| 41 : | const U32 LL_XFER_CHUNK_SIZE = 1000; | ||
| 42 : | |||
| 43 : | const U32 LLXfer::XFER_FILE = 1; | ||
| 44 : | const U32 LLXfer::XFER_VFILE = 2; | ||
| 45 : | const U32 LLXfer::XFER_MEM = 3; | ||
| 46 : | |||
| 47 : | /////////////////////////////////////////////////////////// | ||
| 48 : | |||
| 49 : | LLXfer::LLXfer (S32 chunk_size) | ||
| 50 : | { | ||
| 51 : | init(chunk_size); | ||
| 52 : | } | ||
| 53 : | |||
| 54 : | /////////////////////////////////////////////////////////// | ||
| 55 : | |||
| 56 : | LLXfer::~LLXfer () | ||
| 57 : | { | ||
| 58 : | cleanup(); | ||
| 59 : | } | ||
| 60 : | |||
| 61 : | /////////////////////////////////////////////////////////// | ||
| 62 : | |||
| 63 : | void LLXfer::init (S32 chunk_size) | ||
| 64 : | { | ||
| 65 : | mID = 0; | ||
| 66 : | |||
| 67 : | mPacketNum = -1; // there's a preincrement before sending the zeroth packet | ||
| 68 : | mXferSize = 0; | ||
| 69 : | |||
| 70 : | mStatus = e_LL_XFER_UNINITIALIZED; | ||
| 71 : | mNext = NULL; | ||
| 72 : | mWaitingForACK = FALSE; | ||
| 73 : | |||
| 74 : | mCallback = NULL; | ||
| 75 : | mCallbackDataHandle = NULL; | ||
| 76 : | |||
| 77 : | mBufferContainsEOF = FALSE; | ||
| 78 : | mBuffer = NULL; | ||
| 79 : | mBufferLength = 0; | ||
| 80 : | mBufferStartOffset = 0; | ||
| 81 : | |||
| 82 : | mRetries = 0; | ||
| 83 : | |||
| 84 : | if (chunk_size < 1) | ||
| 85 : | { | ||
| 86 : | chunk_size = LL_XFER_CHUNK_SIZE; | ||
| 87 : | } | ||
| 88 : | mChunkSize = chunk_size; | ||
| 89 : | } | ||
| 90 : | |||
| 91 : | /////////////////////////////////////////////////////////// | ||
| 92 : | |||
| 93 : | void LLXfer::cleanup () | ||
| 94 : | { | ||
| 95 : | if (mBuffer) | ||
| 96 : | { | ||
| 97 : | delete[] mBuffer; | ||
| 98 : | mBuffer = NULL; | ||
| 99 : | } | ||
| 100 : | } | ||
| 101 : | |||
| 102 : | /////////////////////////////////////////////////////////// | ||
| 103 : | |||
| 104 : | S32 LLXfer::startSend (U64 xfer_id, const LLHost &remote_host) | ||
| 105 : | { | ||
| 106 : | llwarns << "undifferentiated LLXfer::startSend for " << getFileName() << llendl; | ||
| 107 : | return (-1); | ||
| 108 : | } | ||
| 109 : | |||
| 110 : | /////////////////////////////////////////////////////////// | ||
| 111 : | |||
| 112 : | void LLXfer::setXferSize (S32 xfer_size) | ||
| 113 : | { | ||
| 114 : | mXferSize = xfer_size; | ||
| 115 : | // cout << "starting transfer of size: " << xfer_size << endl; | ||
| 116 : | } | ||
| 117 : | |||
| 118 : | /////////////////////////////////////////////////////////// | ||
| 119 : | |||
| 120 : | S32 LLXfer::startDownload() | ||
| 121 : | { | ||
| 122 : | llwarns << "undifferentiated LLXfer::startDownload for " << getFileName() | ||
| 123 : | << llendl; | ||
| 124 : | return (-1); | ||
| 125 : | } | ||
| 126 : | |||
| 127 : | /////////////////////////////////////////////////////////// | ||
| 128 : | |||
| 129 : | S32 LLXfer::receiveData (char *datap, S32 data_size) | ||
| 130 : | { | ||
| 131 : | S32 retval = 0; | ||
| 132 : | |||
| 133 : | if (((S32) mBufferLength + data_size) > getMaxBufferSize()) | ||
| 134 : | { | ||
| 135 : | retval = flush(); | ||
| 136 : | } | ||
| 137 : | |||
| 138 : | if (!retval) | ||
| 139 : | { | ||
| 140 : | if (datap != NULL) | ||
| 141 : | { | ||
| 142 : | memcpy(&mBuffer[mBufferLength],datap,data_size); /*Flawfinder: ignore*/ | ||
| 143 : | mBufferLength += data_size; | ||
| 144 : | } | ||
| 145 : | else | ||
| 146 : | { | ||
| 147 : | llerrs << "NULL data passed in receiveData" << llendl; | ||
| 148 : | } | ||
| 149 : | } | ||
| 150 : | |||
| 151 : | return (retval); | ||
| 152 : | } | ||
| 153 : | |||
| 154 : | /////////////////////////////////////////////////////////// | ||
| 155 : | |||
| 156 : | S32 LLXfer::flush() | ||
| 157 : | { | ||
| 158 : | // only files have somewhere to flush to | ||
| 159 : | // if we get called with a flush it means we've blown past our | ||
| 160 : | // allocated buffer size | ||
| 161 : | |||
| 162 : | return (-1); | ||
| 163 : | } | ||
| 164 : | |||
| 165 : | |||
| 166 : | /////////////////////////////////////////////////////////// | ||
| 167 : | |||
| 168 : | S32 LLXfer::suck(S32 start_position) | ||
| 169 : | { | ||
| 170 : | llwarns << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << llendl; | ||
| 171 : | return (-1); | ||
| 172 : | } | ||
| 173 : | |||
| 174 : | /////////////////////////////////////////////////////////// | ||
| 175 : | |||
| 176 : | void LLXfer::sendPacket(S32 packet_num) | ||
| 177 : | { | ||
| 178 : | char fdata_buf[LL_XFER_LARGE_PAYLOAD+4]; /* Flawfinder: ignore */ | ||
| 179 : | S32 fdata_size = mChunkSize; | ||
| 180 : | BOOL last_packet = FALSE; | ||
| 181 : | S32 num_copy = 0; | ||
| 182 : | |||
| 183 : | // if the desired packet is not in our current buffered excerpt from the file. . . | ||
| 184 : | if (((U32)packet_num*fdata_size < mBufferStartOffset) | ||
| 185 : | || ((U32)llmin((U32)mXferSize,(U32)((U32)(packet_num+1)*fdata_size)) > mBufferStartOffset + mBufferLength)) | ||
| 186 : | |||
| 187 : | { | ||
| 188 : | if (suck(packet_num*fdata_size)) // returns non-zero on failure | ||
| 189 : | { | ||
| 190 : | abort(LL_ERR_EOF); | ||
| 191 : | return; | ||
| 192 : | } | ||
| 193 : | } | ||
| 194 : | |||
| 195 : | S32 desired_read_position = 0; | ||
| 196 : | |||
| 197 : | desired_read_position = packet_num * fdata_size - mBufferStartOffset; | ||
| 198 : | |||
| 199 : | fdata_size = llmin((S32)mBufferLength-desired_read_position, mChunkSize); | ||
| 200 : | |||
| 201 : | if (fdata_size < 0) | ||
| 202 : | { | ||
| 203 : | llwarns << "negative data size in xfer send, aborting" << llendl; | ||
| 204 : | abort(LL_ERR_EOF); | ||
| 205 : | return; | ||
| 206 : | } | ||
| 207 : | |||
| 208 : | if (((U32)(desired_read_position + fdata_size) >= (U32)mBufferLength) && (mBufferContainsEOF)) | ||
| 209 : | { | ||
| 210 : | last_packet = TRUE; | ||
| 211 : | } | ||
| 212 : | |||
| 213 : | if (packet_num) | ||
| 214 : | { | ||
| 215 : | num_copy = llmin(fdata_size, (S32)sizeof(fdata_buf)); | ||
| 216 : | num_copy = llmin(num_copy, (S32)(mBufferLength - desired_read_position)); | ||
| 217 : | if (num_copy > 0) | ||
| 218 : | { | ||
| 219 : | memcpy(fdata_buf,&mBuffer[desired_read_position],num_copy); /*Flawfinder: ignore*/ | ||
| 220 : | } | ||
| 221 : | } | ||
| 222 : | else | ||
| 223 : | { | ||
| 224 : | // if we're the first packet, encode size as an additional S32 | ||
| 225 : | // at start of data. | ||
| 226 : | num_copy = llmin(fdata_size, (S32)(sizeof(fdata_buf)-sizeof(S32))); | ||
| 227 : | num_copy = llmin( | ||
| 228 : | num_copy, | ||
| 229 : | (S32)(mBufferLength - desired_read_position)); | ||
| 230 : | if (num_copy > 0) | ||
| 231 : | { | ||
| 232 : | memcpy( /*Flawfinder: ignore*/ | ||
| 233 : | fdata_buf + sizeof(S32), | ||
| 234 : | &mBuffer[desired_read_position], | ||
| 235 : | num_copy); | ||
| 236 : | } | ||
| 237 : | fdata_size += sizeof(S32); | ||
| 238 : | htonmemcpy(fdata_buf,&mXferSize, MVT_S32, sizeof(S32)); | ||
| 239 : | } | ||
| 240 : | |||
| 241 : | S32 encoded_packetnum = encodePacketNum(packet_num,last_packet); | ||
| 242 : | |||
| 243 : | if (fdata_size) | ||
| 244 : | { | ||
| 245 : | // send the packet | ||
| 246 : | gMessageSystem->newMessageFast(_PREHASH_SendXferPacket); | ||
| 247 : | gMessageSystem->nextBlockFast(_PREHASH_XferID); | ||
| 248 : | |||
| 249 : | gMessageSystem->addU64Fast(_PREHASH_ID, mID); | ||
| 250 : | gMessageSystem->addU32Fast(_PREHASH_Packet, encoded_packetnum); | ||
| 251 : | |||
| 252 : | gMessageSystem->nextBlockFast(_PREHASH_DataPacket); | ||
| 253 : | gMessageSystem->addBinaryDataFast(_PREHASH_Data, &fdata_buf,fdata_size); | ||
| 254 : | |||
| 255 : | gMessageSystem->sendMessage(mRemoteHost); | ||
| 256 : | |||
| 257 : | ACKTimer.reset(); | ||
| 258 : | mWaitingForACK = TRUE; | ||
| 259 : | } | ||
| 260 : | if (last_packet) | ||
| 261 : | { | ||
| 262 : | mStatus = e_LL_XFER_COMPLETE; | ||
| 263 : | } | ||
| 264 : | else | ||
| 265 : | { | ||
| 266 : | mStatus = e_LL_XFER_IN_PROGRESS; | ||
| 267 : | } | ||
| 268 : | } | ||
| 269 : | |||
| 270 : | /////////////////////////////////////////////////////////// | ||
| 271 : | |||
| 272 : | void LLXfer::sendNextPacket() | ||
| 273 : | { | ||
| 274 : | mRetries = 0; | ||
| 275 : | sendPacket(++mPacketNum); | ||
| 276 : | } | ||
| 277 : | |||
| 278 : | /////////////////////////////////////////////////////////// | ||
| 279 : | |||
| 280 : | void LLXfer::resendLastPacket() | ||
| 281 : | { | ||
| 282 : | mRetries++; | ||
| 283 : | sendPacket(mPacketNum); | ||
| 284 : | } | ||
| 285 : | |||
| 286 : | /////////////////////////////////////////////////////////// | ||
| 287 : | |||
| 288 : | S32 LLXfer::processEOF() | ||
| 289 : | { | ||
| 290 : | S32 retval = 0; | ||
| 291 : | |||
| 292 : | mStatus = e_LL_XFER_COMPLETE; | ||
| 293 : | |||
| 294 : | if (LL_ERR_NOERR == mCallbackResult) | ||
| 295 : | { | ||
| 296 : | llinfos << "xfer from " << mRemoteHost << " complete: " << getFileName() | ||
| 297 : | << llendl; | ||
| 298 : | } | ||
| 299 : | else | ||
| 300 : | { | ||
| 301 : | llinfos << "xfer from " << mRemoteHost << " failed, code " | ||
| 302 : | << mCallbackResult << ": " << getFileName() << llendl; | ||
| 303 : | } | ||
| 304 : | |||
| 305 : | if (mCallback) | ||
| 306 : | { | ||
| 307 : | mCallback(mCallbackDataHandle,mCallbackResult,LL_EXSTAT_NONE); | ||
| 308 : | } | ||
| 309 : | |||
| 310 : | return(retval); | ||
| 311 : | } | ||
| 312 : | |||
| 313 : | /////////////////////////////////////////////////////////// | ||
| 314 : | |||
| 315 : | S32 LLXfer::encodePacketNum(S32 packet_num, BOOL is_EOF) | ||
| 316 : | { | ||
| 317 : | if (is_EOF) | ||
| 318 : | { | ||
| 319 : | packet_num |= 0x80000000; | ||
| 320 : | } | ||
| 321 : | return packet_num; | ||
| 322 : | } | ||
| 323 : | |||
| 324 : | /////////////////////////////////////////////////////////// | ||
| 325 : | |||
| 326 : | void LLXfer::abort (S32 result_code) | ||
| 327 : | { | ||
| 328 : | mCallbackResult = result_code; | ||
| 329 : | |||
| 330 : | llinfos << "Aborting xfer from " << mRemoteHost << " named " << getFileName() | ||
| 331 : | << " - error: " << result_code << llendl; | ||
| 332 : | |||
| 333 : | gMessageSystem->newMessageFast(_PREHASH_AbortXfer); | ||
| 334 : | gMessageSystem->nextBlockFast(_PREHASH_XferID); | ||
| 335 : | gMessageSystem->addU64Fast(_PREHASH_ID, mID); | ||
| 336 : | gMessageSystem->addS32Fast(_PREHASH_Result, result_code); | ||
| 337 : | |||
| 338 : | gMessageSystem->sendMessage(mRemoteHost); | ||
| 339 : | |||
| 340 : | mStatus = e_LL_XFER_ABORTED; | ||
| 341 : | } | ||
| 342 : | |||
| 343 : | |||
| 344 : | /////////////////////////////////////////////////////////// | ||
| 345 : | |||
| 346 : | std::string LLXfer::getFileName() | ||
| 347 : | { | ||
| 348 : | return U64_to_str(mID); | ||
| 349 : | } | ||
| 350 : | |||
| 351 : | /////////////////////////////////////////////////////////// | ||
| 352 : | |||
| 353 : | U32 LLXfer::getXferTypeTag() | ||
| 354 : | { | ||
| 355 : | return 0; | ||
| 356 : | } | ||
| 357 : | |||
| 358 : | /////////////////////////////////////////////////////////// | ||
| 359 : | |||
| 360 : | S32 LLXfer::getMaxBufferSize () | ||
| 361 : | { | ||
| 362 : | return(mXferSize); | ||
| 363 : | } | ||
| 364 : | |||
| 365 : | |||
| 366 : | std::ostream& operator<< (std::ostream& os, LLXfer &hh) | ||
| 367 : | { | ||
| 368 : | os << hh.getFileName() ; | ||
| 369 : | return os; | ||
| 370 : | } | ||
| 371 : | |||
| 372 : | |||
| 373 : | |||
| 374 : | |||
| 375 : | |||
| 376 : | |||
| 377 : | |||
| 378 : | |||
| 379 : |
| ViewVC Help | |
| Powered by ViewVC 1.0.0 |

