* 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:
John Hurliman
2006-06-01 08:09:12 +00:00
parent 19f531a625
commit 2bcf2add62
17 changed files with 1378 additions and 747 deletions

View File

@@ -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
View 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_

View File

@@ -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_

View File

@@ -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
View 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_

View File

@@ -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);
};

View File

@@ -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; };

View File

@@ -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_

View File

@@ -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_

View File

@@ -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);

View File

@@ -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
View 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, &currentID, 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;
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;