* Moved more of the login code out of the client and in to the library
* Packet ACKs are sent automatically now * Converting more pointers to boost::shared_ptr objects * Completely redesigned Packet class * PacketBuilder files containing packet construction functions * Fixed a few of the naming inconsistencies * test_app is currently dumping real estate sales data git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@12 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
7
Jamfile
7
Jamfile
@@ -8,6 +8,7 @@ lib libcrypto : : <name>crypto ;
|
||||
lib libsocket : : <name>socket ;
|
||||
lib libnsl : : <name>nsl ;
|
||||
lib boostthread : : <name>boost_thread ;
|
||||
lib libcurl : : <name>curl ;
|
||||
|
||||
if $(UNIX)
|
||||
{
|
||||
@@ -21,12 +22,14 @@ if $(UNIX)
|
||||
}
|
||||
|
||||
lib secondlife
|
||||
: [ glob src/*.cpp ]
|
||||
openssl
|
||||
: [ glob src/*.cpp ]
|
||||
openssl
|
||||
libcrypto
|
||||
libcurl
|
||||
boostthread
|
||||
$(SOCKET_LIBS)
|
||||
: <threading>multi
|
||||
<variant>debug:<define>DEBUG
|
||||
;
|
||||
|
||||
build-project test_app ;
|
||||
|
||||
317
include/Fields.h
Normal file
317
include/Fields.h
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright (c) 2006, Second Life Reverse Engineering Team
|
||||
* All rights reserved.
|
||||
*
|
||||
* - Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Second Life Reverse Engineering Team nor the names
|
||||
* of its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SL_FIELDS_
|
||||
#define _SL_FIELDS_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
namespace types
|
||||
{
|
||||
enum Type {
|
||||
Invalid = -1,
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
S8,
|
||||
S16,
|
||||
S32,
|
||||
S64,
|
||||
F32,
|
||||
F64,
|
||||
LLUUID,
|
||||
Bool,
|
||||
LLVector3,
|
||||
LLVector3d,
|
||||
LLVector4,
|
||||
LLQuaternion,
|
||||
IPADDR,
|
||||
IPPORT,
|
||||
Variable,
|
||||
Fixed,
|
||||
Single,
|
||||
Multiple
|
||||
};
|
||||
};
|
||||
|
||||
namespace frequencies
|
||||
{
|
||||
enum Frequency {
|
||||
Invalid = 0,
|
||||
Low,
|
||||
Medium,
|
||||
High
|
||||
};
|
||||
};
|
||||
|
||||
// This will be phased out in time
|
||||
struct SimpleLLUUID {
|
||||
byte data[16];
|
||||
SimpleLLUUID() { *this = 0; };
|
||||
SimpleLLUUID(std::string p) { hexstr2bin(packUUID(p).c_str(), data, 16); };
|
||||
SimpleLLUUID(const int p) { for (size_t i = 0; i < 16; i++) { data[i] = (byte)p; } };
|
||||
SimpleLLUUID operator=(const int p) { for (size_t i = 0; i < 16; i++) { data[i] = (byte)p; } return *this; };
|
||||
SimpleLLUUID operator=(SimpleLLUUID p) { memcpy(data, p.data, 16); return *this; };
|
||||
SimpleLLUUID operator=(std::string p) { hexstr2bin(packUUID(p).c_str(), data, 16); return *this; };
|
||||
};
|
||||
|
||||
/*
|
||||
typedef struct llVector3 {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} llVector3;
|
||||
|
||||
typedef struct llVector3d {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} llVector3d;
|
||||
|
||||
typedef struct llQuaternion {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float s;
|
||||
} llQuaternion;
|
||||
|
||||
#define llVector4 llQuaternion
|
||||
*/
|
||||
|
||||
// Use a void pointer for the field since it is of varying type
|
||||
typedef boost::shared_ptr<void> FieldPtr;
|
||||
|
||||
class Field
|
||||
{
|
||||
public:
|
||||
types::Type type;
|
||||
|
||||
Field() { type = types::Invalid; };
|
||||
};
|
||||
|
||||
class U8 : public Field
|
||||
{
|
||||
public:
|
||||
byte data;
|
||||
|
||||
U8(byte* _data) { type = types::U8; data = *(byte*)_data; };
|
||||
};
|
||||
|
||||
class U16 : Field
|
||||
{
|
||||
public:
|
||||
unsigned short data;
|
||||
|
||||
U16(byte* _data) { type = types::U16; data = *(unsigned short*)_data; };
|
||||
};
|
||||
|
||||
class U32 : Field
|
||||
{
|
||||
public:
|
||||
unsigned int data;
|
||||
|
||||
U32(byte* _data) { type = types::U32; data = *(unsigned int*)_data; };
|
||||
};
|
||||
|
||||
class U64_ : Field
|
||||
{
|
||||
public:
|
||||
unsigned long long data:64;
|
||||
|
||||
U64_(byte* _data) { type = types::U64; data = *(unsigned long long int*)_data; };
|
||||
};
|
||||
|
||||
class S8 : Field
|
||||
{
|
||||
public:
|
||||
char data;
|
||||
|
||||
S8(byte* _data) { type = types::S8; data = *(char*)_data; };
|
||||
};
|
||||
|
||||
class S16 : Field
|
||||
{
|
||||
public:
|
||||
short data;
|
||||
|
||||
S16(byte* _data) { type = types::S16; data = *(short*)_data; };
|
||||
};
|
||||
|
||||
class S32 : Field
|
||||
{
|
||||
public:
|
||||
int data;
|
||||
|
||||
S32(byte* _data) { type = types::S32; data = *(int*)_data; };
|
||||
};
|
||||
|
||||
class S64 : Field
|
||||
{
|
||||
public:
|
||||
long long int data:64;
|
||||
|
||||
S64(byte* _data) { type = types::S64; data = *(long long int*)_data; };
|
||||
};
|
||||
|
||||
class F32 : Field
|
||||
{
|
||||
public:
|
||||
float data;
|
||||
|
||||
F32(byte* _data) { type = types::F32; data = *(float*)_data; };
|
||||
};
|
||||
|
||||
class F64 : Field
|
||||
{
|
||||
public:
|
||||
double data;
|
||||
|
||||
F64(byte* _data) { type = types::F64; data = *(double*)_data; };
|
||||
};
|
||||
|
||||
class LLUUID : Field
|
||||
{
|
||||
public:
|
||||
byte data[16];
|
||||
|
||||
LLUUID(byte* _data) { type = types::LLUUID; memcpy(data, _data, 16); };
|
||||
};
|
||||
|
||||
class Bool : Field
|
||||
{
|
||||
public:
|
||||
bool data;
|
||||
|
||||
Bool(byte* _data) { type = types::Bool; data = *(bool*)_data; };
|
||||
};
|
||||
|
||||
class LLVector3 : Field
|
||||
{
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
LLVector3(byte* _data)
|
||||
{
|
||||
type = types::LLVector3;
|
||||
x = *(float*)(_data);
|
||||
y = *(float*)(_data + sizeof(float));
|
||||
z = *(float*)(_data + sizeof(float) + sizeof(float));
|
||||
};
|
||||
};
|
||||
|
||||
class LLVector3d : Field
|
||||
{
|
||||
public:
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
|
||||
LLVector3d(byte* _data)
|
||||
{
|
||||
type = types::LLVector3d;
|
||||
x = *(double*)(_data);
|
||||
y = *(double*)(_data + sizeof(double));
|
||||
z = *(double*)(_data + sizeof(double) + sizeof(double));
|
||||
};
|
||||
};
|
||||
|
||||
class LLVector4 : Field
|
||||
{
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float s;
|
||||
|
||||
LLVector4(byte* _data)
|
||||
{
|
||||
type = types::LLVector4;
|
||||
x = *(float*)(_data);
|
||||
y = *(float*)(_data + sizeof(float));
|
||||
z = *(float*)(_data + sizeof(float) + sizeof(float));
|
||||
s = *(float*)(_data + sizeof(float) + sizeof(float) + sizeof(float));
|
||||
};
|
||||
};
|
||||
|
||||
class LLQuaternion : Field
|
||||
{
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float s;
|
||||
|
||||
LLQuaternion(byte* _data)
|
||||
{
|
||||
type = types::LLQuaternion;
|
||||
x = *(float*)(_data);
|
||||
y = *(float*)(_data + sizeof(float));
|
||||
z = *(float*)(_data + sizeof(float) + sizeof(float));
|
||||
s = *(float*)(_data + sizeof(float) + sizeof(float) + sizeof(float));
|
||||
};
|
||||
};
|
||||
|
||||
class IPADDR : Field
|
||||
{
|
||||
public:
|
||||
int data;
|
||||
|
||||
IPADDR(byte* _data) { type = types::IPADDR; data = *(int*)_data; };
|
||||
};
|
||||
|
||||
class IPPORT : Field
|
||||
{
|
||||
public:
|
||||
unsigned short data;
|
||||
|
||||
IPPORT(byte* _data) { type = types::IPPORT; data = *(unsigned short*)_data; };
|
||||
};
|
||||
|
||||
class Variable : Field
|
||||
{
|
||||
public:
|
||||
byte length;
|
||||
byte* data;
|
||||
|
||||
Variable(byte* _data, byte _length = 0)
|
||||
{
|
||||
type = types::Variable;
|
||||
length = _length;
|
||||
data = (byte*)malloc(length);
|
||||
memcpy(data, _data, length);
|
||||
};
|
||||
~Variable() { free(data); };
|
||||
|
||||
std::string dataString() { return std::string((char*)data); };
|
||||
};
|
||||
|
||||
#endif //_SL_FIELDS_
|
||||
@@ -68,20 +68,19 @@ class SecondLife;
|
||||
class LIBSECONDLIFE_CLASS_DECL Network
|
||||
{
|
||||
protected:
|
||||
boost::asio::demuxer _demuxer;
|
||||
std::vector<SimConnection*> _connections;
|
||||
std::list<Packet*> _inbox;
|
||||
boost::asio::demuxer _demuxer;
|
||||
std::vector<SimConnectionPtr> _connections;
|
||||
std::list<PacketPtr> _inbox;
|
||||
ProtocolManager* _protocol;
|
||||
SecondLife* _secondlife;
|
||||
|
||||
LLUUID _agent_id;
|
||||
LLUUID _session_id;
|
||||
LLUUID _secure_session_id;
|
||||
SimConnectionPtr _currentSim;
|
||||
SimpleLLUUID _agent_id;
|
||||
SimpleLLUUID _session_id;
|
||||
SimpleLLUUID _secure_session_id;
|
||||
|
||||
public:
|
||||
// Debug
|
||||
SimConnection* _currentSim;
|
||||
boost::mutex _inboxMutex;
|
||||
loginCallback callback;
|
||||
boost::mutex inboxMutex;
|
||||
|
||||
Network(ProtocolManager* protocol, SecondLife* secondlife);
|
||||
virtual ~Network();
|
||||
@@ -90,22 +89,28 @@ public:
|
||||
size_t major, size_t minor, size_t patch, size_t build,
|
||||
std::string platform, std::string viewerDigest, std::string userAgent, std::string author,
|
||||
loginCallback handler, std::string url);
|
||||
int connectSim(boost::asio::ipv4::address ip, unsigned short port, U32 code, bool setCurrent = false);
|
||||
int connectSim(boost::asio::ipv4::address ip, unsigned short port, unsigned int code, bool setCurrent = false);
|
||||
|
||||
void listen(SimConnection* sim);
|
||||
void listen(SimConnectionPtr sim);
|
||||
|
||||
int sendPacket(boost::asio::ipv4::address ip, unsigned short port, Packet* packet);
|
||||
int sendPacket(Packet* packet);
|
||||
int sendPacket(boost::asio::ipv4::address ip, unsigned short port, PacketPtr packet);
|
||||
int sendPacket(PacketPtr packet);
|
||||
void receivePacket(const boost::asio::error& error, std::size_t length, char* receiveBuffer);
|
||||
|
||||
std::list<Packet*>* inbox() { return &_inbox; };
|
||||
std::list<PacketPtr>* inbox() { return &_inbox; };
|
||||
|
||||
LLUUID agent_id() { return _agent_id; };
|
||||
void agent_id(LLUUID agent_id) { _agent_id = agent_id; };
|
||||
LLUUID session_id() { return _session_id; };
|
||||
void session_id(LLUUID session_id) { _session_id = session_id; };
|
||||
LLUUID secure_session_id() { return _secure_session_id; };
|
||||
void secure_session_id(LLUUID secure_session_id) { _secure_session_id = secure_session_id; };
|
||||
ProtocolManager* protocol() { return _protocol; };
|
||||
|
||||
SimConnectionPtr currentSim() { return _currentSim; };
|
||||
|
||||
SimpleLLUUID agent_id() { return _agent_id; };
|
||||
void agent_id(SimpleLLUUID agent_id) { _agent_id = agent_id; };
|
||||
|
||||
SimpleLLUUID session_id() { return _session_id; };
|
||||
void session_id(SimpleLLUUID session_id) { _session_id = session_id; };
|
||||
|
||||
SimpleLLUUID secure_session_id() { return _secure_session_id; };
|
||||
void secure_session_id(SimpleLLUUID secure_session_id) { _secure_session_id = secure_session_id; };
|
||||
};
|
||||
|
||||
#endif //_SL_NETWORK_
|
||||
|
||||
@@ -31,47 +31,89 @@
|
||||
#define _SL_PACKET_
|
||||
|
||||
#include "includes.h"
|
||||
#include "Fields.h"
|
||||
#include "ProtocolManager.h"
|
||||
|
||||
// Higher value will mean less realloc()s, more wasted memory. Lower value is
|
||||
// vice versa.
|
||||
#define DEFAULT_PACKET_SIZE 32
|
||||
// Forward definitions for the smart pointers
|
||||
class PacketField;
|
||||
class PacketBlock;
|
||||
class Packet;
|
||||
|
||||
// Smart pointers for the packet-related classes
|
||||
typedef boost::shared_ptr<Packet> PacketPtr;
|
||||
typedef boost::shared_ptr<PacketBlock> PacketBlockPtr;
|
||||
typedef boost::shared_ptr<PacketField> PacketFieldPtr;
|
||||
|
||||
// Smart pointer lists
|
||||
typedef std::vector<PacketBlockPtr> BlockList;
|
||||
typedef std::vector<PacketFieldPtr> FieldList;
|
||||
|
||||
//
|
||||
class PacketField
|
||||
{
|
||||
public:
|
||||
packetField* layout;
|
||||
byte* data;
|
||||
size_t length;
|
||||
|
||||
PacketField(packetField* _layout, byte* _data, size_t _length)
|
||||
{ layout = _layout; data = _data; length = _length; };
|
||||
|
||||
std::string name() { return layout->name; };
|
||||
types::Type type() { return layout->type; };
|
||||
};
|
||||
|
||||
//
|
||||
class PacketBlock
|
||||
{
|
||||
public:
|
||||
packetBlock* layout;
|
||||
FieldList fields;
|
||||
|
||||
PacketBlock(packetBlock* _layout) { layout = _layout; };
|
||||
|
||||
std::string name() { return layout->name; };
|
||||
};
|
||||
|
||||
//
|
||||
class LIBSECONDLIFE_CLASS_DECL Packet
|
||||
{
|
||||
protected:
|
||||
packetDiagram* _layout;
|
||||
byte* _buffer;
|
||||
size_t _length;
|
||||
frequencies::Frequency _frequency;
|
||||
std::string _command;
|
||||
ProtocolManager* _protocol;
|
||||
byte _headerLength;
|
||||
packetDiagram* _layout;
|
||||
|
||||
public:
|
||||
Packet(std::string command = "TestMessage", ProtocolManager* protocol = NULL, size_t length = 0);
|
||||
Packet(unsigned short command, ProtocolManager* protocol, byte* buffer, size_t length, ll::frequency frequency);
|
||||
virtual ~Packet();
|
||||
//std::vector<BlockContainerPtr> blockContainers;
|
||||
|
||||
std::string command();
|
||||
bool command(std::string command);
|
||||
|
||||
ll::llType fieldType(std::string block, std::string field);
|
||||
void* getField(std::string block, size_t blockNumber, std::string field, size_t fieldNumber);
|
||||
int setField(std::string block, size_t blockNumber, std::string field, size_t fieldNumber, void* value);
|
||||
Packet(std::string command, ProtocolManager* protocol);
|
||||
Packet(byte* buffer, size_t length, ProtocolManager* protocol);
|
||||
~Packet() { free(_buffer); };
|
||||
|
||||
void payload(byte* payload, size_t payloadLength);
|
||||
|
||||
byte* buffer() { return _buffer; };
|
||||
size_t length() { return _length; };
|
||||
byte* rawData();
|
||||
void rawData(byte* buffer, size_t length);
|
||||
|
||||
ll::frequency frequency();
|
||||
|
||||
|
||||
std::string command() { return _command; };
|
||||
packetDiagram* layout() { return _layout; };
|
||||
frequencies::Frequency frequency() { return _frequency; };
|
||||
unsigned short flags();
|
||||
void flags(unsigned short flags);
|
||||
|
||||
unsigned short sequence();
|
||||
void sequence(unsigned short sequence);
|
||||
|
||||
// Debug
|
||||
packetDiagram* layout() { return _layout; };
|
||||
|
||||
size_t headerLength();
|
||||
|
||||
boost::any getField(std::string blockName, std::string fieldName);
|
||||
boost::any getField(std::string blockName, size_t blockNumber, std::string fieldName);
|
||||
PacketBlockPtr getBlock(std::string blockName);
|
||||
PacketBlockPtr getBlock(std::string blockName, size_t blockNumber);
|
||||
BlockList getBlocks();
|
||||
};
|
||||
|
||||
#endif //_SL_PACKET_
|
||||
|
||||
46
include/PacketBuilder.h
Normal file
46
include/PacketBuilder.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2006, Second Life Reverse Engineering Team
|
||||
* All rights reserved.
|
||||
*
|
||||
* - Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* - Neither the name of the Second Life Reverse Engineering Team nor the names
|
||||
* of its contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _SL_BUILDER_
|
||||
#define _SL_BUILDER_
|
||||
|
||||
#include "includes.h"
|
||||
#include "Fields.h"
|
||||
#include "Packet.h"
|
||||
|
||||
PacketPtr PacketAck(ProtocolManager* protocol, std::vector<unsigned int> IDList);
|
||||
PacketPtr PacketAck(ProtocolManager* protocol, unsigned int ID);
|
||||
PacketPtr UseCircuitCode(ProtocolManager* protocol, SimpleLLUUID agentID, SimpleLLUUID sessionID, unsigned int code);
|
||||
PacketPtr CompleteAgentMovement(ProtocolManager* protocol, SimpleLLUUID AgentID, SimpleLLUUID SessionID, unsigned int CircuitCode);
|
||||
PacketPtr RegionHandshakeReply(ProtocolManager* protocol, unsigned int Flags);
|
||||
PacketPtr CompletePingCheck(ProtocolManager* protocol, byte PingID);
|
||||
PacketPtr DirLandQuery(ProtocolManager* protocol, bool ReservedNewbie, bool ForSale, SimpleLLUUID QueryID, bool Auction,
|
||||
unsigned int QueryFlags, SimpleLLUUID AgentID, SimpleLLUUID SessionID);
|
||||
|
||||
#endif //_SL_BUILDER_
|
||||
@@ -31,77 +31,19 @@
|
||||
#define _SL_PROTOCOLMANAGER_
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
namespace ll
|
||||
{
|
||||
enum llType {
|
||||
INVALID_TYPE = -1,
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
S8,
|
||||
S16,
|
||||
S32,
|
||||
S64,
|
||||
F8,
|
||||
F16,
|
||||
F32,
|
||||
F64,
|
||||
LLUUID,
|
||||
BOOL,
|
||||
LLVector3,
|
||||
LLVector3d,
|
||||
LLVector4,
|
||||
LLQuaternion,
|
||||
IPADDR,
|
||||
IPPORT,
|
||||
Variable,
|
||||
Fixed,
|
||||
Single,
|
||||
Multiple
|
||||
};
|
||||
|
||||
enum frequency {
|
||||
Invalid = 0,
|
||||
Low,
|
||||
Medium,
|
||||
High
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct llVector3 {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} llVector3;
|
||||
|
||||
typedef struct llVector3d {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} llVector3d;
|
||||
|
||||
typedef struct llQuaternion {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float s;
|
||||
} llQuaternion;
|
||||
|
||||
#define llVector4 llQuaternion
|
||||
#include "Fields.h"
|
||||
|
||||
struct packetField {
|
||||
int keywordPosition;
|
||||
std::string name;
|
||||
ll::llType type;
|
||||
size_t frequency;
|
||||
types::Type type;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
struct packetBlock {
|
||||
int keywordPosition;
|
||||
std::string name;
|
||||
int frequency;
|
||||
int count;
|
||||
std::list<packetField*> fields;
|
||||
};
|
||||
|
||||
@@ -127,12 +69,14 @@ namespace std
|
||||
typedef struct packetDiagram {
|
||||
unsigned short id;
|
||||
std::string name;
|
||||
ll::frequency frequency;
|
||||
frequencies::Frequency frequency;
|
||||
bool trusted;
|
||||
bool encoded;
|
||||
std::list<packetBlock*> blocks;
|
||||
} packetDiagram;
|
||||
|
||||
// Convenience function
|
||||
FieldPtr createField(packetField* field, byte* data);
|
||||
|
||||
class ProtocolManager
|
||||
{
|
||||
@@ -162,13 +106,17 @@ public:
|
||||
int keywordPosition(std::string keyword);
|
||||
|
||||
packetDiagram* command(std::string command);
|
||||
packetDiagram* command(unsigned short command, ll::frequency frequency);
|
||||
std::string commandString(unsigned short command, ll::frequency frequency);
|
||||
ll::llType fieldType(std::string type);
|
||||
int typeSize(ll::llType type);
|
||||
std::string typeName(ll::llType type);
|
||||
int blockFrequency(packetDiagram* layout, std::string block);
|
||||
packetDiagram* command(unsigned short command, frequencies::Frequency frequency);
|
||||
|
||||
std::string commandString(unsigned short command, frequencies::Frequency frequency);
|
||||
|
||||
types::Type fieldType(std::string type);
|
||||
int typeSize(types::Type type);
|
||||
std::string typeName(types::Type type);
|
||||
|
||||
int blockCount(packetDiagram* layout, std::string block);
|
||||
size_t blockSize(packetDiagram* layout, std::string block);
|
||||
|
||||
int fieldOffset(packetDiagram* layout, std::string block, std::string field);
|
||||
};
|
||||
|
||||
|
||||
@@ -34,10 +34,12 @@
|
||||
#include "ProtocolManager.h"
|
||||
#include "SimConnection.h"
|
||||
#include "Network.h"
|
||||
#include "Fields.h"
|
||||
#include "PacketBuilder.h"
|
||||
|
||||
// Model for the callbacks:
|
||||
// void functionname(std::string command, Packet*)
|
||||
typedef boost::function2<void, std::string, Packet*> callback;
|
||||
// void functionname(std::string command, PacketPtr)
|
||||
typedef boost::function2<void, std::string, PacketPtr> callback;
|
||||
|
||||
class LIBSECONDLIFE_CLASS_DECL SecondLife
|
||||
{
|
||||
@@ -70,19 +72,19 @@ public:
|
||||
loginCallback handler, std::string url = "https://login.agni.lindenlab.com/cgi-bin/login.cgi")
|
||||
{ _network->login(firstName, lastName, password, mac, major, minor, patch, build, platform, viewerDigest,
|
||||
userAgent, author, handler, url); };
|
||||
void connectSim(boost::asio::ipv4::address ip, unsigned short port, U32 code, bool setCurrent = false)
|
||||
void connectSim(boost::asio::ipv4::address ip, unsigned short port, unsigned int code, bool setCurrent = false)
|
||||
{ _network->connectSim(ip, port, code, setCurrent); };
|
||||
|
||||
int sendPacket(Packet* packet) { return _network->sendPacket(packet); };
|
||||
int sendPacket(PacketPtr packet) { return _network->sendPacket(packet); };
|
||||
|
||||
LLUUID agent_id() { return _network->agent_id(); };
|
||||
void agent_id(LLUUID agent_id) { _network->agent_id(agent_id); };
|
||||
SimpleLLUUID agent_id() { return _network->agent_id(); };
|
||||
void agent_id(SimpleLLUUID agent_id) { _network->agent_id(agent_id); };
|
||||
|
||||
LLUUID session_id() { return _network->session_id(); };
|
||||
void session_id(LLUUID session_id) { _network->session_id(session_id); };
|
||||
SimpleLLUUID session_id() { return _network->session_id(); };
|
||||
void session_id(SimpleLLUUID session_id) { _network->session_id(session_id); };
|
||||
|
||||
LLUUID secure_session_id() { return _network->secure_session_id(); };
|
||||
void secure_session_id(LLUUID secure_session_id) { _network->secure_session_id(secure_session_id); };
|
||||
SimpleLLUUID secure_session_id() { return _network->secure_session_id(); };
|
||||
void secure_session_id(SimpleLLUUID secure_session_id) { _network->secure_session_id(secure_session_id); };
|
||||
|
||||
ProtocolManager* protocol() { return _protocol; };
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class SimConnection
|
||||
{
|
||||
protected:
|
||||
std::string _name;
|
||||
U32 _code;
|
||||
unsigned int _code;
|
||||
boost::asio::ipv4::udp::endpoint _endpoint;
|
||||
boost::asio::datagram_socket* _socket;
|
||||
bool _running;
|
||||
@@ -48,14 +48,14 @@ protected:
|
||||
|
||||
public:
|
||||
SimConnection();
|
||||
SimConnection(boost::asio::ipv4::address ip, unsigned short port, U32 code);
|
||||
SimConnection(boost::asio::ipv4::address ip, unsigned short port, unsigned int code);
|
||||
virtual ~SimConnection();
|
||||
|
||||
std::string name() { return _name; };
|
||||
void name(std::string name) { _name = name; };
|
||||
|
||||
U32 code() { return _code; };
|
||||
void code(U32 code) { _code = code; };
|
||||
unsigned int code() { return _code; };
|
||||
void code(unsigned int code) { _code = code; };
|
||||
|
||||
boost::asio::ipv4::udp::endpoint endpoint() { return _endpoint; };
|
||||
void endpoint(boost::asio::ipv4::udp::endpoint endpoint) { _endpoint = endpoint; };
|
||||
@@ -81,4 +81,6 @@ public:
|
||||
bool operator!=(SimConnection &p);
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<SimConnection> SimConnectionPtr;
|
||||
|
||||
#endif //_SL_SIMCONNECTION_
|
||||
|
||||
@@ -45,10 +45,13 @@
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/shared_array.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/any.hpp>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
@@ -74,8 +77,8 @@ void hexstr2bin(const char* hex, byte* buf, size_t len);
|
||||
std::string rpcGetString(char* buffer, const char* name);
|
||||
int rpcGetU32(char* buffer, const char* name);
|
||||
std::string packUUID(std::string uuid);
|
||||
int zeroDecode(char* src, int srclen, char* dest, int destlen);
|
||||
int zeroEncode(char* src, int srclen, char* dest, int destlen);
|
||||
int zeroDecode(byte* src, int srclen, byte* dest);
|
||||
int zeroEncode(byte* src, int srclen, byte* dest);
|
||||
|
||||
// Global logging facility
|
||||
enum LogLevel {
|
||||
@@ -86,28 +89,23 @@ enum LogLevel {
|
||||
|
||||
void log(std::string line, LogLevel level);
|
||||
|
||||
// Global data types
|
||||
typedef unsigned int U32;
|
||||
typedef unsigned char U8;
|
||||
struct LLUUID {
|
||||
byte data[16];
|
||||
LLUUID() { *this = 0; };
|
||||
LLUUID(std::string p) { hexstr2bin(packUUID(p).c_str(), data, 16); };
|
||||
LLUUID operator=(const int p) { for (size_t i = 0; i < 16; i++) { data[i] = (byte)p; } return *this; };
|
||||
LLUUID operator=(LLUUID p) { memcpy(data, p.data, 16); return *this; };
|
||||
LLUUID operator=(std::string p) { hexstr2bin(packUUID(p).c_str(), data, 16); return *this; };
|
||||
};
|
||||
|
||||
// Platform-specific defines
|
||||
#ifdef WIN32
|
||||
#pragma warning (disable : 4996 4251)
|
||||
#ifdef LIBSECONDLIFE_EXPORTS
|
||||
#define LIBSECONDLIFE_CLASS_DECL __declspec(dllexport)
|
||||
#pragma warning (disable : 4996 4251)
|
||||
|
||||
#ifdef LIBSECONDLIFE_EXPORTS
|
||||
#define LIBSECONDLIFE_CLASS_DECL __declspec(dllexport)
|
||||
#else
|
||||
#define LIBSECONDLIFE_CLASS_DECL __declspec(dllimport)
|
||||
#endif //LIBSECONDLIFE_EXPORTS
|
||||
#elif GCC4
|
||||
#ifdef LIBSECONDLIFE_EXPORTS
|
||||
#define LIBSECONDLIFE_CLASS_DECL ((visibility("visible")))
|
||||
#else
|
||||
#define LIBSECONDLIFE_CLASS_DECL
|
||||
#endif //LIBSECONDLIFE_EXPORTS
|
||||
#else
|
||||
#define LIBSECONDLIFE_CLASS_DECL __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define LIBSECONDLIFE_CLASS_DECL
|
||||
#endif
|
||||
#define LIBSECONDLIFE_CLASS_DECL
|
||||
#endif //WIN32
|
||||
|
||||
#endif //_SL_INCLUDES_
|
||||
|
||||
213
src/Network.cpp
213
src/Network.cpp
@@ -1,13 +1,13 @@
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "Network.h"
|
||||
#include "PacketBuilder.h"
|
||||
#include "md5.h"
|
||||
|
||||
Network::Network(ProtocolManager* protocol, SecondLife* secondlife)
|
||||
{
|
||||
_protocol = protocol;
|
||||
_secondlife = secondlife;
|
||||
_currentSim = NULL;
|
||||
_agent_id = 0;
|
||||
_session_id = 0;
|
||||
_secure_session_id = 0;
|
||||
@@ -18,22 +18,13 @@ Network::~Network()
|
||||
#ifdef DEBUG
|
||||
std::cout << "Network::~Network() destructor called" << std::endl;
|
||||
#endif
|
||||
std::vector<SimConnection*>::iterator connection;
|
||||
std::list<Packet*>::iterator packet;
|
||||
|
||||
for (connection = _connections.begin(); connection != _connections.end(); ++connection) {
|
||||
delete (*connection);
|
||||
}
|
||||
|
||||
for (packet = _inbox.begin(); packet != _inbox.end(); ++packet) {
|
||||
delete (*packet);
|
||||
}
|
||||
}
|
||||
|
||||
size_t loginReply(void* buffer, size_t size, size_t nmemb, void* userp)
|
||||
{
|
||||
loginParameters login;
|
||||
loginCallback* handler = (loginCallback*)userp;
|
||||
Network* network = (Network*)userp;
|
||||
loginCallback callback = network->callback;
|
||||
char* reply = (char*)buffer;
|
||||
std::string msg;
|
||||
int realsize = size * nmemb;
|
||||
@@ -41,7 +32,7 @@ size_t loginReply(void* buffer, size_t size, size_t nmemb, void* userp)
|
||||
if (!reply) {
|
||||
login.reason = "libsecondlife";
|
||||
login.message = "There was an error connecting to the login server, check the log file for details";
|
||||
(*handler)(login);
|
||||
callback(login);
|
||||
return realsize;
|
||||
}
|
||||
|
||||
@@ -49,7 +40,6 @@ size_t loginReply(void* buffer, size_t size, size_t nmemb, void* userp)
|
||||
if (msg.length()) {
|
||||
login.reason = msg;
|
||||
login.message = rpcGetString(reply, "<name>message</name>");
|
||||
log("Network::loginReply(): Login failed. Reason: " + login.reason + ". Message: " + login.message, WARNING);
|
||||
} else {
|
||||
msg = rpcGetString(reply, "login</name><value><string>true");
|
||||
if (msg.length()) {
|
||||
@@ -76,8 +66,25 @@ size_t loginReply(void* buffer, size_t size, size_t nmemb, void* userp)
|
||||
}
|
||||
}
|
||||
|
||||
(*handler)(login);
|
||||
|
||||
if (login.reason.length()) {
|
||||
log("Network::loginReply(): Login failed. Reason: " + login.reason + ". Message: " + login.message, WARNING);
|
||||
} else {
|
||||
// Set the variables received from login
|
||||
network->session_id((SimpleLLUUID)login.session_id);
|
||||
network->secure_session_id((SimpleLLUUID)login.secure_session_id);
|
||||
network->agent_id((SimpleLLUUID)login.agent_id);
|
||||
|
||||
boost::asio::ipv4::address address(login.sim_ip);
|
||||
network->connectSim(address, login.sim_port, login.circuit_code, true);
|
||||
|
||||
// Build and send the packet to move our avatar in to the sim
|
||||
PacketPtr packetPtr = CompleteAgentMovement(network->protocol(), network->agent_id(),
|
||||
network->session_id(), login.circuit_code);
|
||||
network->sendPacket(packetPtr);
|
||||
}
|
||||
|
||||
callback(login);
|
||||
|
||||
return realsize;
|
||||
}
|
||||
|
||||
@@ -136,6 +143,9 @@ void Network::login(std::string firstName, std::string lastName, std::string pas
|
||||
headers = curl_slist_append(headers, "Accept-Encoding: gzip");
|
||||
headers = curl_slist_append(headers, "Content-Type: text/xml");
|
||||
|
||||
//TODO: Maybe find a more elegant solution?
|
||||
callback = handler;
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, loginError);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20);
|
||||
@@ -144,8 +154,8 @@ void Network::login(std::string firstName, std::string lastName, std::string pas
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, loginRequest.length());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, loginReply);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &handler);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
|
||||
|
||||
response = curl_easy_perform(curl);
|
||||
|
||||
if (response) {
|
||||
@@ -161,7 +171,7 @@ void Network::login(std::string firstName, std::string lastName, std::string pas
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
int Network::connectSim(boost::asio::ipv4::address ip, unsigned short port, U32 code, bool setCurrent)
|
||||
int Network::connectSim(boost::asio::ipv4::address ip, unsigned short port, unsigned int code, bool setCurrent)
|
||||
{
|
||||
// Check if we are already connected to this sim
|
||||
for (size_t i = 0; i < _connections.size(); i++) {
|
||||
@@ -171,38 +181,35 @@ int Network::connectSim(boost::asio::ipv4::address ip, unsigned short port, U32
|
||||
}
|
||||
}
|
||||
|
||||
// Build a connection packet
|
||||
Packet* packet = new Packet("UseCircuitCode", _protocol, 44);
|
||||
packet->setField("CircuitCode", 1, "ID", 1, &_agent_id);
|
||||
packet->setField("CircuitCode", 1, "SessionID", 1, &_session_id);
|
||||
packet->setField("CircuitCode", 1, "Code", 1, &code);
|
||||
// Build the connection packet
|
||||
PacketPtr packetPtr = UseCircuitCode(_protocol, _agent_id, _session_id, code);
|
||||
|
||||
// Create the SimConnection
|
||||
SimConnection* sim = new SimConnection(ip, port, code);
|
||||
SimConnectionPtr sim(new SimConnection(ip, port, code));
|
||||
if (setCurrent || !_currentSim) _currentSim = sim;
|
||||
|
||||
// Set the packet sequence number
|
||||
packet->sequence(sim->sequence());
|
||||
packetPtr->sequence(sim->sequence());
|
||||
|
||||
boost::asio::datagram_socket* socket = new boost::asio::datagram_socket(_demuxer, boost::asio::ipv4::udp::endpoint(0));
|
||||
sim->socket(socket);
|
||||
|
||||
// Push this connection on to the list
|
||||
_connections.push_back(sim);
|
||||
|
||||
|
||||
// Send the packet
|
||||
try {
|
||||
size_t bytesSent = socket->send_to(boost::asio::buffer(packet->rawData(), packet->length()), 0, sim->endpoint());
|
||||
// Debug
|
||||
printf("Network::connectSim(): Sent %i byte connection packet\n", bytesSent);
|
||||
|
||||
delete packet;
|
||||
size_t bytesSent = socket->send_to(boost::asio::buffer(packetPtr->buffer(), packetPtr->length()), 0, sim->endpoint());
|
||||
#ifdef DEBUG
|
||||
std::stringstream message;
|
||||
message << "Network::connectSim(): Sent " << bytesSent << " byte connection packet";
|
||||
log(message.str(), INFO);
|
||||
#endif
|
||||
} catch (boost::asio::error& e) {
|
||||
std::stringstream message;
|
||||
message << "Network::connectSim(): " << e;
|
||||
log(message.str(), ERROR);
|
||||
|
||||
delete packet;
|
||||
return -2;
|
||||
}
|
||||
|
||||
@@ -212,7 +219,7 @@ int Network::connectSim(boost::asio::ipv4::address ip, unsigned short port, U32
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Network::listen(SimConnection* sim)
|
||||
void Network::listen(SimConnectionPtr sim)
|
||||
{
|
||||
// Start listening on this socket
|
||||
while (sim && sim->running()) {
|
||||
@@ -240,63 +247,59 @@ void Network::listen(SimConnection* sim)
|
||||
|
||||
void Network::receivePacket(const boost::asio::error& error, std::size_t length, char* receiveBuffer)
|
||||
{
|
||||
Packet* packet;
|
||||
unsigned short command;
|
||||
byte* buffer = (byte*)receiveBuffer;
|
||||
PacketPtr packet;
|
||||
|
||||
if (length < 6) {
|
||||
log("Network::receivePacket(): Received packet less than six bytes, ignoring", WARNING);
|
||||
return;
|
||||
if (receiveBuffer[0] & MSG_RELIABLE) {
|
||||
// This packet requires an ACK
|
||||
//TODO: Instead of generating an ACK for each incoming packet, we're supposed to be appending
|
||||
// these to any outgoing low commands. An implementation idea would be to add this sequence
|
||||
// number to a list, and if it's the first on the list set a short timer that will send any
|
||||
// ACKs in the list in a single packet. Meanwhile, any time a Low packet goes out it can check
|
||||
// this list and append the ACKs. Packet class will need an appendACKs() function. Would be a
|
||||
// good use of the asynchronous design of the sending and receiving.
|
||||
unsigned short id = ntohs(*(unsigned short*)(receiveBuffer + 2));
|
||||
PacketPtr ackPacket = PacketAck(_protocol, id);
|
||||
sendPacket(ackPacket);
|
||||
}
|
||||
|
||||
if (buffer[4] == 0xFF) {
|
||||
if (buffer[5] == 0xFF) {
|
||||
// Low frequency packet
|
||||
memcpy(&command, &buffer[6], 2);
|
||||
command = ntohs(command);
|
||||
if (receiveBuffer[0] & MSG_APPENDED_ACKS) {
|
||||
//TODO: Run through the packet backwards picking up the ACKs, then adjust length
|
||||
}
|
||||
|
||||
if (_protocol->commandString(command, ll::Low) == "PacketAck") {
|
||||
// TODO: At some point we'll want to track these Acks
|
||||
#ifdef DEBUG
|
||||
log("Network::receivePacket(): Received PacketAck", INFO);
|
||||
#endif
|
||||
return;
|
||||
} else {
|
||||
packet = new Packet(command, _protocol, buffer, length, ll::Low);
|
||||
}
|
||||
} else {
|
||||
// Medium frequency packet
|
||||
command = (unsigned short)buffer[5];
|
||||
packet = new Packet(command, _protocol, buffer, length, ll::Medium);
|
||||
}
|
||||
if (receiveBuffer[0] & MSG_ZEROCODED) {
|
||||
//TODO: Can we optimize the size of this buffer?
|
||||
byte zeroBuffer[8192];
|
||||
|
||||
size_t zeroLength = zeroDecode((byte*)receiveBuffer, length, zeroBuffer);
|
||||
packet.reset(new Packet(zeroBuffer, zeroLength, _protocol));
|
||||
} else {
|
||||
// High frequency packet
|
||||
command = (unsigned short)buffer[4];
|
||||
|
||||
if (_protocol->commandString(command, ll::High) == "StartPingCheck") {
|
||||
// Ping request from the server, respond
|
||||
packet = new Packet(command, _protocol, buffer, length, ll::High);
|
||||
U8 pingID = *(U8*)packet->getField("PingID", 1, "PingID", 1);
|
||||
|
||||
//TODO: Should we be looking at OldestUnacked as well?
|
||||
delete packet;
|
||||
|
||||
packet = new Packet("CompletePingCheck", _protocol, 6);
|
||||
packet->setField("PingID", 1, "PingID", 1, &pingID);
|
||||
sendPacket(packet);
|
||||
|
||||
return;
|
||||
} else {
|
||||
packet = new Packet(command, _protocol, buffer, length, ll::High);
|
||||
}
|
||||
packet.reset(new Packet((byte*)receiveBuffer, length, _protocol));
|
||||
}
|
||||
|
||||
// Push it on to the list
|
||||
boost::mutex::scoped_lock lock(_inboxMutex);
|
||||
_inbox.push_back(packet);
|
||||
//TODO: The library-level callback handler std::map will replace these if/else statements
|
||||
if (packet->command() == "PacketAck") {
|
||||
// TODO: Keep a list of outgoing reliable packets and check for incoming ACKs on them
|
||||
} else if (packet->command() == "StartPingCheck") {
|
||||
//TODO: Handle OldestUnacked
|
||||
byte* buffer = packet->buffer();
|
||||
byte pingID = buffer[5];
|
||||
|
||||
packet = CompletePingCheck(_protocol, pingID);
|
||||
sendPacket(packet);
|
||||
} else if (packet->command() == "RegionHandshake") {
|
||||
//FIXME: What are the Flags supposed to be for this packet?
|
||||
PacketPtr replyPacket = RegionHandshakeReply(_protocol, 0);
|
||||
sendPacket(replyPacket);
|
||||
|
||||
boost::mutex::scoped_lock lock(inboxMutex);
|
||||
_inbox.push_back(packet);
|
||||
} else {
|
||||
boost::mutex::scoped_lock lock(inboxMutex);
|
||||
_inbox.push_back(packet);
|
||||
}
|
||||
}
|
||||
|
||||
int Network::sendPacket(boost::asio::ipv4::address ip, unsigned short port, Packet* packet)
|
||||
int Network::sendPacket(boost::asio::ipv4::address ip, unsigned short port, PacketPtr packet)
|
||||
{
|
||||
size_t sent;
|
||||
bool found = false;
|
||||
@@ -311,22 +314,48 @@ int Network::sendPacket(boost::asio::ipv4::address ip, unsigned short port, Pack
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
//FIXME: Log
|
||||
log("Network::sendPacket(): Trying to send a packet to a sim we're not connected to", ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the packet sequence number
|
||||
packet->sequence(_connections[i]->sequence());
|
||||
|
||||
try {
|
||||
sent = _connections[i]->socket()->send_to(boost::asio::buffer(packet->rawData(), packet->length()),
|
||||
0, _connections[i]->endpoint());
|
||||
} catch (boost::asio::error& e) {
|
||||
std::stringstream message;
|
||||
message << "Network::sendPacket(): " << e;
|
||||
log(message.str(), ERROR);
|
||||
if (packet->frequency() == frequencies::Low) {
|
||||
//TODO: If any ACKs need to be sent append them to this packet and set the flag
|
||||
}
|
||||
|
||||
return -2;
|
||||
if (packet->buffer()[0] & MSG_RELIABLE) {
|
||||
//TODO: Append this packet to a list of outgoing MSG_RELIABLE packets, and create a timeout for
|
||||
// resending unACKed packets
|
||||
}
|
||||
|
||||
if (packet->buffer()[0] & MSG_ZEROCODED) {
|
||||
//TODO: This shouldn't need to be much larger than the raw packet itself
|
||||
byte zeroBuffer[8192];
|
||||
size_t length = zeroEncode(packet->buffer(), packet->length(), zeroBuffer);
|
||||
|
||||
try {
|
||||
sent = _connections[i]->socket()->send_to(boost::asio::buffer(zeroBuffer, length), 0,
|
||||
_connections[i]->endpoint());
|
||||
} catch (boost::asio::error& e) {
|
||||
std::stringstream message;
|
||||
message << "Network::sendPacket(): " << e << " (1)";
|
||||
log(message.str(), ERROR);
|
||||
|
||||
return -2;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
sent = _connections[i]->socket()->send_to(boost::asio::buffer(packet->buffer(), packet->length()),
|
||||
0, _connections[i]->endpoint());
|
||||
} catch (boost::asio::error& e) {
|
||||
std::stringstream message;
|
||||
message << "Network::sendPacket(): " << e << " (2)";
|
||||
log(message.str(), ERROR);
|
||||
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -338,7 +367,7 @@ int Network::sendPacket(boost::asio::ipv4::address ip, unsigned short port, Pack
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Network::sendPacket(Packet* packet)
|
||||
int Network::sendPacket(PacketPtr packet)
|
||||
{
|
||||
if (!_currentSim) {
|
||||
log("Network::sendPacket() called when there is no current sim", ERROR);
|
||||
|
||||
762
src/Packet.cpp
762
src/Packet.cpp
@@ -1,361 +1,401 @@
|
||||
#include "Packet.h"
|
||||
|
||||
Packet::Packet(std::string command, ProtocolManager* protocol, size_t length)
|
||||
{
|
||||
// Make the minimum length sane to avoid excessive bounds checking
|
||||
_length = (length > 5) ? length : 0;
|
||||
_protocol = protocol;
|
||||
unsigned short flags;
|
||||
|
||||
_layout = _protocol->command(command);
|
||||
|
||||
if (!_layout) {
|
||||
log("Packet::Packet(): Trying to initialize with invalid command: " + command, ERROR);
|
||||
_buffer = NULL;
|
||||
_length = 0;
|
||||
} else {
|
||||
_buffer = (byte*)calloc(_length ? _length : DEFAULT_PACKET_SIZE, sizeof(byte));
|
||||
|
||||
if (!_buffer) {
|
||||
std::stringstream message;
|
||||
message << "Packet::Packet(): " << (_length ? _length : DEFAULT_PACKET_SIZE) << " byte calloc failed";
|
||||
log(message.str(), ERROR);
|
||||
_length = 0;
|
||||
}
|
||||
|
||||
// Setup the flags
|
||||
//FIXME: The flags are wrong right now, UseCircuitCode is supposed to be 0x4000 but
|
||||
// the current setup has it at 0x0000 according to the protocol map. Was
|
||||
// snowcrash wrong? Why are virtually all packets (except acks) sent with
|
||||
// 0x4000 when lots of commands are untrusted? trusted != reliable?
|
||||
flags = (_layout->trusted & MSG_RELIABLE) + (_layout->encoded & MSG_ZEROCODED);
|
||||
|
||||
//FIXME: Serious hack to temporarily work around the aforementioned problem
|
||||
if (!flags) {
|
||||
flags = 0x40;
|
||||
}
|
||||
|
||||
memcpy(_buffer, &flags, 2);
|
||||
|
||||
// Setup the frequency/id bytes
|
||||
switch (_layout->frequency) {
|
||||
case ll::Low:
|
||||
if (_length < 8) {
|
||||
_buffer = (byte*)realloc(_buffer, 8);
|
||||
if (!_buffer) {
|
||||
log("Packet::Packet(): 8 byte realloc failed", ERROR);
|
||||
_length = 0;
|
||||
} else {
|
||||
_length = 8;
|
||||
}
|
||||
}
|
||||
|
||||
_buffer[4] = 0xFF;
|
||||
_buffer[5] = 0xFF;
|
||||
flags = htons(_layout->id);
|
||||
memcpy(_buffer + 6, &flags, 2);
|
||||
_headerLength = 8;
|
||||
break;
|
||||
case ll::Medium:
|
||||
if (_length < 6) {
|
||||
_buffer = (byte*)realloc(_buffer, 6);
|
||||
if (!_buffer) {
|
||||
log("Packet::Packet(): 6 byte realloc failed", ERROR);
|
||||
_length = 0;
|
||||
} else {
|
||||
_length = 6;
|
||||
}
|
||||
}
|
||||
|
||||
_buffer[4] = 0xFF;
|
||||
_buffer[5] = _layout->id;
|
||||
_headerLength = 6;
|
||||
break;
|
||||
case ll::High:
|
||||
if (_length < 5) {
|
||||
_buffer = (byte*)realloc(_buffer, 5);
|
||||
if (!_buffer) {
|
||||
log("Packet::Packet(): 5 byte realloc failed", ERROR);
|
||||
_length = 0;
|
||||
} else {
|
||||
_length = 5;
|
||||
}
|
||||
}
|
||||
|
||||
_buffer[4] = _layout->id;
|
||||
_headerLength = 5;
|
||||
break;
|
||||
case ll::Invalid:
|
||||
//FIXME: Log
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Packet::Packet(unsigned short command, ProtocolManager* protocol, byte* buffer, size_t length, ll::frequency frequency)
|
||||
{
|
||||
_length = length;
|
||||
_protocol = protocol;
|
||||
_layout = _protocol->command(command, frequency);
|
||||
|
||||
if (!_layout) {
|
||||
std::stringstream message;
|
||||
message << "Packet::Packet(): Trying to build a packet from unknown command code " << command <<
|
||||
", frequency " << frequency;
|
||||
log(message.str(), ERROR);
|
||||
}
|
||||
|
||||
_buffer = (byte*)malloc(length);
|
||||
if (!_buffer) {
|
||||
//FIXME: Log memory error
|
||||
_length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(_buffer, buffer, length);
|
||||
|
||||
switch (frequency) {
|
||||
case ll::Low:
|
||||
_headerLength = 8;
|
||||
case ll::Medium:
|
||||
_headerLength = 6;
|
||||
case ll::High:
|
||||
_headerLength = 5;
|
||||
case ll::Invalid:
|
||||
_headerLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Packet::~Packet()
|
||||
{
|
||||
free(_buffer);
|
||||
}
|
||||
|
||||
ll::frequency Packet::frequency()
|
||||
{
|
||||
return _layout ? _layout->frequency : ll::Invalid;
|
||||
}
|
||||
|
||||
unsigned short Packet::flags()
|
||||
{
|
||||
if (_length < 2) {
|
||||
log("Packet::flags(): Flags requested on a datagram less than 2 bytes", WARNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (unsigned short)*_buffer;
|
||||
}
|
||||
|
||||
void Packet::flags(unsigned short flags)
|
||||
{
|
||||
if (_length < 2) {
|
||||
// Make room, assume the default packet size
|
||||
_buffer = (byte*)realloc(_buffer, DEFAULT_PACKET_SIZE);
|
||||
|
||||
if (!_buffer) {
|
||||
std::stringstream message;
|
||||
message << "Packet::flags(): " << DEFAULT_PACKET_SIZE << " byte realloc failed";
|
||||
log(message.str(), ERROR);
|
||||
|
||||
_length = 0;
|
||||
return;
|
||||
} else {
|
||||
_length = 2;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(_buffer, &flags, 2);
|
||||
}
|
||||
|
||||
unsigned short Packet::sequence()
|
||||
{
|
||||
if (_length < 4) {
|
||||
log("Packet::sequence(): Sequence requested on a datagram less than 4 bytes", WARNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned short sequence;
|
||||
memcpy(&sequence, _buffer + 2, 2);
|
||||
//return ntohs((unsigned short)*(_buffer + 2));
|
||||
return ntohs(sequence);
|
||||
}
|
||||
|
||||
void Packet::sequence(unsigned short sequence)
|
||||
{
|
||||
if (_length < 4) {
|
||||
// Make room, assume the default packet size
|
||||
_buffer = (byte*)realloc(_buffer, DEFAULT_PACKET_SIZE);
|
||||
|
||||
if (!_buffer) {
|
||||
std::stringstream message;
|
||||
message << "Packet::sequence(): " << DEFAULT_PACKET_SIZE << " byte realloc failed";
|
||||
log(message.str(), ERROR);
|
||||
|
||||
_length = 0;
|
||||
return;
|
||||
} else {
|
||||
_length = 4;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short nSequence = htons(sequence);
|
||||
memcpy(_buffer + 2, &nSequence, sizeof(sequence));
|
||||
}
|
||||
|
||||
std::string Packet::command()
|
||||
{
|
||||
return _layout->name;
|
||||
}
|
||||
|
||||
bool Packet::command(std::string command)
|
||||
{
|
||||
packetDiagram* layout = _protocol->command(command);
|
||||
if (!layout) return false;
|
||||
|
||||
_layout = layout;
|
||||
return true;
|
||||
}
|
||||
|
||||
ll::llType Packet::fieldType(std::string block, std::string field)
|
||||
{
|
||||
std::list<packetBlock*>::iterator i;
|
||||
|
||||
for (i = _layout->blocks.begin(); i != _layout->blocks.end(); ++i) {
|
||||
if ((*i)->name == block) {
|
||||
packetBlock* block = (*i);
|
||||
|
||||
std::list<packetField*>::iterator j;
|
||||
|
||||
for (j = block->fields.begin(); j != block->fields.end(); ++j) {
|
||||
if ((*j)->name == field) {
|
||||
return (*j)->type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log("Packet::fieldType(): Couldn't find field " + field + " in block " + block, ERROR);
|
||||
return ll::INVALID_TYPE;
|
||||
}
|
||||
|
||||
log("Packet::fieldType(): Couldn't find block " + block, ERROR);
|
||||
return ll::INVALID_TYPE;
|
||||
}
|
||||
|
||||
void* Packet::getField(std::string block, size_t blockNumber, std::string field, size_t fieldNumber)
|
||||
{
|
||||
// Check how many blocks this field can hold, and if blockNumber is in range
|
||||
int frequency = _protocol->blockFrequency(_layout, block);
|
||||
if (frequency != -1 && (int)blockNumber > frequency) {
|
||||
// blockNumber is out of range
|
||||
//FIXME: Log
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find the total offset for the field
|
||||
size_t blockSize = _protocol->blockSize(_layout, block);
|
||||
if (!blockSize) {
|
||||
//FIXME: Log
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find out what type of field this is
|
||||
ll::llType type = fieldType(block, field);
|
||||
if (type == ll::INVALID_TYPE) {
|
||||
log("Packet::getField(): Couldn't find field type for: " + field + ", in block: " + block, ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the offset for this field
|
||||
int fieldOffset = _protocol->fieldOffset(_layout, block, field);
|
||||
if (fieldOffset < 0) {
|
||||
log("Packet::getField(): Couldn't get the field offset for: " + field + ", in block: " + block, ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get the size of this type of field
|
||||
size_t fieldSize = _protocol->typeSize(type);
|
||||
|
||||
return (void*)(_buffer + _headerLength + blockSize * blockNumber + fieldOffset + fieldSize * (fieldNumber - 1));
|
||||
}
|
||||
|
||||
int Packet::setField(std::string block, size_t blockNumber, std::string field, size_t fieldNumber, void* value)
|
||||
{
|
||||
if (!_layout) {
|
||||
//FIXME: Log
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Find out what type of field this is
|
||||
ll::llType type = fieldType(block, field);
|
||||
if (type == ll::INVALID_TYPE) {
|
||||
log("Packet::setField(): Couldn't find field type for: " + field + ", in block: " + block, ERROR);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Check how many blocks this field can hold, and if blockNumber is in range
|
||||
int frequency = _protocol->blockFrequency(_layout, block);
|
||||
if (blockNumber <= 0 || (frequency != -1 && (int)blockNumber > frequency)) {
|
||||
// blockNumber is out of range
|
||||
//FIXME: Log
|
||||
return -3;
|
||||
}
|
||||
|
||||
// Find the total offset for the field
|
||||
size_t blockSize = _protocol->blockSize(_layout, block);
|
||||
if (!blockSize) {
|
||||
//FIXME: Log
|
||||
return -4;
|
||||
}
|
||||
|
||||
int fieldOffset = _protocol->fieldOffset(_layout, block, field);
|
||||
if (fieldOffset < 0) {
|
||||
log("Packet::setField(): Couldn't get the field offset for: " + field + ", in block: " + block, ERROR);
|
||||
return -5;
|
||||
}
|
||||
|
||||
size_t fieldSize = _protocol->typeSize(type);
|
||||
size_t offset = _headerLength + blockSize * (blockNumber - 1) + fieldOffset + fieldSize * (fieldNumber - 1);
|
||||
|
||||
// Reallocate memory if necessary
|
||||
if ((offset + fieldSize) > _length) {
|
||||
_buffer = (byte*)realloc(_buffer, offset + fieldSize);
|
||||
if (!_buffer) {
|
||||
std::stringstream message;
|
||||
message << "Packet::setField(): " << offset + fieldSize << " byte realloc failed";
|
||||
log(message.str(), ERROR);
|
||||
|
||||
_length = 0;
|
||||
return -6;
|
||||
}
|
||||
|
||||
_length = offset + fieldSize;
|
||||
}
|
||||
|
||||
// Write the actual value
|
||||
memcpy(_buffer + offset, value, fieldSize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte* Packet::rawData()
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
void Packet::rawData(byte* buffer, size_t length)
|
||||
{
|
||||
if (length > _length) {
|
||||
_buffer = (byte*)realloc(_buffer, length);
|
||||
if (!_buffer) {
|
||||
std::stringstream message;
|
||||
message << "Packet::rawData(): " << length << " byte realloc failed";
|
||||
log(message.str(), ERROR);
|
||||
|
||||
_length = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(_buffer, buffer, length);
|
||||
_length = length;
|
||||
}
|
||||
#include "Packet.h"
|
||||
|
||||
/*BlockContainer::BlockContainer(packetBlock* _layout)
|
||||
{
|
||||
layout = _layout;
|
||||
|
||||
if (layout) {
|
||||
variable = ((layout->frequency == -1) ? true : false);
|
||||
}
|
||||
}
|
||||
|
||||
BlockContainer::BlockContainer(ProtocolManager* protocol, std::string command, std::string blockName)
|
||||
{
|
||||
std::list<packetBlock*>::iterator block;
|
||||
|
||||
packetDiagram* _layout = protocol->command(command);
|
||||
|
||||
if (_layout) {
|
||||
for (block = _layout->blocks.begin(); block != _layout->blocks.end(); ++block) {
|
||||
if ((*block)->name == blockName) {
|
||||
layout = (*block);
|
||||
variable = ((layout->frequency == -1) ? true : false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log("BlockContainer::BlockContainer(): Block lookup: " + blockName + ", failed in command: " + command, ERROR);
|
||||
} else {
|
||||
log("BlockContainer::BlockContainer(): Command lookup failed: " + command, ERROR);
|
||||
}
|
||||
}*/
|
||||
|
||||
Packet::Packet(std::string command, ProtocolManager* protocol)
|
||||
{
|
||||
unsigned short id;
|
||||
|
||||
_protocol = protocol;
|
||||
_command = command;
|
||||
_layout = _protocol->command(_command);
|
||||
|
||||
if (!_layout) {
|
||||
log("Packet::Packet(): Initializing with invalid command: \"" + _command + "\"", ERROR);
|
||||
_buffer = NULL;
|
||||
_length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_frequency = _layout->frequency;
|
||||
|
||||
switch (_layout->frequency) {
|
||||
case frequencies::Low:
|
||||
_buffer = (byte*)malloc(8);
|
||||
_buffer[4] = _buffer[5] = 0xFF;
|
||||
id = _layout->id;
|
||||
id = htons(id);
|
||||
memcpy(_buffer + 6, &id, 2);
|
||||
_length = 8;
|
||||
break;
|
||||
case frequencies::Medium:
|
||||
_buffer = (byte*)malloc(6);
|
||||
_buffer[4] = 0xFF;
|
||||
_buffer[5] = (byte)_layout->id;
|
||||
_length = 6;
|
||||
break;
|
||||
case frequencies::High:
|
||||
_buffer = (byte*)malloc(5);
|
||||
_buffer[4] = (byte)_layout->id;
|
||||
_length = 5;
|
||||
break;
|
||||
case frequencies::Invalid:
|
||||
log("Packet::Packet(): Command \"" + _command + "\" has an invalid frequency", ERROR);
|
||||
_buffer = NULL;
|
||||
_length = 0;
|
||||
return;
|
||||
default:
|
||||
log("Packet::Packet(): Command \"" + _command + "\" has an unknown frequency", ERROR);
|
||||
_buffer = NULL;
|
||||
_length = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Packet::Packet(byte* buffer, size_t length, ProtocolManager* protocol)
|
||||
{
|
||||
unsigned short command;
|
||||
|
||||
_protocol = protocol;
|
||||
|
||||
_buffer = (byte*)malloc(length);
|
||||
if (!_buffer) {
|
||||
log("Packet::Packet(): malloc() failed", ERROR);
|
||||
_length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(_buffer, buffer, length);
|
||||
_length = length;
|
||||
|
||||
// Determine the packet frequency
|
||||
if (_length > 4) {
|
||||
if (_buffer[4] == 0xFF) {
|
||||
if (_buffer[5] == 0xFF) {
|
||||
// Low frequency
|
||||
_frequency = frequencies::Low;
|
||||
memcpy(&command, &_buffer[6], 2);
|
||||
command = ntohs(command);
|
||||
_layout = _protocol->command(command, frequencies::Low);
|
||||
_command = _protocol->commandString(command, frequencies::Low);
|
||||
} else {
|
||||
// Medium frequency
|
||||
_frequency = frequencies::Medium;
|
||||
command = _buffer[5];
|
||||
_layout = _protocol->command(command, frequencies::Medium);
|
||||
_command = _protocol->commandString(command, frequencies::Medium);
|
||||
}
|
||||
} else {
|
||||
// High frequency
|
||||
_frequency = frequencies::High;
|
||||
command = _buffer[4];
|
||||
_layout = _protocol->command(command, frequencies::High);
|
||||
_command = _protocol->commandString(command, frequencies::High);
|
||||
}
|
||||
} else {
|
||||
log("Received a datagram less than five bytes", WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
void Packet::payload(byte* payload, size_t payloadLength)
|
||||
{
|
||||
if (_buffer) {
|
||||
_buffer = (byte*)realloc(_buffer, _length + payloadLength);
|
||||
|
||||
if (_buffer) {
|
||||
memcpy(_buffer + _length, payload, payloadLength);
|
||||
_length += payloadLength;
|
||||
} else {
|
||||
log("Packet::payload(): realloc() failed", ERROR);
|
||||
}
|
||||
} else {
|
||||
log("Packet::payload(): Attempting to append a payload to a packet with a null buffer", ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short Packet::flags()
|
||||
{
|
||||
unsigned short* flags = (unsigned short*)_buffer;
|
||||
return ntohs(*flags);
|
||||
}
|
||||
|
||||
void Packet::flags(unsigned short flags)
|
||||
{
|
||||
if (_buffer && _length > 2) {
|
||||
memcpy(_buffer, &flags, 2);
|
||||
} else {
|
||||
log("Packet::flags(): Null or too short buffer", ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short Packet::sequence()
|
||||
{
|
||||
unsigned short* sequence = (unsigned short*)(_buffer + 2);
|
||||
return ntohs(*sequence);
|
||||
}
|
||||
|
||||
void Packet::sequence(unsigned short sequence)
|
||||
{
|
||||
if (_buffer && _length > 4) {
|
||||
sequence = htons(sequence);
|
||||
memcpy(_buffer + 2, &sequence, 2);
|
||||
} else {
|
||||
log("Packet::sequence(): Null or too short buffer", ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Packet::headerLength()
|
||||
{
|
||||
if (_layout) {
|
||||
switch (_layout->frequency) {
|
||||
case frequencies::Low:
|
||||
return 8;
|
||||
case frequencies::Medium:
|
||||
return 6;
|
||||
case frequencies::High:
|
||||
return 5;
|
||||
case frequencies::Invalid:
|
||||
log("Packet::headerLength(): Invalid frequency", ERROR);
|
||||
break;
|
||||
default:
|
||||
log("Packet::headerLength(): Unknown frequency", ERROR);
|
||||
}
|
||||
} else {
|
||||
log("Packet::headerLength(): layout is NULL", ERROR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
boost::any Packet::getField(std::string blockName, std::string fieldName)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
boost::any Packet::getField(std::string blockName, size_t blockNumber, std::string fieldName)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PacketBlockPtr Packet::getBlock(std::string blockName)
|
||||
{
|
||||
PacketBlockPtr block;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
PacketBlockPtr Packet::getBlock(std::string blockName, size_t blockNumber)
|
||||
{
|
||||
PacketBlockPtr block;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
BlockList Packet::getBlocks()
|
||||
{
|
||||
std::list<packetBlock*>::iterator blockMap;
|
||||
std::list<packetField*>::iterator fieldMap;
|
||||
BlockList blockList;
|
||||
PacketBlockPtr block;
|
||||
size_t pos = headerLength();
|
||||
|
||||
for (blockMap = _layout->blocks.begin(); blockMap != _layout->blocks.end(); ++blockMap) {
|
||||
size_t blockCount;
|
||||
|
||||
if ((*blockMap)->count == -1) {
|
||||
if (pos < _length) {
|
||||
blockCount = _buffer[pos];
|
||||
pos++;
|
||||
} else {
|
||||
log("Packet::getBlocks(): goto 1 reached", WARNING);
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
blockCount = (*blockMap)->count;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < blockCount; ++i) {
|
||||
block.reset(new PacketBlock(*blockMap));
|
||||
blockList.push_back(block);
|
||||
|
||||
for (fieldMap = (*blockMap)->fields.begin(); fieldMap != (*blockMap)->fields.end(); ++fieldMap) {
|
||||
size_t fieldCount = (*fieldMap)->count;
|
||||
|
||||
for (size_t j = 0; j < fieldCount; ++j) {
|
||||
size_t fieldSize;
|
||||
|
||||
if ((*fieldMap)->type == types::Variable) {
|
||||
if (pos < _length) {
|
||||
fieldSize = _buffer[pos];
|
||||
pos++;
|
||||
} else {
|
||||
log("Packet::getBlocks(): goto 2 reached", WARNING);
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
fieldSize = _protocol->typeSize((*fieldMap)->type);
|
||||
}
|
||||
|
||||
if (pos + fieldSize <= _length) {
|
||||
PacketFieldPtr packetFieldPtr(new PacketField(*fieldMap, _buffer + pos, fieldSize));
|
||||
block->fields.push_back(packetFieldPtr);
|
||||
|
||||
pos += fieldSize;
|
||||
} else {
|
||||
log("Packet::getBlocks(): goto 3 reached", WARNING);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
return blockList;
|
||||
}
|
||||
|
||||
|
||||
/*void Packet::unserialize()
|
||||
{
|
||||
size_t pos;
|
||||
size_t i;
|
||||
size_t j;
|
||||
size_t fieldSize;
|
||||
byte frequency;
|
||||
byte fieldFrequency;
|
||||
unsigned short command;
|
||||
std::list<packetBlock*>::iterator block;
|
||||
std::list<packetField*>::iterator field;
|
||||
|
||||
// Determine the packet frequency
|
||||
if (_length > 4) {
|
||||
if (_buffer[4] == 0xFF) {
|
||||
if (_buffer[5] == 0xFF) {
|
||||
// Low frequency
|
||||
_frequency = frequencies::Low;
|
||||
memcpy(&command, &_buffer[6], 2);
|
||||
command = ntohs(command);
|
||||
_layout = _protocol->command(command, frequencies::Low);
|
||||
_command = _protocol->commandString(command, frequencies::Low);
|
||||
pos = 8;
|
||||
} else {
|
||||
// Medium frequency
|
||||
_frequency = frequencies::Medium;
|
||||
command = _buffer[5];
|
||||
_layout = _protocol->command(command, frequencies::Medium);
|
||||
_command = _protocol->commandString(command, frequencies::Medium);
|
||||
pos = 6;
|
||||
}
|
||||
} else {
|
||||
// High frequency
|
||||
_frequency = frequencies::High;
|
||||
command = _buffer[4];
|
||||
_layout = _protocol->command(command, frequencies::High);
|
||||
_command = _protocol->commandString(command, frequencies::High);
|
||||
pos = 5;
|
||||
}
|
||||
} else {
|
||||
pos = _length;
|
||||
}
|
||||
|
||||
// Clear any old structures
|
||||
blockContainers.clear();
|
||||
|
||||
// Iterate through the packet map
|
||||
if (_layout) {
|
||||
for (block = _layout->blocks.begin(); block != _layout->blocks.end(); ++block) {
|
||||
if (pos <= _length) {
|
||||
// Get the number of occurrences for this block
|
||||
if ((*block)->frequency == -1) {
|
||||
// First byte of a variable block is the number of occurrences (frequency)
|
||||
memcpy(&frequency, _buffer + pos, 1);
|
||||
pos++;
|
||||
} else {
|
||||
frequency = (*block)->frequency;
|
||||
}
|
||||
|
||||
// Create a BlockContainer for this block
|
||||
BlockContainerPtr blockContainerPtr(new BlockContainer((*block)));
|
||||
blockContainers.push_back(blockContainerPtr);
|
||||
|
||||
// Iterate through this set of blocks
|
||||
for (i = 0; i < frequency; ++i) {
|
||||
BlockPtr blockPtr(new Block());
|
||||
blockContainerPtr->blocks.push_back(blockPtr);
|
||||
|
||||
// Iterate through this block
|
||||
for (field = (*block)->fields.begin(); field != (*block)->fields.end(); ++field) {
|
||||
if (pos <= _length) {
|
||||
fieldFrequency = (*field)->frequency;
|
||||
|
||||
for (j = 0; j < fieldFrequency; j++) {
|
||||
if ((*field)->type == types::Variable) {
|
||||
// First byte of a variable field is the length in bytes
|
||||
size_t length;
|
||||
memcpy(&length, _buffer + pos, 1);
|
||||
pos++;
|
||||
|
||||
FieldPtr fieldPtr(new Variable(_buffer + pos, length));
|
||||
blockPtr->push_back(fieldPtr);
|
||||
pos += length;
|
||||
} else {
|
||||
// Get the size of this field
|
||||
fieldSize = _protocol->typeSize((*field)->type);
|
||||
|
||||
if (pos + fieldSize <= _length) {
|
||||
FieldPtr fieldPtr = createField((*field), _buffer + pos);
|
||||
blockPtr->push_back(fieldPtr);
|
||||
pos += fieldSize;
|
||||
} else {
|
||||
log("Reached the end of the packet before the end of the map (1)", WARNING);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//log("Reached the end of the packet before the end of the map (2)", WARNING);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log("Reached the end of the packet before the end of the map (3)", WARNING);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log("Packet::unserialize(): Trying to unserialize a packet with no layout", ERROR);
|
||||
}
|
||||
|
||||
done:
|
||||
return;
|
||||
}*/
|
||||
|
||||
111
src/PacketBuilder.cpp
Normal file
111
src/PacketBuilder.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "PacketBuilder.h"
|
||||
|
||||
PacketPtr PacketAck(ProtocolManager* protocol, std::vector<unsigned int> IDList)
|
||||
{
|
||||
PacketPtr packet(new Packet("PacketAck", protocol));
|
||||
size_t length = IDList.size() * 4 + 1;
|
||||
byte* bytePtr = (byte*)malloc(length);
|
||||
std::vector<unsigned int>::iterator ID;
|
||||
unsigned int currentID;
|
||||
size_t pos = 1;
|
||||
|
||||
bytePtr[0] = (byte)IDList.size();
|
||||
|
||||
for (ID = IDList.begin(); ID != IDList.end(); ++ID) {
|
||||
currentID = *ID;
|
||||
memcpy(bytePtr + pos, ¤tID, 4);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
packet->payload(bytePtr, length);
|
||||
packet->flags(0);
|
||||
|
||||
free(bytePtr);
|
||||
return packet;
|
||||
}
|
||||
|
||||
PacketPtr PacketAck(ProtocolManager* protocol, unsigned int ID)
|
||||
{
|
||||
PacketPtr packet(new Packet("PacketAck", protocol));
|
||||
byte bytePtr[5];
|
||||
|
||||
bytePtr[0] = 1;
|
||||
|
||||
memcpy(bytePtr + 1, &ID, 4);
|
||||
|
||||
packet->payload(bytePtr, 5);
|
||||
packet->flags(0);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
PacketPtr UseCircuitCode(ProtocolManager* protocol, SimpleLLUUID AgentID, SimpleLLUUID SessionID, unsigned int Code)
|
||||
{
|
||||
PacketPtr packet(new Packet("UseCircuitCode", protocol));
|
||||
byte* bytePtr = (byte*)malloc(36);
|
||||
|
||||
memcpy(bytePtr, AgentID.data, 16);
|
||||
memcpy(bytePtr + 16, SessionID.data, 16);
|
||||
memcpy(bytePtr + 32, &Code, 4);
|
||||
|
||||
packet->payload(bytePtr, 36);
|
||||
packet->flags(htons(0x4000));
|
||||
|
||||
free(bytePtr);
|
||||
return packet;
|
||||
}
|
||||
|
||||
PacketPtr CompleteAgentMovement(ProtocolManager* protocol, SimpleLLUUID AgentID, SimpleLLUUID SessionID, unsigned int CircuitCode)
|
||||
{
|
||||
PacketPtr packet(new Packet("CompleteAgentMovement", protocol));
|
||||
byte* bytePtr = (byte*)malloc(36);
|
||||
unsigned short flags = MSG_RELIABLE;
|
||||
|
||||
memcpy(bytePtr, AgentID.data, 16);
|
||||
memcpy(bytePtr + 16, SessionID.data, 16);
|
||||
memcpy(bytePtr + 32, &CircuitCode, 4);
|
||||
|
||||
packet->payload(bytePtr, 36);
|
||||
packet->flags(htons(flags));
|
||||
|
||||
free(bytePtr);
|
||||
return packet;
|
||||
}
|
||||
|
||||
PacketPtr RegionHandshakeReply(ProtocolManager* protocol, unsigned int Flags)
|
||||
{
|
||||
PacketPtr packet(new Packet("RegionHandshakeReply", protocol));
|
||||
packet->payload((byte*)&Flags, 4);
|
||||
packet->flags(0);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
PacketPtr CompletePingCheck(ProtocolManager* protocol, byte PingID)
|
||||
{
|
||||
PacketPtr packet(new Packet("CompletePingCheck", protocol));
|
||||
packet->payload(&PingID, 1);
|
||||
packet->flags(0);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
PacketPtr DirLandQuery(ProtocolManager* protocol, bool ReservedNewbie, bool ForSale, SimpleLLUUID QueryID, bool Auction,
|
||||
unsigned int QueryFlags, SimpleLLUUID AgentID, SimpleLLUUID SessionID)
|
||||
{
|
||||
PacketPtr packet(new Packet("DirLandQuery", protocol));
|
||||
byte bytePtr[55];
|
||||
|
||||
bytePtr[0] = ReservedNewbie;
|
||||
bytePtr[1] = ForSale;
|
||||
memcpy(bytePtr + 2, QueryID.data, 16);
|
||||
bytePtr[18] = Auction;
|
||||
memcpy(bytePtr + 19, &QueryFlags, 4);
|
||||
memcpy(bytePtr + 23, AgentID.data, 16);
|
||||
memcpy(bytePtr + 39, SessionID.data, 16);
|
||||
|
||||
packet->payload(bytePtr, 55);
|
||||
packet->flags(0);
|
||||
|
||||
return packet;
|
||||
}
|
||||
@@ -31,6 +31,79 @@ bool getBlockMarkers(const char* buffer, size_t &start, size_t &end, size_t &chi
|
||||
return false;
|
||||
}
|
||||
|
||||
FieldPtr createField(packetField* field, byte* data)
|
||||
{
|
||||
FieldPtr fieldPtr;
|
||||
|
||||
switch (field->type) {
|
||||
case types::U8:
|
||||
fieldPtr.reset(new U8(data));
|
||||
break;
|
||||
case types::U16:
|
||||
fieldPtr.reset(new U16(data));
|
||||
break;
|
||||
case types::U32:
|
||||
fieldPtr.reset(new U32(data));
|
||||
break;
|
||||
case types::U64:
|
||||
fieldPtr.reset(new U64_(data));
|
||||
break;
|
||||
case types::S8:
|
||||
fieldPtr.reset(new S8(data));
|
||||
break;
|
||||
case types::S16:
|
||||
fieldPtr.reset(new S16(data));
|
||||
break;
|
||||
case types::S32:
|
||||
fieldPtr.reset(new S32(data));
|
||||
break;
|
||||
case types::S64:
|
||||
fieldPtr.reset(new S64(data));
|
||||
break;
|
||||
case types::F32:
|
||||
fieldPtr.reset(new F32(data));
|
||||
break;
|
||||
case types::F64:
|
||||
fieldPtr.reset(new F64(data));
|
||||
break;
|
||||
case types::LLUUID:
|
||||
fieldPtr.reset(new LLUUID(data));
|
||||
break;
|
||||
case types::Bool:
|
||||
fieldPtr.reset(new Bool(data));
|
||||
break;
|
||||
case types::LLVector3:
|
||||
fieldPtr.reset(new LLVector3(data));
|
||||
break;
|
||||
case types::LLVector3d:
|
||||
fieldPtr.reset(new LLVector3d(data));
|
||||
break;
|
||||
case types::LLVector4:
|
||||
fieldPtr.reset(new LLVector4(data));
|
||||
break;
|
||||
case types::LLQuaternion:
|
||||
fieldPtr.reset(new LLQuaternion(data));
|
||||
break;
|
||||
case types::IPADDR:
|
||||
fieldPtr.reset(new IPADDR(data));
|
||||
break;
|
||||
case types::IPPORT:
|
||||
fieldPtr.reset(new IPPORT(data));
|
||||
break;
|
||||
case types::Variable:
|
||||
log("Packet::createField(): Variable type", ERROR);
|
||||
break;
|
||||
case types::Invalid:
|
||||
log("Packet::createField(): Invalid type", ERROR);
|
||||
break;
|
||||
default:
|
||||
log("Packet::createField(): Unknown type", ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
return fieldPtr;
|
||||
}
|
||||
|
||||
ProtocolManager::ProtocolManager()
|
||||
{
|
||||
llTypes[0] = "U8";
|
||||
@@ -41,23 +114,21 @@ ProtocolManager::ProtocolManager()
|
||||
llTypes[5] = "S16";
|
||||
llTypes[6] = "S32";
|
||||
llTypes[7] = "S64";
|
||||
llTypes[8] = "F8";
|
||||
llTypes[9] = "F16";
|
||||
llTypes[10] = "F32";
|
||||
llTypes[11] = "F64";
|
||||
llTypes[12] = "LLUUID";
|
||||
llTypes[13] = "BOOL";
|
||||
llTypes[14] = "LLVector3";
|
||||
llTypes[15] = "LLVector3d";
|
||||
llTypes[16] = "LLVector4";
|
||||
llTypes[17] = "LLQuaternion";
|
||||
llTypes[18] = "IPADDR";
|
||||
llTypes[19] = "IPPORT";
|
||||
llTypes[20] = "Variable";
|
||||
llTypes[21] = "Fixed";
|
||||
llTypes[22] = "Single";
|
||||
llTypes[23] = "Multiple";
|
||||
llTypes[24] = "";
|
||||
llTypes[8] = "F32";
|
||||
llTypes[9] = "F64";
|
||||
llTypes[10] = "LLUUID";
|
||||
llTypes[11] = "BOOL";
|
||||
llTypes[12] = "LLVector3";
|
||||
llTypes[13] = "LLVector3d";
|
||||
llTypes[14] = "LLVector4";
|
||||
llTypes[15] = "LLQuaternion";
|
||||
llTypes[16] = "IPADDR";
|
||||
llTypes[17] = "IPPORT";
|
||||
llTypes[18] = "Variable";
|
||||
llTypes[19] = "Fixed";
|
||||
llTypes[20] = "Single";
|
||||
llTypes[21] = "Multiple";
|
||||
llTypes[22] = "";
|
||||
|
||||
llTypesSizes[0] = 1;
|
||||
llTypesSizes[1] = 2;
|
||||
@@ -67,19 +138,17 @@ ProtocolManager::ProtocolManager()
|
||||
llTypesSizes[5] = 2;
|
||||
llTypesSizes[6] = 4;
|
||||
llTypesSizes[7] = 8;
|
||||
llTypesSizes[8] = 1;
|
||||
llTypesSizes[9] = 2;
|
||||
llTypesSizes[10] = 4;
|
||||
llTypesSizes[11] = 8;
|
||||
llTypesSizes[12] = 16;
|
||||
llTypesSizes[13] = 1;
|
||||
llTypesSizes[14] = sizeof(llVector3);
|
||||
llTypesSizes[15] = sizeof(llVector3d);
|
||||
llTypesSizes[16] = sizeof(llVector4);
|
||||
llTypesSizes[17] = sizeof(llQuaternion);
|
||||
llTypesSizes[18] = 4;
|
||||
llTypesSizes[19] = 2;
|
||||
llTypesSizes[20] = -1;
|
||||
llTypesSizes[8] = 4;
|
||||
llTypesSizes[9] = 8;
|
||||
llTypesSizes[10] = 16;
|
||||
llTypesSizes[11] = 1;
|
||||
llTypesSizes[12] = 12;
|
||||
llTypesSizes[13] = 24;
|
||||
llTypesSizes[14] = 16;
|
||||
llTypesSizes[15] = 16;
|
||||
llTypesSizes[16] = 4;
|
||||
llTypesSizes[17] = 2;
|
||||
llTypesSizes[18] = -1;
|
||||
}
|
||||
|
||||
ProtocolManager::~ProtocolManager()
|
||||
@@ -134,7 +203,7 @@ void ProtocolManager::printMap()
|
||||
_lowPackets[i].encoded ? "Unencoded" : "Zerocoded");
|
||||
|
||||
for (j = _lowPackets[i].blocks.begin(); j != _lowPackets[i].blocks.end(); ++j) {
|
||||
printf("\t%04u %s (%02i)\n", (*j)->keywordPosition, (*j)->name.c_str(), (*j)->frequency);
|
||||
printf("\t%04u %s (%02i)\n", (*j)->keywordPosition, (*j)->name.c_str(), (*j)->count);
|
||||
|
||||
for (k = (*j)->fields.begin(); k != (*j)->fields.end(); ++k) {
|
||||
printf("\t\t%04u %s (%s)\n", (*k)->keywordPosition, (*k)->name.c_str(), typeName((*k)->type).c_str());
|
||||
@@ -150,7 +219,7 @@ void ProtocolManager::printMap()
|
||||
_mediumPackets[i].encoded ? "Unencoded" : "Zerocoded");
|
||||
|
||||
for (j = _mediumPackets[i].blocks.begin(); j != _mediumPackets[i].blocks.end(); ++j) {
|
||||
printf("\t%04u %s (%02i)\n", (*j)->keywordPosition, (*j)->name.c_str(), (*j)->frequency);
|
||||
printf("\t%04u %s (%02i)\n", (*j)->keywordPosition, (*j)->name.c_str(), (*j)->count);
|
||||
|
||||
for (k = (*j)->fields.begin(); k != (*j)->fields.end(); ++k) {
|
||||
printf("\t\t%04u %s (%s)\n", (*k)->keywordPosition, (*k)->name.c_str(), typeName((*k)->type).c_str());
|
||||
@@ -166,7 +235,7 @@ void ProtocolManager::printMap()
|
||||
_highPackets[i].encoded ? "Unencoded" : "Zerocoded");
|
||||
|
||||
for (j = _highPackets[i].blocks.begin(); j != _highPackets[i].blocks.end(); ++j) {
|
||||
printf("\t%04u %s (%02i)\n", (*j)->keywordPosition, (*j)->name.c_str(), (*j)->frequency);
|
||||
printf("\t%04u %s (%02i)\n", (*j)->keywordPosition, (*j)->name.c_str(), (*j)->count);
|
||||
|
||||
for (k = (*j)->fields.begin(); k != (*j)->fields.end(); ++k) {
|
||||
printf("\t\t%04u %s (%s)\n", (*k)->keywordPosition, (*k)->name.c_str(), typeName((*k)->type).c_str());
|
||||
@@ -210,10 +279,10 @@ bool ProtocolManager::getFields(packetBlock* block, std::string protocolMap, siz
|
||||
// Get the field type
|
||||
delimiter = temp.find_first_of(" ");
|
||||
if (delimiter != std::string::npos) {
|
||||
field->frequency = atoi(temp.substr(delimiter + 1, temp.length() - delimiter - 1).c_str());
|
||||
field->count = atoi(temp.substr(delimiter + 1, temp.length() - delimiter - 1).c_str());
|
||||
temp = temp.substr(0, delimiter);
|
||||
} else {
|
||||
field->frequency = 1;
|
||||
field->count = 1;
|
||||
}
|
||||
field->type = fieldType(temp);
|
||||
|
||||
@@ -255,14 +324,14 @@ bool ProtocolManager::getBlocks(packetDiagram* packet, std::string protocolMap,
|
||||
// Find the frequency of this block (-1 for variable, 1 for single)
|
||||
temp = block_tokens.at(1);
|
||||
if (temp == "Variable") {
|
||||
block->frequency = -1;
|
||||
block->count = -1;
|
||||
} else if (temp == "Single") {
|
||||
block->frequency = 1;
|
||||
block->count = 1;
|
||||
} else if (temp == "Multiple") {
|
||||
std::istringstream int_stream(block_tokens.at(2));
|
||||
int_stream >> block->frequency;
|
||||
int_stream >> block->count;
|
||||
} else {
|
||||
block->frequency = 5;
|
||||
block->count = 5;
|
||||
}
|
||||
|
||||
// Get the keyword position of this block
|
||||
@@ -400,21 +469,21 @@ int ProtocolManager::buildProtocolMap(std::string filename)
|
||||
int fixed = httoi(temp.c_str()) ^ 0xffff0000;
|
||||
layout = &_lowPackets[fixed];
|
||||
layout->id = fixed;
|
||||
layout->frequency = ll::Low;
|
||||
layout->frequency = frequencies::Low;
|
||||
} else if (temp == "Low") {
|
||||
layout = &_lowPackets[low];
|
||||
layout->id = low;
|
||||
layout->frequency = ll::Low;
|
||||
layout->frequency = frequencies::Low;
|
||||
low++;
|
||||
} else if (temp == "Medium") {
|
||||
layout = &_mediumPackets[medium];
|
||||
layout->id = medium;
|
||||
layout->frequency = ll::Medium;
|
||||
layout->frequency = frequencies::Medium;
|
||||
medium++;
|
||||
} else if (temp == "High") {
|
||||
layout = &_highPackets[high];
|
||||
layout->id = high;
|
||||
layout->frequency = ll::High;
|
||||
layout->frequency = frequencies::High;
|
||||
high++;
|
||||
} else {
|
||||
log("ProtocolManager::buildProtocolMap(): Unknown frequency: " + temp, ERROR);
|
||||
@@ -466,17 +535,17 @@ packetDiagram* ProtocolManager::command(std::string command)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
packetDiagram* ProtocolManager::command(unsigned short command, ll::frequency frequency)
|
||||
packetDiagram* ProtocolManager::command(unsigned short command, frequencies::Frequency frequency)
|
||||
{
|
||||
switch (frequency)
|
||||
{
|
||||
case ll::Low:
|
||||
case frequencies::Low:
|
||||
return &_lowPackets[command];
|
||||
case ll::Medium:
|
||||
case frequencies::Medium:
|
||||
return &_mediumPackets[command];
|
||||
case ll::High:
|
||||
case frequencies::High:
|
||||
return &_highPackets[command];
|
||||
case ll::Invalid:
|
||||
case frequencies::Invalid:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -484,17 +553,17 @@ packetDiagram* ProtocolManager::command(unsigned short command, ll::frequency fr
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string ProtocolManager::commandString(unsigned short command, ll::frequency frequency)
|
||||
std::string ProtocolManager::commandString(unsigned short command, frequencies::Frequency frequency)
|
||||
{
|
||||
switch (frequency)
|
||||
{
|
||||
case ll::Low:
|
||||
case frequencies::Low:
|
||||
return _lowPackets[command].name;
|
||||
case ll::Medium:
|
||||
case frequencies::Medium:
|
||||
return _mediumPackets[command].name;
|
||||
case ll::High:
|
||||
case frequencies::High:
|
||||
return _highPackets[command].name;
|
||||
case ll::Invalid:
|
||||
case frequencies::Invalid:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -504,23 +573,23 @@ std::string ProtocolManager::commandString(unsigned short command, ll::frequency
|
||||
return "";
|
||||
}
|
||||
|
||||
ll::llType ProtocolManager::fieldType(std::string type)
|
||||
types::Type ProtocolManager::fieldType(std::string type)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (llTypes[i].length()) {
|
||||
if (type == llTypes[i]) {
|
||||
return (ll::llType)i;
|
||||
return (types::Type)i;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
log("ProtocolManager::fieldType(): Unknown type: " + type, WARNING);
|
||||
return ll::INVALID_TYPE;
|
||||
return types::Invalid;
|
||||
}
|
||||
|
||||
int ProtocolManager::typeSize(ll::llType type)
|
||||
int ProtocolManager::typeSize(types::Type type)
|
||||
{
|
||||
if (type < 0 || type > 19) {
|
||||
std::stringstream message;
|
||||
@@ -533,7 +602,7 @@ int ProtocolManager::typeSize(ll::llType type)
|
||||
return llTypesSizes[type];
|
||||
}
|
||||
|
||||
std::string ProtocolManager::typeName(ll::llType type)
|
||||
std::string ProtocolManager::typeName(types::Type type)
|
||||
{
|
||||
std::string typeName;
|
||||
|
||||
@@ -550,17 +619,17 @@ std::string ProtocolManager::typeName(ll::llType type)
|
||||
return typeName;
|
||||
}
|
||||
|
||||
int ProtocolManager::blockFrequency(packetDiagram* layout, std::string block)
|
||||
int ProtocolManager::blockCount(packetDiagram* layout, std::string block)
|
||||
{
|
||||
std::list<packetBlock*>::iterator i;
|
||||
|
||||
for ( i = layout->blocks.begin(); i != layout->blocks.end(); ++i) {
|
||||
if ((*i)->name == block) {
|
||||
return (*i)->frequency;
|
||||
return (*i)->count;
|
||||
}
|
||||
}
|
||||
|
||||
log("ProtocolManager::blockFrequency(): Unknown block: " + block, WARNING);
|
||||
log("ProtocolManager::blockCount(): Unknown block: " + block, WARNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ SecondLife::~SecondLife()
|
||||
|
||||
void SecondLife::tick()
|
||||
{
|
||||
Packet* packet;
|
||||
std::list<Packet*>* inbox = _network->inbox();
|
||||
|
||||
PacketPtr packet;
|
||||
std::list<PacketPtr>* inbox = _network->inbox();
|
||||
|
||||
// When we get to stream handling, this function will build data stream
|
||||
// classes and append new data, for sounds/images/animations/etc
|
||||
|
||||
@@ -28,8 +28,11 @@ void SecondLife::tick()
|
||||
// firing callbacks as it goes
|
||||
if (_network) {
|
||||
while (inbox->size() > 0) {
|
||||
boost::mutex::scoped_lock lock(_network->inboxMutex);
|
||||
packet = inbox->front();
|
||||
inbox->pop_front();
|
||||
lock.unlock();
|
||||
|
||||
std::string command = packet->command();
|
||||
|
||||
std::map<std::string, callback>::iterator handler = _callbacks.find(command);
|
||||
@@ -43,8 +46,6 @@ void SecondLife::tick()
|
||||
} else {
|
||||
(handler->second)(command, packet);
|
||||
}
|
||||
|
||||
delete packet;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ SimConnection::SimConnection()
|
||||
_sequence = 1;
|
||||
}
|
||||
|
||||
SimConnection::SimConnection(boost::asio::ipv4::address ip, unsigned short port, U32 code)
|
||||
SimConnection::SimConnection(boost::asio::ipv4::address ip, unsigned short port, unsigned int code)
|
||||
{
|
||||
_endpoint = boost::asio::ipv4::udp::endpoint(port, ip);
|
||||
_code = code;
|
||||
|
||||
@@ -194,80 +194,70 @@ void log(std::string line, LogLevel level)
|
||||
|
||||
line += "\n";
|
||||
|
||||
#ifdef DEBUG
|
||||
std::cout << line;
|
||||
|
||||
/*FILE* logFile = fopen("libsecondlife-log.txt", "a");
|
||||
#else
|
||||
FILE* logFile = fopen("libsecondlife-log.txt", "a");
|
||||
if (logFile) {
|
||||
fwrite(line.c_str(), sizeof(char), line.length(), logFile);
|
||||
fclose(logFile);
|
||||
}*/
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int zeroDecode(char* src, int srclen, char* dest, int destlen)
|
||||
int zeroDecode(byte* src, int srclen, byte* dest)
|
||||
{
|
||||
int zerolen = 0;
|
||||
|
||||
if (src[0] & MSG_ZEROCODED) {
|
||||
memcpy(dest, src, 4);
|
||||
zerolen += 4;
|
||||
memcpy(dest, src, 4);
|
||||
zerolen += 4;
|
||||
|
||||
for (int i = zerolen; i < srclen; i++) {
|
||||
if ((unsigned char)src[i] == 0x00) {
|
||||
for (unsigned char j = 0; j < (unsigned char)src[i+1]; j++) {
|
||||
dest[zerolen++] = 0x00;
|
||||
}
|
||||
|
||||
i++;
|
||||
} else {
|
||||
dest[zerolen++] = src[i];
|
||||
for (int i = zerolen; i < srclen; i++) {
|
||||
if (src[i] == 0x00) {
|
||||
for (byte j = 0; j < src[i + 1]; j++) {
|
||||
dest[zerolen++] = 0x00;
|
||||
}
|
||||
|
||||
i++;
|
||||
} else {
|
||||
dest[zerolen++] = src[i];
|
||||
}
|
||||
} else {
|
||||
memcpy(dest, src, srclen);
|
||||
zerolen = srclen;
|
||||
}
|
||||
|
||||
return zerolen;
|
||||
}
|
||||
|
||||
int zeroEncode(char* src, int srclen, char* dest, int destlen)
|
||||
int zeroEncode(byte* src, int srclen, byte* dest)
|
||||
{
|
||||
int zerolen = 0;
|
||||
unsigned char zerocount = 0;
|
||||
byte zerocount = 0;
|
||||
|
||||
if (src[0] & MSG_ZEROCODED) {
|
||||
memcpy(dest, src, 4);
|
||||
zerolen += 4;
|
||||
memcpy(dest, src, 4);
|
||||
zerolen += 4;
|
||||
|
||||
for (int i = zerolen; i < srclen; i++) {
|
||||
if ((unsigned char)src[i] == 0x00) {
|
||||
for (int i = zerolen; i < srclen; i++) {
|
||||
if (src[i] == 0x00) {
|
||||
zerocount++;
|
||||
|
||||
if (zerocount == 0) {
|
||||
dest[zerolen++] = 0x00;
|
||||
dest[zerolen++] = 0xff;
|
||||
zerocount++;
|
||||
|
||||
if (zerocount == 0) {
|
||||
dest[zerolen++] = 0x00;
|
||||
dest[zerolen++] = 0xff;
|
||||
zerocount++;
|
||||
}
|
||||
} else {
|
||||
if (zerocount) {
|
||||
dest[zerolen++] = 0x00;
|
||||
dest[zerolen++] = zerocount;
|
||||
zerocount = 0;
|
||||
}
|
||||
|
||||
dest[zerolen++] = src[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (zerocount) {
|
||||
dest[zerolen++] = 0x00;
|
||||
dest[zerolen++] = zerocount;
|
||||
zerocount = 0;
|
||||
}
|
||||
|
||||
if (zerocount) {
|
||||
dest[zerolen++] = 0x00;
|
||||
dest[zerolen++] = zerocount;
|
||||
dest[zerolen++] = src[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(dest, src, srclen);
|
||||
zerolen = srclen;
|
||||
|
||||
if (zerocount) {
|
||||
dest[zerolen++] = 0x00;
|
||||
dest[zerolen++] = zerocount;
|
||||
}
|
||||
|
||||
return zerolen;
|
||||
|
||||
@@ -6,28 +6,12 @@ SecondLife* client;
|
||||
|
||||
void loginHandler(loginParameters login)
|
||||
{
|
||||
LLUUID tempID;
|
||||
|
||||
if (login.reason.length()) {
|
||||
printf("test_app: Login failed\n");
|
||||
} else {
|
||||
// Set the variables received from login
|
||||
client->session_id((LLUUID)login.session_id);
|
||||
client->secure_session_id((LLUUID)login.secure_session_id);
|
||||
client->agent_id((LLUUID)login.agent_id);
|
||||
|
||||
boost::asio::ipv4::address address(login.sim_ip);
|
||||
client->connectSim(address, login.sim_port, login.circuit_code, true);
|
||||
|
||||
Packet* packet = new Packet("CompleteAgentMovement", client->protocol());
|
||||
|
||||
tempID = client->agent_id();
|
||||
packet->setField("AgentData", 1, "AgentID", 1, &tempID);
|
||||
tempID = client->session_id();
|
||||
packet->setField("AgentData", 1, "SessionID", 1, &tempID);
|
||||
packet->setField("AgentData", 1, "CircuitCode", 1, &login.circuit_code);
|
||||
|
||||
client->sendPacket(packet);
|
||||
PacketPtr packetPtr = DirLandQuery(client->protocol(), false, true, SimpleLLUUID(1), true, 0,
|
||||
client->agent_id(), client->session_id());
|
||||
client->sendPacket(packetPtr);
|
||||
|
||||
while (1) {
|
||||
client->tick();
|
||||
@@ -35,18 +19,64 @@ void loginHandler(loginParameters login)
|
||||
}
|
||||
}
|
||||
|
||||
void ignorePacket(std::string command, Packet* packet)
|
||||
/*void writePacket(std::string command, PacketPtr packet)
|
||||
{
|
||||
//printf("Ignoring...\n");
|
||||
byte* data = packet->buffer();
|
||||
size_t length = packet->length();
|
||||
|
||||
printf("Wrote packet to file\n");
|
||||
|
||||
FILE* file = fopen("dirlandreply.dat", "ab");
|
||||
fwrite(data, length, 1, file);
|
||||
fclose(file);
|
||||
}*/
|
||||
|
||||
void landPacket(std::string command, PacketPtr packet)
|
||||
{
|
||||
FieldList::iterator field;
|
||||
BlockList::iterator block;
|
||||
BlockList blocks = packet->getBlocks();
|
||||
bool firstLand;
|
||||
int area;
|
||||
bool forSale;
|
||||
byte* parcelID;
|
||||
std::string name;
|
||||
bool auction;
|
||||
int salePrice;
|
||||
|
||||
for (block = blocks.begin(); block != blocks.end(); ++block) {
|
||||
if ((*block)->name() == "QueryReplies") {
|
||||
for (field = (*block)->fields.begin(); field != (*block)->fields.end(); ++field) {
|
||||
if ((*field)->name() == "ReservedNewbie") {
|
||||
firstLand = *(*field)->data;
|
||||
} else if ((*field)->name() == "ActualArea") {
|
||||
area = *(int*)(*field)->data;
|
||||
} else if ((*field)->name() == "ForSale") {
|
||||
forSale = *(*field)->data;
|
||||
} else if ((*field)->name() == "ParcelID") {
|
||||
parcelID = (*field)->data;
|
||||
} else if ((*field)->name() == "Name") {
|
||||
name = (char*)(*field)->data;
|
||||
} else if ((*field)->name() == "Auction") {
|
||||
auction = *(*field)->data;
|
||||
} else if ((*field)->name() == "SalePrice") {
|
||||
salePrice = *(int*)(*field)->data;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << name << " | Price: " << salePrice << " | Area: " << area << " | For Sale: "
|
||||
<< forSale << " | Auction: " << auction << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void receivedPacket(std::string command, Packet* packet)
|
||||
void receivedPacket(std::string command, PacketPtr packet)
|
||||
{
|
||||
byte* data = packet->rawData();
|
||||
/*byte* data = packet->buffer();
|
||||
size_t length = packet->length();
|
||||
|
||||
if (!command.length()) {
|
||||
printf("test_app: Received foreign datagram. Possibly %u frequency:\n", packet->frequency());
|
||||
printf("test_app: Received foreign datagram:\n");
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
printf("%02x ", data[i]);
|
||||
@@ -58,7 +88,7 @@ void receivedPacket(std::string command, Packet* packet)
|
||||
|
||||
printf("test_app: Received a %u byte %s datagram (%u)\n", length, command.c_str(), packet->sequence());
|
||||
|
||||
return;
|
||||
return;*/
|
||||
}
|
||||
|
||||
int main()
|
||||
@@ -91,12 +121,10 @@ int main()
|
||||
|
||||
//client->printMap();
|
||||
|
||||
client->registerCallback("ViewerEffect", &ignorePacket);
|
||||
client->registerCallback("SimulatorViewerTimeMessage", &ignorePacket);
|
||||
client->registerCallback("CoarseLocationUpdate", &ignorePacket);
|
||||
client->registerCallback("DirLandReply", &landPacket);
|
||||
client->registerCallback("Default", &receivedPacket);
|
||||
|
||||
client->login("Chelsea", "Cork", "grape", "00:00:00:00:00:00", 1, 10, 0, 34, "Win", "0", "test_app",
|
||||
client->login("Chelsea", "Cork", "grapefruit", "00:00:00:00:00:00", 1, 10, 1, 0, "Win", "0", "test_app",
|
||||
"jhurliman@wsu.edu", loginHandler);
|
||||
|
||||
delete client;
|
||||
|
||||
Reference in New Issue
Block a user