diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llmessage/llxfer.cpp | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llxfer.cpp b/linden/indra/llmessage/llxfer.cpp new file mode 100644 index 0000000..f02d106 --- /dev/null +++ b/linden/indra/llmessage/llxfer.cpp | |||
@@ -0,0 +1,376 @@ | |||
1 | /** | ||
2 | * @file llxfer.cpp | ||
3 | * @brief implementation of LLXfer class for a single xfer. | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | #include "llxfer.h" | ||
31 | #include "lluuid.h" | ||
32 | #include "llerror.h" | ||
33 | #include "llmath.h" | ||
34 | #include "u64.h" | ||
35 | |||
36 | //number of bytes sent in each message | ||
37 | const U32 LL_XFER_CHUNK_SIZE = 1000; | ||
38 | |||
39 | const U32 LLXfer::XFER_FILE = 1; | ||
40 | const U32 LLXfer::XFER_VFILE = 2; | ||
41 | const U32 LLXfer::XFER_MEM = 3; | ||
42 | |||
43 | /////////////////////////////////////////////////////////// | ||
44 | |||
45 | LLXfer::LLXfer (S32 chunk_size) | ||
46 | { | ||
47 | init(chunk_size); | ||
48 | } | ||
49 | |||
50 | /////////////////////////////////////////////////////////// | ||
51 | |||
52 | LLXfer::~LLXfer () | ||
53 | { | ||
54 | free(); | ||
55 | } | ||
56 | |||
57 | /////////////////////////////////////////////////////////// | ||
58 | |||
59 | void LLXfer::init (S32 chunk_size) | ||
60 | { | ||
61 | mID = 0; | ||
62 | |||
63 | mPacketNum = -1; // there's a preincrement before sending the zeroth packet | ||
64 | mXferSize = 0; | ||
65 | |||
66 | mStatus = e_LL_XFER_UNINITIALIZED; | ||
67 | mNext = NULL; | ||
68 | mWaitingForACK = FALSE; | ||
69 | |||
70 | mCallback = NULL; | ||
71 | mCallbackDataHandle = NULL; | ||
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 | |||
89 | void LLXfer::free () | ||
90 | { | ||
91 | if (mBuffer) | ||
92 | { | ||
93 | delete[] mBuffer; | ||
94 | mBuffer = NULL; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /////////////////////////////////////////////////////////// | ||
99 | |||
100 | S32 LLXfer::startSend (U64 xfer_id, const LLHost &remote_host) | ||
101 | { | ||
102 | llwarns << "undifferentiated LLXfer::startSend for " << getName() << llendl; | ||
103 | return (-1); | ||
104 | } | ||
105 | |||
106 | /////////////////////////////////////////////////////////// | ||
107 | |||
108 | void LLXfer::setXferSize (S32 xfer_size) | ||
109 | { | ||
110 | mXferSize = xfer_size; | ||
111 | // cout << "starting transfer of size: " << xfer_size << endl; | ||
112 | } | ||
113 | |||
114 | /////////////////////////////////////////////////////////// | ||
115 | |||
116 | S32 LLXfer::startDownload() | ||
117 | { | ||
118 | llwarns << "undifferentiated LLXfer::startDownload for " << getName() | ||
119 | << llendl; | ||
120 | return (-1); | ||
121 | } | ||
122 | |||
123 | /////////////////////////////////////////////////////////// | ||
124 | |||
125 | S32 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); | ||
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 | |||
152 | S32 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 | |||
164 | S32 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 | |||
172 | void 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); | ||
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( | ||
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 | |||
268 | void LLXfer::sendNextPacket() | ||
269 | { | ||
270 | mRetries = 0; | ||
271 | sendPacket(++mPacketNum); | ||
272 | } | ||
273 | |||
274 | /////////////////////////////////////////////////////////// | ||
275 | |||
276 | void LLXfer::resendLastPacket() | ||
277 | { | ||
278 | mRetries++; | ||
279 | sendPacket(mPacketNum); | ||
280 | } | ||
281 | |||
282 | /////////////////////////////////////////////////////////// | ||
283 | |||
284 | S32 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: " << getName() | ||
293 | << llendl; | ||
294 | } | ||
295 | else | ||
296 | { | ||
297 | llinfos << "xfer from " << mRemoteHost << " failed, code " | ||
298 | << mCallbackResult << ": " << getName() << llendl; | ||
299 | } | ||
300 | |||
301 | if (mCallback) | ||
302 | { | ||
303 | mCallback(mCallbackDataHandle,mCallbackResult); | ||
304 | } | ||
305 | |||
306 | return(retval); | ||
307 | } | ||
308 | |||
309 | /////////////////////////////////////////////////////////// | ||
310 | |||
311 | S32 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 | |||
322 | void LLXfer::abort (S32 result_code) | ||
323 | { | ||
324 | mCallbackResult = result_code; | ||
325 | |||
326 | llinfos << "Aborting xfer from " << mRemoteHost << " named " << getName() | ||
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 | |||
342 | const char * LLXfer::getName() | ||
343 | { | ||
344 | static char tmp_str[256]; /* Flawfinder: ignore */ | ||
345 | |||
346 | return (U64_to_str(mID, tmp_str, sizeof(tmp_str))); | ||
347 | } | ||
348 | |||
349 | /////////////////////////////////////////////////////////// | ||
350 | |||
351 | U32 LLXfer::getXferTypeTag() | ||
352 | { | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | /////////////////////////////////////////////////////////// | ||
357 | |||
358 | S32 LLXfer::getMaxBufferSize () | ||
359 | { | ||
360 | return(mXferSize); | ||
361 | } | ||
362 | |||
363 | |||
364 | std::ostream& operator<< (std::ostream& os, LLXfer &hh) | ||
365 | { | ||
366 | os << hh.getName() ; | ||
367 | return os; | ||
368 | } | ||
369 | |||
370 | |||
371 | |||
372 | |||
373 | |||
374 | |||
375 | |||
376 | |||