PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llmessage/llxfer.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 375 lines | 235 code | 87 blank | 53 comment | 22 complexity | 5de2c190edbab5fe3a19623d0b487310 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llxfer.cpp
  3. * @brief implementation of LLXfer class for a single xfer.
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "llxfer.h"
  28. #include "lluuid.h"
  29. #include "llerror.h"
  30. #include "llmath.h"
  31. #include "u64.h"
  32. //number of bytes sent in each message
  33. const U32 LL_XFER_CHUNK_SIZE = 1000;
  34. const U32 LLXfer::XFER_FILE = 1;
  35. const U32 LLXfer::XFER_VFILE = 2;
  36. const U32 LLXfer::XFER_MEM = 3;
  37. ///////////////////////////////////////////////////////////
  38. LLXfer::LLXfer (S32 chunk_size)
  39. {
  40. init(chunk_size);
  41. }
  42. ///////////////////////////////////////////////////////////
  43. LLXfer::~LLXfer ()
  44. {
  45. cleanup();
  46. }
  47. ///////////////////////////////////////////////////////////
  48. void LLXfer::init (S32 chunk_size)
  49. {
  50. mID = 0;
  51. mPacketNum = -1; // there's a preincrement before sending the zeroth packet
  52. mXferSize = 0;
  53. mStatus = e_LL_XFER_UNINITIALIZED;
  54. mNext = NULL;
  55. mWaitingForACK = FALSE;
  56. mCallback = NULL;
  57. mCallbackDataHandle = NULL;
  58. mCallbackResult = 0;
  59. mBufferContainsEOF = FALSE;
  60. mBuffer = NULL;
  61. mBufferLength = 0;
  62. mBufferStartOffset = 0;
  63. mRetries = 0;
  64. if (chunk_size < 1)
  65. {
  66. chunk_size = LL_XFER_CHUNK_SIZE;
  67. }
  68. mChunkSize = chunk_size;
  69. }
  70. ///////////////////////////////////////////////////////////
  71. void LLXfer::cleanup ()
  72. {
  73. if (mBuffer)
  74. {
  75. delete[] mBuffer;
  76. mBuffer = NULL;
  77. }
  78. }
  79. ///////////////////////////////////////////////////////////
  80. S32 LLXfer::startSend (U64 xfer_id, const LLHost &remote_host)
  81. {
  82. llwarns << "undifferentiated LLXfer::startSend for " << getFileName() << llendl;
  83. return (-1);
  84. }
  85. ///////////////////////////////////////////////////////////
  86. void LLXfer::setXferSize (S32 xfer_size)
  87. {
  88. mXferSize = xfer_size;
  89. // cout << "starting transfer of size: " << xfer_size << endl;
  90. }
  91. ///////////////////////////////////////////////////////////
  92. S32 LLXfer::startDownload()
  93. {
  94. llwarns << "undifferentiated LLXfer::startDownload for " << getFileName()
  95. << llendl;
  96. return (-1);
  97. }
  98. ///////////////////////////////////////////////////////////
  99. S32 LLXfer::receiveData (char *datap, S32 data_size)
  100. {
  101. S32 retval = 0;
  102. if (((S32) mBufferLength + data_size) > getMaxBufferSize())
  103. {
  104. retval = flush();
  105. }
  106. if (!retval)
  107. {
  108. if (datap != NULL)
  109. {
  110. memcpy(&mBuffer[mBufferLength],datap,data_size); /*Flawfinder: ignore*/
  111. mBufferLength += data_size;
  112. }
  113. else
  114. {
  115. llerrs << "NULL data passed in receiveData" << llendl;
  116. }
  117. }
  118. return (retval);
  119. }
  120. ///////////////////////////////////////////////////////////
  121. S32 LLXfer::flush()
  122. {
  123. // only files have somewhere to flush to
  124. // if we get called with a flush it means we've blown past our
  125. // allocated buffer size
  126. return (-1);
  127. }
  128. ///////////////////////////////////////////////////////////
  129. S32 LLXfer::suck(S32 start_position)
  130. {
  131. llwarns << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << llendl;
  132. return (-1);
  133. }
  134. ///////////////////////////////////////////////////////////
  135. void LLXfer::sendPacket(S32 packet_num)
  136. {
  137. char fdata_buf[LL_XFER_LARGE_PAYLOAD+4]; /* Flawfinder: ignore */
  138. S32 fdata_size = mChunkSize;
  139. BOOL last_packet = FALSE;
  140. S32 num_copy = 0;
  141. // if the desired packet is not in our current buffered excerpt from the file. . .
  142. if (((U32)packet_num*fdata_size < mBufferStartOffset)
  143. || ((U32)llmin((U32)mXferSize,(U32)((U32)(packet_num+1)*fdata_size)) > mBufferStartOffset + mBufferLength))
  144. {
  145. if (suck(packet_num*fdata_size)) // returns non-zero on failure
  146. {
  147. abort(LL_ERR_EOF);
  148. return;
  149. }
  150. }
  151. S32 desired_read_position = 0;
  152. desired_read_position = packet_num * fdata_size - mBufferStartOffset;
  153. fdata_size = llmin((S32)mBufferLength-desired_read_position, mChunkSize);
  154. if (fdata_size < 0)
  155. {
  156. llwarns << "negative data size in xfer send, aborting" << llendl;
  157. abort(LL_ERR_EOF);
  158. return;
  159. }
  160. if (((U32)(desired_read_position + fdata_size) >= (U32)mBufferLength) && (mBufferContainsEOF))
  161. {
  162. last_packet = TRUE;
  163. }
  164. if (packet_num)
  165. {
  166. num_copy = llmin(fdata_size, (S32)sizeof(fdata_buf));
  167. num_copy = llmin(num_copy, (S32)(mBufferLength - desired_read_position));
  168. if (num_copy > 0)
  169. {
  170. memcpy(fdata_buf,&mBuffer[desired_read_position],num_copy); /*Flawfinder: ignore*/
  171. }
  172. }
  173. else
  174. {
  175. // if we're the first packet, encode size as an additional S32
  176. // at start of data.
  177. num_copy = llmin(fdata_size, (S32)(sizeof(fdata_buf)-sizeof(S32)));
  178. num_copy = llmin(
  179. num_copy,
  180. (S32)(mBufferLength - desired_read_position));
  181. if (num_copy > 0)
  182. {
  183. memcpy( /*Flawfinder: ignore*/
  184. fdata_buf + sizeof(S32),
  185. &mBuffer[desired_read_position],
  186. num_copy);
  187. }
  188. fdata_size += sizeof(S32);
  189. htonmemcpy(fdata_buf,&mXferSize, MVT_S32, sizeof(S32));
  190. }
  191. S32 encoded_packetnum = encodePacketNum(packet_num,last_packet);
  192. if (fdata_size)
  193. {
  194. // send the packet
  195. gMessageSystem->newMessageFast(_PREHASH_SendXferPacket);
  196. gMessageSystem->nextBlockFast(_PREHASH_XferID);
  197. gMessageSystem->addU64Fast(_PREHASH_ID, mID);
  198. gMessageSystem->addU32Fast(_PREHASH_Packet, encoded_packetnum);
  199. gMessageSystem->nextBlockFast(_PREHASH_DataPacket);
  200. gMessageSystem->addBinaryDataFast(_PREHASH_Data, &fdata_buf,fdata_size);
  201. gMessageSystem->sendMessage(mRemoteHost);
  202. ACKTimer.reset();
  203. mWaitingForACK = TRUE;
  204. }
  205. if (last_packet)
  206. {
  207. mStatus = e_LL_XFER_COMPLETE;
  208. }
  209. else
  210. {
  211. mStatus = e_LL_XFER_IN_PROGRESS;
  212. }
  213. }
  214. ///////////////////////////////////////////////////////////
  215. void LLXfer::sendNextPacket()
  216. {
  217. mRetries = 0;
  218. sendPacket(++mPacketNum);
  219. }
  220. ///////////////////////////////////////////////////////////
  221. void LLXfer::resendLastPacket()
  222. {
  223. mRetries++;
  224. sendPacket(mPacketNum);
  225. }
  226. ///////////////////////////////////////////////////////////
  227. S32 LLXfer::processEOF()
  228. {
  229. S32 retval = 0;
  230. mStatus = e_LL_XFER_COMPLETE;
  231. if (LL_ERR_NOERR == mCallbackResult)
  232. {
  233. llinfos << "xfer from " << mRemoteHost << " complete: " << getFileName()
  234. << llendl;
  235. }
  236. else
  237. {
  238. llinfos << "xfer from " << mRemoteHost << " failed, code "
  239. << mCallbackResult << ": " << getFileName() << llendl;
  240. }
  241. if (mCallback)
  242. {
  243. mCallback(mCallbackDataHandle,mCallbackResult,LL_EXSTAT_NONE);
  244. }
  245. return(retval);
  246. }
  247. ///////////////////////////////////////////////////////////
  248. S32 LLXfer::encodePacketNum(S32 packet_num, BOOL is_EOF)
  249. {
  250. if (is_EOF)
  251. {
  252. packet_num |= 0x80000000;
  253. }
  254. return packet_num;
  255. }
  256. ///////////////////////////////////////////////////////////
  257. void LLXfer::abort (S32 result_code)
  258. {
  259. mCallbackResult = result_code;
  260. llinfos << "Aborting xfer from " << mRemoteHost << " named " << getFileName()
  261. << " - error: " << result_code << llendl;
  262. gMessageSystem->newMessageFast(_PREHASH_AbortXfer);
  263. gMessageSystem->nextBlockFast(_PREHASH_XferID);
  264. gMessageSystem->addU64Fast(_PREHASH_ID, mID);
  265. gMessageSystem->addS32Fast(_PREHASH_Result, result_code);
  266. gMessageSystem->sendMessage(mRemoteHost);
  267. mStatus = e_LL_XFER_ABORTED;
  268. }
  269. ///////////////////////////////////////////////////////////
  270. std::string LLXfer::getFileName()
  271. {
  272. return U64_to_str(mID);
  273. }
  274. ///////////////////////////////////////////////////////////
  275. U32 LLXfer::getXferTypeTag()
  276. {
  277. return 0;
  278. }
  279. ///////////////////////////////////////////////////////////
  280. S32 LLXfer::getMaxBufferSize ()
  281. {
  282. return(mXferSize);
  283. }
  284. std::ostream& operator<< (std::ostream& os, LLXfer &hh)
  285. {
  286. os << hh.getFileName() ;
  287. return os;
  288. }