PageRenderTime 31ms CodeModel.GetById 12ms app.highlight 16ms RepoModel.GetById 1ms 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
  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
 27#include "linden_common.h"
 28
 29#include "llxfer.h"
 30#include "lluuid.h"
 31#include "llerror.h"
 32#include "llmath.h"
 33#include "u64.h"
 34
 35//number of bytes sent in each message
 36const U32 LL_XFER_CHUNK_SIZE = 1000;
 37
 38const U32 LLXfer::XFER_FILE = 1;
 39const U32 LLXfer::XFER_VFILE = 2;
 40const U32 LLXfer::XFER_MEM = 3;
 41
 42///////////////////////////////////////////////////////////
 43
 44LLXfer::LLXfer (S32 chunk_size)
 45{
 46	init(chunk_size);
 47}
 48
 49///////////////////////////////////////////////////////////
 50
 51LLXfer::~LLXfer ()
 52{
 53	cleanup();
 54}
 55
 56///////////////////////////////////////////////////////////
 57
 58void LLXfer::init (S32 chunk_size)
 59{
 60	mID = 0;
 61
 62	mPacketNum = -1; // there's a preincrement before sending the zeroth packet
 63	mXferSize = 0;
 64
 65	mStatus = e_LL_XFER_UNINITIALIZED;
 66	mNext = NULL;
 67	mWaitingForACK = FALSE;
 68	
 69	mCallback = NULL;
 70	mCallbackDataHandle = NULL;
 71	mCallbackResult = 0;
 72
 73	mBufferContainsEOF = FALSE;
 74	mBuffer = NULL;
 75	mBufferLength = 0;
 76	mBufferStartOffset = 0;
 77
 78	mRetries = 0;
 79
 80	if (chunk_size < 1)
 81	{
 82		chunk_size = LL_XFER_CHUNK_SIZE;
 83	}
 84	mChunkSize = chunk_size;
 85}
 86	
 87///////////////////////////////////////////////////////////
 88
 89void LLXfer::cleanup ()
 90{
 91	if (mBuffer)
 92	{
 93		delete[] mBuffer;
 94		mBuffer = NULL;
 95	}
 96}
 97
 98///////////////////////////////////////////////////////////
 99
100S32 LLXfer::startSend (U64 xfer_id, const LLHost &remote_host)
101{
102	llwarns << "undifferentiated LLXfer::startSend for " << getFileName() << llendl;
103	return (-1);
104}
105
106///////////////////////////////////////////////////////////
107
108void LLXfer::setXferSize (S32 xfer_size)
109{	
110	mXferSize = xfer_size;
111//	cout << "starting transfer of size: " << xfer_size << endl;
112}
113
114///////////////////////////////////////////////////////////
115
116S32 LLXfer::startDownload()
117{
118	llwarns << "undifferentiated LLXfer::startDownload for " << getFileName()
119			<< llendl;
120	return (-1);
121}
122
123///////////////////////////////////////////////////////////
124
125S32 LLXfer::receiveData (char *datap, S32 data_size)
126{
127	S32 retval = 0;
128
129	if (((S32) mBufferLength + data_size) > getMaxBufferSize())
130	{
131		retval = flush();
132	}
133
134	if (!retval)
135	{
136		if (datap != NULL)
137		{
138			memcpy(&mBuffer[mBufferLength],datap,data_size);	/*Flawfinder: ignore*/
139			mBufferLength += data_size;
140		}
141		else
142		{
143			llerrs << "NULL data passed in receiveData" << llendl;
144		}
145	}
146
147	return (retval);
148}
149
150///////////////////////////////////////////////////////////
151
152S32 LLXfer::flush()
153{
154	// only files have somewhere to flush to
155	// if we get called with a flush it means we've blown past our
156	// allocated buffer size
157
158	return (-1);
159}
160
161
162///////////////////////////////////////////////////////////
163
164S32 LLXfer::suck(S32 start_position)
165{
166	llwarns << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << llendl;
167	return (-1);
168}
169
170///////////////////////////////////////////////////////////
171
172void LLXfer::sendPacket(S32 packet_num)
173{
174	char fdata_buf[LL_XFER_LARGE_PAYLOAD+4];		/* Flawfinder: ignore */
175	S32 fdata_size = mChunkSize;
176	BOOL last_packet = FALSE;
177	S32 num_copy = 0;
178
179	// if the desired packet is not in our current buffered excerpt from the file. . . 
180	if (((U32)packet_num*fdata_size < mBufferStartOffset) 
181		|| ((U32)llmin((U32)mXferSize,(U32)((U32)(packet_num+1)*fdata_size)) > mBufferStartOffset + mBufferLength))
182	
183	{
184		if (suck(packet_num*fdata_size))  // returns non-zero on failure
185		{
186			abort(LL_ERR_EOF);
187			return;
188		}	
189	}
190		
191	S32 desired_read_position = 0;
192		
193	desired_read_position = packet_num * fdata_size - mBufferStartOffset;
194	
195	fdata_size = llmin((S32)mBufferLength-desired_read_position, mChunkSize);
196
197	if (fdata_size < 0)
198	{
199		llwarns << "negative data size in xfer send, aborting" << llendl;
200		abort(LL_ERR_EOF);
201		return;
202	}
203
204	if (((U32)(desired_read_position + fdata_size) >= (U32)mBufferLength) && (mBufferContainsEOF))
205	{
206		last_packet = TRUE;
207	}
208		
209	if (packet_num)
210	{ 
211		num_copy = llmin(fdata_size, (S32)sizeof(fdata_buf));
212		num_copy = llmin(num_copy, (S32)(mBufferLength - desired_read_position));
213		if (num_copy > 0)
214		{
215			memcpy(fdata_buf,&mBuffer[desired_read_position],num_copy);	/*Flawfinder: ignore*/
216		}
217	}
218	else  
219	{
220		// if we're the first packet, encode size as an additional S32
221		// at start of data.
222		num_copy = llmin(fdata_size, (S32)(sizeof(fdata_buf)-sizeof(S32)));
223		num_copy = llmin(
224			num_copy,
225			(S32)(mBufferLength - desired_read_position));
226		if (num_copy > 0)
227		{
228			memcpy(	/*Flawfinder: ignore*/
229				fdata_buf + sizeof(S32),
230				&mBuffer[desired_read_position],
231				num_copy);
232		}
233		fdata_size += sizeof(S32);
234		htonmemcpy(fdata_buf,&mXferSize, MVT_S32, sizeof(S32));
235	}
236
237	S32 encoded_packetnum = encodePacketNum(packet_num,last_packet);
238		
239	if (fdata_size)
240	{
241		// send the packet 
242		gMessageSystem->newMessageFast(_PREHASH_SendXferPacket);
243		gMessageSystem->nextBlockFast(_PREHASH_XferID);
244		
245		gMessageSystem->addU64Fast(_PREHASH_ID, mID);
246		gMessageSystem->addU32Fast(_PREHASH_Packet, encoded_packetnum);
247		
248		gMessageSystem->nextBlockFast(_PREHASH_DataPacket);
249		gMessageSystem->addBinaryDataFast(_PREHASH_Data, &fdata_buf,fdata_size);
250			
251		gMessageSystem->sendMessage(mRemoteHost);
252
253		ACKTimer.reset();
254		mWaitingForACK = TRUE;
255	}
256	if (last_packet)
257	{
258		mStatus = e_LL_XFER_COMPLETE;	
259	}
260	else
261	{
262		mStatus = e_LL_XFER_IN_PROGRESS;
263	}
264}
265
266///////////////////////////////////////////////////////////
267
268void LLXfer::sendNextPacket()
269{
270	mRetries = 0;
271	sendPacket(++mPacketNum);
272}
273
274///////////////////////////////////////////////////////////
275
276void LLXfer::resendLastPacket()
277{
278	mRetries++;
279	sendPacket(mPacketNum);
280}
281
282///////////////////////////////////////////////////////////
283
284S32 LLXfer::processEOF()
285{
286	S32 retval = 0;
287
288	mStatus = e_LL_XFER_COMPLETE;
289
290	if (LL_ERR_NOERR == mCallbackResult)
291	{
292		llinfos << "xfer from " << mRemoteHost << " complete: " << getFileName()
293				<< llendl;
294	}
295	else
296	{
297		llinfos << "xfer from " << mRemoteHost << " failed, code "
298				<< mCallbackResult << ": " << getFileName() << llendl;
299	}
300
301	if (mCallback)
302	{
303		mCallback(mCallbackDataHandle,mCallbackResult,LL_EXSTAT_NONE);
304	}
305
306	return(retval);
307}
308
309///////////////////////////////////////////////////////////
310
311S32 LLXfer::encodePacketNum(S32 packet_num, BOOL is_EOF)
312{
313	if (is_EOF)
314	{
315		packet_num |= 0x80000000;
316	}
317	return packet_num;
318}
319
320///////////////////////////////////////////////////////////
321
322void LLXfer::abort (S32 result_code)
323{
324	mCallbackResult = result_code;
325
326	llinfos << "Aborting xfer from " << mRemoteHost << " named " << getFileName()
327			<< " - error: " << result_code << llendl;
328
329	gMessageSystem->newMessageFast(_PREHASH_AbortXfer);
330	gMessageSystem->nextBlockFast(_PREHASH_XferID);
331	gMessageSystem->addU64Fast(_PREHASH_ID, mID);
332	gMessageSystem->addS32Fast(_PREHASH_Result, result_code);
333	
334	gMessageSystem->sendMessage(mRemoteHost);
335
336	mStatus = e_LL_XFER_ABORTED;
337}
338
339
340///////////////////////////////////////////////////////////
341
342std::string LLXfer::getFileName() 
343{
344	return U64_to_str(mID);
345}
346
347///////////////////////////////////////////////////////////
348
349U32 LLXfer::getXferTypeTag()
350{
351	return 0;
352}
353
354///////////////////////////////////////////////////////////
355
356S32 LLXfer::getMaxBufferSize ()
357{
358	return(mXferSize);
359}
360
361
362std::ostream& operator<< (std::ostream& os, LLXfer &hh)
363{
364	os << hh.getFileName() ;
365	return os;
366}
367
368
369
370
371
372
373
374
375