Imported existing code
This commit is contained in:
366
indra/llmessage/llpacketring.cpp
Normal file
366
indra/llmessage/llpacketring.cpp
Normal file
@@ -0,0 +1,366 @@
|
||||
/**
|
||||
* @file llpacketring.cpp
|
||||
* @brief implementation of LLPacketRing class for a packet.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llpacketring.h"
|
||||
|
||||
// linden library includes
|
||||
#include "llerror.h"
|
||||
#include "lltimer.h"
|
||||
#include "timing.h"
|
||||
#include "llrand.h"
|
||||
#include "u64.h"
|
||||
|
||||
#include "llsocks5.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
LLPacketRing::LLPacketRing () :
|
||||
mUseInThrottle(FALSE),
|
||||
mUseOutThrottle(FALSE),
|
||||
mInThrottle(256000.f),
|
||||
mOutThrottle(64000.f),
|
||||
mActualBitsIn(0),
|
||||
mActualBitsOut(0),
|
||||
mMaxBufferLength(64000),
|
||||
mInBufferLength(0),
|
||||
mOutBufferLength(0),
|
||||
mDropPercentage(0.0f),
|
||||
mPacketsToDrop(0x0)
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
LLPacketRing::~LLPacketRing ()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
void LLPacketRing::cleanup ()
|
||||
{
|
||||
LLPacketBuffer *packetp;
|
||||
|
||||
while (!mReceiveQueue.empty())
|
||||
{
|
||||
packetp = mReceiveQueue.front();
|
||||
delete packetp;
|
||||
mReceiveQueue.pop();
|
||||
}
|
||||
|
||||
while (!mSendQueue.empty())
|
||||
{
|
||||
packetp = mSendQueue.front();
|
||||
delete packetp;
|
||||
mSendQueue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
void LLPacketRing::dropPackets (U32 num_to_drop)
|
||||
{
|
||||
mPacketsToDrop += num_to_drop;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
void LLPacketRing::setDropPercentage (F32 percent_to_drop)
|
||||
{
|
||||
mDropPercentage = percent_to_drop;
|
||||
}
|
||||
|
||||
void LLPacketRing::setUseInThrottle(const BOOL use_throttle)
|
||||
{
|
||||
mUseInThrottle = use_throttle;
|
||||
}
|
||||
|
||||
void LLPacketRing::setUseOutThrottle(const BOOL use_throttle)
|
||||
{
|
||||
mUseOutThrottle = use_throttle;
|
||||
}
|
||||
|
||||
void LLPacketRing::setInBandwidth(const F32 bps)
|
||||
{
|
||||
mInThrottle.setRate(bps);
|
||||
}
|
||||
|
||||
void LLPacketRing::setOutBandwidth(const F32 bps)
|
||||
{
|
||||
mOutThrottle.setRate(bps);
|
||||
}
|
||||
///////////////////////////////////////////////////////////
|
||||
S32 LLPacketRing::receiveFromRing (S32 socket, char *datap)
|
||||
{
|
||||
|
||||
if (mInThrottle.checkOverflow(0))
|
||||
{
|
||||
// We don't have enough bandwidth, don't give them a packet.
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLPacketBuffer *packetp = NULL;
|
||||
if (mReceiveQueue.empty())
|
||||
{
|
||||
// No packets on the queue, don't give them any.
|
||||
return 0;
|
||||
}
|
||||
|
||||
S32 packet_size = 0;
|
||||
packetp = mReceiveQueue.front();
|
||||
mReceiveQueue.pop();
|
||||
packet_size = packetp->getSize();
|
||||
if (packetp->getData() != NULL)
|
||||
{
|
||||
memcpy(datap, packetp->getData(), packet_size); /*Flawfinder: ignore*/
|
||||
}
|
||||
// need to set sender IP/port!!
|
||||
mLastSender = packetp->getHost();
|
||||
mLastReceivingIF = packetp->getReceivingInterface();
|
||||
delete packetp;
|
||||
|
||||
this->mInBufferLength -= packet_size;
|
||||
|
||||
// Adjust the throttle
|
||||
mInThrottle.throttleOverflow(packet_size * 8.f);
|
||||
return packet_size;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
S32 LLPacketRing::receivePacket (S32 socket, char *datap)
|
||||
{
|
||||
S32 packet_size = 0;
|
||||
|
||||
// If using the throttle, simulate a limited size input buffer.
|
||||
if (mUseInThrottle)
|
||||
{
|
||||
BOOL done = FALSE;
|
||||
|
||||
// push any current net packet (if any) onto delay ring
|
||||
while (!done)
|
||||
{
|
||||
LLPacketBuffer *packetp;
|
||||
packetp = new LLPacketBuffer(socket);
|
||||
|
||||
if (packetp->getSize())
|
||||
{
|
||||
mActualBitsIn += packetp->getSize() * 8;
|
||||
|
||||
// Fake packet loss
|
||||
if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
|
||||
{
|
||||
mPacketsToDrop++;
|
||||
}
|
||||
|
||||
if (mPacketsToDrop)
|
||||
{
|
||||
delete packetp;
|
||||
packetp = NULL;
|
||||
packet_size = 0;
|
||||
mPacketsToDrop--;
|
||||
}
|
||||
}
|
||||
|
||||
// If we faked packet loss, then we don't have a packet
|
||||
// to use for buffer overflow testing
|
||||
if (packetp)
|
||||
{
|
||||
if (mInBufferLength + packetp->getSize() > mMaxBufferLength)
|
||||
{
|
||||
// Toss it.
|
||||
llwarns << "Throwing away packet, overflowing buffer" << llendl;
|
||||
delete packetp;
|
||||
packetp = NULL;
|
||||
}
|
||||
else if (packetp->getSize())
|
||||
{
|
||||
mReceiveQueue.push(packetp);
|
||||
mInBufferLength += packetp->getSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete packetp;
|
||||
packetp = NULL;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No packetp, keep going? - no packetp == faked packet loss
|
||||
}
|
||||
}
|
||||
|
||||
// Now, grab data off of the receive queue according to our
|
||||
// throttled bandwidth settings.
|
||||
packet_size = receiveFromRing(socket, datap);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no delay, pull straight from net
|
||||
if (LLSocks::isEnabled())
|
||||
{
|
||||
proxywrap_t * header;
|
||||
datap = datap-10;
|
||||
header = (proxywrap_t *)datap;
|
||||
packet_size = receive_packet(socket, datap);
|
||||
mLastSender.setAddress(header->addr);
|
||||
mLastSender.setPort(ntohs(header->port));
|
||||
if (packet_size > 10)
|
||||
{
|
||||
packet_size -= 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
packet_size = receive_packet(socket, datap);
|
||||
mLastSender = ::get_sender();
|
||||
}
|
||||
|
||||
mLastReceivingIF = ::get_receiving_interface();
|
||||
|
||||
if (packet_size) // did we actually get a packet?
|
||||
{
|
||||
if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
|
||||
{
|
||||
mPacketsToDrop++;
|
||||
}
|
||||
|
||||
if (mPacketsToDrop)
|
||||
{
|
||||
packet_size = 0;
|
||||
mPacketsToDrop--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return packet_size;
|
||||
}
|
||||
|
||||
BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host)
|
||||
{
|
||||
BOOL status = TRUE;
|
||||
if (!mUseOutThrottle)
|
||||
{
|
||||
return doSendPacket(h_socket, send_buffer, buf_size, host );
|
||||
}
|
||||
else
|
||||
{
|
||||
mActualBitsOut += buf_size * 8;
|
||||
LLPacketBuffer *packetp = NULL;
|
||||
// See if we've got enough throttle to send a packet.
|
||||
while (!mOutThrottle.checkOverflow(0.f))
|
||||
{
|
||||
// While we have enough bandwidth, send a packet from the queue or the current packet
|
||||
|
||||
S32 packet_size = 0;
|
||||
if (!mSendQueue.empty())
|
||||
{
|
||||
// Send a packet off of the queue
|
||||
LLPacketBuffer *packetp = mSendQueue.front();
|
||||
mSendQueue.pop();
|
||||
|
||||
mOutBufferLength -= packetp->getSize();
|
||||
packet_size = packetp->getSize();
|
||||
|
||||
status = doSendPacket(h_socket, packetp->getData(), packet_size, packetp->getHost());
|
||||
|
||||
delete packetp;
|
||||
// Update the throttle
|
||||
mOutThrottle.throttleOverflow(packet_size * 8.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the queue's empty, we can just send this packet right away.
|
||||
status = doSendPacket(h_socket, send_buffer, buf_size, host );
|
||||
packet_size = buf_size;
|
||||
|
||||
// Update the throttle
|
||||
mOutThrottle.throttleOverflow(packet_size * 8.f);
|
||||
|
||||
// This was the packet we're sending now, there are no other packets
|
||||
// that we need to send
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We haven't sent the incoming packet, add it to the queue
|
||||
if (mOutBufferLength + buf_size > mMaxBufferLength)
|
||||
{
|
||||
// Nuke this packet, we overflowed the buffer.
|
||||
// Toss it.
|
||||
llwarns << "Throwing away outbound packet, overflowing buffer" << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
static LLTimer queue_timer;
|
||||
if ((mOutBufferLength > 4192) && queue_timer.getElapsedTimeF32() > 1.f)
|
||||
{
|
||||
// Add it to the queue
|
||||
llinfos << "Outbound packet queue " << mOutBufferLength << " bytes" << llendl;
|
||||
queue_timer.reset();
|
||||
}
|
||||
packetp = new LLPacketBuffer(host, send_buffer, buf_size);
|
||||
|
||||
mOutBufferLength += packetp->getSize();
|
||||
mSendQueue.push(packetp);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BOOL LLPacketRing::doSendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host)
|
||||
{
|
||||
|
||||
if (!LLSocks::isEnabled())
|
||||
{
|
||||
return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());
|
||||
}
|
||||
|
||||
proxywrap_t *socks_header = (proxywrap_t *)&mProxyWrappedSendBuffer;
|
||||
socks_header->rsv = 0;
|
||||
socks_header->addr = host.getAddress();
|
||||
socks_header->port = htons(host.getPort());
|
||||
socks_header->atype = ADDRESS_IPV4;
|
||||
socks_header->frag = 0;
|
||||
|
||||
memcpy(mProxyWrappedSendBuffer+10, send_buffer, buf_size);
|
||||
|
||||
return send_packet(h_socket,(const char*) mProxyWrappedSendBuffer, buf_size+10, LLSocks::getInstance()->getUDPPproxy().getAddress(), LLSocks::getInstance()->getUDPPproxy().getPort());
|
||||
}
|
||||
Reference in New Issue
Block a user