PageRenderTime 42ms CodeModel.GetById 20ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/llpacketring.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 372 lines | 261 code | 51 blank | 60 comment | 29 complexity | d7104c5355757fffdfc464539c2d67d2 MD5 | raw file
  1/** 
  2 * @file llpacketring.cpp
  3 * @brief implementation of LLPacketRing class for a packet.
  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 "llpacketring.h"
 30
 31#if LL_WINDOWS
 32	#include <winsock2.h>
 33#else
 34	#include <sys/socket.h>
 35	#include <netinet/in.h>
 36#endif
 37
 38// linden library includes
 39#include "llerror.h"
 40#include "lltimer.h"
 41#include "llproxy.h"
 42#include "llrand.h"
 43#include "message.h"
 44#include "timing.h"
 45#include "u64.h"
 46
 47///////////////////////////////////////////////////////////
 48LLPacketRing::LLPacketRing () :
 49	mUseInThrottle(FALSE),
 50	mUseOutThrottle(FALSE),
 51	mInThrottle(256000.f),
 52	mOutThrottle(64000.f),
 53	mActualBitsIn(0),
 54	mActualBitsOut(0),
 55	mMaxBufferLength(64000),
 56	mInBufferLength(0),
 57	mOutBufferLength(0),
 58	mDropPercentage(0.0f),
 59	mPacketsToDrop(0x0)
 60{
 61}
 62
 63///////////////////////////////////////////////////////////
 64LLPacketRing::~LLPacketRing ()
 65{
 66	cleanup();
 67}
 68	
 69///////////////////////////////////////////////////////////
 70void LLPacketRing::cleanup ()
 71{
 72	LLPacketBuffer *packetp;
 73
 74	while (!mReceiveQueue.empty())
 75	{
 76		packetp = mReceiveQueue.front();
 77		delete packetp;
 78		mReceiveQueue.pop();
 79	}
 80
 81	while (!mSendQueue.empty())
 82	{
 83		packetp = mSendQueue.front();
 84		delete packetp;
 85		mSendQueue.pop();
 86	}
 87}
 88
 89///////////////////////////////////////////////////////////
 90void LLPacketRing::dropPackets (U32 num_to_drop)
 91{
 92	mPacketsToDrop += num_to_drop;
 93}
 94
 95///////////////////////////////////////////////////////////
 96void LLPacketRing::setDropPercentage (F32 percent_to_drop)
 97{
 98	mDropPercentage = percent_to_drop;
 99}
100
101void LLPacketRing::setUseInThrottle(const BOOL use_throttle)
102{
103	mUseInThrottle = use_throttle;
104}
105
106void LLPacketRing::setUseOutThrottle(const BOOL use_throttle)
107{
108	mUseOutThrottle = use_throttle;
109}
110
111void LLPacketRing::setInBandwidth(const F32 bps)
112{
113	mInThrottle.setRate(bps);
114}
115
116void LLPacketRing::setOutBandwidth(const F32 bps)
117{
118	mOutThrottle.setRate(bps);
119}
120///////////////////////////////////////////////////////////
121S32 LLPacketRing::receiveFromRing (S32 socket, char *datap)
122{
123
124	if (mInThrottle.checkOverflow(0))
125	{
126		// We don't have enough bandwidth, don't give them a packet.
127		return 0;
128	}
129
130	LLPacketBuffer *packetp = NULL;
131	if (mReceiveQueue.empty())
132	{
133		// No packets on the queue, don't give them any.
134		return 0;
135	}
136
137	S32 packet_size = 0;
138	packetp = mReceiveQueue.front();
139	mReceiveQueue.pop();
140	packet_size = packetp->getSize();
141	if (packetp->getData() != NULL)
142	{
143		memcpy(datap, packetp->getData(), packet_size);	/*Flawfinder: ignore*/
144	}
145	// need to set sender IP/port!!
146	mLastSender = packetp->getHost();
147	mLastReceivingIF = packetp->getReceivingInterface();
148	delete packetp;
149
150	this->mInBufferLength -= packet_size;
151
152	// Adjust the throttle
153	mInThrottle.throttleOverflow(packet_size * 8.f);
154	return packet_size;
155}
156
157///////////////////////////////////////////////////////////
158S32 LLPacketRing::receivePacket (S32 socket, char *datap)
159{
160	S32 packet_size = 0;
161
162	// If using the throttle, simulate a limited size input buffer.
163	if (mUseInThrottle)
164	{
165		BOOL done = FALSE;
166
167		// push any current net packet (if any) onto delay ring
168		while (!done)
169		{
170			LLPacketBuffer *packetp;
171			packetp = new LLPacketBuffer(socket);
172
173			if (packetp->getSize())
174			{
175				mActualBitsIn += packetp->getSize() * 8;
176
177				// Fake packet loss
178				if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
179				{
180					mPacketsToDrop++;
181				}
182
183				if (mPacketsToDrop)
184				{
185					delete packetp;
186					packetp = NULL;
187					packet_size = 0;
188					mPacketsToDrop--;
189				}
190			}
191
192			// If we faked packet loss, then we don't have a packet
193			// to use for buffer overflow testing
194			if (packetp)
195			{
196				if (mInBufferLength + packetp->getSize() > mMaxBufferLength)
197				{
198					// Toss it.
199					llwarns << "Throwing away packet, overflowing buffer" << llendl;
200					delete packetp;
201					packetp = NULL;
202				}
203				else if (packetp->getSize())
204				{
205					mReceiveQueue.push(packetp);
206					mInBufferLength += packetp->getSize();
207				}
208				else
209				{
210					delete packetp;
211					packetp = NULL;
212					done = true;
213				}
214			}
215			else
216			{
217				// No packetp, keep going? - no packetp == faked packet loss
218			}
219		}
220
221		// Now, grab data off of the receive queue according to our
222		// throttled bandwidth settings.
223		packet_size = receiveFromRing(socket, datap);
224	}
225	else
226	{
227		// no delay, pull straight from net
228		if (LLProxy::isSOCKSProxyEnabled())
229		{
230			U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
231			packet_size = receive_packet(socket, static_cast<char*>(static_cast<void*>(buffer)));
232			
233			if (packet_size > SOCKS_HEADER_SIZE)
234			{
235				// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
236				memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE);
237				proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
238				mLastSender.setAddress(header->addr);
239				mLastSender.setPort(ntohs(header->port));
240
241				packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
242			}
243			else
244			{
245				packet_size = 0;
246			}
247		}
248		else
249		{
250			packet_size = receive_packet(socket, datap);
251			mLastSender = ::get_sender();
252		}
253
254		mLastReceivingIF = ::get_receiving_interface();
255
256		if (packet_size)  // did we actually get a packet?
257		{
258			if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
259			{
260				mPacketsToDrop++;
261			}
262
263			if (mPacketsToDrop)
264			{
265				packet_size = 0;
266				mPacketsToDrop--;
267			}
268		}
269	}
270
271	return packet_size;
272}
273
274BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host)
275{
276	BOOL status = TRUE;
277	if (!mUseOutThrottle)
278	{
279		return sendPacketImpl(h_socket, send_buffer, buf_size, host );
280	}
281	else
282	{
283		mActualBitsOut += buf_size * 8;
284		LLPacketBuffer *packetp = NULL;
285		// See if we've got enough throttle to send a packet.
286		while (!mOutThrottle.checkOverflow(0.f))
287		{
288			// While we have enough bandwidth, send a packet from the queue or the current packet
289
290			S32 packet_size = 0;
291			if (!mSendQueue.empty())
292			{
293				// Send a packet off of the queue
294				LLPacketBuffer *packetp = mSendQueue.front();
295				mSendQueue.pop();
296
297				mOutBufferLength -= packetp->getSize();
298				packet_size = packetp->getSize();
299
300				status = sendPacketImpl(h_socket, packetp->getData(), packet_size, packetp->getHost());
301				
302				delete packetp;
303				// Update the throttle
304				mOutThrottle.throttleOverflow(packet_size * 8.f);
305			}
306			else
307			{
308				// If the queue's empty, we can just send this packet right away.
309				status =  sendPacketImpl(h_socket, send_buffer, buf_size, host );
310				packet_size = buf_size;
311
312				// Update the throttle
313				mOutThrottle.throttleOverflow(packet_size * 8.f);
314
315				// This was the packet we're sending now, there are no other packets
316				// that we need to send
317				return status;
318			}
319
320		}
321
322		// We haven't sent the incoming packet, add it to the queue
323		if (mOutBufferLength + buf_size > mMaxBufferLength)
324		{
325			// Nuke this packet, we overflowed the buffer.
326			// Toss it.
327			llwarns << "Throwing away outbound packet, overflowing buffer" << llendl;
328		}
329		else
330		{
331			static LLTimer queue_timer;
332			if ((mOutBufferLength > 4192) && queue_timer.getElapsedTimeF32() > 1.f)
333			{
334				// Add it to the queue
335				llinfos << "Outbound packet queue " << mOutBufferLength << " bytes" << llendl;
336				queue_timer.reset();
337			}
338			packetp = new LLPacketBuffer(host, send_buffer, buf_size);
339
340			mOutBufferLength += packetp->getSize();
341			mSendQueue.push(packetp);
342		}
343	}
344
345	return status;
346}
347
348BOOL LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host)
349{
350	
351	if (!LLProxy::isSOCKSProxyEnabled())
352	{
353		return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());
354	}
355
356	char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
357
358	proxywrap_t *socks_header = static_cast<proxywrap_t*>(static_cast<void*>(&headered_send_buffer));
359	socks_header->rsv   = 0;
360	socks_header->addr  = host.getAddress();
361	socks_header->port  = htons(host.getPort());
362	socks_header->atype = ADDRESS_IPV4;
363	socks_header->frag  = 0;
364
365	memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, send_buffer, buf_size);
366
367	return send_packet(	h_socket,
368						headered_send_buffer,
369						buf_size + SOCKS_HEADER_SIZE,
370						LLProxy::getInstance()->getUDPProxy().getAddress(),
371						LLProxy::getInstance()->getUDPProxy().getPort());
372}