From 2bcf2add62279af0fc8271aa081ea0f5cf75a02c Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 1 Jun 2006 08:09:12 +0000 Subject: [PATCH] * 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 --- Jamfile | 7 +- include/Fields.h | 317 ++++++++++++++++ include/Network.h | 47 +-- include/Packet.h | 86 +++-- include/PacketBuilder.h | 46 +++ include/ProtocolManager.h | 86 +---- include/SecondLife.h | 22 +- include/SimConnection.h | 10 +- include/includes.h | 42 +-- src/Network.cpp | 213 ++++++----- src/Packet.cpp | 762 ++++++++++++++++++++------------------ src/PacketBuilder.cpp | 111 ++++++ src/ProtocolManager.cpp | 191 +++++++--- src/SecondLife.cpp | 11 +- src/SimConnection.cpp | 2 +- src/functions.cpp | 86 ++--- test_app/main.cpp | 86 +++-- 17 files changed, 1378 insertions(+), 747 deletions(-) create mode 100644 include/Fields.h create mode 100644 include/PacketBuilder.h create mode 100644 src/PacketBuilder.cpp diff --git a/Jamfile b/Jamfile index bdb98b28..2b42754d 100644 --- a/Jamfile +++ b/Jamfile @@ -8,6 +8,7 @@ lib libcrypto : : crypto ; lib libsocket : : socket ; lib libnsl : : nsl ; lib boostthread : : boost_thread ; +lib libcurl : : curl ; if $(UNIX) { @@ -21,12 +22,14 @@ if $(UNIX) } lib secondlife - : [ glob src/*.cpp ] - openssl + : [ glob src/*.cpp ] + openssl libcrypto + libcurl boostthread $(SOCKET_LIBS) : multi + debug:DEBUG ; build-project test_app ; diff --git a/include/Fields.h b/include/Fields.h new file mode 100644 index 00000000..53807220 --- /dev/null +++ b/include/Fields.h @@ -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 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_ diff --git a/include/Network.h b/include/Network.h index d0ca18f0..285a655c 100644 --- a/include/Network.h +++ b/include/Network.h @@ -68,20 +68,19 @@ class SecondLife; class LIBSECONDLIFE_CLASS_DECL Network { protected: - boost::asio::demuxer _demuxer; - std::vector _connections; - std::list _inbox; + boost::asio::demuxer _demuxer; + std::vector _connections; + std::list _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* inbox() { return &_inbox; }; + std::list* 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_ diff --git a/include/Packet.h b/include/Packet.h index 62d5e034..ce87005c 100644 --- a/include/Packet.h +++ b/include/Packet.h @@ -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 PacketPtr; +typedef boost::shared_ptr PacketBlockPtr; +typedef boost::shared_ptr PacketFieldPtr; + +// Smart pointer lists +typedef std::vector BlockList; +typedef std::vector 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 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_ diff --git a/include/PacketBuilder.h b/include/PacketBuilder.h new file mode 100644 index 00000000..3d9b2c89 --- /dev/null +++ b/include/PacketBuilder.h @@ -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 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_ diff --git a/include/ProtocolManager.h b/include/ProtocolManager.h index 2cf0c874..c6e092f6 100644 --- a/include/ProtocolManager.h +++ b/include/ProtocolManager.h @@ -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 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 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); }; diff --git a/include/SecondLife.h b/include/SecondLife.h index b743ab87..e52d2601 100644 --- a/include/SecondLife.h +++ b/include/SecondLife.h @@ -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 callback; +// void functionname(std::string command, PacketPtr) +typedef boost::function2 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; }; diff --git a/include/SimConnection.h b/include/SimConnection.h index 4e48b6f4..da77fa46 100644 --- a/include/SimConnection.h +++ b/include/SimConnection.h @@ -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 SimConnectionPtr; + #endif //_SL_SIMCONNECTION_ diff --git a/include/includes.h b/include/includes.h index 12f74bb2..a5d8084c 100644 --- a/include/includes.h +++ b/include/includes.h @@ -45,10 +45,13 @@ #include #include #include +#include +#include #include #include #include #include +#include #include @@ -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_ diff --git a/src/Network.cpp b/src/Network.cpp index e65914eb..956ecc0d 100644 --- a/src/Network.cpp +++ b/src/Network.cpp @@ -1,13 +1,13 @@ #include #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::iterator connection; - std::list::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, "message"); - log("Network::loginReply(): Login failed. Reason: " + login.reason + ". Message: " + login.message, WARNING); } else { msg = rpcGetString(reply, "logintrue"); 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); diff --git a/src/Packet.cpp b/src/Packet.cpp index 9835fb1f..1c3802f2 100644 --- a/src/Packet.cpp +++ b/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::iterator i; - - for (i = _layout->blocks.begin(); i != _layout->blocks.end(); ++i) { - if ((*i)->name == block) { - packetBlock* block = (*i); - - std::list::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::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::iterator blockMap; + std::list::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::iterator block; + std::list::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; +}*/ diff --git a/src/PacketBuilder.cpp b/src/PacketBuilder.cpp new file mode 100644 index 00000000..3ff58cc8 --- /dev/null +++ b/src/PacketBuilder.cpp @@ -0,0 +1,111 @@ +#include "PacketBuilder.h" + +PacketPtr PacketAck(ProtocolManager* protocol, std::vector IDList) +{ + PacketPtr packet(new Packet("PacketAck", protocol)); + size_t length = IDList.size() * 4 + 1; + byte* bytePtr = (byte*)malloc(length); + std::vector::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; +} diff --git a/src/ProtocolManager.cpp b/src/ProtocolManager.cpp index 37e88f92..e4266588 100644 --- a/src/ProtocolManager.cpp +++ b/src/ProtocolManager.cpp @@ -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::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; } diff --git a/src/SecondLife.cpp b/src/SecondLife.cpp index a6f7d556..09879609 100644 --- a/src/SecondLife.cpp +++ b/src/SecondLife.cpp @@ -18,9 +18,9 @@ SecondLife::~SecondLife() void SecondLife::tick() { - Packet* packet; - std::list* inbox = _network->inbox(); - + PacketPtr packet; + std::list* 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::iterator handler = _callbacks.find(command); @@ -43,8 +46,6 @@ void SecondLife::tick() } else { (handler->second)(command, packet); } - - delete packet; } } diff --git a/src/SimConnection.cpp b/src/SimConnection.cpp index 222e4fc9..ef069758 100644 --- a/src/SimConnection.cpp +++ b/src/SimConnection.cpp @@ -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; diff --git a/src/functions.cpp b/src/functions.cpp index 0a5c98af..896f5d87 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -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; diff --git a/test_app/main.cpp b/test_app/main.cpp index 1e312772..99f78012 100644 --- a/test_app/main.cpp +++ b/test_app/main.cpp @@ -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;