Added VChatAPI library

This commit is contained in:
Anonymous
2014-01-17 05:18:10 -07:00
parent 4fae2dfe0f
commit 4ba1363775
97 changed files with 29311 additions and 62 deletions
@@ -40,36 +40,31 @@ endif()
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/shared
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCommandParser/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCompression/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDatabaseInterface/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCompression/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFile/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedGame/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedLog/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMath/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedLog/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMath/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMathArchive/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMessageDispatch/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMessageDispatch/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetwork/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetworkMessages/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedRandom/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedSynchronization/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedThread/include/public
#${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedUtility/include/public
#${SWG_ENGINE_SOURCE_DIR}/server/library/serverKeyShare/include/public
#${SWG_ENGINE_SOURCE_DIR}/server/library/serverNetworkMessages/include/public
#${SWG_ENGINE_SOURCE_DIR}/server/library/serverUtility/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetworkMessages/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedThread/include/public
${SWG_ENGINE_SOURCE_DIR}/server/library/serverMetrics/include/public
${SWG_ENGINE_SOURCE_DIR}/server/library/serverNetworkMessages/include/public
${SWG_ENGINE_SOURCE_DIR}/server/library/serverUtility/include/public
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include
#${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localization/include
#${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localizationArchive/include/public
#${SWG_EXTERNALS_SOURCE_DIR}/ours/library/singleton/include
#${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include
#${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicodeArchive/include/public
#${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/platform/projects
#${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/platform/utils
#${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/udplibrary
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localization/include
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localizationArchive/include/public
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/singleton/include
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicodeArchive/include/public
${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/soePlatform/ChatAPI/projects
${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/soePlatform/ChatAPI/utils
${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/soePlatform/VChatAPI/projects/VChat
${SWG_EXTERNALS_SOURCE_DIR}/3rd/library/soePlatform/VChatAPI/utils2.0/utils
)
link_directories(${STLPORT_LIBDIR})
@@ -80,41 +75,33 @@ add_executable(ChatServer
)
target_link_libraries(ChatServer
# sharedCommandParser
# sharedCompression
# sharedDatabaseInterface
# sharedDatabaseInterface_oci
# sharedDebug
# sharedFile
# sharedFoundation
# sharedGame
# sharedLog
# sharedMath
# sharedMemoryManager
# sharedMessageDispatch
# sharedNetwork
# sharedNetworkMessages
# sharedRandom
# sharedSynchronization
# sharedThread
# sharedUtility
# serverKeyShare
# serverNetworkMessages
# serverUtility
# archive
# crypto
# fileInterface
# localization
# localizationArchive
# unicode
# unicodeArchive
# Base
# CommonAPI
# LoginAPI
# MonAPI2
# udplibrary
# ${ZLIB_LIBRARY}
# ${ORACLE_LIBRARY}
sharedCompression
sharedDebug
sharedFile
sharedFoundation
sharedLog
sharedMath
sharedMemoryManager
sharedMessageDispatch
sharedNetwork
sharedNetworkMessages
sharedRandom
sharedSynchronization
sharedThread
sharedUtility
serverMetrics
serverNetworkMessages
serverUtility
archive
fileInterface
localization
localizationArchive
unicode
unicodeArchive
udplibrary
ChatMono
VChatAPI
${ZLIB_LIBRARY}
)
if(WIN32)
+1
View File
@@ -1,2 +1,3 @@
add_subdirectory(ChatAPI)
add_subdirectory(VChatAPI)
@@ -151,9 +151,7 @@ else()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../utils/Base/linux)
endif()
include_directories()
add_library(ChatMono
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
)
@@ -0,0 +1,2 @@
add_subdirectory(projects)
@@ -0,0 +1,2 @@
add_subdirectory(VChat)
@@ -0,0 +1,2 @@
add_subdirectory(VChatAPI)
@@ -0,0 +1,100 @@
add_definitions(-DAPI_NAMESPACE=VChatSystem)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../../../utils2.0/utils
${CMAKE_CURRENT_SOURCE_DIR}/../../../utils2.0/utils/Api
)
add_library(VChatAPI
clientSerialize.h
common.cpp
common.h
messages.cpp
messages.h
strings.h
VChatAPI.cpp
VChatAPI.h
VChatAPICore.cpp
VChatAPICore.h
VChatAPITypes.h
../../../utils2.0/utils/Api/api.cpp
../../../utils2.0/utils/Api/api.h
../../../utils2.0/utils/Api/apiMacros.h
../../../utils2.0/utils/Api/apiMessages.cpp
../../../utils2.0/utils/Api/apiMessages.h
../../../utils2.0/utils/Api/apiPinned.cpp
../../../utils2.0/utils/Api/apiPinned.h
../../../utils2.0/utils/Api/apiTypeNameValuePair.h
../../../utils2.0/utils/Api/apiTypePlatUnicodeString.h
../../../utils2.0/utils/Api/protocol.h
../../../utils2.0/utils/Base/Base32.cpp
../../../utils2.0/utils/Base/Base32.h
../../../utils2.0/utils/Base/Base64.cpp
../../../utils2.0/utils/Base/Base64.h
../../../utils2.0/utils/Base/basicConfig.cpp
../../../utils2.0/utils/Base/basicConfig.h
../../../utils2.0/utils/Base/cmdLine.cpp
../../../utils2.0/utils/Base/cmdLine.h
../../../utils2.0/utils/Base/date.cpp
../../../utils2.0/utils/Base/date.h
../../../utils2.0/utils/Base/dateUtils.h
../../../utils2.0/utils/Base/expirationQueue.h
../../../utils2.0/utils/Base/genericRateLimitingMechanism.h
../../../utils2.0/utils/Base/hash.h
../../../utils2.0/utils/Base/hashtable.hpp
../../../utils2.0/utils/Base/log.cpp
../../../utils2.0/utils/Base/log.h
../../../utils2.0/utils/Base/MD5.cpp
../../../utils2.0/utils/Base/MD5.h
../../../utils2.0/utils/Base/monitorAPI.cpp
../../../utils2.0/utils/Base/monitorAPI.h
../../../utils2.0/utils/Base/monitorData.cpp
../../../utils2.0/utils/Base/monitorData.h
../../../utils2.0/utils/Base/pid.cpp
../../../utils2.0/utils/Base/pid.h
../../../utils2.0/utils/Base/priority.hpp
../../../utils2.0/utils/Base/profile.cpp
../../../utils2.0/utils/Base/profile.h
../../../utils2.0/utils/Base/refptr.h
../../../utils2.0/utils/Base/serialize.h
../../../utils2.0/utils/Base/serializeClasses.h
../../../utils2.0/utils/Base/serializeStringVector.cpp
../../../utils2.0/utils/Base/serializeStringVector.h
../../../utils2.0/utils/Base/serializeTemplates.h
../../../utils2.0/utils/Base/stringutils.cpp
../../../utils2.0/utils/Base/stringutils.h
../../../utils2.0/utils/Base/substringSearchTree.h
../../../utils2.0/utils/Base/systemLog.cpp
../../../utils2.0/utils/Base/systemLog.h
../../../utils2.0/utils/Base/thread.cpp
../../../utils2.0/utils/Base/thread.h
../../../utils2.0/utils/Base/timer.h
../../../utils2.0/utils/Base/trackMessageFailures.cpp
../../../utils2.0/utils/Base/trackMessageFailures.h
../../../utils2.0/utils/Base/types.h
../../../utils2.0/utils/Base/utf8.cpp
../../../utils2.0/utils/Base/utf8.h
../../../utils2.0/utils/TcpLibrary/Clock.cpp
../../../utils2.0/utils/TcpLibrary/Clock.h
../../../utils2.0/utils/TcpLibrary/IPAddress.cpp
../../../utils2.0/utils/TcpLibrary/IPAddress.h
../../../utils2.0/utils/TcpLibrary/TcpBlockAllocator.cpp
../../../utils2.0/utils/TcpLibrary/TcpBlockAllocator.h
../../../utils2.0/utils/TcpLibrary/TcpConnection.cpp
../../../utils2.0/utils/TcpLibrary/TcpConnection.h
../../../utils2.0/utils/TcpLibrary/TcpHandlers.h
../../../utils2.0/utils/TcpLibrary/TcpListener.cpp
../../../utils2.0/utils/TcpLibrary/TcpListener.h
../../../utils2.0/utils/TcpLibrary/TcpManager.cpp
../../../utils2.0/utils/TcpLibrary/TcpManager.h
../../../utils2.0/utils/UdpLibrary/UdpHandler.hpp
../../../utils2.0/utils/UdpLibrary/UdpLibrary.cpp
../../../utils2.0/utils/UdpLibrary/UdpLibrary.hpp
../../../utils2.0/utils/UdpLibrary/UdpListener.cpp
../../../utils2.0/utils/UdpLibrary/UdpListener.h
)
@@ -0,0 +1,456 @@
#ifdef WIN32
#pragma warning (disable : 4786 4514)
#endif
#include <string>
#include <vector>
#include "VChatAPICore.h"
#include "messages.h"
#include "common.h"
#include "Base/hash.h"
#ifdef WIN32
#include <winsock2.h>
#elif linux
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
using namespace std;
namespace VChatSystem
{
//////////////////////////////////////////////////////////////////////////////////////////////
// VChatAPI
//
VChatAPI::VChatAPI(const char * hostList, unsigned connectionType, const char * failoverHostList, unsigned connectionLimit, unsigned maxMsgSize, unsigned bufferSize)
: mConnectionType(connectionType)
{
mCore = new VChatAPICore(*this, hostList, failoverHostList, connectionLimit, maxMsgSize, bufferSize);
}
VChatAPI::~VChatAPI()
{
delete mCore;
}
void VChatAPI::Process()
{
mCore->Process();
}
unsigned VChatAPI::ConnectionCount() const
{
return mCore->GetConnectionCount();
}
unsigned VChatAPI::GetAccount(const std::string &avatarName,
const std::string &game,
const std::string &server,
unsigned userID,
unsigned avatarID,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::GetAccountRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetAvatarName(avatarName);
message.SetGame(game);
message.SetServer(server);
message.SetUserID(userID);
message.SetAvatarID(avatarID);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_GET_ACCOUNT_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::GetChannel(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::GetChannelRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetChannelName(channelName);
message.SetGame(game);
message.SetServer(server);
message.SetDescription(description);
message.SetPassword(password);
message.SetLimit(limit);
message.SetPersistent(persistent);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_GET_CHANNEL_REQUEST, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::GetProximityChannel( const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent,
unsigned maxRange,
unsigned clamping,
float rollOff,
float maxGain,
unsigned distModel,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::GetProximityChannelRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetChannelName(channelName);
message.SetGame(game);
message.SetServer(server);
message.SetDescription(description);
message.SetPassword(password);
message.SetLimit(limit);
message.SetPersistent(persistent);
message.SetMaxRange(maxRange);
message.SetClamping(clamping);
message.SetRollOff(rollOff);
message.SetMaxGain(maxGain);
message.SetDistModel(distModel);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_GET_PROXIMITY_CHANNEL_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::ChannelCommand( const std::string &srcUserName,
const std::string &destUserName,
const std::string &destChannelAddress,
unsigned command,
unsigned banTimeout,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::ChannelCommandRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetSrcUserName(srcUserName);
message.SetDestUserName(destUserName);
message.SetDestChannelAddress(destChannelAddress);
message.SetCommand(command);
message.SetBanTimeout(banTimeout);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_CHANNEL_COMMAND_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::DeactivateVoiceAccount(const std::string &avatarName,
const std::string &gameName,
const std::string &serverName,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::DeactivateVoiceAccountRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetAvatarName(avatarName);
message.SetGame(gameName);
message.SetServer(serverName);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_DEACTIVATE_ACCOUNT_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::ChangePassword(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &password,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::ChangePasswordRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetChannelName(channelName);
message.SetGame(game);
message.SetServer(server);
message.SetPassword(password);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_CHANGE_PASSWORD_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::GetAllChannels(void *user, unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::GetAllChannelsRequest message;
message.SetTrackingNumber (trackingNumber);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_GET_ALL_CHANNELS_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::DeleteChannel(const std::string &channelName,
const std::string &game,
const std::string &server,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::DeleteChannelRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetChannelName(channelName);
message.SetGame(game);
message.SetServer(server);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_DELETE_CHANNEL_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::SetUserData( unsigned userID,
unsigned attributes,
const std::string &email,
const std::string &phoneNumber,
const std::string & PIN,
const std::string & smsAccount,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::SetUserDataRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetUserID(userID);
message.SetAttributes(attributes);
message.SetEmail(email);
message.SetPhoneNumber(phoneNumber);
message.SetPin(PIN);
message.SetSmsAccount(smsAccount);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_SET_USER_DATA_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::SetBanStatus(unsigned userID,
unsigned banStatus,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::SetBanStatusRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetUserID(userID);
message.SetBanStatus(banStatus);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_SET_BAN_STATUS_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::GetChannelInfo(const std::string &channelName,
const std::string &game,
const std::string &server,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::GetChannelInfoRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetChannelName(channelName);
message.SetGame(game);
message.SetServer(server);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_GET_CHANNEL_INFO_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::GetChannelV2(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::GetChannelRequestV2 message;
message.SetTrackingNumber (trackingNumber);
message.SetChannelName(channelName);
message.SetGame(game);
message.SetServer(server);
message.SetDescription(description);
message.SetPassword(password);
message.SetLimit(limit);
message.SetPersistent(persistent);
// send message
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_GET_CHANNEL_REPLY_V2, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::AddCharacterChannel(const unsigned stationID,
const unsigned avatarID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode,
const std::string &channelType,
const std::string &channelDescription,
const std::string &password,
const std::string &channelAddress,
const std::string &locale,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::AddCharacterChannelRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetStationID(stationID);
message.SetAvatarID(avatarID);
message.SetCharacterName(characterName);
message.SetWorldName(worldName);
message.SetGameCode(gameCode);
message.SetChannelType(channelType);
message.SetChannelDescription(channelDescription);
message.SetPassword(password);
message.SetChannelAddress(channelAddress);
message.SetLocale(locale);
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_ADD_CHARACTER_CHANNEL_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::RemoveCharacterChannel(const unsigned stationID,
const unsigned avatarID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode,
const std::string &channelType,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::RemoveCharacterChannelRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetStationID(stationID);
message.SetAvatarID(avatarID);
message.SetCharacterName(characterName);
message.SetWorldName(worldName);
message.SetGameCode(gameCode);
message.SetChannelType(channelType);
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_REMOVE_CHARACTER_CHANNEL_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
unsigned VChatAPI::GetCharacterChannel(const unsigned stationID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode,
void *user,
unsigned timeout)
{
unsigned trackingNumber = mCore->GetTrackingNumber();
Message::GetCharacterChannelRequest message;
message.SetTrackingNumber (trackingNumber);
message.SetStationID(stationID);
message.SetCharacterName(characterName);
message.SetWorldName(worldName);
message.SetGameCode(gameCode);
unsigned char buffer[10240];
memset(buffer, 0, 10240);
unsigned length = message.Write(buffer, sizeof(buffer));
mCore->Send(buffer, length);
mCore->PrepareCallback(MESSAGE_GET_CHARACTER_CHANNEL_REPLY, trackingNumber, RESULT_TIMEOUT, user, timeout);
return trackingNumber;
}
} // end VChatAPI namespace
@@ -0,0 +1,532 @@
#ifndef _VCHAT_SERVER_API_H_
#define _VCHAT_SERVER_API_H_
#include <vector>
#include "VChatAPITypes.h"
//#include "CardinalServerUtils.h"
namespace VChatSystem
{
// forward declarations
class VChatAPICore;
static const unsigned DEFAULT_VCHAT_API_TIMEOUT = 25;
class VChatAPI
{
protected:
VChatAPICore * mCore;
protected:
unsigned mConnectionType;
public:
VChatAPI( const char * hostList, unsigned connectionType = CONNECTION_TYPE_VHCAT_SYSTEM,const char * failoverHostList = 0, unsigned connectionLimit = 0, unsigned maxMsgSize = 1*1024, unsigned bufferSize = 64*1024 );
virtual ~VChatAPI();
void Process();
unsigned ConnectionCount() const;
////////////////////////////////////////
// Connection Callbacks
virtual void OnConnectionOpened( const char * address ) = 0;
virtual void OnConnectionFailed( const char * address ) = 0;
virtual void OnConnectionClosed( const char * address, const char * reason ) = 0;
virtual void OnConnectionShutdownNotified( const char * address, unsigned outstandingRequests ) { }
////////////////////////////////////////
//////////////////////////////////////////
// GetAccount - will get a players login credentials. If none exist
// it will create the player with Vivox.
// avatarName - Name of the avatar to login.
// game the game code of the calling game
// server the world, server or some other identifier for the area of the game that the character is tied to.
//
// The name will parsed and transformed into:
// “<WorldName>.<avatarName>@<GameCode>.vivox.com”
//
// userID station ID of the player
// avatarID the ID of the chat avatar, or some other character identifier.
//
unsigned GetAccount(const std::string &avatarName,
const std::string &game,
const std::string &server,
unsigned userID,
unsigned avatarID,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
///////////////////////////////////////////////
// OnGetAccount
//
// userID station ID of the player.
// accountID the Vivox account ID.
// voicePassword the password for this users Vivox account.
// encodedVoiceAccount - the account name encoded with modified
// base64 algorithm. This should be used to login.
// URI - the url that this server is connected to.
virtual void OnGetAccount(unsigned track,
unsigned result,
unsigned userID,
unsigned accountID,
const std::string &voicePassword,
const std::string &encodedVoiceAccount,
const std::string &URI,
void *user) = 0;
//////////////////////////////////////////
// channelName - Name of the channel to retrieve. See below for examples.
// game the game code of the calling game
// server the world, server or some other identifier for the area of the game that the channel is tied to.
//
// The name will parsed and transformed into:
// group (private) - <game>.<server>.group.<id> channelName would be: group.<id>
// raid (private) - <game>.<server>.raid.<id> channelName would be: raid.<id>
// raid leader (optional, private) - <game>.<server>.raidleader.<id> channelName would be: raidleader.<id>
// guild (private, persistent) - <game>.<server>.guild.<name> channelName would be: guild.<name>
// guild leader (private, persistent) - <game>.<server>.guildleader.<name> channelName would be: guildleader.<name>
// tell (private) - game.server.characterA_characterB channelName would be: characterA_characterB
// say (public, proximity) - game.server.zone channelName would be: zone
// user generated (public/private) - <game>.<server>.user.<channel> channelName would be: user.<channel>
// description description of the room.
// password password needed to enter the channel. If the password is empty it will not be passed to Vivox. (optional)
// limit - Optional hard limit on the number of users allowed on this channel
// persistent true persistent channel, false temporary channel.
unsigned GetChannel(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
//////////////////////////////////////////
// channelName the channel name. Form is above.
// channelURI - uri returned by Vivox
// channelID Vivox assigned channel id.
virtual void OnGetChannel(unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
void *user) = 0;
///////////////////////////////////////////////
// channelName - Name of the channel to retrieve.
// game the game code of the calling game
// server the world, server or some other identifier for the area of the game that the channel is tied to.
// description description of the room.
// password password needed to enter the channel. If the password is empty it will not be passed to Vivox. (optional)
// limit - Optional hard limit on the number of users allowed on this channel
// persistent true persistent channel, false temporary channel.
// maxRange - Also known as the audible threshold distance. This is the distance beyond which a participant is considered 'out of range'. When participants cross this threshold distance from a particular listening position in a channel, a roster list updates for the channel occur, which indi-cate an entry being added (or removed, as the case may be) from the participants list. No audio is received by the listener for participants beyond this range. (The default value 80).
// clamping - This is the distance from the listener below which the 'gain roll-off' effects for a given audio roll-off model (see below) are not applied. In effect, it is the 'audio plateau' distance (in the sense that the gain is constant up this distance, and then falls off). (The default value is 10)
// rollOff - This value indicates how sharp the audio attenuation will 'roll-off' between the clamping and maximum distances. Larger values will result in steeper roll-off. The extent of roll-off will depend on the distance model chosen. (Default value is 2.0).
// maxGain - The gain setting for all speakers in this channel. Note, that in practice this should not be raised above 2.5 or auditory distress may result. (The default value is 1.0).
// distModel =<0 | 1| 2 | 3> - There are four possible values as described below:
//(The default model is Inverse Distance Clamped.)
// • None: No distance based attenuation is applied. All speakers are rendered as if they were in the same position as the listener. The audio from speakers will drop to 0 abruptly at the maximum distance.
// • (1) Inverse Distance Clamped: The attenuation increases in inverse proportion to the distance. The roll-off factor n is the inverse of the slope of the attenuation curve.
// • (2) Linear Distance Clamped: The attenuation increases in linear proportion to the distance. The roll-off factor is the negative slope of the attenuation curve.
// • (3) Exponent Distance Clamped: The attenuation increases in inverse proportion to the distance raised to the power of the roll-off factor.
unsigned GetProximityChannel(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent,
unsigned maxRange,
unsigned clamping,
float rollOff,
float maxGain,
unsigned distModel,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
///////////////////////////////////////////////
// channelName the channel name.
// channelURI - uri returned by Vivox
// channelID Vivox assigned channel id.
virtual void OnGetProximityChannel (unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
void *user) = 0;
//////////////////////////////////////////
// This will be used to operate on existing active channels and to provide moderators and owner the ability to mute, kick, ban users along with other commands.
// srcUserName the owner and/or moderator of this channel with the ability to perform this command.
// destUserName the user on whom to perform the operation
// Both user names should be of the form:
// “<WorldName>.<avatarName>”
// destChannelAddress Full address of the channel where the operation will be performed.
// command The commands below will be placed in an enum that will be distributed with the API.
// • mute - mute user
// • unmute - unmute user
// • kick - drop user from the channel, reentry only after 60 seconds
// • hangup drop user from the channel without banning them
// • invite - add user to the channel
// • ban - ban user, permanently from the channel
// • unban - unban user from the channel
// • chan_lock - lock the channel for any additional participants
// • chan_unlock - unlock the channel for any additional participants
// • mute_all mute all callers except the requestor
// • unmute_all unmute all callers
// banTimeout - if command is ban, timeout for ban in seconds.
unsigned ChannelCommand(const std::string &srcUserName,
const std::string &destUserName,
const std::string &destChannelAddress,
unsigned command,
unsigned banTimeout,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
virtual void OnChannelCommand(unsigned track,
unsigned result,
void *user) = 0;
///////////////////////////////////////////////
// DeactivateVoiceAccount
// In the event that a character is moved, transferred or
// banned the account needs to be de-activated. A new voice
// account will be created for the moved/transferred user when
// they log in with their new character.
unsigned DeactivateVoiceAccount(const std::string &avatarName,
const std::string &game,
const std::string &server,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
virtual void OnDeactivateVoiceAccount(unsigned track,
unsigned result,
void *user) = 0;
///////////////////////////////////////////////
// ChangePassword
// This will reset the password for the channel.
// NOTE: If a blank password is passed in this will
// be sent to the Vivox API.
//
// channelName - Name of the channel to retrieve.
// game the game code of the calling game
// server the world, server or some other identifier for the area of the game that the channel is tied to.
// password password needed to enter the channel. This will modify the password for the channel
unsigned ChangePassword(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &password,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
///////////////////////////////////////////////
// OnChangePassword
virtual void OnChangePassword(unsigned track,
unsigned result,
void *user) = 0;
////////////////////////////////////////////////////////////
// GetAllChannels
// Will get all channels from the Vivox server.
//
unsigned GetAllChannels(void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
///////////////////////////////////////////////
// OnGetAllChannels
//
// channels - a vector of channels that Vivox returned to the server.
//
// from common.h:
// struct Channel
// {
// std::string m_channelName;
// std::string m_channelURI;
// std::string m_channelPassword;
// unsigned m_channelID;
// unsigned m_channelType;
// };
//
// Channel Type can be the following:
// typedef enum ChannelType
// {
// CHAN_TYPE_UNKNOWN = 0,
// CHAN_TYPE_DIR,
// CHAN_TYPE_CHANNEL,
// CHAN_TYPE_PROXIMITY
// };
//
virtual void OnGetAllChannels(unsigned track,
unsigned result,
const ChannelVec_t & channels,
void *user) = 0;
///////////////////////////////////////////////
// DeleteChannel
//
// Removes the channel from the Vivox server.
//
// channelName - Name of the channel to retrieve.
// game the game code of the calling game
// server the world, server or some other identifier for the area of the game that the channel is tied to.
//
unsigned DeleteChannel( const std::string &channelName,
const std::string &game,
const std::string &server,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
///////////////////////////////////////////////
// OnDeleteChannel
virtual void OnDeleteChannel(unsigned track,
unsigned result,
void *user) = 0;
///////////////////////////////////////////////
// SetUserData
//
// Sets data at the user level (ie. Station Account) that is valid
// valid across all characters for that user.
//
// userID - the userID that is tied to the station account
unsigned SetUserData(unsigned userID,
unsigned attributes,
const std::string & email,
const std::string & phoneNumber,
const std::string & PIN,
const std::string & smsAccount,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
///////////////////////////////////////////////
// OnSetUserData
virtual void OnSetUserData( unsigned track,
unsigned result,
void *user) = 0;
///////////////////////////////////////////////
// SetBanStatus
//
// Sets the ban status at the user level (ie. Station Account)
// This primarily for CS to ban users from Voice for all of
// their characters.
//
// userID - the userID that is tied to the station account
// banStatus - one of the following:
// typedef enum BanStatus
// {
// BAN = 0,
// UNBAN
// };
//
unsigned SetBanStatus(unsigned userID,
unsigned banStatus,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
///////////////////////////////////////////////
// OnSetBanStatus
virtual void OnSetBanStatus(unsigned track,
unsigned result,
void *user) = 0;
//////////////////////////////////////////
// channelName - Name of the channel to retrieve. See below for examples.
// game the game code of the calling game
// server the world, server or some other identifier for the area of the game that the channel is tied to.
//
// The name will parsed and transformed into:
// group (private) - <game>.<server>.group.<id> channelName would be: group.<id>
// raid (private) - <game>.<server>.raid.<id> channelName would be: raid.<id>
// raid leader (optional, private) - <game>.<server>.raidleader.<id> channelName would be: raidleader.<id>
// guild (private, persistent) - <game>.<server>.guild.<name> channelName would be: guild.<name>
// guild leader (private, persistent) - <game>.<server>.guildleader.<name> channelName would be: guildleader.<name>
// tell (private) - game.server.characterA_characterB channelName would be: characterA_characterB
// say (public, proximity) - game.server.zone channelName would be: zone
// user generated (public/private) - <game>.<server>.user.<channel> channelName would be: user.<channel>
unsigned GetChannelInfo(const std::string &channelName,
const std::string &game,
const std::string &server,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
//////////////////////////////////////////
// channelName the channel name. Form is above.
// channelURI - uri returned by Vivox
// channelID Vivox assigned channel id.
virtual void OnGetChannelInfo(unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
void *user) = 0;
//////////////////////////////////////////
// This is identical to GetChannel except the callback will
// let the caller know if the channel was created or an existing
// channel was retrieved.
//
// channelName - Name of the channel to retrieve. See below for examples.
// game the game code of the calling game
// server the world, server or some other identifier for the area of the game that the channel is tied to.
//
// The name will parsed and transformed into:
// group (private) - <game>.<server>.group.<id> channelName would be: group.<id>
// raid (private) - <game>.<server>.raid.<id> channelName would be: raid.<id>
// raid leader (optional, private) - <game>.<server>.raidleader.<id> channelName would be: raidleader.<id>
// guild (private, persistent) - <game>.<server>.guild.<name> channelName would be: guild.<name>
// guild leader (private, persistent) - <game>.<server>.guildleader.<name> channelName would be: guildleader.<name>
// tell (private) - game.server.characterA_characterB channelName would be: characterA_characterB
// say (public, proximity) - game.server.zone channelName would be: zone
// user generated (public/private) - <game>.<server>.user.<channel> channelName would be: user.<channel>
// description description of the room.
// password password needed to enter the channel. If the password is empty it will not be passed to Vivox. (optional)
// limit - Optional hard limit on the number of users allowed on this channel
// persistent true persistent channel, false temporary channel.
unsigned GetChannelV2(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
//////////////////////////////////////////
// channelName the channel name. Form is above.
// channelURI - uri returned by Vivox
// channelID Vivox assigned channel id.
// isNewChannel
virtual void OnGetChannelV2(unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
unsigned isNewChannel,
void *user) = 0;
//////////////////////////////////////////
// Character channels are to be maintained by the game teams.
// These will be used to store channels that the customer is allowed to access in game.
// the descriptions will be localized so that the display will match what the customer sees in game
// There will be just straight through db access on each of these calls
// When a character is deleted they should all be removed, when it is renamed these should be updated, etc.
// Common params:
// stationID -- the station id associated with the character
// avatarID -- the internal id for the character uint64
// characterName -- utf8 character name
// worldName -- utf8 string for the world name
// gameCode -- utf8 string with the gamecode such as EQ, EQ2, SWG, etc.
// channelType -- (utf8 internal description to identify the channel type (guild, officers, etc.)
// channelDescription -- localized description will be displayed to the user from station launcher
// channelID -- unsigned channelID
// channelURI -- URI for the channel with vivox
// locale -- locale for the description such as en_US
//////////////////////////////////////////
//////////////////////////////////////////
// AddCharacterChannel
//
// params:
// stationID
// avatarID
// characterName
// channelType
// channelDescription -- localized
// channelID
// channelURI
// locale
unsigned AddCharacterChannel(const unsigned stationID,
const unsigned avatarID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode,
const std::string &channelType,
const std::string &channelDescription,
const std::string &password,
const std::string &channelAddress,
const std::string &locale,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
virtual void OnAddCharacterChannel(unsigned track,
unsigned result,
void *user) = 0;
//////////////////////////////////////////
// RemoveCharacterChannel
//
// params:
// stationID
// avatarID
// characterName
// worldName
// gameCode
// channelType
// channelDescription -- localized
// channelID
// channelURI
// locale
unsigned RemoveCharacterChannel(const unsigned stationID,
const unsigned avatarID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode,
const std::string &channelType,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
virtual void OnRemoveCharacterChannel(unsigned track,
unsigned result,
void *user) = 0;
//////////////////////////////////////////
// GetCharacterChannel
//
// params:
// stationID
// avatarID
// characterName
// channelType
// channelDescription -- localized
// channelID
// channelURI
// locale
unsigned GetCharacterChannel(const unsigned stationID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode,
void *user,
unsigned timeout = DEFAULT_VCHAT_API_TIMEOUT);
virtual void OnGetCharacterChannel(unsigned track,
unsigned result,
const CharacterChannelVec_t &characterChannels,
void * user) = 0;
};
} // end namespace
#endif // end #ifndef _VCHAT_SERVER_API_H_
@@ -0,0 +1,332 @@
#ifdef WIN32
#pragma warning (disable : 4786 4514)
#endif
#include <stdio.h>
#include <time.h>
#include "VChatAPICore.h"
#include "messages.h"
#include "Base/hash.h"
using namespace std;
//using namespace API_NAMESPACE::Message;
namespace VChatSystem
{
VChatAPICore::VChatAPICore(VChatAPI & client, const char * hostList, const char * failoverHostList,
unsigned connectionLimit, unsigned maxMsgSize, unsigned bufferSize)
: CommonAPI(hostList, failoverHostList, connectionLimit, maxMsgSize, bufferSize)
, mClient(client)
{
// requests
RegisterTrackedMessage(MESSAGE_GET_ACCOUNT_REQUEST);
RegisterTrackedMessage(MESSAGE_GET_CHANNEL_REQUEST);
RegisterTrackedMessage(MESSAGE_GET_PROXIMITY_CHANNEL_REQUEST);
RegisterTrackedMessage(MESSAGE_CHANNEL_COMMAND_REQUEST);
RegisterTrackedMessage(MESSAGE_DEACTIVATE_ACCOUNT_REQUEST);
RegisterTrackedMessage(MESSAGE_CHANGE_PASSWORD_REQUEST);
RegisterTrackedMessage(MESSAGE_GET_ALL_CHANNELS_REQUEST);
RegisterTrackedMessage(MESSAGE_DELETE_CHANNEL_REQUEST);
RegisterTrackedMessage(MESSAGE_SET_USER_DATA_REQUEST);
RegisterTrackedMessage(MESSAGE_SET_BAN_STATUS_REQUEST);
RegisterTrackedMessage(MESSAGE_GET_CHANNEL_INFO_REQUEST);
RegisterTrackedMessage(MESSAGE_GET_CHANNEL_REQUEST_V2);
RegisterTrackedMessage(MESSAGE_ADD_CHARACTER_CHANNEL);
RegisterTrackedMessage(MESSAGE_REMOVE_CHARACTER_CHANNEL);
RegisterTrackedMessage(MESSAGE_GET_CHARACTER_CHANNEL);
RegisterTrackedMessage(MESSAGE_UPDATE_CHARACTER_CHANNEL);
// replies
RegisterTrackedMessage(MESSAGE_GET_ACCOUNT_REPLY);
RegisterTrackedMessage(MESSAGE_GET_CHANNEL_REPLY);
RegisterTrackedMessage(MESSAGE_GET_PROXIMITY_CHANNEL_REPLY);
RegisterTrackedMessage(MESSAGE_CHANNEL_COMMAND_REPLY);
RegisterTrackedMessage(MESSAGE_DEACTIVATE_ACCOUNT_REPLY);
RegisterTrackedMessage(MESSAGE_CHANGE_PASSWORD_REPLY);
RegisterTrackedMessage(MESSAGE_GET_ALL_CHANNELS_REPLY);
RegisterTrackedMessage(MESSAGE_DELETE_CHANNEL_REPLY);
RegisterTrackedMessage(MESSAGE_SET_USER_DATA_REPLY);
RegisterTrackedMessage(MESSAGE_SET_BAN_STATUS_REPLY);
RegisterTrackedMessage(MESSAGE_GET_CHANNEL_INFO_REPLY);
RegisterTrackedMessage(MESSAGE_GET_CHANNEL_REPLY_V2);
RegisterTrackedMessage(MESSAGE_ADD_CHARACTER_CHANNEL_REPLY);
RegisterTrackedMessage(MESSAGE_REMOVE_CHARACTER_CHANNEL_REPLY);
RegisterTrackedMessage(MESSAGE_GET_CHARACTER_CHANNEL_REPLY);
RegisterTrackedMessage(MESSAGE_UPDATE_CHARACTER_CHANNEL_REPLY);
}
VChatAPICore::~VChatAPICore()
{
}
const char * VChatAPICore::GetVersion()
{
return "2008.04.25";
}
HashValue_t VChatAPICore::CreateHashValue(const string & name)
{
return HashUserName(name.c_str());
}
unsigned VChatAPICore::CheckMessageId(const unsigned char * data, unsigned dataLen)
{
API_NAMESPACE::Message::Basic message;
message.Read(data, dataLen);
return message.GetMsgId();
}
unsigned VChatAPICore::CheckTrackingNumber(const unsigned char * data, unsigned dataLen)
{
API_NAMESPACE::Message::Tracked message;
message.Read(data, dataLen);
return message.GetTrackingNumber();
}
unsigned VChatAPICore::FormatStatusMsg(unsigned char * buffer, unsigned size)
{
API_NAMESPACE::Message::Connect message;
message.SetVersion(GetVersion());
return message.Write(buffer, size);
}
bool VChatAPICore::CheckConnectReply(const unsigned char * data, unsigned dataLen)
{
API_NAMESPACE::Message::ConnectReply message;
return (message.Read(data, dataLen) &&
message.GetMsgId() == MESSAGE_CONNECT_REPLY &&
message.GetResult() == RESULT_SUCCESS);
}
void VChatAPICore::OnConnectionOpened(const char * address)
{
mClient.OnConnectionOpened(address);
}
void VChatAPICore::OnConnectionFailed(const char * address)
{
mClient.OnConnectionFailed(address);
}
void VChatAPICore::OnConnectionClosed(const char * address, const char * reason)
{
mClient.OnConnectionClosed(address, reason);
}
void VChatAPICore::OnConnectionShutdownNotified(const char * address, unsigned outstandingRequests)
{
mClient.OnConnectionShutdownNotified(address, outstandingRequests);
}
/////////////////////////////////////////
// request callbacks for successful communication
/////////////////////////////////////////
void VChatAPICore::Callback(const unsigned char * data, unsigned dataLen, unsigned messageId, void * userData)
{
switch (messageId)
{
case MESSAGE_GET_ACCOUNT_REPLY:
{
Message::GetAccountReply message;
if(message.Read(data, dataLen))
mClient.OnGetAccount(message.GetTrackingNumber(), message.GetResult(), message.GetUserID(), message.GetAccountID(), message.GetVoicePassword(), message.GetEncodedAccountName(), message.GetURI(), userData);
break;
}
case MESSAGE_GET_CHANNEL_REPLY:
{
Message::GetChannelReply message;
if(message.Read(data, dataLen))
mClient.OnGetChannel(message.GetTrackingNumber(), message.GetResult(), message.GetChannelName(), message.GetChannelURI(), message.GetChannelID(), userData);
break;
}
case MESSAGE_GET_PROXIMITY_CHANNEL_REPLY:
{
Message::GetProximityChannelReply message;
if(message.Read(data, dataLen))
mClient.OnGetProximityChannel(message.GetTrackingNumber(), message.GetResult(), message.GetChannelName(), message.GetChannelURI(), message.GetChannelID(), userData);
break;
}
case MESSAGE_CHANNEL_COMMAND_REPLY:
{
Message::ChannelCommandReply message;
if(message.Read(data, dataLen))
mClient.OnChannelCommand(message.GetTrackingNumber(), message.GetResult(), userData);
break;
}
case MESSAGE_DEACTIVATE_ACCOUNT_REPLY:
{
Message::DeactivateVoiceAccountReply message;
if(message.Read(data, dataLen))
mClient.OnDeactivateVoiceAccount(message.GetTrackingNumber(), message.GetResult(), userData);
break;
}
case MESSAGE_CHANGE_PASSWORD_REPLY:
{
Message::ChangePasswordReply message;
if(message.Read(data, dataLen))
mClient.OnChangePassword(message.GetTrackingNumber(), message.GetResult(), userData);
break;
}
case MESSAGE_GET_ALL_CHANNELS_REPLY:
{
Message::GetAllChannelsReply message;
if(message.Read(data, dataLen))
mClient.OnGetAllChannels(message.GetTrackingNumber(), message.GetResult(), message.GetChannelsVec(), userData);
break;
}
case MESSAGE_DELETE_CHANNEL_REPLY:
{
Message::DeleteChannelReply message;
if(message.Read(data, dataLen))
mClient.OnDeleteChannel(message.GetTrackingNumber(), message.GetResult(), userData);
break;
}
case MESSAGE_SET_USER_DATA_REPLY:
{
Message::SetUserDataReply message;
if(message.Read(data, dataLen))
mClient.OnSetUserData(message.GetTrackingNumber(), message.GetResult(), userData);
break;
}
case MESSAGE_SET_BAN_STATUS_REPLY:
{
Message::SetBanStatusReply message;
if(message.Read(data, dataLen))
mClient.OnSetBanStatus(message.GetTrackingNumber(), message.GetResult(), userData);
break;
}
case MESSAGE_GET_CHANNEL_INFO_REPLY:
{
Message::GetChannelInfoReply message;
if(message.Read(data, dataLen))
mClient.OnGetChannelInfo(message.GetTrackingNumber(), message.GetResult(), message.GetChannelName(), message.GetChannelURI(), message.GetChannelID(), userData);
break;
}
case MESSAGE_GET_CHANNEL_REPLY_V2:
{
Message::GetChannelReplyV2 message;
if(message.Read(data, dataLen))
mClient.OnGetChannelV2(message.GetTrackingNumber(), message.GetResult(), message.GetChannelName(), message.GetChannelURI(), message.GetChannelID(), message.GetIsNewChannel(),userData);
break;
}
case MESSAGE_ADD_CHARACTER_CHANNEL_REPLY:
{
Message::AddCharacterChannelReply message;
if(message.Read(data, dataLen))
mClient.OnAddCharacterChannel(message.GetTrackingNumber(), message.GetResult(), userData);
break;
}
case MESSAGE_REMOVE_CHARACTER_CHANNEL_REPLY:
{
Message::RemoveCharacterChannelReply message;
if(message.Read(data, dataLen))
mClient.OnRemoveCharacterChannel(message.GetTrackingNumber(), message.GetResult(), userData);
break;
}
case MESSAGE_GET_CHARACTER_CHANNEL_REPLY:
{
Message::GetCharacterChannelReply message;
if(message.Read(data, dataLen))
mClient.OnGetCharacterChannel(message.GetTrackingNumber(), message.GetResult(), message.GetChannelList(), userData);
break;
}
default:
break;
}
}
/////////////////////////////////////////
// TIMEOUT callbacks
/////////////////////////////////////////
void VChatAPICore::Callback(unsigned messageId, unsigned trackingNumber, unsigned result, void * userData)
{
switch (messageId)
{
case MESSAGE_GET_ACCOUNT_REPLY:
{
mClient.OnGetAccount(trackingNumber, result, 0, 0, std::string(), std::string(), std::string(), userData);
break;
}
case MESSAGE_GET_CHANNEL_REPLY:
{
mClient.OnGetChannel(trackingNumber, result, std::string(), std::string(), 0, userData);
break;
}
case MESSAGE_GET_PROXIMITY_CHANNEL_REPLY:
{
mClient.OnGetProximityChannel(trackingNumber, result, std::string(), std::string(), 0, userData);
break;
}
case MESSAGE_CHANNEL_COMMAND_REPLY:
{
mClient.OnChannelCommand(trackingNumber, result, userData);
break;
}
case MESSAGE_DEACTIVATE_ACCOUNT_REPLY:
{
mClient.OnDeactivateVoiceAccount(trackingNumber, result, userData);
break;
}
case MESSAGE_CHANGE_PASSWORD_REPLY:
{
mClient.OnChangePassword(trackingNumber, result, userData);
break;
}
case MESSAGE_GET_ALL_CHANNELS_REPLY:
{
mClient.OnGetAllChannels(trackingNumber, result, ChannelVec_t(), userData);
break;
}
case MESSAGE_DELETE_CHANNEL_REPLY:
{
mClient.OnDeleteChannel(trackingNumber, result, userData);
break;
}
case MESSAGE_SET_USER_DATA_REPLY:
{
mClient.OnSetUserData(trackingNumber, result, userData);
break;
}
case MESSAGE_SET_BAN_STATUS_REPLY:
{
mClient.OnSetBanStatus(trackingNumber, result, userData);
break;
}
case MESSAGE_GET_CHANNEL_INFO_REPLY:
{
mClient.OnGetChannelInfo(trackingNumber, result, std::string(), std::string(), 0, userData);
break;
}
case MESSAGE_GET_CHANNEL_REPLY_V2:
{
mClient.OnGetChannelV2(trackingNumber, result, std::string(), std::string(), 0, 0, userData);
break;
}
case MESSAGE_ADD_CHARACTER_CHANNEL_REPLY:
{
mClient.OnAddCharacterChannel(trackingNumber, result, userData);
break;
}
case MESSAGE_REMOVE_CHARACTER_CHANNEL_REPLY:
{
mClient.OnRemoveCharacterChannel(trackingNumber, result,userData);
break;
}
case MESSAGE_GET_CHARACTER_CHANNEL_REPLY:
{
mClient.OnGetCharacterChannel(trackingNumber, result, CharacterChannelVec_t(), userData);
break;
}
default :
break;
}
}
}
@@ -0,0 +1,60 @@
#ifndef _VCHAT_SERVER_API_CORE_H_
#define _VCHAT_SERVER_API_CORE_H_
#include "clientSerialize.h"
#include "VChatAPI.h"
#ifndef _VCHAT_API_API_HEADERS_
#define _VCHAT_API_API_HEADERS_
#ifndef API_NAMESPACE
#define API_NAMESPACE VChatSystem
#include "Api/api.h"
#undef API_NAMESPACE
#else
#include "Api/api.h"
#endif
#endif
using namespace API_NAMESPACE;
namespace VChatSystem
{
extern const char * encryptionKey;
class VChatAPICore : public CommonAPI
{
private:
VChatAPI & mClient;
public:
VChatAPICore(VChatAPI & client, const char * hostList, const char * failoverHostList = 0, unsigned connectionLimit = 0, unsigned maxMsgSize = 1*1024, unsigned bufferSize = 64*1024);
virtual ~VChatAPICore();
virtual const char * GetVersion();
virtual unsigned CheckMessageId(const unsigned char * data, unsigned dataLen);
virtual unsigned CheckTrackingNumber(const unsigned char * data, unsigned dataLen);
virtual unsigned FormatStatusMsg(unsigned char * buffer, unsigned size);
virtual bool CheckConnectReply(const unsigned char * data, unsigned dataLen);
virtual void OnConnectionOpened(const char * address);
virtual void OnConnectionFailed(const char * address);
virtual void OnConnectionClosed(const char * address, const char * reason);
virtual void OnConnectionShutdownNotified(const char * address, unsigned outstandingRequests);
virtual void Callback(const unsigned char * data, unsigned dataLen, unsigned messageId, void * userData);
virtual void Callback(unsigned messageId, unsigned trackingNumber, unsigned result, void * userData);
HashValue_t CreateHashValue(const std::string & name);
private:
VChatAPICore(const VChatAPICore &);
VChatAPICore & operator=(const VChatAPICore &);
};
}
#endif //_VCHAT_SERVER_API_CORE_H_
@@ -0,0 +1,215 @@
#ifndef _VCHAT_SERVER_API_TYPES_H_
#define _VCHAT_SERVER_API_TYPES_H_
#include "common.h"
#include "Api/apiTypeNameValuePair.h"
#define MAX_ARRAY 100
#define MAX_LENGTH_METHOD_ID 32
#define MAX_LENGTH_RAW_XML_MESSAGE 4096
////////////////////////////////////////////////////////////////////////////
// defines for dealing with 64 bit integers that work between unix and windows
// EX:
// printf(" a long variable["FMT_QUAD"]\n", QUAD(1234567890123456));
#ifdef _WIN32
#define QUAD(X) X##i64
#define UQUAD(X) X##ui64
#define SQUAD(X) X##i64
#define FMT_QUAD "%I64d"
#define FMT_QUADU "%I64u"
#else
#define QUAD(X) X##LL
#define UQUAD(X) X##ULL
#define SQUAD(X) X##LL
#define FMT_QUAD "%lld"
#define FMT_QUADU "%llu"
#endif
namespace VChatSystem
{
#define RETURN_TEST(X) if (X != RESULT_SUCCESS) return X;
typedef unsigned TrackingNumber;
typedef unsigned TransactionResultCode;
typedef long long TransactionId;
typedef unsigned ResultCode;
typedef enum ResultCode_t
{
RESULT_SUCCESS = 0,
RESULT_TIMEOUT,
RESULT_FAILURE,
RESULT_INVALID_PARAM,
RESULT_DATABASE_FAILURE,
RESULT_NETWORK_FAILURE,
RESULT_NOT_IMPLEMENTED,
RESULT_NOT_SUPPORTED,
RESULT_SYSTEM_FAILURE,
RESULT_PROTOCOL_VIOLATION,
RESULT_NOT_FOUND,
RESULT_TCP_CONNECTION_NOT_AVAILABLE,
RESULT_RESPONSE_XML_INVALID,
RESULT_RESPONSE_VIVOX_FAILURE,
RESULT_USER_ACCOUNT_BANNED,
RESULT_NAME_EXCEEDS_VIVOX_LIMIT,
RESULT_NO_CHANNELS_FOUND_FOR_CHARACTER,
// vivox error codes
RESULT_VIVOX_WRONG_USER_CREDENTIALS = 200,
RESULT_VIVOX_EXPIRED_USER_CREDENTIALS = 201,
RESULT_VIVOX_MISSING_USER_CREDENTIALS = 202,
RESULT_VIVOX_USER_NOT_LOGGED_IN = 203,
RESULT_VIVOX_ACCOUNT_CANT_PERFORM_OP = 212,
RESULT_VIVOX_FAILED_RETRIEVING_DIR = 220,
RESULT_VIVOX_PARAMS_MISSING = 300,
RESULT_VIVOX_UNKNOWN_MODE = 301,
RESULT_VIVOX_UNABLE_TO_PARSE_ARG = 302,
RESULT_VIVOX_ACCOUNT_CREATION_FAILED = 400,
RESULT_VIVOX_ACCOUNT_DEACTIVATE_FAILED = 401,
RESULT_VIVOX_ACCOUNT_ACTIVATE_FAILED = 402,
RESULT_VIVOX_ACCOUNT_DOESNT_EXIST = 403,
RESULT_VIVOX_ACCOUNT_RETRIEVAL_FAILED = 404,
RESULT_VIVOX_ACCOUNT_UPDATE_FAILED = 405,
RESULT_VIVOX_ACCOUNT_DELETE_FAILED = 406,
RESULT_VIVOX_RETRIEVING_SRC_USER = 450,
RESULT_VIVOX_CHANNEL_ADD_FAILED = 451,
RESULT_VIVOX_CHANNEL_UPDATE_FAILED = 452,
RESULT_VIVOX_CHANNEL_RETRIEVE_FAILED = 453,
RESULT_VIVOX_FEATURE_NAME_UNKNOWN = 500,
RESULT_VIVOX_FEATURE_RETRIEVAL_FAILED = 501,
RESULT_VIVOX_FEATURE_SET_FAILED = 502,
RESULT_VIVOX_FEATURE_UPDATE_FAILED = 503,
RESULT_VIVOX_FEATURE_DELETE_FAILED = 504,
RESULT_VIVOX_RETRIEVE_USER_FAILED = 505,
RESULT_VIVOX_RETRIEVE_FEATURE_LIST_FAILED = 506,
RESULT_VIVOX_CHANNEL_RETRIEVE_USERS_FAILED = 700,
RESULT_VIVOX_CHANNEL_MUTE_ALL_FAILED = 701,
RESULT_VIVOX_CHANNEL_UNMUTE_ALL_FAILED = 702,
RESULT_VIVOX_CHANNEL_INVITE_FAILED = 703,
RESULT_VIVOX_CHANNEL_RETRIEVING_ACL_FAILED = 704,
RESULT_VIVOX_CHANNEL_DELETE_ACL_FAILED = 706,
RESULT_VIVOX_CHANNEL_LOCKING_FAILED = 707,
RESULT_VIVOX_CHANNEL_UNLOCKING_FAILED = 708,
RESULT_VIVOX_CHANNEL_CREATING_FAILED = 709,
RESULT_VIVOX_CHANNEL_RETRIEVE_FAILED_EX = 710,
RESULT_VIVOX_USER_NOT_ON_CHANNEL = 711,
RESULT_VIVOX_UNABLE_TO_COMPLETE_CHANNEL_LOOKUP = 712,
RESULT_END
};
typedef enum CommandType_t
{
COMMAND_MUTE = 0,
COMMAND_UNMUTE,
COMMAND_KICK,
COMMAND_HANGUP,
COMMAND_INVITE,
COMMAND_BAN,
COMMAND_UNBAN,
COMMAND_CHAN_LOCK,
COMMAND_CHAN_UNLOCK,
COMMAND_MUTE_ALL,
COMMAND_UNMUTE_ALL,
COMMAND_ADD_MODERATOR,
COMMAND_DELETE_MODERATOR,
COMMAND_ADD_ACL,
COMMAND_DELETE_ACL,
COMMAND_DROP_ALL,
COMMAND_END
};
typedef enum ConnectionType
{
CONNECTION_TYPE_UNKNOWN = 0,
CONNECTION_TYPE_VHCAT_SYSTEM
};
typedef enum ChannelType
{
CHAN_TYPE_UNKNOWN = 0,
CHAN_TYPE_DIR,
CHAN_TYPE_CHANNEL,
CHAN_TYPE_PROXIMITY
};
typedef enum BanStatus
{
BAN = 0,
UNBAN
};
//Following from Account Server
const unsigned MAX_MSG_SIZE=64*1024;
const unsigned REQ_ID_FIELD_SIZE = 30;
const unsigned MIN_ACCOUNT_NAME_SIZE = 4; const unsigned MAX_ACCOUNT_NAME_SIZE = 15;
const unsigned MIN_ACCOUNT_PASSWORD_SIZE = 5; const unsigned MAX_ACCOUNT_PASSWORD_SIZE = 255;
const unsigned MIN_REASON_SIZE = 0; const unsigned MAX_REASON_SIZE = 2000;
const unsigned MIN_PASSWORD_SIZE = 8; const unsigned MAX_PASSWORD_SIZE = 255;
const unsigned MIN_SECURITY_ANSWER_SIZE = 0; const unsigned MAX_SECURITY_ANSWER_SIZE = 255;
const unsigned MIN_EMAIL_SIZE = 0; const unsigned MAX_EMAIL_SIZE = 255;
const unsigned MIN_STATION_HANDLE_SIZE = 0; const unsigned MAX_STATION_HANDLE_SIZE = 31;
const unsigned MIN_STATION_NAME_SIZE = 0; const unsigned MAX_STATION_NAME_SIZE = 50;
const unsigned MIN_MEMBER_TYPE_SIZE = 0; const unsigned MAX_MEMBER_TYPE_SIZE = 31;
const unsigned MIN_MEMBER_ID_SIZE = 0; const unsigned MAX_MEMBER_ID_SIZE = 31;
const unsigned MIN_RESET_TYPE_SIZE = 0; const unsigned MAX_RESET_TYPE_SIZE = 31;
const unsigned MIN_PASSWORD_EMAIL_SIZE = 0; const unsigned MAX_PASSWORD_EMAIL_SIZE = 255;
const unsigned MIN_COUNTRY_CODE_SIZE = 2; const unsigned MAX_COUNTRY_CODE_SIZE = 2;
const unsigned MIN_COUNTRY_NAME_SIZE = 0; const unsigned MAX_COUNTRY_NAME_SIZE = 255;
const unsigned MIN_CURRENCY_SIZE = 0; const unsigned MAX_CURRENCY_SIZE = 31;
const unsigned MIN_RESET_ID_SIZE = 0; const unsigned MAX_RESET_ID_SIZE = 20;
const unsigned MIN_LANG_SIZE = 2; const unsigned MAX_LANG_SIZE = 2 + 1 + 2;
const unsigned MIN_OPTIN_TYPE_SIZE = 0; const unsigned MAX_OPTIN_TYPE_SIZE = 255;
const unsigned MIN_OPTIN_ID_SIZE = 0; const unsigned MAX_OPTIN_ID_SIZE = 255;
typedef unsigned SessionType_t;
/*enum RequestType
{
REQUEST_TRANS_INIT_LOOKUP = 0x0,
REQUEST_TRANS_AUTH,
REQUEST_TRANS_AUTH_BRIDGE_LOOKUP,
// Add new request type codes here
REQUEST_END
};
*/
enum ApiResultCode
{
API_RESULT_UNKNOWN = 0
,API_RESULT_SUCCESS= 1
,API_RESULT_FAIL = 2
,API_RESULT_FAIL_DISCONNECTED
,API_RESULT_FAIL_RATE_LIMIT_EXCEEDED
// uncertain result error codes
,API_RESULT_FAIL_API_TIMEOUT = 100
,API_RESULT_FAIL_SERVER_TIMEOUT
,API_RESULT_FAIL_BAD_MESSAGE_FORMAT
,API_RESULT_FAIL_TRANSPORT
,API_RESULT_FAIL_READ_MESSAGE
,API_RESULT_FAIL_SERVER_READ_MESSAGE
,API_RESULT_FAIL_SERVER_WRITE_MESSAGE
// API parameter error codeS(do not use for server side)
,API_RESULT_FAIL_BAD_PARAMS = 200
};
} // end namespace CardinalServerAPI
#endif //_VCHAT_SERVER_API_TYPES_H_
@@ -0,0 +1,114 @@
#ifndef _VCHAT_CLIENT_SERIALIZE_H_
#define _VCHAT_CLIENT_SERIALIZE_H_
#include "common.h"
namespace soe
{
inline unsigned Write(unsigned char * stream, unsigned size, const VChatSystem::Channel & data, unsigned version = 0)
{
return data.Write(stream, size);
}
inline unsigned Read(const unsigned char * stream, unsigned size, VChatSystem::Channel & data, unsigned, unsigned version = 0)
{
return data.Read(stream, size);
}
inline unsigned Write(unsigned char * stream, unsigned size, const VChatSystem::CharacterChannel & data, unsigned version = 0)
{
return data.Write(stream, size);
}
inline unsigned Read(const unsigned char * stream, unsigned size, VChatSystem::CharacterChannel & data, unsigned, unsigned version = 0)
{
return data.Read(stream, size);
}
inline unsigned Write(unsigned char * stream, unsigned size, const VChatSystem::ChannelVec_t & data, unsigned version = 0)
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = soe::Write(stream + bytesTotal, size - bytesTotal, (unsigned)data.size()));
if (!bytes) return 0;
for (size_t i = 0; i < data.size(); i++)
{
bytesTotal += (bytes = soe::Write(stream + bytesTotal, size - bytesTotal, data[i]));
if (!bytes) return 0;
}
return bytesTotal;
}
inline unsigned Read(const unsigned char * stream, unsigned size, VChatSystem::ChannelVec_t & data, unsigned maxLen = 1, unsigned version = 0)
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
data.clear();
int vsize = 0;
bytesTotal += (bytes = soe::Read(stream + bytesTotal, size - bytesTotal, vsize));
if (!bytes) return 0;
for (int i = 0; i < vsize; i++)
{
VChatSystem::Channel tmpData;
bytesTotal += (bytes = soe::Read(stream + bytesTotal, size - bytesTotal, tmpData, 1));
if (!bytes)
{
return 0;
}
data.push_back(tmpData);
}
return bytesTotal;
}
inline unsigned Write(unsigned char * stream, unsigned size, const VChatSystem::CharacterChannelVec_t & data, unsigned version = 0)
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = soe::Write(stream + bytesTotal, size - bytesTotal, (unsigned)data.size()));
if (!bytes) return 0;
for (size_t i = 0; i < data.size(); i++)
{
bytesTotal += (bytes = soe::Write(stream + bytesTotal, size - bytesTotal, data[i]));
if (!bytes) return 0;
}
return bytesTotal;
}
inline unsigned Read(const unsigned char * stream, unsigned size, VChatSystem::CharacterChannelVec_t & data, unsigned maxLen = 1, unsigned version = 0)
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
data.clear();
int vsize = 0;
bytesTotal += (bytes = soe::Read(stream + bytesTotal, size - bytesTotal, vsize));
if (!bytes) return 0;
for (int i = 0; i < vsize; i++)
{
VChatSystem::CharacterChannel tmpData;
bytesTotal += (bytes = soe::Read(stream + bytesTotal, size - bytesTotal, tmpData, 1));
if (!bytes)
{
return 0;
}
data.push_back(tmpData);
}
return bytesTotal;
}
};
#endif //_VCHAT_CLIENT_SERIALIZE_H_
@@ -0,0 +1,334 @@
#include "common.h"
#include "Base/Base64.h"
#include "Base/Base32.h"
#include <algorithm>
#include "Base/stringutils.h"
using namespace Base;
namespace VChatSystem
{
unsigned Channel::Write(unsigned char * stream, unsigned size) const
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_channelName));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_channelURI));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_channelPassword));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_channelID));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_channelType));
if (!bytes) return 0;
return bytesTotal;
}
unsigned Channel::Read(const unsigned char * stream, unsigned size)
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_channelName, MAX_CHANNEL_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_channelURI, MAX_CHANNEL_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_channelPassword, MAX_PASSWORD_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_channelID));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_channelType));
if (!bytes) return 0;
return bytesTotal;
}
unsigned CharacterChannel::Write(unsigned char * stream, unsigned size) const
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_stationID));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_avatarID));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_characterName));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_worldName));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_gameCode));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_channelType));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_channelDescription));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_channelAddress));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_locale));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, m_password));
if (!bytes) return 0;
return bytesTotal;
}
unsigned CharacterChannel::Read(const unsigned char * stream, unsigned size)
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_stationID));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_avatarID));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_characterName, MAX_FULL_NAME_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_worldName, MAX_WORLD_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_gameCode, MAX_GAME_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_channelType, MAX_FULL_NAME_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_channelDescription, MAX_DESCRIPTION_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_channelAddress, MAX_CHANNEL_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_locale, MAX_FULL_NAME_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, m_password, MAX_PASSWORD_LEN));
if (!bytes) return 0;
return bytesTotal;
}
const char * VIV0X_DOT_COM = ".vivox.com";
void CreateUserURI(const std::string & avatarName, const std::string & game, const std::string & server, std::string & outUserURI)
{
outUserURI = server;
outUserURI += ".";
outUserURI += avatarName;
outUserURI += "@";
outUserURI += game;
outUserURI += VIV0X_DOT_COM;
}
void CreateUserName(const std::string & avatarName, const std::string & server, std::string & outUserName)
{
outUserName = server;
outUserName += ".";
outUserName += avatarName;
}
void CreateChannelURI(const std::string & channelName, const std::string & game, const std::string & server, std::string & outChannelURI)
{
outChannelURI = game;
outChannelURI += ".";
outChannelURI += server;
outChannelURI += ".";
outChannelURI += channelName;
}
void GetChannelComponents(const std::string & channelURI, std::string & name, std::string & server, std::string & game)
{
char seps[] = ".\n";
char *token;
// this will muck with the actual string so make a copy
// not very efficient but who cares...
std::string tmpTokenee = channelURI;
token = strtok((char*)tmpTokenee.c_str(), seps );
if( token != NULL )
{
game = token;
/* Get next token: */
token = strtok( NULL, seps );
}
if( token != NULL )
{
server = token;
/* Get next token: */
token = strtok( NULL, seps );
}
if( token != NULL )
{
name = token;
/* Get next token: */
token = strtok( NULL, seps );
}
while ( token != NULL )
{
name += ".";
name += token;
/* Get next token: */
token = strtok( NULL, seps );
}
}
void GetUserNameComponents(const std::string & userName, std::string & server, std::string & name)
{
char seps[] = ".\n";
char *token;
// this will muck with the actual string so make a copy
// not very efficient but who cares...
std::string tmpTokenee = userName;
token = strtok((char*)tmpTokenee.c_str(), seps );
if( token != NULL )
{
server = token;
/* Get next token: */
token = strtok( NULL, seps );
}
if( token != NULL )
{
name = token;
/* Get next token: */
token = strtok( NULL, seps );
}
while ( token != NULL )
{
name += ".";
name += token;
/* Get next token: */
token = strtok( NULL, seps );
}
}
std::string HexEncodeString(const std::string & input)
{
std::string retString;
soe::Base64::HexEncode((unsigned char *)input.c_str(), (unsigned)input.length(), retString, true);
return retString;
}
void EncodeVivoxString(const std::string & input, std::string & output)
{
std::string tmpInput = soe::tolowercase(input);
const unsigned outLen = Base32::GetEncode32Length((int)tmpInput.length());
unsigned char * outBuffer = new unsigned char[outLen + 1];
if(Base32::Encode32((unsigned char*)tmpInput.c_str(), (int)tmpInput.length(), outBuffer))
{
Base32::Map32(outBuffer, outLen);
outBuffer[outLen] = 0;
output = (char*)outBuffer;
}
if (outBuffer)
{
delete [] outBuffer;
}
}
void DecodeVivoxString(const std::string & input, std::string & output)
{
std::string tmpInput = soe::touppercase(input);
unsigned char tmpBuffer[256];
int inputLen = (int)tmpInput.length();
memset(tmpBuffer, 0, 256);
memcpy(tmpBuffer, tmpInput.c_str(), inputLen);
const unsigned outLen = Base32::GetDecode32Length((int)inputLen);
unsigned char * outBuffer = new unsigned char[outLen + 1];
Base32::Unmap32(tmpBuffer, inputLen);
if(Base32::Decode32(tmpBuffer, inputLen, outBuffer))
{
outBuffer[outLen] = 0;
output = (char*)outBuffer;
}
if (outBuffer)
{
delete [] outBuffer;
}
}
void GetEncodedUserName(const std::string & name, const std::string & server, std::string & encodedName)
{
std::string tmpName;
EncodeVivoxString(name, tmpName);
CreateUserName(tmpName, server, encodedName);
}
void GetDecodedUserName(const std::string & username, std::string & decodedName)
{
std::string name, server, decoded;
GetUserNameComponents(username, server, name);
DecodeVivoxString(name, decoded);
CreateUserName(decoded, server, decodedName);
}
void GetEncodedChannelName(const std::string & name, const std::string & server, const std::string & game, std::string & encodedName)
{
std::string tmpName;
EncodeVivoxString(name, tmpName);
CreateChannelURI(tmpName, game, server, encodedName);
}
void GetDecodedChannelName(const std::string & channelName, std::string & decodedChannelName)
{
std::string name, server, game, decoded;
GetChannelComponents(channelName, name, server, game);
DecodeVivoxString(name, decoded);
CreateChannelURI(decoded, game, server, decodedChannelName);
}
};
@@ -0,0 +1,114 @@
#ifndef _VCHAT_SERVER_COMMON_H_
#define _VCHAT_SERVER_COMMON_H_
#include <string>
#include <vector>
#ifndef SOE__DATE_H
#include <Base/date.h>
#endif
namespace VChatSystem
{
// Add common enumerated types or constants here
typedef unsigned char HashValue_t;
const unsigned MAX_PARAM_LEN = 6400;
const unsigned MAX_STUFF_LEN = 64000;
const unsigned MAX_NAME_PAIR_LEN = 256;
const unsigned MAX_VALUE_PAIR_LEN = 256;
const unsigned MAX_AVATAR_LEN = 50;
const unsigned MAX_CHANNEL_LEN = 255;
const unsigned MAX_DESCRIPTION_LEN = 256;
const unsigned MAX_FULL_NAME_LEN = 1024;
const unsigned MAX_GAME_LEN = 255;
const unsigned MAX_PASSWORD_LEN = 30;
const unsigned MAX_CHAT_AVATAR_LEN = 255;
const unsigned MAX_WORLD_LEN = 255;
const unsigned MAX_EMAIL_LEN = 255;
const unsigned MAX_PHONE_NUMBER_LEN = 255;
const unsigned MAX_PIN_LEN = 255;
const unsigned MAX_SMS_ACCT_LEN = 255;
const unsigned MAX_CHANNEL_ID_LEN = 100;
const unsigned MAX_URI_LEN = 255;
const unsigned VIVOX_NAME_LIMIT = 63;
struct Channel
{
Channel(): m_channelID(0) , m_channelType(0) {}
~Channel() {}
std::string m_channelName;
std::string m_channelURI;
std::string m_channelPassword;
unsigned m_channelID;
unsigned m_channelType;
unsigned Write(unsigned char * stream, unsigned size) const;
unsigned Read(const unsigned char * stream, unsigned size);
};
typedef std::vector<Channel> ChannelVec_t;
struct CharacterChannel
{
CharacterChannel(): m_stationID(0), m_avatarID(0){}
~CharacterChannel() {}
unsigned m_stationID;
unsigned m_avatarID;
std::string m_characterName;
std::string m_worldName;
std::string m_gameCode;
std::string m_channelType;
std::string m_channelDescription;
std::string m_channelAddress;
std::string m_locale;
std::string m_password;
unsigned Write(unsigned char * stream, unsigned size) const;
unsigned Read(const unsigned char * stream, unsigned size);
};
typedef std::vector<CharacterChannel> CharacterChannelVec_t;
// given avatarName, game and server returns outUserURI in the form of [email protected]
void CreateUserURI(const std::string & avatarName, const std::string & game, const std::string & server, std::string & outUserURI);
// given avatarName and server returns outUserName in the form of server.avatarName
void CreateUserName(const std::string & avatarName, const std::string & server, std::string & outUserName);
// given channelName, game and server returns outChannelURI in the form of game.server.channelName
void CreateChannelURI(const std::string & channelName, const std::string & game, const std::string & server, std::string & outChannelURI);
// given input of game.server.channel will break into seperate strings
void GetChannelComponents(const std::string & channelURI, std::string & name, std::string & server, std::string & game);
// given input of server.userName will break into seperate strings
void GetUserNameComponents(const std::string & userName, std::string & server, std::string & name);
std::string HexEncodeString(const std::string & input);
// encodes the string using a modified base64 encoding.
void EncodeVivoxString(const std::string & input, std::string & output);
// reverses a string encoded with EncodeVivoxString
void DecodeVivoxString(const std::string & input, std::string & output);
// given a name and server will return encodedName in the form of game.server.EncodedName
void GetEncodedUserName(const std::string & name, const std::string & server, std::string & encodedName);
// given an input of server.EncodedName will return server.DecodedName
void GetDecodedUserName(const std::string & username, std::string & decodedName);
// given a name and server will return encodedName in the form of server.EncodedName
void GetEncodedChannelName(const std::string & name, const std::string & server, const std::string & game, std::string & encodedName);
// given an input of game.server.EncodedName will return game.server.DecodedName
void GetDecodedChannelName(const std::string & channelName, std::string & decodedChannelName);
}
#endif //_VCHAT_SERVER_COMMON_H_
@@ -0,0 +1,277 @@
#ifdef WIN32
#pragma warning (disable : 4786 4514)
#endif
#include "messages.h"
using namespace std;
namespace VChatSystem
{
namespace Message
{
////////////////////////////////////////
// Login
ImplementMessageBegin(GetAccountRequest, Tracked)
ImplementMessageMemberEx(AvatarName, std::string(), MAX_AVATAR_LEN)
ImplementMessageMemberEx(Game, std::string(), MAX_GAME_LEN)
ImplementMessageMemberEx(Server, std::string(), MAX_WORLD_LEN)
ImplementMessageMember(UserID, 0)
ImplementMessageMember(AvatarID, 0)
ImplementMessageEnd
ImplementMessageBegin(GetAccountReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageMember(UserID, 0)
ImplementMessageMember(AccountID, 0)
ImplementMessageMemberEx(VoicePassword, std::string(), MAX_PASSWORD_LEN)
ImplementMessageMemberEx(EncodedAccountName, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMemberEx(URI, std::string(), MAX_URI_LEN)
ImplementMessageEnd
////////////////////////////////////////
// GetChannel
ImplementMessageBegin(GetChannelRequest, Tracked)
ImplementMessageMemberEx(ChannelName, std::string(), MAX_CHANNEL_LEN)
ImplementMessageMemberEx(Game, std::string(), MAX_GAME_LEN)
ImplementMessageMemberEx(Server, std::string(), MAX_WORLD_LEN)
ImplementMessageMemberEx(Description, std::string(), MAX_DESCRIPTION_LEN)
ImplementMessageMemberEx(Password, std::string(), MAX_PASSWORD_LEN)
ImplementMessageMember(Limit, 0)
ImplementMessageMember(Persistent, 0)
ImplementMessageEnd
ImplementMessageBegin(GetChannelReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageMemberEx(ChannelName, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMemberEx(ChannelURI, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMember(ChannelID, 0)
ImplementMessageEnd
///////////////////////////////////////
// GetProximityChannel
ImplementMessageBegin(GetProximityChannelRequest, Tracked)
ImplementMessageMemberEx(ChannelName, std::string(), MAX_CHANNEL_LEN)
ImplementMessageMemberEx(Game, std::string(), MAX_GAME_LEN)
ImplementMessageMemberEx(Server, std::string(), MAX_WORLD_LEN)
ImplementMessageMemberEx(Description, std::string(), MAX_DESCRIPTION_LEN)
ImplementMessageMemberEx(Password, std::string(), MAX_PASSWORD_LEN)
ImplementMessageMember(Limit, 0)
ImplementMessageMember(Persistent, 0)
ImplementMessageMember(MaxRange, 0)
ImplementMessageMember(Clamping, 0)
ImplementMessageMember(RollOff, 0)
ImplementMessageMember(MaxGain, 0)
ImplementMessageMember(DistModel, 0)
ImplementMessageEnd
ImplementMessageBegin(GetProximityChannelReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageMemberEx(ChannelName, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMemberEx(ChannelURI, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMember(ChannelID, 0)
ImplementMessageEnd
///////////////////////////////////////
// ChannelCommand
ImplementMessageBegin(ChannelCommandRequest, Tracked)
ImplementMessageMemberEx(SrcUserName, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMemberEx(DestUserName, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMemberEx(DestChannelAddress, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMember(Command, 0)
ImplementMessageMember(BanTimeout, 0)
ImplementMessageEnd
ImplementMessageBegin(ChannelCommandReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageEnd
///////////////////////////////////////
// DeactivateVoiceAccount
ImplementMessageBegin(DeactivateVoiceAccountRequest, Tracked)
ImplementMessageMemberEx(AvatarName, std::string(), MAX_AVATAR_LEN)
ImplementMessageMemberEx(Game, std::string(), MAX_GAME_LEN)
ImplementMessageMemberEx(Server, std::string(), MAX_WORLD_LEN)
ImplementMessageEnd
ImplementMessageBegin(DeactivateVoiceAccountReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageEnd
///////////////////////////////////////
// ChangePassword
ImplementMessageBegin(ChangePasswordRequest, Tracked)
ImplementMessageMemberEx(ChannelName, std::string(), MAX_CHANNEL_LEN)
ImplementMessageMemberEx(Game, std::string(), MAX_GAME_LEN)
ImplementMessageMemberEx(Server, std::string(), MAX_WORLD_LEN)
ImplementMessageMemberEx(Password, std::string(), MAX_PASSWORD_LEN)
ImplementMessageEnd
ImplementMessageBegin(ChangePasswordReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageEnd
////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// GetAllChannels
ImplementMessageBegin(GetAllChannelsRequest, Tracked)
ImplementMessageEnd
////////////////////////////////////////////////////////////////////////////////
// GetAllChannelsReply
ImplementMessageBegin(GetAllChannelsReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageMemberEx(ChannelsVec, ChannelVec_t(), 4096)
ImplementMessageEnd
///////////////////////////////////////
// DeleteChannelRequest
ImplementMessageBegin(DeleteChannelRequest, Tracked)
ImplementMessageMemberEx(ChannelName, std::string(), MAX_CHANNEL_LEN)
ImplementMessageMemberEx(Game, std::string(), MAX_GAME_LEN)
ImplementMessageMemberEx(Server, std::string(), MAX_WORLD_LEN)
ImplementMessageEnd
ImplementMessageBegin(DeleteChannelReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageEnd
///////////////////////////////////////
// SetUserData
ImplementMessageBegin(SetUserDataRequest, Tracked)
ImplementMessageMember(UserID, 0)
ImplementMessageMember(Attributes, 0)
ImplementMessageMemberEx(Email, std::string(), MAX_EMAIL_LEN)
ImplementMessageMemberEx(PhoneNumber, std::string(), MAX_PHONE_NUMBER_LEN)
ImplementMessageMemberEx(Pin, std::string(), MAX_PIN_LEN)
ImplementMessageMemberEx(SmsAccount, std::string(), MAX_SMS_ACCT_LEN)
ImplementMessageEnd
ImplementMessageBegin(SetUserDataReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageEnd
///////////////////////////////////////
// SetBanStatus
ImplementMessageBegin(SetBanStatusRequest, Tracked)
ImplementMessageMember(UserID, 0)
ImplementMessageMember(BanStatus, 0)
ImplementMessageEnd
ImplementMessageBegin(SetBanStatusReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageEnd
////////////////////////////////////////
// GetChannel
ImplementMessageBegin(GetChannelInfoRequest, Tracked)
ImplementMessageMemberEx(ChannelName, std::string(), MAX_CHANNEL_LEN)
ImplementMessageMemberEx(Game, std::string(), MAX_GAME_LEN)
ImplementMessageMemberEx(Server, std::string(), MAX_WORLD_LEN)
ImplementMessageEnd
ImplementMessageBegin(GetChannelInfoReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageMemberEx(ChannelName, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMemberEx(ChannelURI, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMember(ChannelID, 0)
ImplementMessageEnd
////////////////////////////////////////
// GetChannel
ImplementMessageBegin(GetChannelRequestV2, Tracked)
ImplementMessageMemberEx(ChannelName, std::string(), MAX_CHANNEL_LEN)
ImplementMessageMemberEx(Game, std::string(), MAX_GAME_LEN)
ImplementMessageMemberEx(Server, std::string(), MAX_WORLD_LEN)
ImplementMessageMemberEx(Description, std::string(), MAX_DESCRIPTION_LEN)
ImplementMessageMemberEx(Password, std::string(), MAX_PASSWORD_LEN)
ImplementMessageMember(Limit, 0)
ImplementMessageMember(Persistent, 0)
ImplementMessageEnd
ImplementMessageBegin(GetChannelReplyV2, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageMemberEx(ChannelName, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMemberEx(ChannelURI, std::string(), MAX_FULL_NAME_LEN)
ImplementMessageMember(ChannelID, 0)
ImplementMessageMember(IsNewChannel, 0)
ImplementMessageEnd
////////////////////////////////////////
// AddCharacterChannel
ImplementMessageBegin(AddCharacterChannelRequest, Tracked)
ImplementMessageMember( StationID,0 )
ImplementMessageMember( AvatarID, 0 )
ImplementMessageMemberEx( CharacterName, std::string(),MAX_FULL_NAME_LEN )
ImplementMessageMemberEx( WorldName, std::string(), MAX_WORLD_LEN )
ImplementMessageMemberEx( GameCode, std::string(), MAX_GAME_LEN )
ImplementMessageMemberEx( ChannelType, std::string(),MAX_FULL_NAME_LEN )
ImplementMessageMemberEx( ChannelDescription, std::string(), MAX_DESCRIPTION_LEN )
ImplementMessageMemberEx( Password, std::string(), MAX_PASSWORD_LEN)
ImplementMessageMemberEx( ChannelAddress, std::string(),MAX_CHANNEL_LEN )
ImplementMessageMemberEx( Locale, std::string(),MAX_FULL_NAME_LEN )
ImplementMessageEnd
ImplementMessageBegin(AddCharacterChannelReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageEnd
////////////////////////////////////////
// RemoveCharacterChannel
ImplementMessageBegin(RemoveCharacterChannelRequest, Tracked)
ImplementMessageMember( StationID,0 )
ImplementMessageMember( AvatarID, 0 )
ImplementMessageMemberEx( CharacterName, std::string(),MAX_FULL_NAME_LEN )
ImplementMessageMemberEx( WorldName, std::string(), MAX_WORLD_LEN )
ImplementMessageMemberEx( GameCode, std::string(), MAX_GAME_LEN )
ImplementMessageMemberEx( ChannelType, std::string(),MAX_FULL_NAME_LEN )
ImplementMessageEnd
ImplementMessageBegin(RemoveCharacterChannelReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageEnd
////////////////////////////////////////
// GetCharacterChannel
ImplementMessageBegin(GetCharacterChannelRequest, Tracked)
ImplementMessageMember( StationID,0 )
ImplementMessageMemberEx( CharacterName, std::string(),MAX_FULL_NAME_LEN )
ImplementMessageMemberEx( WorldName, std::string(), MAX_WORLD_LEN )
ImplementMessageMemberEx( GameCode, std::string(), MAX_GAME_LEN )
ImplementMessageEnd
ImplementMessageBegin(GetCharacterChannelReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageMemberEx(ChannelList, CharacterChannelVec_t(), MAX_NAME_PAIR_LEN)
ImplementMessageEnd
////////////////////////////////////////
// UpdateCharacterChannel
ImplementMessageBegin(UpdateCharacterChannelRequest, Tracked)
ImplementMessageMember( StationID,0 )
ImplementMessageMember( AvatarID, 0 )
ImplementMessageMemberEx( CharacterName, std::string(),MAX_FULL_NAME_LEN )
ImplementMessageMemberEx( WorldName, std::string(), MAX_WORLD_LEN )
ImplementMessageMemberEx( GameCode, std::string(), MAX_GAME_LEN )
ImplementMessageMemberEx( ChannelType, std::string(),MAX_FULL_NAME_LEN )
ImplementMessageMemberEx( ChannelDescription, std::string(), MAX_DESCRIPTION_LEN )
ImplementMessageMember( ChannelID, 0 )
ImplementMessageMemberEx( Password, std::string(), MAX_PASSWORD_LEN)
ImplementMessageMemberEx( ChannelURI, std::string(),MAX_FULL_NAME_LEN )
ImplementMessageMemberEx( Locale, std::string(),MAX_FULL_NAME_LEN )
ImplementMessageEnd
ImplementMessageBegin(UpdateCharacterChannelReply, TrackedReply)
ImplementMessageMember(Result, 0)
ImplementMessageEnd
}
}
@@ -0,0 +1,350 @@
#ifndef _VCHAT_SERVER_API_MESSAGES_H_
#define _VCHAT_SERVER_API_MESSAGES_H_
#include <string>
#include <vector>
#include "clientSerialize.h"
#ifndef _VCHAT_API_API_HEADERS_
#define _VCHAT_API_API_HEADERS_
#ifndef API_NAMESPACE
#define API_NAMESPACE VChatSystem
#include "Api/api.h"
#undef API_NAMESPACE
#else
#include "Api/api.h"
#endif
#endif
namespace VChatSystem
{
enum
{
// internal message
MESSAGE_RETRY_NOTIFICATIONS = 1,
// Requests
MESSAGE_GET_ACCOUNT_REQUEST = 0x1100,
MESSAGE_GET_CHANNEL_REQUEST,
MESSAGE_GET_PROXIMITY_CHANNEL_REQUEST,
MESSAGE_CHANNEL_COMMAND_REQUEST,
MESSAGE_DEACTIVATE_ACCOUNT_REQUEST,
MESSAGE_CHANGE_PASSWORD_REQUEST,
MESSAGE_GET_ALL_CHANNELS_REQUEST,
MESSAGE_DELETE_CHANNEL_REQUEST,
MESSAGE_SET_USER_DATA_REQUEST,
MESSAGE_SET_BAN_STATUS_REQUEST,
MESSAGE_GET_CHANNEL_INFO_REQUEST,
MESSAGE_GET_CHANNEL_REQUEST_V2,
MESSAGE_ADD_CHARACTER_CHANNEL,
MESSAGE_REMOVE_CHARACTER_CHANNEL,
MESSAGE_GET_CHARACTER_CHANNEL,
MESSAGE_UPDATE_CHARACTER_CHANNEL,
// Replies
MESSAGE_GET_ACCOUNT_REPLY = 0x8100,
MESSAGE_GET_CHANNEL_REPLY,
MESSAGE_GET_PROXIMITY_CHANNEL_REPLY,
MESSAGE_CHANNEL_COMMAND_REPLY,
MESSAGE_DEACTIVATE_ACCOUNT_REPLY,
MESSAGE_CHANGE_PASSWORD_REPLY,
MESSAGE_GET_ALL_CHANNELS_REPLY,
MESSAGE_DELETE_CHANNEL_REPLY,
MESSAGE_SET_USER_DATA_REPLY,
MESSAGE_SET_BAN_STATUS_REPLY,
MESSAGE_GET_CHANNEL_INFO_REPLY,
MESSAGE_GET_CHANNEL_REPLY_V2,
MESSAGE_ADD_CHARACTER_CHANNEL_REPLY,
MESSAGE_REMOVE_CHARACTER_CHANNEL_REPLY,
MESSAGE_GET_CHARACTER_CHANNEL_REPLY,
MESSAGE_UPDATE_CHARACTER_CHANNEL_REPLY,
};
namespace Message
{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
// Login
DefineMessageBegin(GetAccountRequest, Tracked, MESSAGE_GET_ACCOUNT_REQUEST)
DefineMessageMember(AvatarName, std::string)
DefineMessageMember(Game, std::string)
DefineMessageMember(Server, std::string)
DefineMessageMember(UserID, unsigned)
DefineMessageMember(AvatarID, unsigned)
DefineMessageEnd
DefineMessageBegin(GetAccountReply, TrackedReply, MESSAGE_GET_ACCOUNT_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageMember(UserID, unsigned)
DefineMessageMember(AccountID, unsigned)
DefineMessageMember(VoicePassword, std::string)
DefineMessageMember(EncodedAccountName, std::string)
DefineMessageMember(URI, std::string)
DefineMessageEnd
////////////////////////////////////////
// GetChannel
DefineMessageBegin(GetChannelRequest, Tracked, MESSAGE_GET_CHANNEL_REQUEST)
DefineMessageMember(ChannelName, std::string)
DefineMessageMember(Game, std::string)
DefineMessageMember(Server, std::string)
DefineMessageMember(Description, std::string)
DefineMessageMember(Password, std::string)
DefineMessageMember(Limit, unsigned)
DefineMessageMember(Persistent, unsigned)
DefineMessageEnd
DefineMessageBegin(GetChannelReply, TrackedReply, MESSAGE_GET_CHANNEL_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageMember(ChannelName, std::string)
DefineMessageMember(ChannelURI, std::string)
DefineMessageMember(ChannelID, unsigned)
DefineMessageEnd
///////////////////////////////////////
// GetProximityChannel
DefineMessageBegin(GetProximityChannelRequest, Tracked, MESSAGE_GET_PROXIMITY_CHANNEL_REQUEST)
DefineMessageMember(ChannelName, std::string)
DefineMessageMember(Game, std::string)
DefineMessageMember(Server, std::string)
DefineMessageMember(Description, std::string)
DefineMessageMember(Password, std::string)
DefineMessageMember(Limit, unsigned)
DefineMessageMember(Persistent, unsigned)
DefineMessageMember(MaxRange, unsigned)
DefineMessageMember(Clamping, unsigned)
DefineMessageMember(RollOff, float)
DefineMessageMember(MaxGain, float)
DefineMessageMember(DistModel, unsigned)
DefineMessageEnd
DefineMessageBegin(GetProximityChannelReply, TrackedReply, MESSAGE_GET_PROXIMITY_CHANNEL_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageMember(ChannelName, std::string)
DefineMessageMember(ChannelURI, std::string)
DefineMessageMember(ChannelID, unsigned)
DefineMessageEnd
///////////////////////////////////////
// ChannelCommand
DefineMessageBegin(ChannelCommandRequest, Tracked, MESSAGE_CHANNEL_COMMAND_REQUEST)
DefineMessageMember(SrcUserName, std::string)
DefineMessageMember(DestUserName, std::string)
DefineMessageMember(DestChannelAddress, std::string)
DefineMessageMember(Command, unsigned)
DefineMessageMember(BanTimeout, unsigned)
DefineMessageEnd
DefineMessageBegin(ChannelCommandReply, TrackedReply, MESSAGE_CHANNEL_COMMAND_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageEnd
///////////////////////////////////////
// DeactivateVoiceAccount
DefineMessageBegin(DeactivateVoiceAccountRequest, Tracked, MESSAGE_DEACTIVATE_ACCOUNT_REQUEST)
DefineMessageMember(AvatarName, std::string)
DefineMessageMember(Game, std::string)
DefineMessageMember(Server, std::string)
DefineMessageEnd
DefineMessageBegin(DeactivateVoiceAccountReply, TrackedReply, MESSAGE_DEACTIVATE_ACCOUNT_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageEnd
///////////////////////////////////////
// ChangePassword
DefineMessageBegin(ChangePasswordRequest, Tracked, MESSAGE_CHANGE_PASSWORD_REQUEST)
DefineMessageMember(ChannelName, std::string)
DefineMessageMember(Game, std::string)
DefineMessageMember(Server, std::string)
DefineMessageMember(Password, std::string)
DefineMessageEnd
DefineMessageBegin(ChangePasswordReply, TrackedReply, MESSAGE_CHANGE_PASSWORD_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageEnd
////////////////////////////////////////////////////////////////////////////////
// GetAllChannels
DefineMessageBegin(GetAllChannelsRequest, Tracked, MESSAGE_GET_ALL_CHANNELS_REQUEST)
DefineMessageEnd
DefineMessageBegin(GetAllChannelsReply, TrackedReply, MESSAGE_GET_ALL_CHANNELS_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageMember(ChannelsVec, ChannelVec_t)
DefineMessageEnd
///////////////////////////////////////
// DeleteChannel
DefineMessageBegin(DeleteChannelRequest, Tracked, MESSAGE_DELETE_CHANNEL_REQUEST)
DefineMessageMember(ChannelName, std::string)
DefineMessageMember(Game, std::string)
DefineMessageMember(Server, std::string)
DefineMessageEnd
DefineMessageBegin(DeleteChannelReply, TrackedReply, MESSAGE_DELETE_CHANNEL_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageEnd
///////////////////////////////////////
// SetUserData
DefineMessageBegin(SetUserDataRequest, Tracked, MESSAGE_SET_USER_DATA_REQUEST)
DefineMessageMember(UserID, unsigned)
DefineMessageMember(Attributes, unsigned)
DefineMessageMember(Email, std::string)
DefineMessageMember(PhoneNumber, std::string)
DefineMessageMember(Pin, std::string)
DefineMessageMember(SmsAccount, std::string)
DefineMessageEnd
DefineMessageBegin(SetUserDataReply, TrackedReply, MESSAGE_SET_USER_DATA_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageEnd
///////////////////////////////////////
// SetBanStatus
DefineMessageBegin(SetBanStatusRequest, Tracked, MESSAGE_SET_BAN_STATUS_REQUEST)
DefineMessageMember(UserID, unsigned)
DefineMessageMember(BanStatus, unsigned)
DefineMessageEnd
DefineMessageBegin(SetBanStatusReply, TrackedReply, MESSAGE_SET_BAN_STATUS_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageEnd
////////////////////////////////////////
// GetChannelInfo
DefineMessageBegin(GetChannelInfoRequest, Tracked, MESSAGE_GET_CHANNEL_INFO_REQUEST)
DefineMessageMember(ChannelName, std::string)
DefineMessageMember(Game, std::string)
DefineMessageMember(Server, std::string)
DefineMessageEnd
DefineMessageBegin(GetChannelInfoReply, TrackedReply, MESSAGE_GET_CHANNEL_INFO_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageMember(ChannelName, std::string)
DefineMessageMember(ChannelURI, std::string)
DefineMessageMember(ChannelID, unsigned)
DefineMessageEnd
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
// GetChannel
DefineMessageBegin(GetChannelRequestV2, Tracked, MESSAGE_GET_CHANNEL_REQUEST_V2)
DefineMessageMember(ChannelName, std::string)
DefineMessageMember(Game, std::string)
DefineMessageMember(Server, std::string)
DefineMessageMember(Description, std::string)
DefineMessageMember(Password, std::string)
DefineMessageMember(Limit, unsigned)
DefineMessageMember(Persistent, unsigned)
DefineMessageEnd
DefineMessageBegin(GetChannelReplyV2, TrackedReply, MESSAGE_GET_CHANNEL_REPLY_V2)
DefineMessageMember(Result, unsigned)
DefineMessageMember(ChannelName, std::string)
DefineMessageMember(ChannelURI, std::string)
DefineMessageMember(ChannelID, unsigned)
DefineMessageMember(IsNewChannel, unsigned)
DefineMessageEnd
////////////////////////////////////////
// AddCharacterChannel
DefineMessageBegin(AddCharacterChannelRequest, Tracked, MESSAGE_ADD_CHARACTER_CHANNEL)
DefineMessageMember( StationID,unsigned )
DefineMessageMember( AvatarID, unsigned )
DefineMessageMember( CharacterName, std::string )
DefineMessageMember( WorldName, std::string )
DefineMessageMember( GameCode, std::string )
DefineMessageMember( ChannelType, std::string )
DefineMessageMember( ChannelDescription, std::string )
DefineMessageMember( Password, std::string)
DefineMessageMember( ChannelAddress, std::string )
DefineMessageMember( Locale, std::string )
DefineMessageEnd
DefineMessageBegin(AddCharacterChannelReply, TrackedReply, MESSAGE_ADD_CHARACTER_CHANNEL_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageEnd
////////////////////////////////////////
// RemoveCharacterChannel
DefineMessageBegin(RemoveCharacterChannelRequest, Tracked, MESSAGE_REMOVE_CHARACTER_CHANNEL)
DefineMessageMember( StationID,unsigned )
DefineMessageMember( AvatarID, unsigned )
DefineMessageMember( CharacterName, std::string )
DefineMessageMember( WorldName, std::string )
DefineMessageMember( GameCode, std::string )
DefineMessageMember( ChannelType, std::string )
DefineMessageEnd
DefineMessageBegin(RemoveCharacterChannelReply, TrackedReply, MESSAGE_REMOVE_CHARACTER_CHANNEL_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageEnd
////////////////////////////////////////
// GetCharacterChannel
DefineMessageBegin(GetCharacterChannelRequest, Tracked, MESSAGE_GET_CHARACTER_CHANNEL)
DefineMessageMember( StationID,unsigned )
DefineMessageMember( CharacterName, std::string )
DefineMessageMember( WorldName, std::string )
DefineMessageMember( GameCode, std::string )
DefineMessageEnd
DefineMessageBegin(GetCharacterChannelReply, TrackedReply, MESSAGE_GET_CHARACTER_CHANNEL_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageMember(ChannelList, CharacterChannelVec_t)
DefineMessageEnd
////////////////////////////////////////
// UpdateCharacterChannel
DefineMessageBegin(UpdateCharacterChannelRequest, Tracked, MESSAGE_UPDATE_CHARACTER_CHANNEL)
DefineMessageMember( StationID,unsigned )
DefineMessageMember( AvatarID, unsigned )
DefineMessageMember( CharacterName, std::string )
DefineMessageMember( WorldName, std::string )
DefineMessageMember( GameCode, std::string )
DefineMessageMember( ChannelType, std::string )
DefineMessageMember( ChannelDescription, std::string )
DefineMessageMember( ChannelID, unsigned )
DefineMessageMember( Password, std::string)
DefineMessageMember( ChannelURI, std::string )
DefineMessageMember( Locale, std::string )
DefineMessageEnd
DefineMessageBegin(UpdateCharacterChannelReply, TrackedReply, MESSAGE_UPDATE_CHARACTER_CHANNEL_REPLY)
DefineMessageMember(Result, unsigned)
DefineMessageEnd
/* ,
,
,
MESSAGE_UPDATE_CHARACTER_CHANNEL,*/
////////////////////////////////////////////////////////////////////////////////
} // namepsace Message
} // namespace API_NAMESPACE
#endif //_VCHAT_SERVER_API_MESSAGES_H_
@@ -0,0 +1,149 @@
#ifndef _VCHAT_SERVER_API_STRINGS_H_
#define _VCHAT_SERVER_API_STRINGS_H_
#include <map>
#include <string>
#include "VChatAPI.h"
#include "messages.h"
#include "common.h"
namespace VChatSystem
{
typedef std::pair<unsigned, std::string> Id2Text_t;
typedef std::map<unsigned,std::string> Id2TextMap_t;
//////////////////////////////////////////////////////////////////////////////////
// ResultString
//
static const Id2Text_t _resultString[] =
{
Id2Text_t(RESULT_SUCCESS, "RESULT_SUCCESS"),
Id2Text_t(RESULT_TIMEOUT, "RESULT_TIMEOUT"),
Id2Text_t(RESULT_FAILURE, "RESULT_SYSTEM_ERROR"),
Id2Text_t(RESULT_INVALID_PARAM, "RESULT_INVALID_PARAM"),
Id2Text_t(RESULT_DATABASE_FAILURE, "RESULT_DATABASE_FAILURE"),
Id2Text_t(RESULT_NETWORK_FAILURE, "RESULT_NETWORK_FAILURE"),
Id2Text_t(RESULT_NOT_IMPLEMENTED, "RESULT_NOT_IMPLEMENTED"),
Id2Text_t(RESULT_NOT_SUPPORTED, "RESULT_NOT_SUPPORTED"),
Id2Text_t(RESULT_TCP_CONNECTION_NOT_AVAILABLE, "RESULT_TCP_CONNECTION_NOT_AVAILABLE"),
Id2Text_t(RESULT_RESPONSE_XML_INVALID, "RESULT_RESPONSE_XML_INVALID"),
Id2Text_t(RESULT_RESPONSE_VIVOX_FAILURE, "RESULT_RESPONSE_VIVOX_FAILURE"),
Id2Text_t(RESULT_USER_ACCOUNT_BANNED, "RESULT_USER_ACCOUNT_BANNED"),
Id2Text_t(RESULT_NAME_EXCEEDS_VIVOX_LIMIT, "RESULT_NAME_EXCEEDS_VIVOX_LIMIT"),
Id2Text_t(RESULT_NO_CHANNELS_FOUND_FOR_CHARACTER, "RESULT_NO_CHANNELS_FOUND_FOR_CHARACTER"),
Id2Text_t(RESULT_VIVOX_WRONG_USER_CREDENTIALS, "RESULT_VIVOX_WRONG_USER_CREDENTIALS"),
Id2Text_t(RESULT_VIVOX_EXPIRED_USER_CREDENTIALS, "RESULT_VIVOX_EXPIRED_USER_CREDENTIALS"),
Id2Text_t(RESULT_VIVOX_MISSING_USER_CREDENTIALS, "RESULT_VIVOX_MISSING_USER_CREDENTIALS"),
Id2Text_t(RESULT_VIVOX_USER_NOT_LOGGED_IN, "RESULT_VIVOX_USER_NOT_LOGGED_IN"),
Id2Text_t(RESULT_VIVOX_ACCOUNT_CANT_PERFORM_OP, "RESULT_VIVOX_ACCOUNT_CANT_PERFORM_OP"),
Id2Text_t(RESULT_VIVOX_FAILED_RETRIEVING_DIR, "RESULT_VIVOX_FAILED_RETRIEVING_DIR"),
Id2Text_t(RESULT_VIVOX_PARAMS_MISSING, "RESULT_VIVOX_PARAMS_MISSING"),
Id2Text_t(RESULT_VIVOX_UNKNOWN_MODE, "RESULT_VIVOX_UNKNOWN_MODE"),
Id2Text_t(RESULT_VIVOX_UNABLE_TO_PARSE_ARG, "RESULT_VIVOX_UNABLE_TO_PARSE_ARG"),
Id2Text_t(RESULT_VIVOX_ACCOUNT_CREATION_FAILED, "RESULT_VIVOX_ACCOUNT_CREATION_FAILED"),
Id2Text_t(RESULT_VIVOX_ACCOUNT_DEACTIVATE_FAILED, "RESULT_VIVOX_ACCOUNT_DEACTIVATE_FAILED"),
Id2Text_t(RESULT_VIVOX_ACCOUNT_ACTIVATE_FAILED, "RESULT_VIVOX_ACCOUNT_ACTIVATE_FAILED"),
Id2Text_t(RESULT_VIVOX_ACCOUNT_DOESNT_EXIST, "RESULT_VIVOX_ACCOUNT_DOESNT_EXIST"),
Id2Text_t(RESULT_VIVOX_ACCOUNT_RETRIEVAL_FAILED, "RESULT_VIVOX_ACCOUNT_RETRIEVAL_FAILED"),
Id2Text_t(RESULT_VIVOX_ACCOUNT_UPDATE_FAILED, "RESULT_VIVOX_ACCOUNT_UPDATE_FAILED"),
Id2Text_t(RESULT_VIVOX_ACCOUNT_DELETE_FAILED, "RESULT_VIVOX_ACCOUNT_DELETE_FAILED"),
Id2Text_t(RESULT_VIVOX_RETRIEVING_SRC_USER, "RESULT_VIVOX_RETRIEVING_SRC_USER"),
Id2Text_t(RESULT_VIVOX_CHANNEL_ADD_FAILED, "RESULT_VIVOX_CHANNEL_ADD_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_UPDATE_FAILED, "RESULT_VIVOX_CHANNEL_UPDATE_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_RETRIEVE_FAILED, "RESULT_VIVOX_CHANNEL_RETRIEVE_FAILED"),
Id2Text_t(RESULT_VIVOX_FEATURE_NAME_UNKNOWN, "RESULT_VIVOX_FEATURE_NAME_UNKNOWN"),
Id2Text_t(RESULT_VIVOX_FEATURE_RETRIEVAL_FAILED, "RESULT_VIVOX_FEATURE_RETRIEVAL_FAILED"),
Id2Text_t(RESULT_VIVOX_FEATURE_SET_FAILED, "RESULT_VIVOX_FEATURE_SET_FAILED"),
Id2Text_t(RESULT_VIVOX_FEATURE_UPDATE_FAILED, "RESULT_VIVOX_FEATURE_UPDATE_FAILED"),
Id2Text_t(RESULT_VIVOX_FEATURE_DELETE_FAILED, "RESULT_VIVOX_FEATURE_DELETE_FAILED"),
Id2Text_t(RESULT_VIVOX_RETRIEVE_USER_FAILED, "RESULT_VIVOX_RETRIEVE_USER_FAILED"),
Id2Text_t(RESULT_VIVOX_RETRIEVE_FEATURE_LIST_FAILED, "RESULT_VIVOX_RETRIEVE_FEATURE_LIST_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_RETRIEVE_USERS_FAILED, "RESULT_VIVOX_CHANNEL_RETRIEVE_USERS_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_MUTE_ALL_FAILED, "RESULT_VIVOX_CHANNEL_MUTE_ALL_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_UNMUTE_ALL_FAILED, "RESULT_VIVOX_CHANNEL_UNMUTE_ALL_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_INVITE_FAILED, "RESULT_VIVOX_CHANNEL_INVITE_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_RETRIEVING_ACL_FAILED, "RESULT_VIVOX_CHANNEL_RETRIEVING_ACL_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_DELETE_ACL_FAILED, "RESULT_VIVOX_CHANNEL_DELETE_ACL_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_LOCKING_FAILED, "RESULT_VIVOX_CHANNEL_LOCKING_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_UNLOCKING_FAILED, "RESULT_VIVOX_CHANNEL_UNLOCKING_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_CREATING_FAILED, "RESULT_VIVOX_CHANNEL_CREATING_FAILED"),
Id2Text_t(RESULT_VIVOX_CHANNEL_RETRIEVE_FAILED_EX, "RESULT_VIVOX_CHANNEL_RETRIEVE_FAILED_EX"),
Id2Text_t(RESULT_VIVOX_USER_NOT_ON_CHANNEL, "RESULT_VIVOX_USER_NOT_ON_CHANNEL"),
Id2Text_t(RESULT_VIVOX_UNABLE_TO_COMPLETE_CHANNEL_LOOKUP, "RESULT_VIVOX_UNABLE_TO_COMPLETE_CHANNEL_LOOKUP"),
Id2Text_t(RESULT_END, "RESULT_END")
};
static const int _ResultCount = sizeof(_resultString) / sizeof(Id2Text_t);
static Id2TextMap_t ResultString((const Id2TextMap_t::value_type *)&_resultString[0],(const Id2TextMap_t::value_type *)&_resultString[_ResultCount]);
//////////////////////////////////////////////////////////////////////////////////
// CommandString
//
static const Id2Text_t _commandString[] =
{
Id2Text_t(MESSAGE_CONNECT, "MSG_CONNECT"),
Id2Text_t(MESSAGE_GET_ACCOUNT_REQUEST, "MESSAGE_GET_ACCOUNT_REQUEST"),
Id2Text_t(MESSAGE_GET_CHANNEL_REQUEST, "MESSAGE_GET_CHANNEL_REQUEST"),
Id2Text_t(MESSAGE_GET_PROXIMITY_CHANNEL_REQUEST, "MESSAGE_GET_PROXIMITY_CHANNEL_REQUEST"),
Id2Text_t(MESSAGE_CHANNEL_COMMAND_REQUEST, "MESSAGE_CHANNEL_COMMAND_REQUEST"),
Id2Text_t(MESSAGE_DEACTIVATE_ACCOUNT_REQUEST, "MESSAGE_DEACTIVATE_ACCOUNT_REQUEST"),
Id2Text_t(MESSAGE_CHANGE_PASSWORD_REQUEST, "MESSAGE_CHANGE_PASSWORD_REQUEST"),
Id2Text_t(MESSAGE_GET_ALL_CHANNELS_REQUEST, "MESSAGE_GET_ALL_CHANNELS_REQUEST"),
Id2Text_t(MESSAGE_DELETE_CHANNEL_REQUEST, "MESSAGE_DELETE_CHANNEL_REQUEST"),
Id2Text_t(MESSAGE_SET_USER_DATA_REQUEST, "MESSAGE_SET_USER_DATA_REQUEST"),
Id2Text_t(MESSAGE_SET_BAN_STATUS_REQUEST, "MESSAGE_SET_BAN_STATUS_REQUEST"),
Id2Text_t(MESSAGE_GET_CHANNEL_INFO_REQUEST, "MESSAGE_GET_CHANNEL_INFO_REQUEST"),
Id2Text_t(MESSAGE_GET_CHANNEL_REQUEST_V2, "MESSAGE_GET_CHANNEL_REQUEST_V2"),
Id2Text_t(MESSAGE_ADD_CHARACTER_CHANNEL, "MESSAGE_ADD_CHARACTER_CHANNEL"),
Id2Text_t(MESSAGE_REMOVE_CHARACTER_CHANNEL, "MESSAGE_REMOVE_CHARACTER_CHANNEL"),
Id2Text_t(MESSAGE_GET_CHARACTER_CHANNEL, "MESSAGE_GET_CHARACTER_CHANNEL"),
Id2Text_t(MESSAGE_UPDATE_CHARACTER_CHANNEL, "MESSAGE_UPDATE_CHARACTER_CHANNEL")
};
static const int _CommandCount = sizeof(_commandString) / sizeof(Id2Text_t);
static Id2TextMap_t CommandString((const Id2TextMap_t::value_type *)&_commandString[0],(const Id2TextMap_t::value_type *)&_commandString[_CommandCount]);
//////////////////////////////////////////////////////////////////////////////////
// ChannelCommandString
//
static const Id2Text_t _channelCommandString[] =
{
Id2Text_t(COMMAND_MUTE, "mute"),
Id2Text_t(COMMAND_UNMUTE, "unmute"),
Id2Text_t(COMMAND_KICK, "kick"),
Id2Text_t(COMMAND_HANGUP, "hangup"),
Id2Text_t(COMMAND_INVITE, "invite"),
Id2Text_t(COMMAND_BAN, "ban"),
Id2Text_t(COMMAND_UNBAN, "unban"),
Id2Text_t(COMMAND_CHAN_LOCK, "chan_lock"),
Id2Text_t(COMMAND_CHAN_UNLOCK, "chan_unlock"),
Id2Text_t(COMMAND_MUTE_ALL, "mute_all"),
Id2Text_t(COMMAND_UNMUTE_ALL, "unmute_all"),
Id2Text_t(COMMAND_ADD_MODERATOR, "mod_addu"),
Id2Text_t(COMMAND_DELETE_MODERATOR, "mod_delu"),
Id2Text_t(COMMAND_ADD_ACL, "acl_add"),
Id2Text_t(COMMAND_DELETE_ACL, "acl_delete"),
Id2Text_t(COMMAND_DROP_ALL, "drop_all"),
Id2Text_t(COMMAND_END, "COMMAND_END")
};
static const int _ChannelCommandCount = sizeof(_channelCommandString) / sizeof(Id2Text_t);
static Id2TextMap_t ChannelCommandString((const Id2TextMap_t::value_type *)&_channelCommandString[0],(const Id2TextMap_t::value_type *)&_channelCommandString[_ChannelCommandCount]);
}
#endif //_VCHAT_SERVER_API_STRINGS_H_
@@ -0,0 +1,514 @@
#include "VChatClient.h"
#include "Base/timer.h"
#include "VChatAPI/strings.h"
VChatClient::VChatClient(const char *hostlist)
: VChatAPI(hostlist)
, m_isDone(false)
, m_failed(false)
, m_isConnected(false)
, m_result(RESULT_FAILURE)
{
}
VChatClient::~VChatClient(void)
{
}
unsigned VChatClient::GetAccountEx(const std::string &avatarName,
const std::string &game,
const std::string &world,
unsigned userID,
unsigned avatarID)
{
Reset();
VChatAPI::GetAccount(avatarName, game, world, userID, avatarID, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnGetAccount(unsigned track,
unsigned result,
unsigned userID,
unsigned accountID,
const std::string &voicePassword,
const std::string &encodedVoiceAccount,
const std::string &URI,
void *user)
{
printf ("OnLogin track = %d, result = %s\n", track, ResultString[result].c_str());
printf ("\t UserID(%d)\n\t AccountID(%d)\n\t",
userID,
accountID);
printf ("\t Password(%s)\n",
voicePassword.c_str());
printf ("\t EncodedName(%s)\n",
encodedVoiceAccount.c_str());
printf ("\t URI(%s)\n",
URI.c_str());
m_avatarID = accountID;
m_track = track;
//m_previousUser = encodedVoiceAccount;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::DeactivateVoiceAccount(const std::string &avatarName,
const std::string &game,
const std::string &world)
{
Reset();
VChatAPI::DeactivateVoiceAccount(avatarName, game, world, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnDeactivateVoiceAccount( unsigned track,
unsigned result,
void *user)
{
printf ("OnDeactivateVoiceAccount track = %d, result = %s\n", track, ResultString[result].c_str());
m_track = track;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::GetChannelEx( const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent)
{
Reset();
VChatAPI::GetChannel(channelName, game, server, description, password, limit, persistent, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnGetChannel( unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
void *user)
{
printf ("OnGetChannel track = %d, result = %s\n", track, ResultString[result].c_str());
printf ("\t ChannelName(%s)\n\t ChannelURI(%s)\n\t ChannelID(%d)\n",
channelName.c_str(),
channelURI.c_str(),
channelID);
m_channelID = channelID;
m_channelURI = channelURI;
m_track = track;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::GetProximityChannelEx(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent,
unsigned maxRange,
unsigned clamping,
float rollOff,
float maxGain,
unsigned distModel)
{
Reset();
VChatAPI::GetProximityChannel(channelName, game, server, description, password, limit, persistent, maxRange, clamping, rollOff, maxGain, distModel, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnGetProximityChannel(unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
void *user)
{
printf ("OnGetProximityChannel track = %d, result = %s\n", track, ResultString[result].c_str());
printf ("\t ChannelName(%s)\n\t ChannelURI(%s)\n\t ChannelID(%d)\n",
channelName.c_str(),
channelURI.c_str(),
channelID);
m_track = track;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::ChannelCommandEx( const std::string &srcUserName,
const std::string &destUserName,
const std::string &destChannelAddress,
unsigned command,
unsigned banTimeout)
{
Reset();
VChatAPI::ChannelCommand(srcUserName, destUserName, destChannelAddress, command, banTimeout, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnChannelCommand( unsigned track,
unsigned result,
void *user)
{
printf ("OnChannelCommand track = %d, result = %s\n", track, ResultString[result].c_str());
m_track = track;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::ChangePasswordEx(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &password)
{
Reset();
VChatAPI::ChangePassword(channelName, game, server, password, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnChangePassword( unsigned track,
unsigned result,
void *user)
{
printf ("OnChangePassword track = %d, result = %s\n", track, ResultString[result].c_str());
m_track = track;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::GetAllChannelsEx()
{
Reset();
VChatAPI::GetAllChannels(NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnGetAllChannels( unsigned track,
unsigned result,
const ChannelVec_t & channels,
void *user)
{
printf ("OnGetAllChannels track = %d, result = %s\n", track, ResultString[result].c_str());
for(unsigned i = 0; i < channels.size(); ++i)
{
printf ("\t%d) ChannelName(%s)\n\t ChannelType(%d)\n\t ChannelURI(%s)\n\t ChannelID(%d)\n",
i+1,
channels[i].m_channelName.c_str(),
channels[i].m_channelType,
channels[i].m_channelURI.c_str(),
channels[i].m_channelID);
}
m_track = track;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::DeleteChannelEx(const std::string &channelName,
const std::string &game,
const std::string &server)
{
Reset();
VChatAPI::DeleteChannel(channelName, game, server, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnDeleteChannel(unsigned track,
unsigned result,
void *user)
{
printf ("OnDeleteChannel track = %d, result = %s\n", track, ResultString[result].c_str());
m_track = track;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::SetBanStatusEx(unsigned userID,
unsigned banStatus)
{
Reset();
VChatAPI::SetBanStatus(userID, banStatus, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnSetBanStatus(unsigned track,
unsigned result,
void *user)
{
printf ("OnSetBanStatus track = %d, result = %s\n", track, ResultString[result].c_str());
m_track = track;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::GetChannelInfoEx( const std::string &channelName,
const std::string &game,
const std::string &server)
{
Reset();
VChatAPI::GetChannelInfo(channelName, game, server, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnGetChannelInfo( unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
void *user)
{
printf ("OnGetChannelInfo track = %d, result = %s\n", track, ResultString[result].c_str());
printf ("\t ChannelName(%s)\n\t ChannelURI(%s)\n\t ChannelID(%d)\n",
channelName.c_str(),
channelURI.c_str(),
channelID);
m_track = track;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::GetChannelV2Ex(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent)
{
Reset();
VChatAPI::GetChannelV2(channelName, game, server, description, password, limit, persistent, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnGetChannelV2( unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
unsigned isNewChannel,
void *user)
{
printf ("OnGetChannelV2 track = %d, result = %s\n", track, ResultString[result].c_str());
printf ("\t ChannelName(%s)\n\t ChannelURI(%s)\n\t ChannelID(%d)\n\t NewChannel(%s)\n",
channelName.c_str(),
channelURI.c_str(),
channelID,
isNewChannel?"true":"false");
m_channelID = channelID;
m_channelURI = channelURI;
m_result = result;
m_isDone = true;
}
unsigned VChatClient::AddCharacterChannelEx(const unsigned stationID,
const unsigned avatarID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode,
const std::string &channelType,
const std::string &channelDescription,
const std::string &password,
const std::string &channelAddress,
const std::string &locale)
{
Reset();
VChatAPI::AddCharacterChannel(stationID, avatarID, characterName, worldName,
gameCode, channelType, channelDescription,
password, channelAddress, locale, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnAddCharacterChannel(unsigned track,
unsigned result,
void *user)
{
printf ("OnAddCharacterChannel track = %d, result = %s\n", track, ResultString[result].c_str());
m_result = result;
m_isDone = true;
}
unsigned VChatClient::RemoveCharacterChannelEx( const unsigned stationID,
const unsigned avatarID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode,
const std::string &channelType)
{
Reset();
VChatAPI::RemoveCharacterChannel(stationID, avatarID, characterName, worldName,
gameCode, channelType, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnRemoveCharacterChannel(unsigned track,
unsigned result,
void *user)
{
printf ("OnRemoveCharacterChannel track = %d, result = %s\n", track, ResultString[result].c_str());
m_result = result;
m_isDone = true;
}
unsigned VChatClient::GetCharacterChannelEx(const unsigned stationID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode)
{
Reset();
VChatAPI::GetCharacterChannel(stationID, characterName, worldName, gameCode, NULL);
while(!IsDone() && !HasFailed())
{
Process();
soe::Sleep(10);
}
return m_result;
}
void VChatClient::OnGetCharacterChannel(unsigned track,
unsigned result,
const CharacterChannelVec_t &characterChannels,
void * user)
{
printf ("OnGetCharacterChannel track = %d, result = %s numChannels=%d\n", track, ResultString[result].c_str(), characterChannels.size());
for (unsigned i = 0; i < characterChannels.size(); ++i)
{
PrintChannel(characterChannels[i]);
}
m_result = result;
m_isDone = true;
}
void VChatClient::PrintChannel(const CharacterChannel &characterChannel)
{
printf("Character Channel \n\t m_stationID(%d) \n\t m_avatarID(%d) \n\t m_characterName(%s) \n\t m_worldName(%s) \n", characterChannel.m_stationID, characterChannel.m_avatarID, characterChannel.m_characterName.c_str(), characterChannel.m_worldName.c_str());
printf("\t m_gameCode(%s) \n\t m_channelType(%s) \n\t m_channelDescription(%s) \n", characterChannel.m_gameCode.c_str(), characterChannel.m_channelType.c_str(), characterChannel.m_channelDescription.c_str());
printf("\t m_channelAddress(%s) \n\t m_locale(%s) \n\t m_password(%s)\n", characterChannel.m_channelAddress.c_str(), characterChannel.m_locale.c_str(), characterChannel.m_password.c_str());
}
@@ -0,0 +1,235 @@
#ifndef _VCHAT_CLIENT_H_
#define _VCHAT_CLIENT_H_
#include "VChatAPI/VChatAPI.h"
using namespace VChatSystem;
class VChatClient : public VChatAPI
{
public:
VChatClient(const char * hostList);
virtual ~VChatClient(void);
bool IsConnected() const { return m_isConnected; }
bool HasFailed() const { return m_failed; }
bool IsDone() const { return m_isDone; }
void Reset() { m_isDone = false; m_failed = false; }
inline virtual void OnConnectionOpened( const char * address )
{
m_isConnected = true;
printf("Connection opened to %s\n", address);
}
inline virtual void OnConnectionFailed( const char * address )
{
m_failed = true;
m_isConnected = false;
printf("Connection failed to %s\n", address);
}
inline virtual void OnConnectionClosed( const char * address, const char * reason )
{
m_isConnected = false;
printf("Connection closed to %s because %s\n", address, reason);
}
virtual void OnGetAccount(unsigned track,
unsigned result,
unsigned userID,
unsigned accountID,
const std::string &voicePassword,
const std::string &encodedVoiceAccount,
const std::string &URI,
void *user);
virtual void OnGetChannel(unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
void *user);
virtual void OnGetProximityChannel( unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
void *user );
virtual void OnChannelCommand(unsigned track,
unsigned result,
void *user);
virtual void OnDeactivateVoiceAccount(unsigned track,
unsigned result,
void *user);
virtual void OnChangePassword(unsigned track,
unsigned result,
void *user);
virtual void OnGetAllChannels(unsigned track,
unsigned result,
const ChannelVec_t & channels,
void *user);
virtual void OnDeleteChannel(unsigned track,
unsigned result,
void *user);
virtual void OnSetBanStatus(unsigned track,
unsigned result,
void *user);
virtual void OnGetChannelV2(unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
unsigned isNewChannel,
void *user);
/////////////////////////////////////////////////////////////////////////////
unsigned GetAccountEx(const std::string &avatarName,
const std::string &game,
const std::string &world,
unsigned userID,
unsigned avatarID);
unsigned DeactivateVoiceAccount(const std::string &avatarName,
const std::string &game,
const std::string &world);
unsigned GetChannelEx( const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent);
unsigned GetProximityChannelEx( const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent,
unsigned maxRange,
unsigned clamping,
float rollOff,
float maxGain,
unsigned distModel);
unsigned ChannelCommandEx(const std::string &srcUserName,
const std::string &destUserName,
const std::string &destChannelAddress,
unsigned command,
unsigned banTimeout);
unsigned ChangePasswordEx(const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &password);
unsigned GetAllChannelsEx();
unsigned DeleteChannelEx( const std::string &channelName,
const std::string &game,
const std::string &server);
unsigned SetBanStatusEx(unsigned userID,
unsigned banStatus);
virtual void OnSetUserData( unsigned track,
unsigned result,
void *user)
{
//XXX need to implement
}
unsigned GetChannelInfoEx(const std::string &channelName,
const std::string &game,
const std::string &server);
virtual void OnGetChannelInfo(unsigned track,
unsigned result,
const std::string &channelName,
const std::string &channelURI,
unsigned channelID,
void *user);
virtual unsigned GetChannelV2Ex( const std::string &channelName,
const std::string &game,
const std::string &server,
const std::string &description,
const std::string &password,
unsigned limit,
bool persistent);
unsigned AddCharacterChannelEx( const unsigned stationID,
const unsigned avatarID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode,
const std::string &channelType,
const std::string &channelDescription,
const std::string &password,
const std::string &channelAddress,
const std::string &locale );
virtual void OnAddCharacterChannel(unsigned track,
unsigned result,
void *user);
unsigned RemoveCharacterChannelEx( const unsigned stationID,
const unsigned avatarID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode,
const std::string &channelType);
virtual void OnRemoveCharacterChannel(unsigned track,
unsigned result,
void *user);
unsigned GetCharacterChannelEx(const unsigned stationID,
const std::string &characterName,
const std::string &worldName,
const std::string &gameCode);
virtual void OnGetCharacterChannel(unsigned track,
unsigned result,
const CharacterChannelVec_t &characterChannels,
void * user);
unsigned m_result;
unsigned m_userID;
unsigned m_avatarID;
unsigned m_channelID;
std::string m_channelURI;
unsigned m_track;
std::string m_previousUser;
private:
void PrintChannel(const CharacterChannel &characterChannel);
bool m_isDone;
bool m_failed;
bool m_isConnected;
};
#endif
@@ -0,0 +1,352 @@
#include <stdio.h>
#include <string>
//#include "Clock.h"
#include "Base/cmdLine.h"
#include "Base/timer.h"
#include "VChatClient.h"
#include <time.h>
#include "Base/stringutils.h"
//----------------------------------------------------------------------
//-- this is a SWG hack to work with our modified STLPORT
#ifdef WIN32
enum MemoryManagerNotALeak
{
MM_notALeak
};
void * __cdecl operator new(size_t size, MemoryManagerNotALeak)
{
return operator new(size);
}
#endif
#define HELP_SWITCH "-?"
#define HOST_SWITCH "-h"
#define PORT_SWITCH "-p"
#define USER_SWITCH "-u"
#define TIMEOUT_SWITCH "-t"
#define INTERACTIVE_SWITCH "-i"
#define TEST_INIT_SWITCH "-test"
void printUsage(const char *executableName)
{
printf("Usage : %s [" HELP_SWITCH "] "
HOST_SWITCH " hostlist "
"[" TIMEOUT_SWITCH " timeout_in_seconds] "
"[" INTERACTIVE_SWITCH " waits_for_user_to_exit ] "
"[" TEST_INIT_SWITCH " runs_Init_test ]"
"[" USER_SWITCH " used_with -test valid_user_id ]\n",
executableName);
}
int main(int argc, char **argv){
CmdLine cmdLine;
cmdLine.SplitLine(argc, argv);
std::string hostList = cmdLine.GetSafeArgument(HOST_SWITCH, 0, "localhost:9100");
bool showUsage = cmdLine.HasSwitch(HELP_SWITCH) || !cmdLine.HasSwitch(HOST_SWITCH);
unsigned timeout_in_seconds = atoi(cmdLine.GetSafeArgument(TIMEOUT_SWITCH, 0, "10").c_str());
if (showUsage) {
printUsage(argv[0]);
return 0;
}
srand((unsigned)time(0));
int x = rand();
int y = rand();
y *= x;
unsigned count = 0;
char c;
do
{
VChatClient api(hostList.c_str());
printf("Connecting to %s...\n", hostList.c_str());
while(!api.IsConnected() && !api.HasFailed())
{
api.Process();
soe::Sleep(10);
}
y++;
unsigned result = 0;
char numBuff[32];
sprintf(numBuff, "RandomName%d", y);
std::string name = numBuff;
std::string game = "EQ2";
std::string server = "Butcherblock";
std::string lowerName = soe::tolowercase(name);
std::string lowerServer = soe::tolowercase(server);
std::string lowerGame = soe::tolowercase(game);
printf("Login Request: %s\n", name.c_str());
// first one adds
printf("GetAccountEx -- user: %s\n", name.c_str());
result = api.GetAccountEx(name, game, server, 1111, 9999);
if (!api.m_previousUser.empty())
{
std::string tmpName, tmpServer;
GetUserNameComponents(api.m_previousUser, tmpServer, tmpName);
printf("GetAccountEx -- user: %s\n", tmpName.c_str());
// second one gets.
result = api.GetAccountEx(tmpName, game, tmpServer, 1111, 9999);
}
printf("GetAccountEx -- user: %s\n", name.c_str());
// second one gets.
result = api.GetAccountEx(name, game, server, 1111, 9999);
//
// printf("GetAccountEx -- user: %s\n", lowerName.c_str());
//
// // gets with all lower
// result = api.GetAccountEx(lowerName, lowerGame, lowerServer, 1111, 9999);
//
// printf("GetAccountEx -- user: %s\n", lowerName.c_str());
//
//
// // gets with lowerName
// result = api.GetAccountEx(lowerName, game, server, 1111, 9999);
//
//
// printf("GetAccountEx -- user: %s\n", name.c_str());
//
// // gets with lowerGamer.
// result = api.GetAccountEx(name, lowerGame, server, 1111, 9999);
//
// sprintf(numBuff, "Random Name%d", y);
//
//
//
// // creates account with space.
// result = api.GetAccountEx(numBuff, game, lowerServer, 1111, 9999);
//
//
// // gets account with space.
// result = api.GetAccountEx(numBuff, game, lowerServer, 1111, 9999);
//
//
// sprintf(numBuff, "Random's Name%d", y);
//
// // creates account with space and apostrophe.
// result = api.GetAccountEx(numBuff, game, lowerServer, 1111, 9999);
std::string guild = "guild.";
guild += name;
// result = api.GetChannelInfoEx(guild, game, server);
//
//
//
// result = api.GetChannelEx(guild, game, server, "Description space", "", 3000, 0);
//
//
//
// result = api.GetChannelEx(guild, game, server, "Description space", "", 3000, 0);
std::string guild2 = "guild2.";
guild2 += name;
result = api.GetChannelV2Ex(guild2, game, server, "Description space", "firewall", 100, 0);
//
// result = api.GetChannelV2Ex(guild2, game, server, "Description space", "firewall", 100, 0);
//
//
// result = api.ChangePasswordEx(guild, game, server, "sony1234");
//
//
//
// result = api.GetChannelInfoEx(guild, game, server);
//
//
// std::string space = "Ga illed.";
// space += name;
// result = api.GetChannelEx(space, game, server, "Description's apostrophe", "", 100, 0);
//
//
//
// result = api.GetChannelEx(space, game, server, "Description's apostrophe", "", 100, 0);
//
//
//
// result = api.DeleteChannelEx(space, game, server);
//
// if (count < 100)
// {
//
//
// std::string proximity = "prox-";
// proximity += name;
//
// result = api.GetProximityChannelEx(proximity, game, server, "Description", "", 100, 0, 80, 10, 2.5, 1.5, 1);
//
//
//
// result = api.GetProximityChannelEx(proximity, game, server, "Description", "", 100, 0, 80, 10, 2.5, 1.5, 1);
//
//
//
// result = api.DeleteChannelEx(proximity, game, server);
//
// }
//
// char userBuff[512];
// sprintf (userBuff, "%s.%s", server.c_str(), name.c_str());
//
//
// char channelBuff[512];
// sprintf(channelBuff, "%s.%s.guild.%s", game.c_str(), server.c_str(), name.c_str());
//
//
//
// printf("ChannelCommand user(%s) channel(%s)\n", userBuff, channelBuff);
//
// printf("COMMAND_ADD_MODERATOR ");
// result = api.ChannelCommandEx(userBuff, userBuff, channelBuff, COMMAND_ADD_MODERATOR, 0);
//
//
//
// printf("COMMAND_DELETE_MODERATOR ");
// result = api.ChannelCommandEx(userBuff, userBuff, channelBuff, COMMAND_DELETE_MODERATOR, 0);
//
//
//
// printf("COMMAND_ADD_ACL ");
// result = api.ChannelCommandEx(userBuff, userBuff, channelBuff, COMMAND_ADD_ACL, 0);
//
//
//
//
// printf("COMMAND_DELETE_ACL ");
// result = api.ChannelCommandEx(userBuff, userBuff, channelBuff, COMMAND_DELETE_ACL, 0);
//
//
//
// result = api.DeleteChannelEx(guild, game, server);
//
//
// printf ("\nExpect it return a new channel.\n;");
// result = api.GetChannelV2Ex(guild, game, server, "Description space", "", 100, 0);
//
// // delete again
// result = api.DeleteChannelEx(guild, game, server);
//
//
// //result = api.DeactivateVoiceAccount(name, game, server);
//
//
// sprintf(numBuff, "Deleter.%d", y);
//
// result = api.GetChannelEx(numBuff, game, server, "My Description", "firewall", 400, 1);
//
//
//
// result = api.GetAllChannelsEx();
//
//
//
// printf("Deleting Channel %s\n", numBuff);
//
// result = api.DeleteChannelEx(numBuff, game, server);
//
//
//
// result = api.GetAllChannelsEx();
//
//
// printf("Login user: %s\n", name.c_str());
//
// // first one adds
// result = api.GetAccountEx(name, game, server, 1111, 0);
//
//
//
// result = api.SetBanStatusEx(1111, BAN);
//
//
printf("Login after ban -- user: %s\n", name.c_str());
// first one adds
result = api.GetAccountEx(name, game, server, 1111, 9999);
result = api.SetBanStatusEx(1111, UNBAN);
printf("Login after UNban -- user: %s\n", name.c_str());
// first one adds
result = api.GetAccountEx(name, game, server, 1111, 9999);
result = api.AddCharacterChannelEx(1111, 9999, name, server, game, "Guild",
"Guilds for Geldings", "sony1234", "addr", "en_US");
result = api.GetCharacterChannelEx(1111, name, server, game);
// result = api.UpdateCharacterChannelEx(1111, 9999, name, server, game, "Guild",
// "Guilds for Geldings", api.m_channelID, "secret", api.m_channelURI, "en_US");
//
result = api.AddCharacterChannelEx(1111, 9999, name, server, game, "Guild",
"Guilds for Geldings", "secret", "addr", "en_US");
result = api.GetCharacterChannelEx(1111, name, server, game);
// result = api.UpdateCharacterChannelEx(1111, 9999, name, server, game, "PartyCentral",
// "Wills for Weldings", api.m_channelID, "secret", api.m_channelURI, "en_US");
//
result = api.AddCharacterChannelEx(1111, 9999, name, server, game, "PartyCentral",
"Wills for Weldings", "secret", "addr", "en_US");
result = api.GetCharacterChannelEx(1111, name, server, game);
result = api.RemoveCharacterChannelEx(1111, 9999, name, server, game, "Guild");
result = api.GetCharacterChannelEx(1111, name, server, game);
//////////////////////////////////////////////////////////////////////////////////////////////
printf("Press Enter to go again, x to exit:");
c = getchar();
y++;
count++;
} while (c != 'x');
if (cmdLine.HasSwitch(INTERACTIVE_SWITCH))
{
printf("Press Enter to exit:");
getchar();
}
return 0;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,266 @@
//#ifndef BASE__API_H
//#define BASE__API_H
#include <vector>
#include <list>
#include <set>
#include <map>
#include "Base/profile.h"
#include "Base/stringutils.h"
#ifdef UDP_LIBRARY
#include "UdpLibrary/UdpLibrary.hpp"
#else
#include "TcpLibrary/TcpConnection.h"
#include "TcpLibrary/TcpManager.h"
#endif
#include "apiMessages.h"
#ifndef API_NAMESPACE
#pragma message ("api.h: API_NAMESPACE undefined")
//#else
//#pragma message ("api.h: API_NAMESPACE:")
//#pragma message API_NAMESPACE
#endif
#ifdef API_NAMESPACE
namespace API_NAMESPACE
{
#endif
////////////////////////////////////////////////////////////////////////////////
struct TrackedRequest
{
TrackedRequest();
TrackedRequest(unsigned messageId, unsigned trackingNumber, unsigned result, const void * userData, unsigned timeout = 5);
unsigned mMsgId;
unsigned mTrackingNumber;
unsigned mResult;
void * mUserData;
unsigned mTimeout;
};
////////////////////////////////////////////////////////////////////////////////
#ifdef UDP_LIBRARY
class CommonAPI : UdpConnectionHandler
#else
class CommonAPI : TcpConnectionHandler
#endif
{
#ifdef UDP_LIBRARY
typedef UdpConnection ApiConnection;
#else
typedef TcpConnection ApiConnection;
#endif
typedef std::set<unsigned> TrackingSet_t;
struct ApiConnectionInfo
{
ApiConnectionInfo(ApiConnection * Connection = NULL) : mConnection(Connection), mIsShuttingDown(false) { }
ApiConnection * mConnection;
TrackingSet_t mOutstandingRequests;
bool mIsShuttingDown;
};
typedef std::map<ApiConnection *, std::string> HostMap_t;
typedef std::set<ApiConnection *> ConnectionSet_t;
typedef std::map<ApiConnection *, ApiConnectionInfo> ConnectionMap_t;
typedef std::map<unsigned, TrackedRequest> RequestMap_t;
typedef std::list<std::pair<unsigned,unsigned> > TimeoutList_t;
typedef std::map<unsigned, ApiConnection *> ConnectionTrackMap_t;
typedef std::map<unsigned, TimeoutList_t> TimeoutMap_t;
typedef std::list<unsigned> TrackingList_t;
typedef std::set<unsigned> MessagIdSet_t;
public:
CommonAPI(const char * hostList, const char * failoverHostList = 0, unsigned connectionLimit = 0, unsigned maxMsgSize = 1*1024, unsigned bufferSize = 64*1024);
virtual ~CommonAPI();
void Process();
void DisconnectAll();
void AllowConnections();
unsigned GetConnectionCount() const;
unsigned GetOutstandingRequestCount() const;
unsigned GetLastRequestInputTime() const;
unsigned GetTrackingNumber();
bool Send(const unsigned char *data, unsigned dataLen);
void PrepareCallback(unsigned messageId, unsigned trackingNumber, unsigned result, const void * userData, unsigned timeout = 0);
bool SendAndPrepareCallback(const unsigned char *data, unsigned dataLen, unsigned messageId, unsigned trackingNumber, unsigned result, const void * userData, unsigned timeout);
bool GetCallbackUserData(unsigned trackingNumber, const void **pUserData);
protected:
#ifdef UDP_LIBRARY
virtual UdpManager::Params GetConnectionParams();
virtual void OnConnectComplete(UdpConnection *con);
virtual void OnTerminated(UdpConnection *con);
virtual void OnRoutePacket(UdpConnection *con, const uchar *data, int dataLen);
void SendStatusMsg(UdpConnection *);
#else
virtual TcpManager::TcpParams GetConnectionParams();
virtual void OnConnectRequest(TcpConnection *con);
virtual void OnTerminated(TcpConnection *con);
virtual void OnRoutePacket(TcpConnection *con, const unsigned char *data, int dataLen);
void SendStatusMsg(TcpConnection *);
#endif
virtual unsigned CheckMessageId(const unsigned char * data, unsigned dataLen) = 0;
virtual unsigned CheckTrackingNumber(const unsigned char * data, unsigned dataLen) = 0;
virtual bool CheckConnectReply(const unsigned char * data, unsigned dataLen) { return true; }
bool IsTracked(unsigned msgId);
void RegisterTrackedMessage(unsigned msgId);
// FormatStatusMsg provides a buffer/size for the derived class to write to and returns the size of the message written
// This function is called after connecting and periodically once connected.
virtual unsigned FormatStatusMsg(unsigned char * buffer, unsigned bufferLen) = 0;
virtual void OnConnectionOpened(const char * address) = 0;
virtual void OnConnectionFailed(const char * address) = 0;
virtual void OnConnectionClosed(const char * address, const char * reason) = 0;
virtual void OnConnectionShutdownNotified(const char * address, unsigned outstandingRequests) { }
virtual void Callback(const unsigned char * data, unsigned dataLen, unsigned messageId, void * userData) = 0;
virtual void Callback(unsigned messageId, unsigned trackingNumber, unsigned result, void * userData) = 0;
private:
ApiConnectionInfo * GetNextUsableConnection();
ApiConnectionInfo * FindConnectionInfo(ApiConnection * connection);
void StopTrackingRequest(unsigned trackingNumber);
void SendShutdownNotification(ApiConnectionInfo *pInfo);
#ifdef UDP_LIBRARY
UdpManager * mManager;
#else
TcpManager * mManager;
#endif
std::map<std::string, time_t> mHostReconnectTimeout;
std::list<std::string> mIdleHosts[2];
HostMap_t mHostMap[2];
ConnectionMap_t mActiveHosts[2];
ConnectionSet_t mUsableHosts[2];
ConnectionSet_t::iterator mSendIterator[2];
ConnectionTrackMap_t mRequestConnections;
TrackingList_t mCallbackQueue;
RequestMap_t mRequestMap;
TimeoutMap_t mTimeoutMap;
unsigned mTrackingIndex;
MessagIdSet_t mTrackedMessages;
unsigned mTimeoutTimer;
unsigned mStatusTimer;
unsigned mLastRequestInputTime;
unsigned mConnectionLimit;
unsigned mMaxMsgSize;
unsigned mBufferSize;
bool mInCallback;
bool mRetriedConnection;
bool mShouldTryToConnect;
};
////////////////////////////////////////////////////////////////////////////////
class DECLSPEC VersionMap
{
public:
class InsertionObject
{
public:
InsertionObject(const std::string &versionString, unsigned enumeratedValue);
~InsertionObject() { }
};
static const std::string &getEarliestVersionString();
static unsigned getEarliestVersionEnumeration();
static const std::string &getLatestVersionString();
static unsigned getLatestVersionEnumeration();
static const std::string &getVersionString(unsigned enumeratedValue);
static unsigned getEnumeratedValue(const std::string &versionString);
static void addVersionPair(const std::string &versionString, unsigned enumeratedValue);
private:
VersionMap() { }
~VersionMap() { }
static void initializeMaps();
static std::map<std::string, unsigned> *mspVersionStringToEnumerationMap;
static std::map<unsigned, std::string> *mspEnumerationToVersionStringMap;
};
inline bool IsAtLeastVersion(unsigned version, unsigned test)
{
return ((version != 0) && (version >= test));
}
inline bool IsBeforeVersion(unsigned version, unsigned test)
{
return ((version != 0) && (version < test));
}
#define ADD_VERSION_SUPPORT(__name__, __number__) VersionMap::InsertionObject supportsVersion ## __number__(__name__, __number__)
class DECLSPEC ConfigurationMap
{
public:
class InsertionObject
{
public:
InsertionObject(const std::string &label, std::string &valueHolder);
InsertionObject(const std::string &label, soe::uint32 &valueHolder);
InsertionObject(const std::string &label, soe::int32 &valueHolder);
InsertionObject(const std::string &label, soe::uint16 &valueHolder);
InsertionObject(const std::string &label, soe::int16 &valueHolder);
InsertionObject(const std::string &label, double &valueHolder);
InsertionObject(const std::string &label, float &valueHolder);
~InsertionObject() { }
};
enum EValueType
{
eValueTypeUnknown,
eValueTypeString,
eValueTypeUInt32,
eValueTypeInt32,
eValueTypeUInt16,
eValueTypeInt16,
eValueTypeDouble,
eValueTypeFloat
};
struct ConfigurationEntry
{
ConfigurationEntry() : valueType(eValueTypeUnknown) {}
ConfigurationEntry(const std::string &labelIn, void * valueHolderIn, EValueType valueTypeIn);
std::string label;
void * valueHolder;
EValueType valueType;
};
static void addConfigurationEntry(const ConfigurationEntry &entry);
static void getConfigurationEntries(soe::NameValuePairs_t &labelsAndValues);
static void setConfigurationEntries(const soe::NameValuePairs_t &labelsAndValues);
private:
ConfigurationMap() { }
~ConfigurationMap() { }
static void initializeMap();
typedef std::map<soe::upperCaseString, ConfigurationEntry> LabelToEntryMap_t;
static LabelToEntryMap_t *mspLabelToEntryMap;
};
#define ADD_CONFIG_VAR(Type, Name, Default) \
DECLSPEC Type Name = Default; \
ConfigurationMap::InsertionObject configVariable ## Name(#Name, Name);
/************************************************************************/
/* Call this function after changing any configurable variables */
/* that affect class serialization */
/************************************************************************/
void ForceReinitializationOfAllClassScribes();
#ifdef API_NAMESPACE
}
#endif
//#endif
@@ -0,0 +1,145 @@
#ifndef COMMON_API__MESSAGE_MACROS_H
#define COMMON_API__MESSAGE_MACROS_H
#define DefineMessageBegin(ClassName,BaseClass,MessageID) \
class DECLSPEC ClassName : public BaseClass \
{ \
enum { MESSAGE_ID = MessageID }; \
private: \
class Entry \
{ \
public: \
Entry(); \
virtual ~Entry(); \
}; \
\
static Entry ms_classEntry; \
void InitializeMembers(); \
public: \
ClassName(); \
ClassName(const unsigned messageId); \
ClassName(const ClassName & source); \
virtual Basic * Clone() const; \
virtual Basic * Clone(StorageVector_t &storageVector) const; \
virtual const char * MessageName() const { return #ClassName; } \
virtual const char * MessageIDString() const { return #MessageID; }
#if defined(PRINTABLE_MESSAGES) || defined(TRACK_READ_WRITE_FAILURES)
# define DefineMessageMember(MemberName,Type) \
public: \
class Print##MemberName : public soe::AutoVariable<Type > \
{ \
public: \
virtual const char * VariableName() const { return #MemberName; } \
}; \
public: \
Print##MemberName m##MemberName; \
public: \
const Type & Get##MemberName() const \
{ return m##MemberName.Get(); } \
Type & Get##MemberName() \
{ return m##MemberName.Get(); } \
void Set##MemberName(const Type & value) \
{ m##MemberName.Set((const Type &)value); }
#else
# define DefineMessageMember(MemberName,Type) \
public: \
soe::AutoVariable<Type > m##MemberName; \
public: \
const Type & Get##MemberName() const \
{ return m##MemberName.Get(); } \
Type & Get##MemberName() \
{ return m##MemberName.Get(); } \
void Set##MemberName(const Type & value) \
{ m##MemberName.Set((const Type &)value); }
#endif
#define DefineMessageEnd \
};
#define ImplementMessageBegin(ClassName,BaseClass) \
ClassName::ClassName() : BaseClass(MESSAGE_ID) \
{ \
InitializeMembers(); \
} \
ClassName::ClassName(const unsigned messageId) : BaseClass(messageId) \
{ \
InitializeMembers(); \
} \
ClassName::ClassName(const ClassName & source) \
{ \
InitializeMembers(); \
\
MemberVector_t::iterator iterator; \
MemberVector_t::const_iterator sourceIterator = source.mMembers.begin(); \
for(iterator=mMembers.begin(); iterator!=mMembers.end(); iterator++, sourceIterator++) \
{ \
iterator->data->Copy(sourceIterator->data); \
iterator->size = sourceIterator->size; \
} \
} \
Basic * ClassName::Clone() const \
{ \
ClassName * msg = new ClassName(*this); \
/*msg->InitializeMembers(); */ \
return msg; \
} \
Basic * ClassName::Clone(StorageVector_t & storageVector) const \
{ \
ClassName * msg = new(storageVector) ClassName(*this); \
/*msg->InitializeMembers(); */ \
return msg; \
} \
ClassName::Entry::Entry() \
{ \
ClassName msg; \
\
AddClassMapEntry(msg.GetMsgId(), &msg); \
} \
ClassName::Entry::~Entry() \
{ \
} \
ClassName::Entry ClassName::ms_classEntry; \
void ClassName::InitializeMembers() \
{
#define ImplementMessageMember(MemberName,DefaultValue) \
m##MemberName.Set(DefaultValue); \
Insert(m##MemberName);
#define ImplementMessageMemberEx(MemberName,DefaultValue,MaxLen) \
m##MemberName.Set(DefaultValue); \
Insert(m##MemberName, MaxLen);
#define ImplementVersionAddedMessageMember(MemberName,DefaultValue,Version) \
m##MemberName.Set(DefaultValue); \
Insert(m##MemberName, 1, Version, eAdded);
#define ImplementVersionDroppedMessageMember(MemberName,DefaultValue,Version) \
m##MemberName.Set(DefaultValue); \
Insert(m##MemberName, 1, Version, eDropped);
#define ImplementVersionAddedMessageMemberEx(MemberName,DefaultValue,MaxLen,Version) \
m##MemberName.Set(DefaultValue); \
Insert(m##MemberName, MaxLen, Version, eAdded);
#define ImplementVersionDroppedMessageMemberEx(MemberName,DefaultValue,MaxLen,Version) \
m##MemberName.Set(DefaultValue); \
Insert(m##MemberName, MaxLen, Version, eDropped);
#define ImplementMessageMemberOptional(MemberName,DefaultValue) \
m##MemberName.Set(DefaultValue); \
InsertOptional(m##MemberName);
#define ImplementMessageMemberOptionalEx(MemberName,DefaultValue,MaxLen) \
m##MemberName.Set(DefaultValue); \
InsertOptional(m##MemberName, MaxLen);
#define ImplementMessageEnd \
}
#endif
@@ -0,0 +1,553 @@
#pragma warning (disable: 4514 4786)
#include "apiMessages.h"
namespace API_NAMESPACE
{
namespace Message
{
////////////////////////////////////////////////////////////////////////////////
const std::map<unsigned, Base::DeepPointer> & Base::GetMessageMap() { return *ms_pClassMap; }
// returns the number of bytes Read, or zero if an error occured
unsigned Base::Read(const unsigned char * stream, unsigned size, unsigned version)
{
unsigned bytesTotal = 0;
bool succeeded = true;
MemberVector_t::iterator iterator;
#ifdef TRACK_READ_WRITE_FAILURES
soe::ClearMessageFailureStack();
#endif
for(iterator=mMembers.begin(); iterator!=mMembers.end(); iterator++)
{
MemberInfo_t & memberInfo = *iterator;
if (IsMemberIncluded(version, memberInfo.version, memberInfo.effect))
{
unsigned bytes = memberInfo.data->Read(stream, size, memberInfo.size, version);
if (bytes == 0)
{
#ifdef TRACK_READ_WRITE_FAILURES
soe::PushMessageFailure(soe::PrintToString("%s, %s:%u - failed to read %s.%s, size = %u, version = %u", __FUNCTION__, __FILE__, __LINE__, MessageName(), memberInfo.data->VariableName(), size, version));
#endif
bytesTotal = 0;
succeeded = false;
break;
}
else
{
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
}
}
if (succeeded)
{
for(iterator=mOptionalMembers.begin(); iterator!=mOptionalMembers.end(); iterator++)
{
MemberInfo_t & memberInfo = *iterator;
unsigned bytes = memberInfo.data->Read(stream, size, memberInfo.size, version);
if (bytes == 0)
{
// break, but don't fail the reading process
break;
}
else
{
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
}
}
return bytesTotal;
}
// returns the number of bytes written, or zero if an error occured
unsigned Base::Write(unsigned char * stream, unsigned size, unsigned version) const
{
unsigned bytesTotal = 0;
bool succeeded = true;
MemberVector_t::const_iterator iterator;
#ifdef TRACK_READ_WRITE_FAILURES
soe::ClearMessageFailureStack();
#endif
for (iterator=mMembers.begin(); iterator!=mMembers.end(); iterator++)
{
const MemberInfo_t & memberInfo = *iterator;
if (IsMemberIncluded(version, memberInfo.version, memberInfo.effect))
{
unsigned bytes = memberInfo.data->Write(stream, size, version);
if (bytes == 0)
{
#ifdef TRACK_READ_WRITE_FAILURES
soe::PushMessageFailure(soe::PrintToString("%s, %s:%u - failed to write %s.%s, size = %u, version = %u", __FUNCTION__, __FILE__, __LINE__, MessageName(), memberInfo.data->VariableName(), size, version));
#endif
bytesTotal = 0;
succeeded = false;
break;
}
else
{
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
}
}
if (succeeded)
{
for (iterator=mOptionalMembers.begin(); iterator!=mOptionalMembers.end(); iterator++)
{
const MemberInfo_t & memberInfo = *iterator;
unsigned bytes = memberInfo.data->Write(stream, size, version);
if (bytes == 0)
{
// break, but don't fail the writing process
break;
}
else
{
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
}
}
return bytesTotal;
}
#ifdef PRINTABLE_MESSAGES
int Base::Print(char * stream, unsigned size, unsigned maxDepth) const
{
int bytesTotal = 0;
int bytes = 0;
if (maxDepth == 0) {
bytes = snprintf(stream, size, "%s{mMembers(%u), mOptionalMembers(%u)}", MessageName(), mMembers.size(), mOptionalMembers.size());
return bytes;
}
bytes = snprintf(stream, size, "{");
if (soe::FailedToPrint(bytes, size)) {
bytesTotal = bytes;
return bytesTotal;
} else {
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
bool printedOne = false;
MemberVector_t::const_iterator iterator;
for (iterator=mMembers.begin(); iterator!=mMembers.end(); iterator++)
{
int bytes = 0;
if (printedOne) {
bytes = snprintf(stream, size, ", ");
if (soe::FailedToPrint(bytes, size)) {
bytesTotal = bytes;
return bytesTotal;
} else {
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
} else {
printedOne = true;
}
const MemberInfo_t & memberInfo = *iterator;
bytes = memberInfo.data->Print(stream, size, maxDepth-1);
if (soe::FailedToPrint(bytes, size))
{
bytesTotal = bytes;
return bytesTotal;
}
else
{
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
}
for (iterator=mOptionalMembers.begin(); iterator!=mOptionalMembers.end(); iterator++)
{
int bytes = 0;
if (printedOne) {
bytes = snprintf(stream, size, ", ");
if (soe::FailedToPrint(bytes, size)) {
bytesTotal = bytes;
return bytesTotal;
} else {
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
} else {
printedOne = true;
}
const MemberInfo_t & memberInfo = *iterator;
bytes = memberInfo.data->Print(stream, size, maxDepth-1);
if (soe::FailedToPrint(bytes, size))
{
bytesTotal = bytes;
return bytesTotal;
}
else
{
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
}
if (!soe::FailedToPrint(bytes, size)) {
bytes = snprintf(stream, size, "}");
if (soe::FailedToPrint(bytes, size)) {
bytesTotal = bytes;
} else {
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
}
return bytesTotal;
}
#endif
void * Base::operator new(size_t size)
{
return ::operator new(size);
}
void * Base::operator new(size_t size, void *ptr)
{
return ::operator new(size, ptr);
}
Base * Base::Clone() const
{
return new Base(*this);
}
Base * Base::Clone(StorageVector_t &storageVector) const
{
return new(storageVector) Base(*this);
}
Base * Base::Create(unsigned MsgId, StorageVector_t *pStorageVector)
{
Base * msg = NULL;
if (ms_pClassMap) {
std::map<unsigned, Base::DeepPointer>::iterator classIter = ms_pClassMap->find(MsgId);
if (classIter != ms_pClassMap->end()) {
if (pStorageVector) {
msg = classIter->second->Clone(*pStorageVector);
} else {
msg = classIter->second->Clone();
}
}
}
return msg;
}
const char * Base::GetMessageName(unsigned msgId)
{
const char * requestString = NULL;
if (ms_pClassMap) {
std::map<unsigned, Base::DeepPointer>::iterator classIter = ms_pClassMap->find(msgId);
if (classIter != ms_pClassMap->end()) {
requestString = classIter->second->MessageName();
}
}
return requestString;
}
const char * Base::GetMessageIDString(unsigned msgId)
{
const char * idString = NULL;
if (ms_pClassMap) {
std::map<unsigned, Base::DeepPointer>::iterator classIter = ms_pClassMap->find(msgId);
if (classIter != ms_pClassMap->end()) {
idString = classIter->second->MessageIDString();
}
}
return idString;
}
void Base::AddClassMapEntry(unsigned msgId, const Base * msg)
{
static std::map<unsigned, Base::DeepPointer> classMap;
if (ms_pClassMap == NULL) {
ms_pClassMap = &classMap;
}
std::map<unsigned, Base::DeepPointer>::iterator classIter = ms_pClassMap->find(msgId);
if (classIter == ms_pClassMap->end()) {
(*ms_pClassMap)[msgId] = msg;
}
}
void * Base::operator new(size_t storageSize, StorageVector_t &storageVector)
{
storageSize = (storageSize / sizeof(Storage_t)) + 1;
if (storageVector.size() < storageSize) {
storageVector.resize(storageSize);
}
return &storageVector[0];
}
Base::DeepPointer::DeepPointer() :
m_ptr(NULL)
{
}
Base::DeepPointer::DeepPointer(const Base & source) :
m_ptr(NULL)
{
m_ptr = source.Clone(m_storageVector);
}
Base::DeepPointer::DeepPointer(const Base * source) :
m_ptr(NULL)
{
m_ptr = source->Clone(m_storageVector);
}
Base::DeepPointer::DeepPointer(const DeepPointer & source) :
m_ptr(NULL)
{
if (source.m_ptr) { m_ptr = source->Clone(m_storageVector); }
}
Base::DeepPointer::~DeepPointer()
{
if (m_ptr) { m_ptr->~Base(); }
}
void Base::DeepPointer::SetMessageType(unsigned MsgId)
{
if (m_ptr) { m_ptr->~Base(); }
m_ptr = Create(MsgId, &m_storageVector);
}
Base::DeepPointer & Base::DeepPointer::operator=(const Base * rhs)
{
Base *oldPtr = m_ptr;
m_ptr = rhs ? rhs->Clone(m_storageVector) : NULL;
if (oldPtr) {
oldPtr->~Base();
}
return *this;
}
Base::DeepPointer & Base::DeepPointer::operator=(const DeepPointer & rhs)
{
Base *oldPtr = m_ptr;
m_ptr = rhs.m_ptr ? rhs->Clone(m_storageVector) : NULL;
if (oldPtr) {
oldPtr->~Base();
}
return *this;
}
Base * Base::DeepPointer::operator->() const
{
return m_ptr;
}
Base & Base::DeepPointer::operator*() const
{
return *m_ptr;
}
std::map<unsigned, Base::DeepPointer> *Base::ms_pClassMap = NULL;
#if defined(PRINTABLE_MESSAGES) || defined(TRACK_READ_WRITE_FAILURES)
Basic::Basic()
{
mMsgId.Set(0);
Insert(mMsgId);
mConnectId.Set(0);
Insert(mConnectId);
}
Basic::Basic(const unsigned messageId, const unsigned connectId)
{
mMsgId.Set(messageId);
Insert(mMsgId);
mConnectId.Set(connectId);
Insert(mConnectId);
}
#else
Basic::Basic() :
mMsgId(0),
mConnectId(0)
{
Insert(mMsgId);
Insert(mConnectId);
}
Basic::Basic(const unsigned messageId, const unsigned connectId) :
mMsgId(messageId),
mConnectId(connectId)
{
Insert(mMsgId);
Insert(mConnectId);
}
#endif
Basic::~Basic()
{
}
Basic::Basic(const Basic & source) :
mMsgId(source.mMsgId),
mConnectId(source.mConnectId)
{
// do not copy member pointers - would lead to dangling pointers
Insert(mMsgId);
Insert(mConnectId);
}
Basic & Basic::operator=(const Basic & rhs)
{
// do not copy member pointers - would lead to dangling pointers
mMsgId = rhs.mMsgId;
mConnectId = rhs.mConnectId;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
// NameValuePair
ImplementMessageBegin(NameValuePair, Basic)
ImplementMessageMemberEx(Name, std::string(), 256)
ImplementMessageMemberEx(Value, std::string(), 512)
ImplementMessageEnd
////////////////////////////////////////
// Connect
ImplementMessageBegin(Connect, Basic)
ImplementMessageMemberEx(Version, std::string(), 30)
ImplementMessageMemberEx(Description, std::string(), 64)
ImplementMessageEnd
////////////////////////////////////////
// ConnectReply
ImplementMessageBegin(ConnectReply, Basic)
ImplementMessageMember(Result, 0)
ImplementMessageMemberEx(Version, std::string(), 30)
ImplementMessageEnd
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
// Tracked
ImplementMessageBegin(Tracked, Basic)
ImplementMessageMember(TrackingNumber, 0)
ImplementMessageEnd
////////////////////////////////////////
// TrackedReply
ImplementMessageBegin(TrackedReply, Tracked)
ImplementMessageMember(Result, 0)
ImplementMessageEnd
////////////////////////////////////////
// TrackedReplyEx
ImplementMessageBegin(TrackedReplyEx, TrackedReply)
ImplementMessageMember(Status, 0)
ImplementMessageEnd
////////////////////////////////////////
// TrackedInterimReply
ImplementMessageBegin(TrackedInterimReply, TrackedReply)
ImplementMessageMember(ParentTrackingNumber, 0)
ImplementMessageEnd
////////////////////////////////////////
// GetStatus
ImplementMessageBegin(GetStatus, Tracked)
ImplementMessageEnd
////////////////////////////////////////
// GetStatusReply
ImplementMessageBegin(GetStatusReply, TrackedReply)
ImplementMessageMemberEx(NameValuePairs, std::vector<NameValuePair>(), 100000)
ImplementMessageEnd
////////////////////////////////////////
// ShutdownNotify
ImplementMessageBegin(ShutdownNotify, Basic)
ImplementMessageMember(UnfinishedRequests, 0)
ImplementMessageEnd
ImplementMessageBegin(ShutdownNotifyReply, Basic)
ImplementMessageMember(UnfinishedRequests, 0)
ImplementMessageEnd
////////////////////////////////////////////////////////////////////////////////
}
void Read(soe::NameValuePair &dest, const Message::NameValuePair &src)
{
dest.name = src.GetName();
dest.value = src.GetValue();
}
void Write(const soe::NameValuePair &src, Message::NameValuePair &dest)
{
dest.SetName(src.name);
dest.SetValue(src.value);
}
}
@@ -0,0 +1,454 @@
// Must protect from multiple definition from outside this header
//#ifndef _API_MESSAGES_H
//#define _API_MESSAGES_H
#ifndef API_NAMESPACE
#pragma message ("apiMessages.h: API_NAMESPACE undefined")
//#else
//#pragma message ("apiMessages.h: API_NAMESPACE:")
//#pragma message API_NAMESPACE
#endif
#include <map>
#include <vector>
#include "Base/serializeClasses.h"
#include "apiMacros.h"
#include "apiTypeNameValuePair.h"
// Storage *will* be freed if an exception is thrown in the constructor,
// so disable that warning here.
#pragma warning(disable:4291)
////////////////////////////////////////////////////////////////////////////////
#ifdef API_NAMESPACE
namespace API_NAMESPACE
{
#endif
enum
{
MESSAGE_NULL = 0x0000,
MESSAGE_NAME_VALUE_PAIR = 0x0001,
// Client Messages
MESSAGE_CONNECT = 0x0ff3,
MESSAGE_GET_STATUS = 0x0ff4,
MESSAGE_GET_CONFIGURATION = 0x0ff5,
MESSAGE_SHUTDOWN_NOTIFY = 0x0f00,
// Server Messages
MESSAGE_CONNECT_REPLY = 0x7ff3,
MESSAGE_GET_STATUS_REPLY = 0x7ff4,
MESSAGE_GET_CONFIGURATION_REPLY = 0x7ff5,
MESSAGE_SHUTDOWN_NOTIFY_REPLY = 0x7f00
};
namespace Message
{
////////////////////////////////////////////////////////////////////////////////
class DECLSPEC Base
{
protected:
struct DECLSPEC MemberInfo
{
MemberInfo(soe::AutoVariableBase *dataIn = NULL, unsigned sizeIn = 1, unsigned versionIn = 0, soe::EVersionEffect effectIn = soe::eNoEffect)
: data(dataIn)
, size(sizeIn)
, version(versionIn)
, effect(effectIn)
{ }
soe::AutoVariableBase *data;
unsigned size;
unsigned version;
soe::EVersionEffect effect;
};
typedef struct MemberInfo MemberInfo_t;
// typedef std::pair<soe::AutoVariableBase *, unsigned> MemberInfo_t;
typedef std::vector<MemberInfo_t> MemberVector_t;
public:
typedef soe::uint32 Storage_t;
typedef std::vector<Storage_t> StorageVector_t;
Base() { }
virtual ~Base() { }
void * operator new(size_t size);
void * operator new(size_t size, void *ptr);
void Insert(soe::AutoVariableBase & member, unsigned size = 1, unsigned version = 0, soe::EVersionEffect effect = soe::eNoEffect);
void InsertOptional(soe::AutoVariableBase & member, unsigned size = 1, unsigned version = 0, soe::EVersionEffect effect = soe::eNoEffect);
virtual unsigned Write(unsigned char * stream, unsigned size, unsigned version = 0) const;
virtual unsigned Read(const unsigned char * stream, unsigned size, unsigned version = 0);
#ifdef PRINTABLE_MESSAGES
virtual int Print(char * stream, unsigned size, unsigned maxDepth = INT_MAX) const;
#endif
virtual Base * Clone() const;
virtual Base * Clone(StorageVector_t &storageVector) const;
virtual const char * MessageName() const { return "Base"; }
virtual const char * MessageIDString() const { return "NULL"; }
static Base * Create(unsigned MsgId, StorageVector_t *pStorageVector = NULL);
static const char * GetMessageName(unsigned msgId);
static const char * GetMessageIDString(unsigned msgId);
class DECLSPEC DeepPointer
{
public:
DeepPointer();
DeepPointer(const Base & source);
explicit DeepPointer(const Base * source);
DeepPointer(const DeepPointer & source);
virtual ~DeepPointer();
void SetMessageType(unsigned MsgId);
DeepPointer & operator=(const Base * rhs);
DeepPointer & operator=(const DeepPointer & rhs);
Base * operator->() const;
Base & operator*() const;
operator Base * () const { return m_ptr; }
private:
Base *m_ptr;
StorageVector_t m_storageVector;
};
static const std::map<unsigned, DeepPointer> & GetMessageMap();
protected:
Base(const Base & source) { }
Base & operator=(const Base & rhs) { return *this; }
void * operator new(size_t storageSize, StorageVector_t &storageVector);
public:
static void AddClassMapEntry(unsigned msgId, const Base * msg);
protected:
MemberVector_t mMembers;
MemberVector_t mOptionalMembers;
static std::map<unsigned, DeepPointer> *ms_pClassMap;
};
}
#ifdef API_NAMESPACE
}
#endif
#include "Base/serializeTemplates.h"
#ifdef API_NAMESPACE
namespace API_NAMESPACE
{
#endif
namespace Message
{
class DECLSPEC Basic : public Base
{
public:
Basic();
Basic(const unsigned messageId, const unsigned connectId=0);
virtual ~Basic();
const unsigned GetMsgId() const;
const unsigned GetConnectionId() const;
void SetConnectionId(const unsigned connectId);
virtual const char * MessageName() const { return "Basic"; }
virtual const char * MessageIDString() const { return "NULL_2"; }
protected:
Basic(const Basic & source);
Basic & operator=(const Basic & rhs);
#if defined(PRINTABLE_MESSAGES) || defined(TRACK_READ_WRITE_FAILURES)
public:
class DECLSPEC PrintMsgId : public soe::AutoVariable<unsigned>
{
public:
virtual const char * VariableName() const { return "MsgId"; }
# ifdef PRINTABLE_MESSAGES
virtual int Print(char * stream, unsigned size, unsigned maxDepth=INT_MAX) const
{
int bytes = snprintf(stream, size, "%s(", this->VariableName());
int bytesTotal = 0;
if (soe::FailedToPrint(bytes, size)) {
return bytes;
}
bytesTotal += bytes;
bytes = snprintf(stream+bytesTotal, size, "0x%4.4X", Get());
if (soe::FailedToPrint(bytes, size)) {
return bytes;
}
bytesTotal += bytes;
bytes = snprintf(stream+bytesTotal, size-bytesTotal, ")");
if (soe::FailedToPrint(bytes, size-bytesTotal)) {
return bytes;
}
bytesTotal += bytes;
return bytesTotal;
}
# endif // PRINTABLE_MESSAGES
};
class PrintConnectionId : public soe::AutoVariable<unsigned>
{
public:
virtual const char * VariableName() const { return "CID"; }
# ifdef PRINTABLE_MESSAGES
virtual int Print(char * stream, unsigned size, unsigned maxDepth=INT_MAX) const
{
int bytesTotal = 0;
if (Get()) {
int bytes = snprintf(stream, size, "%s(", this->VariableName());
if (soe::FailedToPrint(bytes, size)) {
return bytes;
}
bytesTotal += bytes;
bytes = snprintf(stream+bytesTotal, size, "0x%4.4X", Get());
if (soe::FailedToPrint(bytes, size)) {
return bytes;
}
bytesTotal += bytes;
bytes = snprintf(stream+bytesTotal, size-bytesTotal, ")");
if (soe::FailedToPrint(bytes, size-bytesTotal)) {
return bytes;
}
bytesTotal += bytes;
}
return bytesTotal;
}
# endif // PRINTABLE_MESSAGES
};
protected:
PrintMsgId mMsgId;
PrintConnectionId mConnectId;
#else
soe::AutoVariable<unsigned> mMsgId;
soe::AutoVariable<unsigned> mConnectId;
#endif // defined(PRINTABLE_MESSAGES) || defined(TRACK_READ_WRITE_FAILURES)
};
inline void Base::Insert(soe::AutoVariableBase & member, unsigned size, unsigned version, soe::EVersionEffect effect)
{
mMembers.push_back(MemberInfo_t(&member,size,version,effect));
}
inline void Base::InsertOptional(soe::AutoVariableBase & member, unsigned size, unsigned version, soe::EVersionEffect effect)
{
mOptionalMembers.push_back(MemberInfo_t(&member,size,version,effect));
}
inline const unsigned Basic::GetMsgId() const
{
return mMsgId.Get();
}
inline const unsigned Basic::GetConnectionId() const
{
return mConnectId.Get();
}
inline void Basic::SetConnectionId(const unsigned connectId)
{
mConnectId.Set(connectId);
mMembers[1] = MemberInfo_t(&mConnectId,1,0,soe::eNoEffect);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
// NameValuePair
DefineMessageBegin(NameValuePair, Basic, MESSAGE_NAME_VALUE_PAIR)
DefineMessageMember(Name, std::string)
DefineMessageMember(Value, std::string)
DefineMessageEnd
////////////////////////////////////////
// Connect
DefineMessageBegin(Connect, Basic, MESSAGE_CONNECT)
DefineMessageMember(Version, std::string)
DefineMessageMember(Description, std::string)
DefineMessageEnd
////////////////////////////////////////
// ConnectReply
DefineMessageBegin(ConnectReply, Basic, MESSAGE_CONNECT_REPLY)
DefineMessageMember(Result, unsigned char)
DefineMessageMember(Version, std::string)
DefineMessageEnd
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////
// Tracked
DefineMessageBegin(Tracked, Basic, MESSAGE_NULL)
DefineMessageMember(TrackingNumber, unsigned)
DefineMessageEnd
////////////////////////////////////////
// TrackedReply
DefineMessageBegin(TrackedReply, Tracked, MESSAGE_NULL)
DefineMessageMember(Result, unsigned)
DefineMessageEnd
////////////////////////////////////////
// TrackedReplyEx
DefineMessageBegin(TrackedReplyEx, TrackedReply, MESSAGE_NULL)
DefineMessageMember(Status, unsigned)
DefineMessageEnd
////////////////////////////////////////
// TrackedInterimReply
DefineMessageBegin(TrackedInterimReply, TrackedReply, MESSAGE_NULL)
DefineMessageMember(ParentTrackingNumber, unsigned)
DefineMessageEnd
////////////////////////////////////////
// GetStatus
DefineMessageBegin(GetStatus, Tracked, MESSAGE_GET_STATUS)
DefineMessageEnd
DefineMessageBegin(GetStatusReply, TrackedReply, MESSAGE_GET_STATUS_REPLY)
DefineMessageMember(NameValuePairs, std::vector<NameValuePair>)
DefineMessageEnd
////////////////////////////////////////
// ShutdownNotify
DefineMessageBegin(ShutdownNotify, Basic, MESSAGE_SHUTDOWN_NOTIFY)
DefineMessageMember(UnfinishedRequests, unsigned)
DefineMessageEnd
DefineMessageBegin(ShutdownNotifyReply, Basic, MESSAGE_SHUTDOWN_NOTIFY_REPLY)
DefineMessageMember(UnfinishedRequests, unsigned)
DefineMessageEnd
////////////////////////////////////////////////////////////////////////////////
}
DECLSPEC void Read(soe::NameValuePair &dest, const Message::NameValuePair &src);
DECLSPEC void Write(const soe::NameValuePair &src, Message::NameValuePair &dest);
#ifdef API_NAMESPACE
}
#endif
namespace soe
{
inline unsigned Write(unsigned char * stream, unsigned size, const API_NAMESPACE::Message::Base & data, unsigned version = 0)
{
unsigned written = 0;
unsigned writtenSize = Write(stream, size, written, version);
if (writtenSize <= 0) { return 0; }
written = data.Write(stream + writtenSize, size - writtenSize, version);
if (written <= 0) { return 0; }
writtenSize = Write(stream, size, written, version);
return (writtenSize + written);
}
inline unsigned Read(const unsigned char * stream, unsigned size, API_NAMESPACE::Message::Base & data, unsigned, unsigned version = 0)
{
unsigned messageSize = 0;
unsigned readSize = Read(stream, size, messageSize, version);
unsigned readIn = 0;
size -= readSize;
stream += readSize;
if (messageSize > size) { return 0; }
readIn = data.Read(stream, messageSize, version);
if (readIn <= 0) { return 0; }
return (readSize + messageSize);
}
inline unsigned Write(unsigned char * stream, unsigned size, const API_NAMESPACE::Message::Base::DeepPointer & data, unsigned version = 0)
{
API_NAMESPACE::Message::Base *msg = (API_NAMESPACE::Message::Base *)data;
if (msg) {
return Write(stream, size, *msg, version);
} else {
return 0;
}
}
inline unsigned Read(const unsigned char * stream, unsigned size, API_NAMESPACE::Message::Base::DeepPointer & data, unsigned, unsigned version = 0)
{
unsigned msgSize = 0;
unsigned msgId = 0;
unsigned sizeSize = Read(stream, size, msgSize, version);
unsigned idSize = (sizeSize > 0) ? Read(stream + sizeSize, size - sizeSize, msgId, version) : 0;
if (idSize <= 0) {
return 0;
}
data.SetMessageType(msgId);
API_NAMESPACE::Message::Base *msg = data;
if (msg) {
return Read(stream, size, *msg, 0, version);
} else {
return 0;
}
}
#ifdef PRINTABLE_MESSAGES
inline int Print(char * stream, unsigned size, const API_NAMESPACE::Message::Base & data, unsigned maxDepth=INT_MAX)
{
return data.Print(stream, size, maxDepth);
}
inline int Print(char * stream, unsigned size, const API_NAMESPACE::Message::Base::DeepPointer & data, unsigned maxDepth=INT_MAX)
{
API_NAMESPACE::Message::Base *msg = (API_NAMESPACE::Message::Base *)data;
if (msg) {
return Print(stream, size, *msg, maxDepth);
} else {
return 0;
}
}
#endif
}
//#endif //_API_MESSAGES_H
@@ -0,0 +1,443 @@
#ifdef WIN32
#pragma warning (disable: 4786)
#endif
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include <algorithm>
#include "Base/timer.h"
#include "Base/serialize.h"
#include "apiPinned.h"
using namespace std;
#ifdef NAMESPACE
namespace NAMESPACE
{
#endif
const unsigned CONNECT_TIMEOUT = 5;
////////////////////////////////////////////////////////////////////////////////
TrackedRequest::TrackedRequest() :
mMsgId(0),
mTrackingNumber(0),
mResult(0),
mUserData(0),
mTimeout(0)
{
}
TrackedRequest::TrackedRequest(unsigned messageId, unsigned trackingNumber, unsigned result, const void * userData, unsigned duration) :
mMsgId(messageId),
mTrackingNumber(trackingNumber),
mResult(result),
mUserData((void *)userData),
mTimeout(0)
{
mTimeout = time(0) + duration;
}
////////////////////////////////////////////////////////////////////////////////
CommonAPI::CommonAPI(const char * hostList, const char * failoverHostList, unsigned connectionLimit, unsigned maxMsgSize, unsigned bufferSize)
: mManager()
, mIdleHosts()
, mHostMap()
, mActiveHosts()
, mCallbackQueue()
, mRequestMap()
, mTimeoutMap()
, mTimeoutTimer(0)
, mStatusTimer(0)
, mConnectionLimit(connectionLimit)
, mInCallback(false)
, mTrackingIndex(1)
{
#ifdef UDP_LIBRARY
UdpManager::Params params = GetConnectionParams();
mManager = new UdpManager(&params);
#else
TcpManager::TcpParams params = GetConnectionParams();
mManager = new TcpManager(params);
#endif
srand(time(0));
if (hostList && hostList[0])
{
std::vector<std::string> orderArray;
std::string hosts = hostList;
unsigned offset = 0;
do
{
unsigned index = hosts.find(' ', offset);
orderArray.push_back(hosts.substr(offset, (index != std::string::npos) ? index-offset : index));
offset = (index != std::string::npos) ? index+1 : index;
}
while (offset != std::string::npos);
while (!orderArray.empty())
{
mIdleHosts[0].push_back(orderArray.back());
orderArray.pop_back();
}
}
if (failoverHostList && failoverHostList[0])
{
std::vector<std::string> orderArray;
std::string hosts = failoverHostList;
unsigned offset = 0;
do
{
unsigned index = hosts.find(' ', offset);
orderArray.push_back(hosts.substr(offset, (index != std::string::npos) ? index-offset : index));
offset = (index != std::string::npos) ? index+1 : index;
}
while (offset != std::string::npos);
while (!orderArray.empty())
{
mIdleHosts[1].push_back(orderArray.back());
orderArray.pop_back();
}
}
}
CommonAPI::~CommonAPI()
{
// ensure that callback mecahnism isn't triggered at this point
HostMap_t::iterator iter;
for (iter = mHostMap[0].begin(); iter != mHostMap[0].end(); iter++)
{
iter->first->SetHandler(0);
iter->first->Release();
}
for (iter = mHostMap[1].begin(); iter != mHostMap[1].end(); iter++)
{
iter->first->SetHandler(0);
iter->first->Release();
}
mManager->Release();
}
#ifdef UDP_LIBRARY
UdpManager::Params CommonAPI::GetConnectionParams()
{
UdpManager::Params params;
// LAN connection
params.maxRawPacketSize = 1460;
params.outgoingBufferSize = 4 * 1024 * 1024;
params.incomingBufferSize = 4 * 1024 * 1024;
params.keepAliveDelay = 15 * 1000;
params.reliableOverflowBytes = 10 * 1024 * 1024;
params.pooledPacketMax = 5000;
params.crcBytes = 2;
params.icmpErrorRetryPeriod = 2000;
params.allowPortRemapping = false; // set to false (optional)
params.oldestUnacknowledgedTimeout = 15 * 1000; // set to 30000 (longer for debugging tolerance)
params.maxDataHoldTime = 0; // set to 0 (this is critical)
params.reliable[0].maxOutstandingBytes = 2 * 1024 * 1024; // set to 2mb
params.reliable[0].maxOutstandingPackets = 4000; // set to 4000
params.reliable[0].resendDelayAdjust = 1500; // set to 1500
params.reliable[0].congestionWindowMinimum = 50000; // set to 50000
return params;
}
#else
TcpManager::TcpParams CommonAPI::GetConnectionParams()
{
TcpManager::TcpParams params;
params.incomingBufferSize = 512*1024;
params.outgoingBufferSize = 512*1024;
params.allocatorBlockSize = 8*1024;
params.allocatorBlockCount = 1024;
params.maxRecvMessageSize = 8*1024;
params.keepAliveDelay = 15 * 1000;
//params.noDataTimeout = 30 * 1000; // server only setting.
return params;
}
#endif
void CommonAPI::RegisterTrackedMessage(unsigned messageId)
{
mTrackedMessages.insert(messageId);
}
bool CommonAPI::IsTracked(unsigned messageId)
{
return mTrackedMessages.find(messageId) != mTrackedMessages.end();
}
unsigned CommonAPI::GetTrackingNumber()
{
if (!mTrackingIndex)
mTrackingIndex++;
return mTrackingIndex++;
}
unsigned CommonAPI::GetConnectionCount()
{
if (mActiveHosts[0].size())
return mActiveHosts[0].size();
else
return mActiveHosts[1].size();
}
#ifdef UDP_LIBRARY
void CommonAPI::OnConnectComplete(UdpConnection * connection)
#else
void CommonAPI::OnConnectRequest(TcpConnection * connection)
#endif
{
HostMap_t::iterator iter;
if ((iter = mHostMap[0].find(connection)) != mHostMap[0].end())
{
mActiveHosts[0].insert(connection);
}
else if ((iter = mHostMap[1].find(connection)) != mHostMap[1].end())
{
mActiveHosts[1].insert(connection);
}
OnConnectionOpened(iter->second.c_str());
// send initial status message
unsigned char buffer[1024];
unsigned size = FormatStatusMsg(buffer, sizeof(buffer));
if (size)
{
#ifdef UDP_LIBRARY
connection->Send(cUdpChannelReliable1, buffer, size);
connection->FlushChannels();
#else
connection->Send((const char*)buffer, size);
#endif
}
}
#ifdef UDP_LIBRARY
void CommonAPI::OnTerminated(UdpConnection * connection)
#else
void CommonAPI::OnTerminated(TcpConnection * connection)
#endif
{
std::string host;
HostMap_t::iterator iter;
if ((iter = mHostMap[0].find(connection)) != mHostMap[0].end())
{
if (mActiveHosts[0].erase(connection) != 0)
{
OnConnectionClosed(iter->second.c_str(), "unknown");
}
else
{
OnConnectionFailed(iter->second.c_str());
}
iter->first->Release();
mIdleHosts[0].push_back(iter->second);
mHostMap[0].erase(iter);
}
else if ((iter = mHostMap[1].find(connection)) != mHostMap[1].end())
{
if (mActiveHosts[1].erase(connection) != 0)
{
OnConnectionClosed(iter->second.c_str(), "unknown");
}
else
{
OnConnectionFailed(iter->second.c_str());
}
iter->first->Release();
mIdleHosts[1].push_back(iter->second);
mHostMap[1].erase(iter);
}
}
#ifdef UDP_LIBRARY
void CommonAPI::OnRoutePacket(UdpConnection * connection, const unsigned char * data, int dataLen)
#else
void CommonAPI::OnRoutePacket(TcpConnection * connection, const unsigned char * data, int dataLen)
#endif
{
// read message id
unsigned msgId = CheckMessageId(data, dataLen);
// if tracked message, lookup in request map
if (IsTracked(msgId))
{
// read tracking number
unsigned trackingNumber = CheckTrackingNumber(data, dataLen);
RequestMap_t::iterator reqIterator = mRequestMap.find(trackingNumber);
if (reqIterator != mRequestMap.end())
{
TrackedRequest & request = reqIterator->second;
Callback(data, dataLen, msgId, (void *)request.mUserData);
mRequestMap.erase(reqIterator);
}
}
else if (msgId)
{
Callback(data, dataLen, msgId, 0);
}
}
bool CommonAPI::Send(unsigned char hashValue, const unsigned char *data, unsigned dataLen)
{
if (!mActiveHosts[0].empty())
{
// get connection that corresponds to hash index
ApiConnection * connection = NULL;
unsigned hashIndex = hashValue % mActiveHosts[0].size();
unsigned curIndex = 0;
for (ConnectionSet_t::iterator it = mActiveHosts[0].begin(); it != mActiveHosts[0].end(); it++, curIndex++)
{
if (hashIndex == curIndex)
{
connection = *it;
break;
}
}
if (!connection)
return false;
#ifdef UDP_LIBRARY
connection->Send(cUdpChannelReliable1, data, dataLen);
#else
connection->Send((const char*)data, dataLen);
#endif
return true;
}
else if (!mActiveHosts[1].empty())
{
// get connection that corresponds to hash index
ApiConnection * connection = NULL;
unsigned hashIndex = hashValue % mActiveHosts[1].size();
unsigned curIndex = 0;
for (ConnectionSet_t::iterator it = mActiveHosts[1].begin(); it != mActiveHosts[1].end(); it++, curIndex++)
{
if (hashIndex == curIndex)
{
connection = *it;
break;
}
}
if (!connection)
return false;
#ifdef UDP_LIBRARY
connection->Send(cUdpChannelReliable1, data, dataLen);
#else
connection->Send((const char *)data, dataLen);
#endif
return true;
}
return false;
}
void CommonAPI::PrepareCallback(unsigned messageId, unsigned trackingNumber, unsigned result, const void * userData, unsigned timeout)
{
TrackedRequest request(messageId, trackingNumber, result, userData, timeout);
mRequestMap[trackingNumber] = request;
if (timeout)
{
mTimeoutMap[timeout].push_back(std::pair<unsigned,unsigned>(trackingNumber,time(0)+timeout));
}
else
{
mCallbackQueue.push_back(trackingNumber);
}
}
void CommonAPI::Process()
{
if (mInCallback)
return;
mInCallback = true;
unsigned currentTime = time(0);
////////////////////////////////////////
// Process connection manager
if (!mIdleHosts[0].empty() && (mHostMap[0].size() < mConnectionLimit || !mConnectionLimit))
{
std::string hostName = mIdleHosts[0].front();
mIdleHosts[0].pop_front();
unsigned index = hostName.find(':');
std::string host = hostName.substr(0, index);
int port = (index != std::string::npos) ? atoi(hostName.substr(index+1, index).c_str()) : 0;
ApiConnection * connection = mManager->EstablishConnection(host.c_str(), port, CONNECT_TIMEOUT);
if (connection)
{
connection->SetHandler(this);
mHostMap[0][connection] = hostName;
}
}
if (!mIdleHosts[1].empty() && (mHostMap[1].size() < mConnectionLimit || !mConnectionLimit))
{
std::string hostName = mIdleHosts[1].front();
mIdleHosts[1].pop_front();
unsigned index = hostName.find(':');
std::string host = hostName.substr(0, index);
int port = (index != std::string::npos) ? atoi(hostName.substr(index+1, index).c_str()) : 0;
ApiConnection * connection = mManager->EstablishConnection(host.c_str(), port, CONNECT_TIMEOUT);
if (connection)
{
connection->SetHandler(this);
mHostMap[1][connection] = hostName;
}
}
mManager->GiveTime();
////////////////////////////////////////
// Check for requests that have timed out once per second
if (mTimeoutTimer != currentTime)
{
TimeoutMap_t::iterator iterator;
for (iterator = mTimeoutMap.begin(); iterator != mTimeoutMap.end(); iterator++)
{
TimeoutList_t & timeoutList = iterator->second;
while (!timeoutList.empty() && timeoutList.front().second < currentTime)
{
RequestMap_t::iterator reqIterator = mRequestMap.find(timeoutList.front().first);
if (reqIterator != mRequestMap.end())
{
TrackedRequest & request = reqIterator->second;
Callback(request.mMsgId, request.mTrackingNumber, request.mResult, (void *)request.mUserData);
mRequestMap.erase(reqIterator);
}
timeoutList.pop_front();
}
}
mTimeoutTimer = currentTime;
}
////////////////////////////////////////
// Process Callback Queue
while (!mCallbackQueue.empty())
{
RequestMap_t::iterator reqIterator = mRequestMap.find(mCallbackQueue.front());
if (reqIterator != mRequestMap.end())
{
TrackedRequest & request = reqIterator->second;
Callback(request.mMsgId, request.mTrackingNumber, request.mResult, (void *)request.mUserData);
mRequestMap.erase(reqIterator);
}
mCallbackQueue.pop_front();
}
mInCallback = false;
}
////////////////////////////////////////////////////////////////////////////////
#ifdef NAMESPACE
}
#endif
@@ -0,0 +1,121 @@
#ifndef BASE__API_H
#define BASE__API_H
#include <vector>
#include <list>
#include <set>
#include <map>
#include "Base/profile.h"
#ifdef UDP_LIBRARY
#include "UdpLibrary/UdpLibrary.hpp"
#else
#include "TcpLibrary/TcpConnection.h"
#include "TcpLibrary/TcpManager.h"
#endif
#include "apiMessages.h"
#ifdef NAMESPACE
namespace NAMESPACE
{
#endif
////////////////////////////////////////////////////////////////////////////////
struct TrackedRequest
{
TrackedRequest();
TrackedRequest(unsigned messageId, unsigned trackingNumber, unsigned result, const void * userData, unsigned timeout = 5);
unsigned mMsgId;
unsigned mTrackingNumber;
unsigned mResult;
void * mUserData;
unsigned mTimeout;
};
////////////////////////////////////////////////////////////////////////////////
#ifdef UDP_LIBRARY
class CommonAPI : UdpConnectionHandler
#else
class CommonAPI : TcpConnectionHandler
#endif
{
#ifdef UDP_LIBRARY
typedef UdpConnection ApiConnection;
#else
typedef TcpConnection ApiConnection;
#endif
typedef std::map<ApiConnection *, std::string> HostMap_t;
typedef std::set<ApiConnection *> ConnectionSet_t;
typedef std::map<unsigned, TrackedRequest> RequestMap_t;
typedef std::list<std::pair<unsigned,unsigned> > TimeoutList_t;
typedef std::map<unsigned, TimeoutList_t> TimeoutMap_t;
typedef std::list<unsigned> TrackingList_t;
typedef std::set<unsigned> MessagIdSet_t;
public:
CommonAPI(const char * hostList, const char * failoverHostList = 0, unsigned connectionLimit = 0, unsigned maxMsgSize = 1*1024, unsigned bufferSize = 64*1024);
virtual ~CommonAPI();
void Process();
unsigned GetConnectionCount();
unsigned GetTrackingNumber();
bool Send(unsigned char hashValue, const unsigned char *data, unsigned dataLen);
void PrepareCallback(unsigned messageId, unsigned trackingNumber, unsigned result, const void * userData, unsigned timeout = 0);
protected:
#ifdef UDP_LIBRARY
virtual UdpManager::Params GetConnectionParams();
virtual void OnConnectComplete(UdpConnection *con);
virtual void OnTerminated(UdpConnection *con);
virtual void OnRoutePacket(UdpConnection *con, const uchar *data, int dataLen);
#else
virtual TcpManager::TcpParams GetConnectionParams();
virtual void OnConnectRequest(TcpConnection *con);
virtual void OnTerminated(TcpConnection *con);
virtual void OnRoutePacket(TcpConnection *con, const unsigned char *data, int dataLen);
#endif
virtual unsigned CheckMessageId(const unsigned char * data, unsigned dataLen) = 0;
virtual unsigned CheckTrackingNumber(const unsigned char * data, unsigned dataLen) = 0;
bool IsTracked(unsigned msgId);
void RegisterTrackedMessage(unsigned msgId);
// FormatStatusMsg provides a buffer/size for the derived class to write to and returns the size of the message written
// This function is called after connecting and periodically once connected.
virtual unsigned FormatStatusMsg(unsigned char * buffer, unsigned bufferLen) = 0;
virtual void OnConnectionOpened(const char * address) = 0;
virtual void OnConnectionFailed(const char * address) = 0;
virtual void OnConnectionClosed(const char * address, const char * reason) = 0;
virtual void Callback(const unsigned char * data, unsigned dataLen, unsigned messageId, void * userData) = 0;
virtual void Callback(unsigned messageId, unsigned trackingNumber, unsigned result, void * userData) = 0;
private:
#ifdef UDP_LIBRARY
UdpManager * mManager;
#else
TcpManager * mManager;
#endif
std::list<std::string> mIdleHosts[2];
HostMap_t mHostMap[2];
ConnectionSet_t mActiveHosts[2];
TrackingList_t mCallbackQueue;
RequestMap_t mRequestMap;
TimeoutMap_t mTimeoutMap;
unsigned mTrackingIndex;
MessagIdSet_t mTrackedMessages;
unsigned mTimeoutTimer;
unsigned mStatusTimer;
unsigned mConnectionLimit;
unsigned mMaxMsgSize;
unsigned mBufferSize;
bool mInCallback;
};
#ifdef NAMESPACE
}
#endif
#endif
@@ -0,0 +1,65 @@
#ifndef API_TYPE_NAME_VALUE_PAIR
#define API_TYPE_NAME_VALUE_PAIR
#include <string>
#include <vector>
#include "Base/serializeClasses.h"
const int MAX_NAME_VALUE_PAIR_NAME_LEN = 256;
const int MAX_NAME_VALUE_PAIR_VALUE_LEN = 512;
namespace soe
{
struct NameValuePair
{
unsigned Write(unsigned char * stream, unsigned size) const
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, name));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, value));
if (!bytes) return 0;
return bytesTotal;
}
unsigned Read(const unsigned char * stream, unsigned size)
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, name, MAX_NAME_VALUE_PAIR_NAME_LEN));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, value, MAX_NAME_VALUE_PAIR_VALUE_LEN));
if (!bytes) return 0;
return bytesTotal;
}
std::string name; //256
std::string value; //512
};
typedef std::vector<NameValuePair> NameValuePairs_t;
inline unsigned Read(const unsigned char * stream, unsigned size, NameValuePair & data, unsigned maxLen, unsigned version = 0)
{
return data.Read(stream, size);
}
inline unsigned Write(unsigned char * stream, unsigned size, const NameValuePair & data, unsigned version = 0)
{
return data.Write(stream, size);
}
inline int Print(char * stream, unsigned size, const NameValuePair & data, unsigned maxDepth = INT_MAX)
{
return 0;
}
}
#endif
@@ -0,0 +1,22 @@
#ifndef API_TYPE_NAME_VALUE_PAIR
#define API_TYPE_NAME_VALUE_PAIR
#include <string>
#include <vector>
#include "Base/serializeClasses.h"
const int MAX_NAME_VALUE_PAIR_NAME_LEN = 256;
const int MAX_NAME_VALUE_PAIR_VALUE_LEN = 512;
namespace soe
{
inline int Print(char * stream, unsigned size, const NameValuePair & data, unsigned maxDepth = INT_MAX)
{
return 0;
}
}
#endif
@@ -0,0 +1,23 @@
#ifndef _PROTOCOL_H_
#define _PROTOCOL_H_
#ifdef _USE_TCP
#include "TcpLibrary/TcpConnection.h"
#include "TcpLibrary/TcpManager.h"
#define PlatConnectionHandler TcpConnectionHandler
#define PlatConnection TcpConnection
#define PlatManager TcpManager
#define PlatManagerHandler TcpManagerHandler
#define PlatParams TcpManager::TcpParams
#else
#include "UdpLibrary/UdpLibrary.hpp"
#define PlatConnectionHandler UdpConnectionHandler
#define PlatConnection UdpConnection
#define PlatManager UdpManager
#define PlatParams UdpManager::Params
#endif
#endif
@@ -0,0 +1,216 @@
#include "Base32.h"
#include <string.h>
#include "types.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
const unsigned char Base32::ms_base32Table[] =
{
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'0',
'1',
'2',
'3',
'4',
'5',
};
int Base32::GetEncode32Length(int bytes)
{
int bits = bytes * 8;
int length = bits / 5;
if((bits % 5) > 0)
{
length++;
}
return length;
}
int Base32::GetDecode32Length(int bytes)
{
int bits = bytes * 5;
int length = bits / 8;
return length;
}
static bool Encode32Block(unsigned char* in5, unsigned char* out8)
{
// pack 5 bytes
soe::uint64 buffer = 0;
for(int i = 0; i < 5; i++)
{
if(i != 0)
{
buffer = (buffer << 8);
}
buffer = buffer | in5[i];
}
// output 8 bytes
for(int j = 7; j >= 0; j--)
{
buffer = buffer << (24 + (7 - j) * 5);
buffer = buffer >> (24 + (7 - j) * 5);
unsigned char c = (unsigned char)(buffer >> (j * 5));
// self check
if(c >= 32) return false;
out8[7 - j] = c;
}
return true;
}
bool Base32::Encode32(unsigned char* in, int inLen, unsigned char* out)
{
if((in == 0) || (inLen <= 0) || (out == 0)) return false;
int d = inLen / 5;
int r = inLen % 5;
unsigned char outBuff[8];
for(int j = 0; j < d; j++)
{
if(!Encode32Block(&in[j * 5], &outBuff[0])) return false;
memmove(&out[j * 8], &outBuff[0], sizeof(unsigned char) * 8);
}
unsigned char padd[5];
memset(padd, 0, sizeof(unsigned char) * 5);
for(int i = 0; i < r; i++)
{
padd[i] = in[inLen - r + i];
}
if(!Encode32Block(&padd[0], &outBuff[0])) return false;
memmove(&out[d * 8], &outBuff[0], sizeof(unsigned char) * GetEncode32Length(r));
return true;
}
static bool Decode32Block(unsigned char* in8, unsigned char* out5)
{
// pack 8 bytes
soe::uint64 buffer = 0;
for(int i = 0; i < 8; i++)
{
// input check
if(in8[i] >= 32) return false;
if(i != 0)
{
buffer = (buffer << 5);
}
buffer = buffer | in8[i];
}
// output 5 bytes
for(int j = 4; j >= 0; j--)
{
out5[4 - j] = (unsigned char)(buffer >> (j * 8));
}
return true;
}
bool Base32::Decode32(unsigned char* in, int inLen, unsigned char* out)
{
if((in == 0) || (inLen <= 0) || (out == 0)) return false;
int d = inLen / 8;
int r = inLen % 8;
unsigned char outBuff[5];
for(int j = 0; j < d; j++)
{
if(!Decode32Block(&in[j * 8], &outBuff[0])) return false;
memmove(&out[j * 5], &outBuff[0], sizeof(unsigned char) * 5);
}
unsigned char padd[8];
memset(padd, 0, sizeof(unsigned char) * 8);
for(int i = 0; i < r; i++)
{
padd[i] = in[inLen - r + i];
}
if(!Decode32Block(&padd[0], &outBuff[0])) return false;
memmove(&out[d * 5], &outBuff[0], sizeof(unsigned char) * GetDecode32Length(r));
return true;
}
bool Base32::Map32(unsigned char* inout32, int inout32Len, unsigned char* alpha32)
{
if((inout32 == 0) || (inout32Len <= 0) || (alpha32 == 0)) return false;
for(int i = 0; i < inout32Len; i++)
{
if(inout32[i] >=32) return false;
inout32[i] = alpha32[inout32[i]];
}
return true;
}
static void ReverseMap(unsigned char* inAlpha32, unsigned char* outMap)
{
memset(outMap, 0, sizeof(unsigned char) * 256);
for(int i = 0; i < 32; i++)
{
outMap[(int)inAlpha32[i]] = i;
}
}
bool Base32::Unmap32(unsigned char* inout32, int inout32Len, unsigned char* alpha32)
{
if((inout32 == 0) || (inout32Len <= 0) || (alpha32 == 0)) return false;
unsigned char rmap[256];
ReverseMap(alpha32, rmap);
for(int i = 0; i < inout32Len; i++)
{
unsigned char c = inout32[i];
int index = (int)c;
inout32[i] = rmap[index];
}
return true;
}
bool Base32::Map32(unsigned char* inout32, int inout32Len)
{
return Map32(inout32, inout32Len, (unsigned char *)ms_base32Table);
}
bool Base32::Unmap32(unsigned char* inout32, int inout32Len)
{
return Unmap32(inout32, inout32Len, (unsigned char *)ms_base32Table);
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,44 @@
#if !defined(_BASE32_H_)
#define _BASE32_H_
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
struct Base32
{
// Decode32 input is the output of Encode32. The out parameters should be unsigned char[] of
// length GetDecode32Length(inLen) and GetEncode32Length(inLen) respectively.
static bool Decode32(unsigned char* in, int inLen, unsigned char* out);
// Encode32 outputs at out bytes with values from 0 to 32 that can be mapped to 32 signs.
static bool Encode32(unsigned char* in, int inLen, unsigned char* out);
static int GetDecode32Length(int bytes);
static int GetEncode32Length(int bytes);
// Both Map32 and Unmap32 do inplace modification of the inout32 array.
// The alpha32 array must be exactly 32 chars long.
// To map the output of Encode32 to an alphabet of 32 characters use Map32.
static bool Map32(unsigned char* inout32, int inout32Len, unsigned char* alpha32);
// To unmap back the output of Map32 to an array understood by Decode32 use Unmap32.
static bool Unmap32(unsigned char* inout32, int inout32Len, unsigned char* alpha32);
// same as above but user the static map, ms_base32Table
static bool Map32(unsigned char* inout32, int inout32Len);
static bool Unmap32(unsigned char* inout32, int inout32Len);
static const unsigned char ms_base32Table[];
};
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // _BASE32_H_
@@ -0,0 +1,499 @@
#include "Base64.h"
#include <stdio.h>
#ifdef WIN32
#define snprintf _snprintf
#endif
namespace soe
{
//----------------------------------------------------------------------------
// Constants
//----------------------------------------------------------------------------
#define BASE64_PAD '='
#define BASE64_PAD_INDEX 64
#define BASE64_ERR ((unsigned char)-1)
#define BASE64_PAD_CODE ((unsigned char)100)
#define BASE64_OUTPUT_LINE 76
#define BASE64_ENCODE_BUFFER ((BASE64_OUTPUT_LINE*3)/4)
#define BASE64_DECODE_ERROR ((unsigned)-1)
#define HEX_ERR 16
#define HEX_LOWER_FORMAT "%2.2x"
#define HEX_UPPER_FORMAT "%2.2X";
const char Base64::ms_base64Table[] =
{
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'+',
'/',
BASE64_PAD
};
//----------------------------------------------------------------------------
// Functions
//----------------------------------------------------------------------------
unsigned char Base64::GetBase64Code(char base64char)
{
if (base64char == BASE64_PAD)
return BASE64_PAD_CODE;
if (base64char >= 'A' && base64char <= 'Z')
return (unsigned char)(base64char - 'A');
if (base64char >= 'a' && base64char <= 'z')
return (unsigned char)(base64char - 'a' + 26);
if (base64char >= '0' && base64char <= '9')
return (unsigned char)(base64char - '0' + 2*26);
if (base64char == '+')
return 2*26+10;
if (base64char == '/')
return 2*26+11;
return BASE64_ERR;
}
unsigned char Base64::GetHexCode(char hexChar)
{
if (hexChar >= '0' && hexChar <= '9')
return (unsigned char)(hexChar - '0');
if (hexChar >= 'A' && hexChar <= 'F')
return (unsigned char)(hexChar - 'A' + 10);
if (hexChar >= 'a' && hexChar <= 'f')
return (unsigned char)(hexChar - 'a' + 10);
return HEX_ERR;
}
unsigned Base64::UUDecodeQuadToTriple(const char *quad, unsigned char *triple)
{
unsigned char b;
unsigned char quadByteCodes[4];
unsigned bytes = 3, i;
for (i = 0; i < 4; i++)
{
b = GetBase64Code(quad[i]);
if (b == BASE64_PAD_CODE)
{
switch(i)
{
case 0: bytes=0; break;
case 1: bytes=0; break;
case 2: bytes=1; break;
case 3: bytes=2; break;
}
break;
}
else if (b == BASE64_ERR)
{
bytes = BASE64_DECODE_ERROR;
}
else
{
quadByteCodes[i] = b;
}
}
triple[0] = (quadByteCodes[0] << 2) | (quadByteCodes[1] >> 4);
triple[1] = (quadByteCodes[1] << 4) | (quadByteCodes[2] >> 2);
triple[2] = (quadByteCodes[2] << 6) | (quadByteCodes[3] >> 0);
return bytes;
}
bool Base64::UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen)
{
unsigned char q[3];
unsigned index;
unsigned bytes;
unsigned char *destIn = dest;
bool noErrors = true;
for (index = 0; index < sourceLen; index += 4)
{
bytes = UUDecodeQuadToTriple(source + index, q);
if (bytes != BASE64_DECODE_ERROR) {
*destLen -= bytes;
if (*destLen >= 0) {
memcpy(dest, (char*)&q, bytes);
} else {
noErrors = false;
}
dest += bytes;
} else {
noErrors = false;
}
}
*destLen = (int)(dest - destIn);
return noErrors;
}
bool Base64::UUDecode(const char *source, unsigned sourceLen, std::string &destString)
{
unsigned char q[3];
unsigned index;
unsigned bytes;
bool noErrors = true;
for (index = 0; index < sourceLen; index += 4)
{
bytes = UUDecodeQuadToTriple(source + index, q);
if (bytes != BASE64_DECODE_ERROR) {
destString.append((char*)&q, bytes);
} else {
noErrors = false;
}
}
return noErrors;
}
bool Base64::UUDecode(const char *source, unsigned sourceLen, std::vector<unsigned char> &destVector)
{
unsigned char q[3];
unsigned index;
unsigned bytes;
bool noErrors = true;
for (index = 0; index < sourceLen; index += 4)
{
bytes = UUDecodeQuadToTriple(source + index, q);
if (bytes != BASE64_DECODE_ERROR) {
for (size_t index = 0; index < bytes; index++)
{
destVector.push_back(q[index]);
}
} else {
noErrors = false;
}
}
return noErrors;
}
unsigned Base64::UUEncodeTripleToQuadPtr(const unsigned char *triple, char* quad, unsigned bytes)
{
unsigned char indices[4];
int quadIndex;
memset(indices, BASE64_PAD_INDEX, sizeof(indices));
switch(bytes)
{
case 3:
indices[3] = (triple[2] ) & 0x0000003F;
indices[2] = (triple[2] >> 6) & 0x0000003F;
case 2:
indices[2] = (indices[2] | (triple[1] << 2)) & 0x0000003F;
indices[1] = (triple[1] >> 4) & 0x0000003F;
case 1:
indices[1] = (indices[1] | (triple[0] << 4)) & 0x0000003F;
indices[0] = (triple[0] >> 2) & 0x0000003F;
case 0:
default:
break;
};
for (quadIndex = 0; quadIndex < 4; quadIndex++) {
quad[quadIndex] = ms_base64Table[indices[quadIndex]];
}
return 0;
}
unsigned Base64::UUEncodeTripleToQuadRef(const std::vector<unsigned char>::const_iterator &triple, char* quad, unsigned bytes)
{
unsigned char indices[4];
int quadIndex;
memset(indices, BASE64_PAD_INDEX, sizeof(indices));
switch(bytes)
{
case 3:
indices[3] = (*(triple+2) ) & 0x0000003F;
indices[2] = (*(triple+2) >> 6) & 0x0000003F;
case 2:
indices[2] = (indices[2] | (*(triple+1) << 2)) & 0x0000003F;
indices[1] = (*(triple+1) >> 4) & 0x0000003F;
case 1:
indices[1] = (indices[1] | (*(triple+0) << 4)) & 0x0000003F;
indices[0] = (*(triple+0) >> 2) & 0x0000003F;
case 0:
default:
break;
};
for (quadIndex = 0; quadIndex < 4; quadIndex++) {
quad[quadIndex] = ms_base64Table[indices[quadIndex]];
}
return 0;
}
bool Base64::UUEncode(const unsigned char *source, unsigned sourceLen, char *dest, unsigned destLen)
{
char quad[5];
unsigned z;
bool noErrors = true;
quad[4] = 0;
// The normal case
for(z = 0; z < sourceLen;z += 3)
{
UUEncodeTripleToQuadPtr(source + z,quad,(z + 3 < sourceLen) ? 3 : (sourceLen - z));
destLen -= strlen(quad);
if (destLen > 0) {
dest += snprintf(dest, sizeof(dest), quad);
} else {
noErrors = false;
}
}
return noErrors;
}
bool Base64::UUEncode(const unsigned char *source, unsigned sourceLen, std::string &destString)
{
char quad[5];
unsigned z;
bool noErrors = true;
quad[4] = 0;
// The normal case
for(z = 0; z < sourceLen;z += 3)
{
UUEncodeTripleToQuadPtr(source + z,quad,(z + 3 < sourceLen) ? 3 : (sourceLen - z));
destString.append(quad);
}
return noErrors;
}
bool Base64::UUEncode(const std::vector<unsigned char> &source, char *dest, unsigned destLen)
{
char quad[5];
unsigned z;
bool noErrors = true;
size_t sourceLen = source.size();
quad[4] = 0;
// The normal case
for(z = 0; z < sourceLen;z += 3)
{
UUEncodeTripleToQuadRef(source.begin() + z,quad,(z + 3 < sourceLen) ? 3 : (sourceLen - z));
if (destLen > 0) {
dest += snprintf(dest, sizeof(dest), quad);
} else {
noErrors = false;
}
}
return noErrors;
}
bool Base64::UUEncode(const std::vector<unsigned char> &source, std::string &destString)
{
char quad[5];
unsigned z;
bool noErrors = true;
size_t sourceLen = source.size();
quad[4] = 0;
// The normal case
for(z = 0; z < sourceLen;z += 3)
{
UUEncodeTripleToQuadRef(source.begin() + z,quad,(z + 3 < sourceLen) ? 3 : (sourceLen - z));
destString.append(quad);
}
return noErrors;
}
bool Base64::HexEncode(const unsigned char *source, unsigned sourceLen, char *dest, unsigned destLen, bool lowercase)
{
const char *format = lowercase ? HEX_LOWER_FORMAT : HEX_UPPER_FORMAT;
bool noErrors = true;
for (; sourceLen > 0; sourceLen--, source++)
{
if (destLen >= 2) {
destLen -= snprintf(dest, sizeof(dest), format, *source);
} else {
noErrors = false;
}
}
return noErrors;
}
bool Base64::HexEncode(const unsigned char *source, unsigned sourceLen, std::string &destString, bool lowercase)
{
const char *format = lowercase ? HEX_LOWER_FORMAT : HEX_UPPER_FORMAT;
char hexBuffer[3];
bool noErrors = true;
hexBuffer[2] = '\0';
for (; sourceLen > 0; sourceLen--, source++)
{
hexBuffer[0] = '\0';
snprintf(hexBuffer, sizeof(hexBuffer), format, *source);
destString.append(hexBuffer);
}
return noErrors;
}
bool Base64::HexDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen)
{
unsigned char *destIn = dest;
unsigned char digits[2];
bool noErrors = true;
for (; sourceLen > 1; sourceLen -= 2, source += 2)
{
if (*destLen > 0) {
digits[0] = GetHexCode(source[0]);
digits[1] = GetHexCode(source[1]);
if ((digits[0] != HEX_ERR) && (digits[1] != HEX_ERR)) {
*dest = (digits[0] * 16) + digits[1];
dest++;
(*destLen)--;
} else {
noErrors = false;
}
} else {
noErrors = false;
}
}
*destLen = dest - destIn;
if (sourceLen == 1) {
noErrors = false;
}
return noErrors;
}
bool Base64::HexDecode(const char *source, unsigned sourceLen, std::string &destString)
{
unsigned char digits[2];
unsigned char byte;
bool noErrors = true;
for (; sourceLen > 1; sourceLen -= 2, source += 2)
{
digits[0] = GetHexCode(source[0]);
digits[1] = GetHexCode(source[1]);
if ((digits[0] != HEX_ERR) && (digits[1] != HEX_ERR)) {
byte = (digits[0] * 16) + digits[1];
destString.append((char *)&byte, 1);
} else {
noErrors = false;
}
}
if (sourceLen == 1) {
noErrors = false;
}
return noErrors;
}
bool Base64::HexDecode(const char *source, unsigned sourceLen, std::vector<unsigned char> &destVector)
{
unsigned char digits[2];
unsigned char byte;
bool noErrors = true;
for (; sourceLen > 1; sourceLen -= 2, source += 2)
{
digits[0] = GetHexCode(source[0]);
digits[1] = GetHexCode(source[1]);
if ((digits[0] != HEX_ERR) && (digits[1] != HEX_ERR)) {
byte = (digits[0] * 16) + digits[1];
destVector.push_back(byte);
} else {
noErrors = false;
}
}
if (sourceLen == 1) {
noErrors = false;
}
return noErrors;
}
};
@@ -0,0 +1,40 @@
#ifndef BASE64_H
#define BASE64_H
#include <string>
#include <vector>
namespace soe
{
class Base64
{
public:
static bool UUEncode(const unsigned char *source, unsigned sourceLen, char *dest, unsigned destLen);
static bool UUEncode(const unsigned char *source, unsigned sourceLen, std::string &destString);
static bool UUEncode(const std::vector<unsigned char> &source, char *dest, unsigned destLen);
static bool UUEncode(const std::vector<unsigned char> &source, std::string &destString);
static bool UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen);
static bool UUDecode(const char *source, unsigned sourceLen, std::vector<unsigned char> &destVector);
static bool UUDecode(const char *source, unsigned sourceLen, std::string &destString);
// these don't *exactly* belong here, but it's a convenient place for them
static bool HexEncode(const unsigned char *source, unsigned sourceLen, char *dest, unsigned destLen, bool lowercase = false);
static bool HexEncode(const unsigned char *source, unsigned sourceLen, std::string &destString, bool lowercase = false);
static bool HexDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen);
static bool HexDecode(const char *source, unsigned sourceLen, std::string &destString);
static bool HexDecode(const char *source, unsigned sourceLen, std::vector<unsigned char> &destVector);
private:
static unsigned UUEncodeTripleToQuadPtr(const unsigned char *triple, char *quad, unsigned bytes);
static unsigned UUEncodeTripleToQuadRef(const std::vector<unsigned char>::const_iterator &triple, char* quad, unsigned bytes);
static unsigned UUDecodeQuadToTriple(const char *quad, unsigned char *triple);
static void Init();
static unsigned char GetBase64Code(char base64char);
static unsigned char GetHexCode(char hexChar);
static const char ms_base64Table[];
};
};
#endif // BASE64_H
@@ -0,0 +1,317 @@
// MD5.cpp: implementation of the MD5 class.
//
//////////////////////////////////////////////////////////////////////
#include "MD5.h"
#include "types.h"
using namespace std;
namespace soe
{
using namespace soe;
MD5::State::State() :
state(4,0),
count(2,0),
buffer(64,0)
{
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
}
static char const init[64] =
{
-128, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
vector<char> MD5::padding(init,init+sizeof(init)/sizeof(init[0]));
MD5::MD5()
{
Init();
}
MD5::MD5(const string & input)
{
Init();
Update(input);
}
vector<int> MD5::Decode(vector<char> achar0, int i, int j)
{
vector<int> ai(16,0);
int l;
int k = l = 0;
for(; l < i; l += 4)
{
ai[k] = achar0[l + j] & 0xff | (achar0[l + 1 + j] & 0xff) << 8 | (achar0[l + 2 + j] & 0xff) << 16 | (achar0[l + 3 + j] & 0xff) << 24;
k++;
}
return ai;
}
vector<char> MD5::Encode(vector<int> ai, int i)
{
vector<char> achar0(i,0);
int k;
int j = k = 0;
for(; k < i; k += 4){
achar0[k] = (char)(ai[j] & 0xff);
achar0[k + 1] = (char)(ai[j] >> 8 & 0xff);
achar0[k + 2] = (char)(ai[j] >> 16 & 0xff);
achar0[k + 3] = (char)(ai[j] >> 24 & 0xff);
j++;
}
return achar0;
}
int MD5::FF(int i, int j, int k, int l, int i1, int j1, int k1)
{
i = uadd(i, j & k | ~j & l, i1, k1);
return uadd(rotate_left(i, j1), j);
}
vector<char> MD5::Final()
{
if (finalsNull)
{
State &state1 = state;
vector<char> achar0 = Encode(state1.count, 8);
int i = state1.count[0] >> 3 & 0x3f;
int j = i >= 56 ? 120 - i : 56 - i;
Update(state1, padding, 0, j);
Update(state1, achar0, 0, 8);
finals = state1;
finalsNull = false;
}
return Encode(finals.state, 16);
}
int MD5::GG(int i, int j, int k, int l, int i1, int j1, int k1)
{
i = uadd(i, j & l | k & ~l, i1, k1);
return uadd(rotate_left(i, j1), j);
}
int MD5::HH(int i, int j, int k, int l, int i1, int j1, int k1)
{
i = uadd(i, j ^ k ^ l, i1, k1);
return uadd(rotate_left(i, j1), j);
}
int MD5::II(int i, int j, int k, int l, int i1, int j1, int k1)
{
i = uadd(i, k ^ (j | ~l), i1, k1);
return uadd(rotate_left(i, j1), j);
}
void MD5::Init()
{
if (padding.size() == 0)
{
padding.resize(64,0);
padding[0] = -128;
}
finalsNull = true;
}
void MD5::Transform(State & state1, vector<char> achar0, int i)
{
int j = state1.state[0];
int k = state1.state[1];
int l = state1.state[2];
int i1 = state1.state[3];
vector<int> ai = Decode(achar0, 64, i);
j = FF(j, k, l, i1, ai[0], 7, 0xd76aa478);
i1 = FF(i1, j, k, l, ai[1], 12, 0xe8c7b756);
l = FF(l, i1, j, k, ai[2], 17, 0x242070db);
k = FF(k, l, i1, j, ai[3], 22, 0xc1bdceee);
j = FF(j, k, l, i1, ai[4], 7, 0xf57c0faf);
i1 = FF(i1, j, k, l, ai[5], 12, 0x4787c62a);
l = FF(l, i1, j, k, ai[6], 17, 0xa8304613);
k = FF(k, l, i1, j, ai[7], 22, 0xfd469501);
j = FF(j, k, l, i1, ai[8], 7, 0x698098d8);
i1 = FF(i1, j, k, l, ai[9], 12, 0x8b44f7af);
l = FF(l, i1, j, k, ai[10], 17, -42063);
k = FF(k, l, i1, j, ai[11], 22, 0x895cd7be);
j = FF(j, k, l, i1, ai[12], 7, 0x6b901122);
i1 = FF(i1, j, k, l, ai[13], 12, 0xfd987193);
l = FF(l, i1, j, k, ai[14], 17, 0xa679438e);
k = FF(k, l, i1, j, ai[15], 22, 0x49b40821);
j = GG(j, k, l, i1, ai[1], 5, 0xf61e2562);
i1 = GG(i1, j, k, l, ai[6], 9, 0xc040b340);
l = GG(l, i1, j, k, ai[11], 14, 0x265e5a51);
k = GG(k, l, i1, j, ai[0], 20, 0xe9b6c7aa);
j = GG(j, k, l, i1, ai[5], 5, 0xd62f105d);
i1 = GG(i1, j, k, l, ai[10], 9, 0x2441453);
l = GG(l, i1, j, k, ai[15], 14, 0xd8a1e681);
k = GG(k, l, i1, j, ai[4], 20, 0xe7d3fbc8);
j = GG(j, k, l, i1, ai[9], 5, 0x21e1cde6);
i1 = GG(i1, j, k, l, ai[14], 9, 0xc33707d6);
l = GG(l, i1, j, k, ai[3], 14, 0xf4d50d87);
k = GG(k, l, i1, j, ai[8], 20, 0x455a14ed);
j = GG(j, k, l, i1, ai[13], 5, 0xa9e3e905);
i1 = GG(i1, j, k, l, ai[2], 9, 0xfcefa3f8);
l = GG(l, i1, j, k, ai[7], 14, 0x676f02d9);
k = GG(k, l, i1, j, ai[12], 20, 0x8d2a4c8a);
j = HH(j, k, l, i1, ai[5], 4, 0xfffa3942);
i1 = HH(i1, j, k, l, ai[8], 11, 0x8771f681);
l = HH(l, i1, j, k, ai[11], 16, 0x6d9d6122);
k = HH(k, l, i1, j, ai[14], 23, 0xfde5380c);
j = HH(j, k, l, i1, ai[1], 4, 0xa4beea44);
i1 = HH(i1, j, k, l, ai[4], 11, 0x4bdecfa9);
l = HH(l, i1, j, k, ai[7], 16, 0xf6bb4b60);
k = HH(k, l, i1, j, ai[10], 23, 0xbebfbc70);
j = HH(j, k, l, i1, ai[13], 4, 0x289b7ec6);
i1 = HH(i1, j, k, l, ai[0], 11, 0xeaa127fa);
l = HH(l, i1, j, k, ai[3], 16, 0xd4ef3085);
k = HH(k, l, i1, j, ai[6], 23, 0x4881d05);
j = HH(j, k, l, i1, ai[9], 4, 0xd9d4d039);
i1 = HH(i1, j, k, l, ai[12], 11, 0xe6db99e5);
l = HH(l, i1, j, k, ai[15], 16, 0x1fa27cf8);
k = HH(k, l, i1, j, ai[2], 23, 0xc4ac5665);
j = II(j, k, l, i1, ai[0], 6, 0xf4292244);
i1 = II(i1, j, k, l, ai[7], 10, 0x432aff97);
l = II(l, i1, j, k, ai[14], 15, 0xab9423a7);
k = II(k, l, i1, j, ai[5], 21, 0xfc93a039);
j = II(j, k, l, i1, ai[12], 6, 0x655b59c3);
i1 = II(i1, j, k, l, ai[3], 10, 0x8f0ccc92);
l = II(l, i1, j, k, ai[10], 15, 0xffeff47d);
k = II(k, l, i1, j, ai[1], 21, 0x85845dd1);
j = II(j, k, l, i1, ai[8], 6, 0x6fa87e4f);
i1 = II(i1, j, k, l, ai[15], 10, 0xfe2ce6e0);
l = II(l, i1, j, k, ai[6], 15, 0xa3014314);
k = II(k, l, i1, j, ai[13], 21, 0x4e0811a1);
j = II(j, k, l, i1, ai[4], 6, 0xf7537e82);
i1 = II(i1, j, k, l, ai[11], 10, 0xbd3af235);
l = II(l, i1, j, k, ai[2], 15, 0x2ad7d2bb);
k = II(k, l, i1, j, ai[9], 21, 0xeb86d391);
state1.state[0] += j;
state1.state[1] += k;
state1.state[2] += l;
state1.state[3] += i1;
}
void MD5::Update(char char0)
{
vector<char> achar0(1,0);
achar0[0] = char0;
Update(achar0, 1);
}
void MD5::Update(State & state1, vector<char> achar0, int i, int j)
{
finalsNull = true;
if (j - i > (int)achar0.size())
j = achar0.size() - i;
int k = state1.count[0] >> 3 & 0x3f;
if ((state1.count[0] += j << 3) < j << 3)
state1.count[1]++;
state1.count[1] += j >> 29;
int l = 64 - k;
int j1;
if(j >= l)
{
for(int i1 = 0; i1 < l; i1++)
state1.buffer[i1 + k] = achar0[i1 + i];
Transform(state1, state1.buffer, 0);
for(j1 = l; j1 + 63 < j; j1 += 64)
Transform(state1, achar0, j1);
k = 0;
}
else
{
j1 = 0;
}
if (j1 < j)
{
int k1 = j1;
for(; j1 < j; j1++)
state1.buffer[(k + j1) - k1] = achar0[j1 + i];
}
}
void MD5::Update(string s)
{
vector<char> achar(s.size(),0);
for (int i=0; i<(int)s.size(); i++)
achar[i] = s[i];
Update( achar, achar.size() );
}
void MD5::Update(vector<char> achar0)
{
Update(achar0, 0, achar0.size());
}
void MD5::Update(vector<char> achar0, int i)
{
Update(state, achar0, 0, i);
}
void MD5::Update(vector<char> achar0, int i, int j)
{
Update(state, achar0, i, j);
}
string MD5::asHex()
{
return asHex(Final());
}
string MD5::asHex(vector<char> achar0)
{
const string hex = "0123456789abcdef";
string stringbuffer;
for (int i = 0; i < (int)achar0.size(); i++)
{
stringbuffer += hex.substr((achar0[i] >> 4) & 0x0f,1);
stringbuffer += hex.substr(achar0[i] & 0x0f,1);
}
return stringbuffer;
}
int MD5::rotate_left(int i, int j)
{
unsigned i1 = i;
unsigned j1 = j;
return i1 << j1 | i1 >> (32 - j1);
}
int MD5::uadd(int i, int j)
{
int64 l = (int64)i & 0x0ffffffffL;
int64 l1 = (int64)j & 0x0ffffffffL;
l += l1;
return (int)(l & 0x0ffffffffL);
}
int MD5::uadd(int i, int j, int k)
{
return uadd(uadd(i, j), k);
}
int MD5::uadd(int i, int j, int k, int l)
{
return uadd(uadd(i, j, k), l);
}
};
@@ -0,0 +1,66 @@
// MD5.h: interface for the MD5 class.
//
//////////////////////////////////////////////////////////////////////
#ifndef MD5_H
#define MD5_H
#include <string>
#include <vector>
namespace soe
{
class MD5
{
struct State
{
State();
std::vector<int> state;
std::vector<int> count;
std::vector<char> buffer;
};
public:
MD5::MD5();
MD5(const std::string &input);
void Init();
std::vector<char> Final();
void Update(char char0);
void Update(State & state1, std::vector<char> achar0, int i, int j);
void Update(std::string s);
void Update(std::vector<char> achar0);
void Update(std::vector<char> achar0, int i);
void Update(std::vector<char> achar0, int i, int j);
std::string asHex();
static std::string asHex(std::vector<char> achar0);
private:
std::vector<int> Decode(std::vector<char> achar0, int i, int j);
std::vector<char> Encode(std::vector<int> ai, int i);
int FF(int i, int j, int k, int l, int i1, int j1, int k1);
int GG(int i, int j, int k, int l, int i1, int j1, int k1);
int HH(int i, int j, int k, int l, int i1, int j1, int k1);
int II(int i, int j, int k, int l, int i1, int j1, int k1);
void Transform(State & state1, std::vector<char> achar0, int i);
int rotate_left(int i, int j);
int uadd(int i, int j);
int uadd(int i, int j, int k);
int uadd(int i, int j, int k, int l);
private:
State state;
State finals;
bool finalsNull;
static std::vector<char> padding;
};
};
#endif // MD5_H
@@ -0,0 +1,128 @@
#ifdef WIN32
#pragma warning( disable: 4786 )
#endif
#include <stdio.h>
#include "basicConfig.h"
#include "profile.h"
#ifdef WIN32
#define snprintf _snprintf
#endif
using namespace std;
////////////////////////////////////////////////////////////////////////////////
BasicConfig::BasicConfig()
: mParamMap()
, mConfigFileName()
{
}
BasicConfig::~BasicConfig()
{
}
void BasicConfig::Push(const soe::NameValuePairs_t & paramValuePairs)
{
for (soe::NameValuePairs_t::const_iterator pIter = paramValuePairs.begin(); pIter != paramValuePairs.end(); pIter++)
{
Set(pIter->name, pIter->value);
}
}
void BasicConfig::Pull(soe::NameValuePairs_t & paramValuePairs) const
{
size_t index = paramValuePairs.size();
paramValuePairs.resize(index + mParamMap.size());
for (ConfigMap_t::const_iterator pIter = mParamMap.begin(); pIter != mParamMap.end(); pIter++, index++)
{
paramValuePairs[index].name = pIter->first;
paramValuePairs[index].value = pIter->second.first;
}
}
void BasicConfig::Load(const std::string & configFile)
{
static const char * config_delimiters1 = " \t\n:[]=";
static const char * config_delimiters2 = "\t\n\"#";
Profile profile("BasicConfig::Load()");
FILE * file;
if (!(file = fopen(configFile.c_str(), "rt")))
return;
char buffer[1024];
while(fgets(buffer, 1024, file))
{
char * key = 0;
char * value = 0;
// read key and value off line
key = strtok(buffer, config_delimiters1);
if (!key || key[0] == '#')
continue;
if (key)
{
value = key + strlen(key) + 1;
while (*value == ' ' || *value == '\t')
value++;
value = strtok(value, config_delimiters2);
if (value)
{
while (value[strlen(value)-1] == ' ')
value[strlen(value)-1] = 0;
}
}
// insert key/value pair into the param map
if (value)
mParamMap[key] = ConfigPair_t(value, atoi(value));
else
mParamMap[key] = ConfigPair_t("", 0);
}
mConfigFileName = configFile;
fclose(file);
OnLoad();
}
void BasicConfig::Set(const std::string & param, int value)
{
// convert integer to string
char buffer[64];
snprintf(buffer, sizeof(buffer), "%d", value);
mParamMap[param] = ConfigPair_t(buffer, value);
}
void BasicConfig::Set(const std::string & param, const std::string & value)
{
mParamMap[param] = ConfigPair_t(value, atoi(value.c_str()));
}
int BasicConfig::GetNumber(const std::string & param)
{
return mParamMap[param].second;
}
std::string BasicConfig::GetString(const std::string & param)
{
return mParamMap[param].first;
}
bool BasicConfig::IsSet(const std::string & param)
{
return mParamMap.find(param) != mParamMap.end();
}
void BasicConfig::OnLoad()
{
}
@@ -0,0 +1,43 @@
#ifndef SERVER__BASIC_CONFIG_H
#define SERVER__BASIC_CONFIG_H
#include <string>
#include <map>
#include <vector>
#include "Api/apiTypeNameValuePair.h"
#include "stringutils.h"
class BasicConfig
{
public:
typedef std::pair<std::string,int> ConfigPair_t;
typedef std::map<soe::lowerCaseString, ConfigPair_t> ConfigMap_t;
BasicConfig();
virtual ~BasicConfig();
void Push(const soe::NameValuePairs_t & paramValuePairs);
void Pull(soe::NameValuePairs_t & paramValuePairs) const;
void Load(const std::string & configFile);
void Set(const std::string & param, int value);
void Set(const std::string & param, const std::string & value);
int GetNumber(const std::string & param);
std::string GetString(const std::string & param);
bool IsSet(const std::string & param);
std::string GetConfigFileName() const { return mConfigFileName; }
virtual void OnLoad();
protected:
ConfigMap_t mParamMap;
std::string mConfigFileName;
private:
char * pConfig; // pointer to file memory
char * pCursor; // current cursor into file memory
};
#endif
@@ -0,0 +1,285 @@
/*------------------------------------------------------
CmdLine
A utility for parsing command lines.
Copyright (C) 1999 Chris Losinger, Smaller Animals Software.
http://www.smalleranimals.com
This software is provided 'as-is', without any express
or implied warranty. In no event will the authors be
held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software
for any purpose, including commercial applications, and
to alter it and redistribute it freely, subject to the
following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
See SACmds.h for more info.
------------------------------------------------------*/
#pragma warning (disable: 4267)
// if you're using MFC, you'll need to un-comment this line
// #include "stdafx.h"
#include "cmdLine.h"
//#include "crtdbg.h"
#include <ctype.h>
#ifdef NAMESPACE
namespace NAMESPACE
{
#endif
/*------------------------------------------------------
int CmdLine::SplitLine(int argc, char **argv)
parse the command line into switches and arguments
returns number of switches found
------------------------------------------------------*/
int CmdLine::SplitLine(int argc, char **argv)
{
clear();
StringType curParam; // current argv[x]
// skip the exe name (start with i = 1)
for (int i = 1; i < argc; i++)
{
// if it's a switch, start a new CmdLine
if (IsSwitch(argv[i]))
{
curParam = argv[i];
StringType arg;
// look at next input string to see if it's a switch or an argument
if (i + 1 < argc)
{
if (!IsSwitch(argv[i + 1]))
{
// it's an argument, not a switch
arg = argv[i + 1];
// skip to next
i++;
}
else
{
arg = "";
}
}
// add it
CmdParam cmd;
// only add non-empty args
if (arg != "")
{
cmd.m_strings.push_back(arg);
}
// add the CmdParam to 'this'
std::pair<CmdLine::iterator, bool> res = insert(CmdLine::value_type(curParam, cmd));
if (res.second) continue;
}
else
{
// it's not a new switch, so it must be more stuff for the last switch
// ...let's add it
CmdLine::iterator theIterator;
// get an iterator for the current param
theIterator = find(curParam);
if (theIterator!=end())
{
(*theIterator).second.m_strings.push_back(argv[i]);
}
else
{
// ??
}
}
}
return size();
}
/*------------------------------------------------------
protected member function
test a parameter to see if it's a switch :
switches are of the form : -x
where 'x' is one or more characters.
the first character of a switch must be non-numeric!
------------------------------------------------------*/
bool CmdLine::IsSwitch(const char *pParam)
{
if (pParam==NULL)
return false;
// switches must non-empty
// must have at least one character after the '-'
int len = strlen(pParam);
if (len <= 1)
{
return false;
}
// switches always start with '-'
if (pParam[0]=='-')
{
// allow negative numbers as arguments.
// ie., don't count them as switches
return (!isdigit(pParam[1]));
}
else
{
return false;
}
}
/*------------------------------------------------------
bool CmdLine::HasSwitch(const char *pSwitch)
was the switch found on the command line ?
ex. if the command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
call return
---- ------
cmdLine.HasSwitch("-a") true
cmdLine.HasSwitch("-z") false
------------------------------------------------------*/
bool CmdLine::HasSwitch(const char *pSwitch)
{
CmdLine::iterator theIterator;
theIterator = find(pSwitch);
return (theIterator!=end());
}
/*------------------------------------------------------
StringType CmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault)
fetch an argument associated with a switch . if the parameter at
index iIdx is not found, this will return the default that you
provide.
example :
command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
call return
---- ------
cmdLine.GetSafeArgument("-a", 0, "zz") p1
cmdLine.GetSafeArgument("-a", 1, "zz") p2
cmdLine.GetSafeArgument("-b", 0, "zz") p4
cmdLine.GetSafeArgument("-b", 1, "zz") zz
------------------------------------------------------*/
StringType CmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault)
{
StringType sRet;
if (pDefault!=NULL)
sRet = pDefault;
try
{
sRet = GetArgument(pSwitch, iIdx);
}
catch (...)
{
}
return sRet;
}
/*------------------------------------------------------
StringType CmdLine::GetArgument(const char *pSwitch, int iIdx)
fetch a argument associated with a switch. throws an exception
of (int)0, if the parameter at index iIdx is not found.
example :
command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
call return
---- ------
cmdLine.GetArgument("-a", 0) p1
cmdLine.GetArgument("-b", 1) throws (int)0, returns an empty string
------------------------------------------------------*/
StringType CmdLine::GetArgument(const char *pSwitch, int iIdx)
{
if (HasSwitch(pSwitch))
{
CmdLine::iterator theIterator;
theIterator = find(pSwitch);
if (theIterator!=end())
{
if ((int)(*theIterator).second.m_strings.size() > iIdx)
{
return (*theIterator).second.m_strings[iIdx];
}
}
}
throw (int)0;
return "";
}
/*------------------------------------------------------
int CmdLine::GetArgumentCount(const char *pSwitch)
returns the number of arguments found for a given switch.
returns -1 if the switch was not found
------------------------------------------------------*/
int CmdLine::GetArgumentCount(const char *pSwitch)
{
int iArgumentCount = -1;
if (HasSwitch(pSwitch))
{
CmdLine::iterator theIterator;
theIterator = find(pSwitch);
if (theIterator!=end())
{
iArgumentCount = (*theIterator).second.m_strings.size();
}
}
return iArgumentCount;
}
#ifdef NAMESPACE
}
#endif
@@ -0,0 +1,245 @@
/*------------------------------------------------------
CmdLine
A utility for parsing command lines.
Copyright (C) 1999 Chris Losinger, Smaller Animals Software.
http://www.smalleranimals.com
This software is provided 'as-is', without any express
or implied warranty. In no event will the authors be
held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software
for any purpose, including commercial applications, and
to alter it and redistribute it freely, subject to the
following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
-------------------------
Example :
Our example application uses a command line that has two
required switches and two optional switches. The app should abort
if the required switches are not present and continue with default
values if the optional switches are not present.
Sample command line :
MyApp.exe -p1 text1 text2 -p2 "this is a big argument" -opt1 -55 -opt2
Switches -p1 and -p2 are required.
p1 has two arguments and p2 has one.
Switches -opt1 and -opt2 are optional.
opt1 requires a numeric argument.
opt2 has no arguments.
Also, assume that the app displays a 'help' screen if the '-h' switch
is present on the command line.
#include "CmdLine.h"
void main(int argc, char **argv)
{
// our cmd line parser object
CmdLine cmdLine;
// parse argc,argv
if (cmdLine.SplitLine(argc, argv) < 1)
{
// no switches were given on the command line, abort
ASSERT(0);
exit(-1);
}
// test for the 'help' case
if (cmdLine.HasSwitch("-h"))
{
show_help();
exit(0);
}
// get the required arguments
StringType p1_1, p1_2, p2_1;
try
{
// if any of these fail, we'll end up in the catch() block
p1_1 = cmdLine.GetArgument("-p1", 0);
p1_2 = cmdLine.GetArgument("-p1", 1);
p2_1 = cmdLine.GetArgument("-p2", 0);
}
catch (...)
{
// one of the required arguments was missing, abort
ASSERT(0);
exit(-1);
}
// get the optional parameters
// convert to an int, default to '100'
int iOpt1Val = atoi(cmdLine.GetSafeArgument("-opt1", 0, 100));
// since opt2 has no arguments, just test for the presence of
// the '-opt2' switch
bool bOptVal2 = cmdLine.HasSwitch("-opt2");
.... and so on....
}
If this class is used in an MFC application, StringType is CString, else
it uses the STL 'string' type.
If this is an MFC app, you can use the __argc and __argv macros from
you CYourWinApp::InitInstance() function in place of the standard argc
and argv variables.
------------------------------------------------------*/
#ifndef SACMDSH
#define SACMDSH
//#include <iostream> // you may need this
#include <map>
#include <string>
#include <vector>
//using namespace std ;
#ifdef NAMESPACE
namespace NAMESPACE
{
#endif
#ifdef __AFX_H__
// if we're using MFC, use CStrings
#define StringType CString
#else
// if we're not using MFC, use STL strings
#define StringType std::string
#endif
// tell the compiler to shut up
#pragma warning(disable:4786)
// handy little container for our argument vector
struct CmdParam
{
std::vector<StringType> m_strings;
};
// this class is actually a map of strings to vectors
typedef std::map<StringType, CmdParam> _CmdLine;
// the command line parser class
class CmdLine : public _CmdLine
{
public:
/*------------------------------------------------------
int CmdLine::SplitLine(int argc, char **argv)
parse the command line into switches and arguments.
returns number of switches found
------------------------------------------------------*/
int SplitLine(int argc, char **argv);
/*------------------------------------------------------
bool CmdLine::HasSwitch(const char *pSwitch)
was the switch found on the command line ?
ex. if the command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
call return
---- ------
cmdLine.HasSwitch("-a") true
cmdLine.HasSwitch("-z") false
------------------------------------------------------*/
bool HasSwitch(const char *pSwitch);
/*------------------------------------------------------
StringType CmdLine::GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault)
fetch an argument associated with a switch . if the parameter at
index iIdx is not found, this will return the default that you
provide.
example :
command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
call return
---- ------
cmdLine.GetSafeArgument("-a", 0, "zz") p1
cmdLine.GetSafeArgument("-a", 1, "zz") p2
cmdLine.GetSafeArgument("-b", 0, "zz") p4
cmdLine.GetSafeArgument("-b", 1, "zz") zz
------------------------------------------------------*/
StringType GetSafeArgument(const char *pSwitch, int iIdx, const char *pDefault);
/*------------------------------------------------------
StringType CmdLine::GetArgument(const char *pSwitch, int iIdx)
fetch a argument associated with a switch. throws an exception
of (int)0, if the parameter at index iIdx is not found.
example :
command line is : app.exe -a p1 p2 p3 -b p4 -c -d p5
call return
---- ------
cmdLine.GetArgument("-a", 0) p1
cmdLine.GetArgument("-b", 1) throws (int)0, returns an empty string
------------------------------------------------------*/
StringType GetArgument(const char *pSwitch, int iIdx);
/*------------------------------------------------------
int CmdLine::GetArgumentCount(const char *pSwitch)
returns the number of arguments found for a given switch.
returns -1 if the switch was not found
------------------------------------------------------*/
int GetArgumentCount(const char *pSwitch);
protected:
/*------------------------------------------------------
protected member function
test a parameter to see if it's a switch :
switches are of the form : -x
where 'x' is one or more characters.
the first character of a switch must be non-numeric!
------------------------------------------------------*/
bool IsSwitch(const char *pParam);
};
#ifdef NAMESPACE
}
#endif
#endif
@@ -0,0 +1,178 @@
#include "date.h"
#ifdef WIN32
# include <sys/types.h>
# include <sys/timeb.h>
#endif
#include <stdio.h>
#include <time.h>
#ifdef WIN32
#define snprintf _snprintf
#endif
namespace soe
{
static time_t date_timegm(struct tm *T)
{
#ifdef WIN32
struct _timeb t;
memset((void*)&t, 0, sizeof(t));
t.timezone = 0;
t.dstflag = -1;
_ftime(&t);
T->tm_min -= t.timezone;
T->tm_isdst = 0;
return mktime(T);
#else
return timegm(T);
#endif
}
Date::Date(time_t src)
: mYear(1900)
, mMonth(1)
, mDay(1)
, mHour(0)
, mMinute(0)
, mSecond(0)
{
struct tm timeStruct;
struct tm *gotTime = NULL;
#ifdef WIN32
gotTime = gmtime(&src);
#else
gotTime = gmtime_r(&src, &timeStruct);
#endif
if (gotTime) {
#ifdef WIN32
timeStruct = *gotTime;
#endif
mYear = timeStruct.tm_year + 1900;
mMonth = timeStruct.tm_mon + 1;
mDay = timeStruct.tm_mday;
mHour = timeStruct.tm_hour;
mMinute = timeStruct.tm_min;
mSecond = timeStruct.tm_sec;
}
}
Date::Date(const std::string &src)
: mYear(0)
, mMonth(0)
, mDay(0)
, mHour(0)
, mMinute(0)
, mSecond(0)
{
#ifdef WIN32
// This code should actually be portable to Linux as well - rlsmith 05/31/2006
int year = 0;
int month = 0;
int day = 0;
int hour = 0;
int minute = 0;
int second = 0;
int res(0);
if (
(6 == (res=sscanf(src.c_str(), "%4d-%02d-%02d %02d:%02d:%02d", &year, &month, &day, &hour, &minute, &second))) ||
(6 == (res=sscanf(src.c_str(), "%4d/%02d/%02d %02d:%02d:%02d", &year, &month, &day, &hour, &minute, &second))) ||
(6 == (res=sscanf(src.c_str(), "%02d-%02d-%4d %02d:%02d:%02d", &month, &day, &year, &hour, &minute, &second))) ||
(6 == (res=sscanf(src.c_str(), "%02d/%02d/%4d %02d:%02d:%02d", &month, &day, &year, &hour, &minute, &second))) ||
(3 == (res=sscanf(src.c_str(), "%02d-%02d-%4d", &month, &day, &year))) ||
(3 == (res=sscanf(src.c_str(), "%02d/%02d/%4d", &month, &day, &year))) ||
(3 == (res=sscanf(src.c_str(), "%4d-%02d-%02d", &year, &month, &day))) ||
(3 == (res=sscanf(src.c_str(), "%4d/%02d/%02d", &year, &month, &day)))
)
{
if (res < 6) // not all time values were parsed, so reset time to 00:00:00
{
mHour = 0;
mMinute = 0;
mSecond = 0;
}
mYear = year;
mMonth = month;
mDay = day;
mHour = hour;
mMinute = minute;
mSecond = second;
}
#else
tm timeStruct;
memset(&timeStruct, 0, sizeof(timeStruct));
if (
strptime(src.c_str(), "%Y-%m-%d %H:%M:%S", &timeStruct) || strptime(src.c_str(), "%Y/%m/%d %H:%M:%S", &timeStruct)
|| strptime(src.c_str(), "%m-%d-%Y %H:%M:%S", &timeStruct) || strptime(src.c_str(), "%m/%d/%Y %H:%M:%S", &timeStruct)
|| strptime(src.c_str(), "%Y-%m-%d", &timeStruct) || strptime(src.c_str(), "%Y/%m/%d", &timeStruct)
|| strptime(src.c_str(), "%m-%d-%Y", &timeStruct) || strptime(src.c_str(), "%m/%d/%Y", &timeStruct)
)
{
mYear = timeStruct.tm_year + 1900;
mMonth = timeStruct.tm_mon + 1;
mDay = timeStruct.tm_mday;
mHour = timeStruct.tm_hour;
mMinute = timeStruct.tm_min;
mSecond = timeStruct.tm_sec;
}
#endif
}
Date::operator std::string() const
{
char buffer[256];
snprintf(buffer, sizeof(buffer), PRINT_FORMAT(), mYear, mMonth, mDay, mHour, mMinute, mSecond);
return std::string(buffer);
}
Date::operator time_t() const
{
struct tm timeStruct;
timeStruct.tm_year = mYear - 1900;
timeStruct.tm_mon = mMonth - 1;
timeStruct.tm_mday = mDay;
timeStruct.tm_hour = mHour;
timeStruct.tm_min = mMinute;
timeStruct.tm_sec = mSecond;
time_t t = date_timegm(&timeStruct);
return t;
}
#define COMPARE_MEMBER(__member_name__, __oper__) \
if (__member_name__ != other.__member_name__) { \
return (__member_name__ __oper__ other.__member_name__); \
} else
#define COMPARE_MEMBER_END(__member_name__, __oper__) \
{ \
return (__member_name__ __oper__ other.__member_name__); \
}
#define COMPARE_DATE_OPER_IMPL(__oper__) \
bool Date::operator __oper__(const Date & other) const \
{ \
COMPARE_MEMBER(mYear, __oper__) \
COMPARE_MEMBER(mMonth, __oper__) \
COMPARE_MEMBER(mDay, __oper__) \
COMPARE_MEMBER(mHour, __oper__) \
COMPARE_MEMBER(mMinute, __oper__) \
COMPARE_MEMBER_END(mSecond, __oper__) \
}
COMPARE_DATE_OPER_IMPL(>)
COMPARE_DATE_OPER_IMPL(>=)
COMPARE_DATE_OPER_IMPL(==)
COMPARE_DATE_OPER_IMPL(<=)
COMPARE_DATE_OPER_IMPL(<)
}
@@ -0,0 +1,94 @@
#ifndef SOE__DATE_H
#define SOE__DATE_H
#include "types.h"
#include "serializeClasses.h"
namespace soe
{
struct Date
{
Date()
: mYear(0)
, mMonth(0)
, mDay(0)
, mHour(0)
, mMinute(0)
, mSecond(0)
{ }
Date(time_t src);
Date(const std::string &src);
operator std::string() const;
operator time_t() const;
bool operator >(const Date & other) const;
bool operator >=(const Date & other) const;
bool operator ==(const Date & other) const;
bool operator <=(const Date & other) const;
bool operator <(const Date & other) const;
static const char * const DATA_FORMAT() { return "YYYY-MM-DD HH24:MI:SS"; }
static const char * const PRINT_FORMAT() { return "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d"; }
soe::uint16 mYear;
soe::uint8 mMonth;
soe::uint8 mDay;
soe::uint8 mHour;
soe::uint8 mMinute;
soe::uint8 mSecond;
};
inline unsigned Read(const unsigned char * stream, unsigned size, Date & data, unsigned maxLen = 1, unsigned version = 0)
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = Read(stream + bytesTotal, size - bytesTotal, data.mYear));
if (!bytes) return 0;
bytesTotal += (bytes = Read(stream + bytesTotal, size - bytesTotal, data.mMonth));
if (!bytes) return 0;
bytesTotal += (bytes = Read(stream + bytesTotal, size - bytesTotal, data.mDay));
if (!bytes) return 0;
bytesTotal += (bytes = Read(stream + bytesTotal, size - bytesTotal, data.mHour));
if (!bytes) return 0;
bytesTotal += (bytes = Read(stream + bytesTotal, size - bytesTotal, data.mMinute));
if (!bytes) return 0;
bytesTotal += (bytes = Read(stream + bytesTotal, size - bytesTotal, data.mSecond));
if (!bytes) return 0;
return bytesTotal;
}
inline unsigned Write(unsigned char * stream, unsigned size, const Date & data, unsigned version = 0)
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = Write(stream + bytesTotal, size - bytesTotal, data.mYear));
if (!bytes) return 0;
bytesTotal += (bytes = Write(stream + bytesTotal, size - bytesTotal, data.mMonth));
if (!bytes) return 0;
bytesTotal += (bytes = Write(stream + bytesTotal, size - bytesTotal, data.mDay));
if (!bytes) return 0;
bytesTotal += (bytes = Write(stream + bytesTotal, size - bytesTotal, data.mHour));
if (!bytes) return 0;
bytesTotal += (bytes = Write(stream + bytesTotal, size - bytesTotal, data.mMinute));
if (!bytes) return 0;
bytesTotal += (bytes = Write(stream + bytesTotal, size - bytesTotal, data.mSecond));
if (!bytes) return 0;
return bytesTotal;
}
#ifdef PRINTABLE_MESSAGES
inline int Print(char * stream, unsigned size, const Date & data, unsigned maxDepth = INT_MAX)
{
return snprintf(stream, size, Date::PRINT_FORMAT(), data.mYear, data.mMonth, data.mDay, data.mHour, data.mMinute, data.mSecond);
}
#endif
}
#endif
@@ -0,0 +1,227 @@
#ifndef _SOE_DATE_UTILS_H_
#define _SOE_DATE_UTILS_H_
#include <time.h>
#ifdef USE_ICU
#include <unicode/calendar.h>
#include <unicode/timezone.h>
#include <unicode/utypes.h>
#endif
#define DST_OFFSET_MINUTES_USA 60 // For USA, offset is 1 hour (60 minutes) for Daylight Saving Time
namespace soe
{
inline time_t startOfWeek(time_t now, int offset)
{
time_t result = now;
result += (offset * 7 * 24 * 60 * 60);//adjust time by #seconds in week for every week offset specifies (could be negative)
tm nowTm;
//get tm struct
memcpy(&nowTm, localtime(&now), sizeof(tm));
//reduce input time_t by seconds applied to the current week in progress
result -= (nowTm.tm_wday * 24 * 60 * 60);//reduce by whole days that have passed since beginning of week
result -= (nowTm.tm_hour * 60 * 60);//reduce by seconds that have passed today in complete hours today
result -= (nowTm.tm_min * 60);//reduce by seconds that have passed in partial hours today
result -= (nowTm.tm_sec);//reduce by seconds that have passed in partial minutes today
return result;
}
inline time_t startOfDay(time_t now, int offset)
{
time_t result = now;
now += (offset * 24 * 60 * 60);//adjust time by #seconds in day for every day offset specifies (could be negative)
tm nowTm;
//get tm struct
memcpy(&nowTm, localtime(&now), sizeof(tm));
//reset hour/min/sec so go to beginning of day
nowTm.tm_hour = 0;
nowTm.tm_min = 0;
nowTm.tm_sec = 0;
//turn that into time_t result
result = mktime(&nowTm);
return result;
}
inline time_t startOfMonth(time_t now, int offset)
{
//TODO: seriously check this algorithm
time_t result = now;
//note: can't do pre-adjustment for offset of months, since months can vary in length
tm nowTm;
//get tm struct
memcpy(&nowTm, localtime(&now), sizeof(tm));
nowTm.tm_hour = 0;
nowTm.tm_min = 0;
nowTm.tm_sec = 0;
nowTm.tm_mday = 1;//day of month will be 1, since we want time_t of beginning of month
//calc new month (and possibly year) from offset
if (offset < 0)
{
if (nowTm.tm_mon >= (-1 * offset))
{
//stay in current year
nowTm.tm_mon += offset;
}
else
{
nowTm.tm_mon = nowTm.tm_mon + (offset % 12) - 12;
//need to adjust year also
if (-12 <= offset)
{
nowTm.tm_year -= 1;
}
else
{
nowTm.tm_year += (offset / 12);
}
}
}
else
{
if (11 - nowTm.tm_mon <= offset)
{
//stay in current year
nowTm.tm_mon += offset;
}
else
{
nowTm.tm_mon = (nowTm.tm_mon + (offset % 12)) - 12;
//need to adjust year also
if (12 >= offset)
{
nowTm.tm_year += 1;
}
else
{
nowTm.tm_year += (offset / 12);
}
}
}
//turn that into time_t result
result = mktime(&nowTm);
return result;
}
inline bool isTimeBeforeDay(time_t now, time_t check, int offset=0)
{
return (startOfDay(now, offset) > check);
}
inline bool isTimeBeforeWeek(time_t now, time_t check, int offset=0)
{
return (startOfWeek(now, offset) > check);
}
inline bool isTimeBeforeMonth(time_t now, time_t check, int offset=0)
{
return (startOfMonth(now, offset) > check);
}
inline time_t localTimeToGmt(int dstOffsetMinutes = DST_OFFSET_MINUTES_USA)
{
time_t localTime = time(NULL);
struct tm gt = *(gmtime(&localTime));
struct tm lt = *(localtime(&localTime));
bool isDst = (lt.tm_isdst? true:false);
return (mktime(&gt) - (isDst? (60 * dstOffsetMinutes):0));
}
#ifdef USE_ICU
inline int getOffsets(const char *id, time_t gmtTime, bool isLocal, int & timeZoneOffsetSecs, int & dstOffsetSecs)
{
double d = gmtTime * 1000.00;
UDate date(d);
UBool local(isLocal);
int32_t rawOffsetMS;
int32_t dstOffsetMS;
UErrorCode ec = U_ZERO_ERROR;
int retval(0);
TimeZone *tz;
if (!id)
tz = TimeZone::createDefault();
else
tz = TimeZone::createTimeZone(id);
Calendar *cal = Calendar::createInstance(tz, ec);
if (U_FAILURE(ec))
{
//cerr<<"cal failed: ec=("<<ec<<"): "<<u_errorName(ec)<<endl;
return ec;
}
//date = cal->getNow();
tz->getOffset(date, local, rawOffsetMS, dstOffsetMS, ec);
if (U_FAILURE(ec))
{
//cerr<<"tz failed: ec=("<<ec<<"): "<<u_errorName(ec)<<endl;
return ec;
}
timeZoneOffsetSecs = rawOffsetMS/1000;
dstOffsetSecs = dstOffsetMS/1000;
return retval;
}
inline int getGMT(time_t & theTime, const char *id = NULL)
{
UDate date;
UErrorCode ec;
int retval(0);
UBool isLocal(true);
int32_t rawOffsetMS;
int32_t dstOffsetMS;
//UnicodeString ID = UnicodeString(id);
TimeZone *tz;
if (!id)
tz = TimeZone::createDefault();
else
tz = TimeZone::createTimeZone(id);
Calendar *cal = Calendar::createInstance(tz, ec);
if (U_FAILURE(ec))
{
//cerr<<"cal failed: ec=("<<ec<<"): "<<u_errorName(ec)<<endl;
return ec;
}
date = cal->getNow(); //FIXME: this is not returning UTC. it is our time in UTC.
//date = cal->getTime(ec);
tz->getOffset(date, isLocal, rawOffsetMS, dstOffsetMS, ec);
UDate tmpDate = date + rawOffsetMS + (cal->inDaylightTime(ec) ? dstOffsetMS : 0);
theTime = (long)(tmpDate/1000.00);
return retval;
}
#endif
}
#endif
@@ -0,0 +1,103 @@
#ifndef EXPIRATION_QUEUE_H
#define EXPIRATION_QUEUE_H
#include <time.h>
#include <map>
#include <set>
template<typename T, typename TimeType = time_t>
class expiration_queue
{
public:
expiration_queue() { }
virtual ~expiration_queue() { }
bool empty() const { return m_expirationMap.empty(); }
bool contains_expired_items(TimeType when) const;
bool contains_item(const T & item) const;
size_t size() const { return m_itemMap.size(); }
const T & top() const;
bool insert(const T & item, TimeType expiration_time);
bool erase(const T & item);
void clear();
private:
typedef std::set<T> item_set_t;
typedef std::map<TimeType , item_set_t> expiration_map_t;
typedef std::map<T, TimeType> item_map_t;
expiration_map_t m_expirationMap;
item_map_t m_itemMap;
};
template<typename T, typename TimeType>
bool expiration_queue<T, TimeType>::contains_expired_items(TimeType when) const
{
return (!m_expirationMap.empty() &&
m_expirationMap.begin()->first <= when);
}
template<typename T, typename TimeType>
bool expiration_queue<T, TimeType>::contains_item(const T & item) const
{
return (m_itemMap.find(item) != m_itemMap.end());
}
template<typename T, typename TimeType>
const T & expiration_queue<T, TimeType>::top() const
{
static T dummy;
if (!m_expirationMap.empty() && !m_expirationMap.begin()->second.empty()) {
const item_set_t & firstSet = m_expirationMap.begin()->second;
return *firstSet.begin();
}
return dummy;
}
template<typename T, typename TimeType>
bool expiration_queue<T, TimeType>::insert(const T & item, TimeType expiration_time)
{
bool erased = erase(item);
m_itemMap[item] = expiration_time;
m_expirationMap[expiration_time].insert(item);
return !erased;
}
template<typename T, typename TimeType>
bool expiration_queue<T, TimeType>::erase(const T & item)
{
typename item_map_t::iterator itIter = m_itemMap.find(item);
bool erased = false;
if (itIter != m_itemMap.end()) {
typename expiration_map_t::iterator expIter = m_expirationMap.find(itIter->second);
if (expIter != m_expirationMap.end()) {
item_set_t & foundSet = expIter->second;
erased = (foundSet.erase(item) > 0);
if (foundSet.empty()) {
m_expirationMap.erase(expIter);
}
}
m_itemMap.erase(itIter);
}
return erased;
}
template<typename T, typename TimeType>
void expiration_queue<T, TimeType>::clear()
{
m_expirationMap.clear(); m_itemMap.clear();
}
#endif // EXPIRATION_QUEUE_H
@@ -0,0 +1,533 @@
#ifndef __GENERIC_RATE_LIMITING_MECHANISM_H__
#define __GENERIC_RATE_LIMITING_MECHANISM_H__
#include "expirationQueue.h"
#include "refptr.h"
#include "rateLimit.h"
#define KEY_PAIR_COMP_OPER(__oper__) \
bool operator __oper__ (const KeyPair & rhs) const \
{ \
if (mFixedKey != rhs.mFixedKey) { \
return (mFixedKey __oper__ rhs.mFixedKey); \
} else { \
return (mArbitraryKey __oper__ rhs.mArbitraryKey); \
} \
}
namespace soe
{
// create a class with the same interface in order to use different limit and counter types for customized behavior
class RateCounter
{
public:
RateCounter() : mCount(0), mLimit(0), mIndex(0), mInterval(0) { }
RateCounter(limit_t count, limit_t limit, interval_t interval, size_t index)
: mCount(count), mLimit(limit), mIndex(index), mInterval(interval) { }
virtual ~RateCounter() { }
unsigned Write(unsigned char * stream, unsigned size) const
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, mCount));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, mLimit));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, mInterval));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Write(stream+bytesTotal, size-bytesTotal, mIndex));
if (!bytes) return 0;
return bytesTotal;
}
unsigned Read(const unsigned char * stream, unsigned size)
{
unsigned bytesTotal = 0;
unsigned bytes = 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, mCount));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, mLimit));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, mInterval));
if (!bytes) return 0;
bytesTotal += (bytes = soe::Read(stream+bytesTotal, size-bytesTotal, mIndex));
if (!bytes) return 0;
return bytesTotal;
}
void Initialize(const RateLimits_t & rateLimits)
{
if (mIndex < rateLimits.size()) {
mLimit = rateLimits[mIndex].mLimit;
mInterval = rateLimits[mIndex].mInterval;
} else {
mLimit = 0;
mInterval = 0;
}
// reset count
mCount = 0;
}
limit_t GetCount() const { return mCount; }
limit_t GetLimit() const { return mLimit; }
interval_t GetInterval() const { return mInterval; }
size_t GetIndex() const { return mIndex; }
limit_t Consume(const RateLimits_t & rateLimits, limit_t count)
{
mCount += count;
return (mLimit - mCount);
}
bool Expire(const RateLimits_t & rateLimits)
{
bool remove = false;
if (mCount > mLimit) {
// raise to next rate limit if count was exceeded
if (mIndex < rateLimits.size()) {
mIndex++;
} else {
// can't go up; make sure we go down if limit vector has shrunk
mIndex = rateLimits.size() - 1;
}
} else {
if (mIndex > 0) {
// drop to previous rate limit if count was not exceeded
mIndex--;
} else {
// remove counter if unused and on initial rate limit
if (mCount == 0) {
remove = true;
}
}
}
// reinitialize
Initialize(rateLimits);
return remove;
}
protected:
limit_t mCount;
limit_t mLimit;
interval_t mInterval;
size_t mIndex;
private:
};
typedef std::vector<RateCounter> RateCounters_t;
inline unsigned Read(const unsigned char * stream, unsigned size, RateCounter & data, unsigned maxLen, unsigned version = 0)
{
return data.Read(stream, size);
}
inline unsigned Write(unsigned char * stream, unsigned size, const RateCounter & data, unsigned version = 0)
{
return data.Write(stream, size);
}
inline int Print(char * stream, unsigned size, const RateCounter & data, unsigned maxDepth = INT_MAX)
{
return 0;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType = RateLimits_t, typename CounterType = RateCounter, typename TimeType = time_t>
class GenericRateLimitingMechanism
{
public:
typedef std::vector<FixedKeyType> FixedKeyTypes_t;
typedef std::vector<ArbitraryKeyType> ArbitraryKeyTypes_t;
typedef std::vector<LimitType> LimitTypes_t;
typedef std::vector<CounterType> CounterTypes_t;
GenericRateLimitingMechanism() { }
virtual ~GenericRateLimitingMechanism() { }
void SetRateLimit(const FixedKeyType & fixedKey, const LimitType & rateLimit);
void UnsetRateLimit(const FixedKeyType & fixedKey);
const LimitType * GetRateLimit(const FixedKeyType & fixedKey) const;
const LimitType * GetNextRateLimit(FixedKeyType & fixedKey) const;
const CounterType * GetRateCounter(const FixedKeyType & fixedKey, const ArbitraryKeyType & arbitraryKey) const;
unsigned GetRateCountersAndFixedKeys(const ArbitraryKeyType & arbitraryKey, CounterTypes_t & counters, FixedKeyTypes_t & fixedKeys) const;
void PutRateCounter(const FixedKeyType & fixedKey, const ArbitraryKeyType & arbitraryKey, const CounterType & counter);
void PutRateCountersAndFixedKeys(const ArbitraryKeyType & arbitraryKey, const CounterTypes_t & counters, const FixedKeyTypes_t & fixedKeys);
bool RemoveRateCounter(const FixedKeyType & fixedKey, const ArbitraryKeyType & arbitraryKey);
unsigned RemoveArbitraryRateCounters(const FixedKeyType & fixedKey);
unsigned RemoveFixedRateCounters(const ArbitraryKeyType & arbitraryKey);
unsigned RemoveAllRateCounters();
limit_t ConsumeRateAllowance(const FixedKeyType & fixedKey, const ArbitraryKeyType & arbitraryKey, limit_t amount, TimeType when);
void ProcessRateCounters(TimeType when);
private:
class KeyPair
{
public:
KeyPair()
{ }
KeyPair(const FixedKeyType & fixedKey, const ArbitraryKeyType & arbitraryKey)
: mFixedKey(fixedKey)
, mArbitraryKey(arbitraryKey)
{ }
virtual ~KeyPair()
{ }
KEY_PAIR_COMP_OPER(<)
KEY_PAIR_COMP_OPER(<=)
KEY_PAIR_COMP_OPER(==)
KEY_PAIR_COMP_OPER(>=)
KEY_PAIR_COMP_OPER(>)
FixedKeyType mFixedKey;
ArbitraryKeyType mArbitraryKey;
};
class RateInfo
{
public:
RateInfo()
{ }
virtual ~RateInfo()
{ }
KeyPair mKeyPair;
CounterType mCounter;
};
typedef ref_ptr<RateInfo> RateInfoRefPtr;
// map types
typedef std::map<FixedKeyType, LimitType> RateLimitByFixedKeyMap_t;
typedef std::map<KeyPair, RateInfoRefPtr> RateCounterByKeyPairMap_t;
// expiration queue type
typedef expiration_queue<KeyPair, TimeType> RateCounterExpirationQueue_t;
// maps
RateLimitByFixedKeyMap_t mRateLimits;
RateCounterByKeyPairMap_t mRateCounters;
// queue
RateCounterExpirationQueue_t mExpirationQueue;
};
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
void GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::SetRateLimit(const FixedKeyType & fixedKey, const LimitType & rateLimit)
{
mRateLimits[fixedKey] = rateLimit;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
void GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::UnsetRateLimit(const FixedKeyType & fixedKey)
{
mRateLimits.erase(fixedKey);
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
const LimitType * GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::GetRateLimit(const FixedKeyType & fixedKey) const
{
LimitType const * rateLimit = NULL;
typename RateLimitByFixedKeyMap_t::const_iterator limIter = mRateLimits.find(fixedKey);
if (limIter != mRateLimits.end()) {
rateLimit = &(limIter->second);
}
return rateLimit;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
const LimitType * GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::GetNextRateLimit(FixedKeyType & fixedKey) const
{
LimitType const * rateLimit = NULL;
typename RateLimitByFixedKeyMap_t::const_iterator limIter = mRateLimits.upper_bound(fixedKey);
if (limIter != mRateLimits.end()) {
fixedKey = limIter->first;
rateLimit = &(limIter->second);
}
return rateLimit;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
const CounterType * GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::GetRateCounter(const FixedKeyType & fixedKey, const ArbitraryKeyType & arbitraryKey) const
{
const CounterType * counter = NULL;
typename RateCounterByKeyPairMap_t::const_iterator counterIter = mRateCounters.find(KeyPair(fixedKey, arbitraryKey));
if (counterIter != mRateCounters.end()) {
counter = &(counterIter->second->mCounter);
}
return counter;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
unsigned GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::GetRateCountersAndFixedKeys(const ArbitraryKeyType & arbitraryKey, CounterTypes_t & counters, FixedKeyTypes_t & fixedKeys) const
{
typename RateCounterByKeyPairMap_t::const_iterator counterIter;
typename RateLimitByFixedKeyMap_t::const_iterator limitIter;
KeyPair keyPair;
keyPair.mArbitraryKey = arbitraryKey;
for (limitIter = mRateLimits.begin(); limitIter != mRateLimits.end(); limitIter++)
{
keyPair.mFixedKey = limitIter->first;
counterIter = mRateCounters.find(keyPair);
if (counterIter != mRateCounters.end()) {
fixedKeys.push_back(counterIter->first.mFixedKey);
counters.push_back(counterIter->second->mCounter);
}
}
return counters.size();
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
void GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::PutRateCounter(const FixedKeyType & fixedKey, const ArbitraryKeyType & arbitraryKey, const CounterType & counter)
{
KeyPair keyPair(fixedKey, arbitraryKey);
RateInfoRefPtr info = mRateCounters[keyPair];
info->mKeyPair = keyPair;
info->mCounter = counter;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
void GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::PutRateCountersAndFixedKeys(const ArbitraryKeyType & arbitraryKey, const CounterTypes_t & counters, const FixedKeyTypes_t & fixedKeys)
{
unsigned count = counters.size() < fixedKeys.size() ? counters.size() : fixedKeys.size();
KeyPair keyPair;
keyPair.mArbitraryKey = arbitraryKey;
for (unsigned index =0; index < count; index++){
keyPair.mFixedKey = fixedKeys[index];
RateInfoRefPtr rateInfoRefPtr = mRateCounters[keyPair];
rateInfoRefPtr->mKeyPair = keyPair;
rateInfoRefPtr->mCounter = counters[index];
}
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
bool GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::RemoveRateCounter(const FixedKeyType & fixedKey, const ArbitraryKeyType & arbitraryKey)
{
bool removed = false;
typename RateCounterByKeyPairMap_t::iterator counterIter = mRateCounters.find(KeyPair(fixedKey, arbitraryKey));
if (counterIter != mRateCounters.end()) {
mExpirationQueue.erase(counterIter->first);
mRateCounters.erase(counterIter);
removed = true;
}
return removed;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
unsigned GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::RemoveArbitraryRateCounters(const FixedKeyType & fixedKey)
{
unsigned numRemoved = 0;
typename RateCounterByKeyPairMap_t::iterator counterIter = mRateCounters.begin();
std::list<KeyPair> keysToRemove;
for (; counterIter != mRateCounters.end(); counterIter++)
{
if (counterIter->first.mFixedKey == fixedKey) {
keysToRemove.push_back(counterIter->first);
}
}
for (typename std::list<KeyPair>::iterator remIter = keysToRemove.begin(); remIter != keysToRemove.end(); remIter++)
{
mExpirationQueue.erase(*remIter);
mRateCounters.erase(*remIter);
numRemoved++;
}
return numRemoved;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
unsigned GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::RemoveFixedRateCounters(const ArbitraryKeyType & arbitraryKey)
{
unsigned numRemoved = 0;
typename RateCounterByKeyPairMap_t::iterator counterIter = mRateCounters.begin();
std::list<KeyPair> keysToRemove;
for (; counterIter != mRateCounters.end(); counterIter++)
{
if (counterIter->first.mArbitraryKey == arbitraryKey) {
keysToRemove.push_back(counterIter->first);
}
}
for (typename std::list<KeyPair>::iterator remIter = keysToRemove.begin(); remIter != keysToRemove.end(); remIter++)
{
mExpirationQueue.erase(*remIter);
mRateCounters.erase(*remIter);
numRemoved++;
}
return numRemoved;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
unsigned GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::RemoveAllRateCounters()
{
unsigned numRemoved = mRateCounters.size();
mExpirationQueue.clear();
mRateCounters.clear();
return numRemoved;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
limit_t GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::ConsumeRateAllowance(const FixedKeyType & fixedKey, const ArbitraryKeyType & arbitraryKey, limit_t amount, TimeType when)
{
limit_t remainingAllowance = INT_MAX;
const LimitType * rateLimit = GetRateLimit(fixedKey);
if (rateLimit) {
typename RateCounterByKeyPairMap_t::iterator counterIter = mRateCounters.find(KeyPair(fixedKey, arbitraryKey));
RateInfoRefPtr info;
KeyPair keyPair(fixedKey, arbitraryKey);
if (counterIter == mRateCounters.end()) {
info = mRateCounters[keyPair];
info->mKeyPair = keyPair;
info->mCounter.Initialize(*rateLimit);
mExpirationQueue.insert(keyPair, when + info->mCounter.GetInterval());
} else {
info = counterIter->second;
}
remainingAllowance = info->mCounter.Consume(*rateLimit, amount);
}
return remainingAllowance;
}
template<typename FixedKeyType, typename ArbitraryKeyType, typename LimitType, typename CounterType, typename TimeType>
void GenericRateLimitingMechanism<FixedKeyType, ArbitraryKeyType, LimitType, CounterType, TimeType>::ProcessRateCounters(TimeType when)
{
while (mExpirationQueue.contains_expired_items(when))
{
KeyPair top = mExpirationQueue.top();
typename RateLimitByFixedKeyMap_t::const_iterator limIter = mRateLimits.find(top.mFixedKey);
RateInfoRefPtr & info = mRateCounters[top];
if ((limIter == mRateLimits.end()) || (info->mCounter.Expire(limIter->second))) {
// clear cache of unused counters
mRateCounters.erase(top);
mExpirationQueue.erase(top);
} else {
// reset expiration time
mExpirationQueue.insert(top, when + info->mCounter.GetInterval());
}
}
}
enum ESingleMemberClass
{
eSingleClassMember = 0
};
template<typename FixedKeyType, typename LimitType = RateLimits_t, typename CounterType = RateCounter, typename TimeType = time_t>
class GenericRateLimitingMechanismFixedOnly : public GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass, LimitType, CounterType, TimeType>
{
public:
GenericRateLimitingMechanismFixedOnly() { }
virtual ~GenericRateLimitingMechanismFixedOnly() { }
const CounterType * GetRateCounter(const FixedKeyType & fixedKey) const
{
return GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass>::GetRateCounter(fixedKey, eSingleClassMember);
}
unsigned GetRateCountersAndFixedKeys(typename GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass, LimitType, CounterType, TimeType>::CounterTypes_t & counters, typename GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass, LimitType, CounterType, TimeType>::FixedKeyTypes_t & fixedKeys) const
{
return GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass>::GetRateCountersAndFixedKeys(eSingleClassMember, counters, fixedKeys);
}
void PutRateCounter(const FixedKeyType & fixedKey, const CounterType & counter)
{
GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass>::PutRateCounter(fixedKey, eSingleClassMember, counter);
}
void PutRateCountersAndFixedKeys(const typename GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass, LimitType, CounterType, TimeType>::CounterTypes_t & counters, const typename GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass, LimitType, CounterType, TimeType>::FixedKeyTypes_t & fixedKeys)
{
return GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass>::PutRateCountersAndFixedKeys(eSingleClassMember, counters, fixedKeys);
}
bool RemoveRateCounter(const FixedKeyType & fixedKey)
{
return GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass>::RemoveRateCounter(fixedKey, eSingleClassMember);
}
limit_t ConsumeRateAllowance(const FixedKeyType & fixedKey, limit_t amount, TimeType when)
{
return GenericRateLimitingMechanism<FixedKeyType, ESingleMemberClass>::ConsumeRateAllowance(fixedKey, eSingleClassMember, amount, when);
}
};
template<typename ArbitraryKeyType, typename LimitType = RateLimits_t, typename CounterType = RateCounter, typename TimeType = time_t>
class GenericRateLimitingMechanismArbitraryOnly : public GenericRateLimitingMechanism<ESingleMemberClass, ArbitraryKeyType, LimitType, CounterType, TimeType>
{
public:
GenericRateLimitingMechanismArbitraryOnly() { }
virtual ~GenericRateLimitingMechanismArbitraryOnly() { }
void SetRateLimit(const LimitType & rateLimit)
{
GenericRateLimitingMechanism<ESingleMemberClass, ArbitraryKeyType>::SetRateLimit(eSingleClassMember, rateLimit);
}
void UnsetRateLimit()
{
GenericRateLimitingMechanism<ESingleMemberClass, ArbitraryKeyType>::UnsetRateLimit(eSingleClassMember);
}
const LimitType * GetRateLimit() const
{
return GenericRateLimitingMechanism<ESingleMemberClass, ArbitraryKeyType>::GetRateLimit(eSingleClassMember);
}
const CounterType * GetRateCounter(const ArbitraryKeyType & arbitraryKey) const
{
return GenericRateLimitingMechanism<ESingleMemberClass, ArbitraryKeyType>::GetRateCounter(eSingleClassMember, arbitraryKey);
}
void PutRateCounter(const ArbitraryKeyType & arbitraryKey, const CounterType & counter)
{
GenericRateLimitingMechanism<ESingleMemberClass, ArbitraryKeyType>::PutRateCounter(eSingleClassMember, arbitraryKey, counter);
}
bool RemoveRateCounter(const ArbitraryKeyType & arbitraryKey)
{
return GenericRateLimitingMechanism<ESingleMemberClass, ArbitraryKeyType>::RemoveRateCounter(eSingleClassMember, arbitraryKey);
}
limit_t ConsumeRateAllowance(const ArbitraryKeyType & arbitaryKey, limit_t amount, TimeType when)
{
return GenericRateLimitingMechanism<ESingleMemberClass, ArbitraryKeyType>::ConsumeRateAllowance(eSingleClassMember, arbitaryKey, amount, when);
}
};
};
#endif // __GENERIC_RATE_LIMITING_MECHANISM_H__
@@ -0,0 +1,239 @@
#ifndef API__HASH_H
#define API__HASH_H
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <assert.h>
#include <string>
#include <string.h>
#include "types.h"
#include "Base/stringutils.h"
#include <stdio.h>
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
#define MAX_HASH_VALUE 0xfe
#define BROADCAST_HASH_VALUE 0xff
inline unsigned char HashAccountId(unsigned accountId) { return (accountId & MAX_HASH_VALUE); }
inline unsigned char HashUserName(const char * name)
{
unsigned value = 0;
while (*name)
{
value += tolower(*name);
name++;
}
return value % MAX_HASH_VALUE;
}
inline unsigned char HashRandom() { return (rand() % MAX_HASH_VALUE); }
const soe::uint64 nMaxCharBits = 0x3f;
const unsigned char nMaxBits = 64;
const unsigned char nEncodeCharBits = 6;
const unsigned char nMaxHashChar = 2;
const unsigned char nMaxRandomChar = 3;
const unsigned nEncodeChars = nMaxBits/nEncodeCharBits;
const unsigned nMaxEncodeChars = nEncodeChars + nMaxRandomChar+ nMaxHashChar + 1;
static const char base64[65] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.?";
unsigned CalcMaxNumforBits(unsigned nBits);
char DecodeChar(char c);
//int HexStringToInt(const char *value);
int HexStringToInt(const std::string &value);
#ifdef _DEBUG
inline std::string printBase64()
{
std::string tmp;
for (unsigned i = 0; i < nMaxBits; i++)
{
char buf[16];
sprintf(buf, "%02d %c=%d, %d\n", i, base64[i], base64[i], DecodeChar(base64[i]));
tmp += buf;
}
return tmp;
}
#endif
/////////////////////////////////////////////////////////////////////////////
// Session ID is a 16 byte string constructed with account ID, random number,
// and hash value. Here is the detail:
// Account ID = 11 bytes (base64 encoded)
// Random Number = 3 bytes (base64 encoded)
// Hash Value = 2 bytes (Hex encoded)
//
inline std::string EncodeSessionID(soe::uint64 accountID, unsigned char hash)
{
char encodeBuf[64];
memset(encodeBuf,0,64);
for (unsigned i = 0; i < nEncodeChars; i++)
{
soe::uint64 shift = nMaxBits-(nEncodeCharBits*(i+1));
soe::uint64 tmp = accountID >> shift;
unsigned char ch = (unsigned char)(tmp & nMaxCharBits);
encodeBuf[i] = base64[ch];
}
unsigned char remainingBits = nMaxBits % nEncodeCharBits;
if (remainingBits != 0)
{
unsigned char nMaxRemainingBits = CalcMaxNumforBits(remainingBits);
unsigned char tmp = (unsigned char)(accountID & nMaxRemainingBits);
encodeBuf[nEncodeChars] = base64[tmp];
}
char randomNum[4];
randomNum[0] = base64[rand()%nMaxBits];
randomNum[1] = base64[rand()%nMaxBits];
randomNum[2] = base64[rand()%nMaxBits];
randomNum[3] = 0;
// add hash
char hashBuf[8];
sprintf(hashBuf, "%02x", hash);
std::string tmp = std::string(encodeBuf) + std::string(randomNum) + std::string(hashBuf);
return tmp;
}
inline bool DecodeSessionID(const std::string & sessionID, soe::uint64 & accountID, unsigned char & hash)
{
if (sessionID.empty() || sessionID.size() > nMaxEncodeChars)
return false;
accountID = 0;
std::string sDecode = sessionID.substr(0, sessionID.size()-nMaxHashChar-nMaxRandomChar);
std::string sHash = sessionID.substr(sessionID.size()-nMaxHashChar, nMaxHashChar);
hash = (unsigned char)HexStringToInt(sHash);
for (unsigned i = 0; i < nEncodeChars; i++)
{
char c = DecodeChar(sDecode[i]);
if (c == -1)
{
// invalid character
return false;
}
soe::uint64 decodeNum = (soe::uint64)c;
if (i == 0)
{
accountID = decodeNum;
}
else
{
accountID = (accountID << nEncodeCharBits) | decodeNum;
}
}
unsigned char remainingBits = nMaxBits % nEncodeCharBits;
if (remainingBits != 0)
{
soe::uint64 decodeNum = (soe::uint64)DecodeChar(sDecode[sDecode.size()-1]);
accountID = (accountID << remainingBits) | decodeNum;
}
return true;
}
inline unsigned CalcMaxNumforBits(unsigned nBits)
{
unsigned maxNum = 0;
for (unsigned i = 0; i < nBits; i++)
{
maxNum |= 1 << i; // pow(2,i);
}
return maxNum;
}
inline char DecodeChar(char c)
{
char num = -1;
if (c >= 48 && c <= 57)
{
num = c - 48;
}
else if (c >= 97 && c <= 122)
{
num = c - 87;
}
else if (c >= 65 && c <= 90)
{
num = c - 29;
}
else if (c == 46)
{
num = 62;
}
else if (c == 63)
{
num = 63;
}
return num;
}
inline int HexStringToInt(const std::string &value)
{
struct CHexMap
{
char chr;
int value;
};
const int HexMapL = 16;
CHexMap HexMap[HexMapL] =
{
{'0', 0}, {'1', 1},
{'2', 2}, {'3', 3},
{'4', 4}, {'5', 5},
{'6', 6}, {'7', 7},
{'8', 8}, {'9', 9},
{'A', 10}, {'B', 11},
{'C', 12}, {'D', 13},
{'E', 14}, {'F', 15}
};
//char *mstr = strupr(strdup(value));
std::string upperstr = soe::touppercase(value);
const char *s = upperstr.c_str();
int result = 0;
if (*s == '0' && *(s + 1) == 'X') s += 2;
bool firsttime = true;
while (*s != '\0')
{
bool found = false;
for (int i = 0; i < HexMapL; i++)
{
if (*s == HexMap[i].chr)
{
if (!firsttime) result <<= 4;
result |= HexMap[i].value;
found = true;
break;
}
}
if (!found) break;
s++;
firsttime = false;
}
//free(mstr);
return result;
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif
@@ -0,0 +1,623 @@
#ifndef HASHTABLE_HPP
#define HASHTABLE_HPP
#include <stddef.h>
#include <memory.h>
////////////////////////////////////////////////////////
// helper functions for the above hash table classes
////////////////////////////////////////////////////////
inline bool IsPrime(int value) // works on positive numbers up 62,710,561
{
static int sPrimeTab[] =
{
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013,
1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373,
1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657,
1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053,
2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129,
2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213,
2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287,
2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357,
2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423,
2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531,
2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617,
2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687,
2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741,
2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819,
2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903,
2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999,
3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079,
3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181,
3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257,
3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413,
3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511,
3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571,
3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643,
3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727,
3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821,
3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907,
3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989,
4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057,
4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139,
4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231,
4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297,
4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409,
4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493,
4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583,
4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657,
4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751,
4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831,
4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937,
4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003,
5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087,
5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179,
5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279,
5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387,
5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443,
5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521,
5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639,
5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693,
5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791,
5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857,
5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939,
5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053,
6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133,
6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221,
6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301,
6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367,
6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473,
6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571,
6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673,
6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761,
6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833,
6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917,
6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997,
7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103,
7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207,
7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297,
7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411,
7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499,
7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561,
7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643,
7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723,
7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829,
7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919
};
for (unsigned int j = 0; j < sizeof(sPrimeTab) / sizeof(int) && sPrimeTab[j] * sPrimeTab[j] < value; j++)
{
if (value % sPrimeTab[j] == 0)
return(false);
}
return(true);
}
// This is a simple hash table template. Any type of object can be stored in this hash table
// provided it can be copied. Resizing the table while in use is generally not recommended.
// putting the same object in the table twice is generally not recommended as it makes the find ambiguous
struct HashTableStatistics
{
int tableSize;
int usedSlots;
int totalEntries;
};
inline int NextPrime(int value)
{
if (value % 2 == 0)
value++;
while (!IsPrime(value))
value += 2;
return(value);
}
inline int HashString(char *string)
{
int h = 0;
while (*string != 0)
h = ((31 * h) + *string++) ^ (h >> 26);
return(h);
}
inline int UpperHashString(char *string)
{
int h = 0;
while (*string != 0)
{
h = ((31 * h) + (*string >= 'a' && *string <= 'z') ? (*string - 0x20) : *string) ^ (h >> 26);
string++;
}
return(h);
}
//////////////////////////////////////////////////////////////////////////
// HashTable
//////////////////////////////////////////////////////////////////////////
template<typename T> class HashTable
{
public:
HashTable(int hashSize);
~HashTable();
void Insert(T& obj, int hashValue);
bool Remove(T& obj, int hashValue);
void Reset(); // removes all entries from the table
T *FindFirst(int hashValue) const; // returns NULL if not found
T *FindNext(T *prevResult) const; // returns NULL if not found
T *WalkFirst() const; // returns NULL if not found
T *WalkNext(T *prevResult) const; // returns NULL if not found
void Resize(int hashSize); // the actual hash size will be rounded up to the next larger prime number (very slow, not recommended)
void GetStatistics(HashTableStatistics *stats) const;
protected:
struct HashEntry
{
T obj;
int hashValue;
HashEntry *nextEntry;
};
HashEntry **mTable;
int mTableSize;
int mEntryCount;
int mStatUsedSlots;
};
template<typename T> HashTable<T>::HashTable(int hashSize)
{
mTable = NULL;
mTableSize = 0;
mEntryCount = 0;
mStatUsedSlots = 0;
Resize(hashSize);
}
template<typename T> HashTable<T>::~HashTable()
{
Reset(); // deletes everything
delete[] mTable;
}
template<typename T> void HashTable<T>::Insert(T& obj, int hashValue)
{
HashEntry *entry = new HashEntry;
entry->obj = obj;
entry->hashValue = hashValue;
int spot = ((unsigned)hashValue) % mTableSize;
if (mTable[spot] == NULL)
{
entry->nextEntry = NULL;
mTable[spot] = entry;
mStatUsedSlots++;
}
else
{
entry->nextEntry = mTable[spot];
mTable[spot] = entry;
}
mEntryCount++;
}
template<typename T> bool HashTable<T>::Remove(T& obj, int hashValue)
{
int spot = ((unsigned)hashValue) % mTableSize;
HashEntry* next = mTable[spot];
HashEntry** prev = &mTable[spot];
while (next != NULL)
{
if (next->obj == obj && next->hashValue == hashValue)
{
*prev = next->nextEntry;
delete next;
mEntryCount--;
if (mTable[spot] == NULL)
mStatUsedSlots--;
return(true);
break;
}
prev = &next->nextEntry;
next = next->nextEntry;
}
return(false);
}
template<typename T> void HashTable<T>::Reset()
{
for (int spot = 0; spot < mTableSize; spot++)
{
HashEntry *curr = mTable[spot];
if (curr != NULL)
{
mStatUsedSlots--;
while (curr != NULL)
{
HashEntry *next = curr->nextEntry;
delete curr;
mEntryCount--;
curr = next;
}
mTable[spot] = NULL;
}
}
}
template<typename T> T *HashTable<T>::FindFirst(int hashValue) const
{
HashEntry *entry = mTable[((unsigned)hashValue) % mTableSize];
while (entry != NULL)
{
if (entry->hashValue == hashValue)
return(&entry->obj);
entry = entry->nextEntry;
}
return(NULL);
}
template<typename T> T *HashTable<T>::FindNext(T *prevResult) const
{
HashEntry *entry = (HashEntry *)(((char *)prevResult) - offsetof(HashEntry, obj));
int hashValue = entry->hashValue;
entry = entry->nextEntry;
while (entry != NULL)
{
if (entry->hashValue == hashValue)
return(&entry->obj);
entry = entry->nextEntry;
}
return(NULL);
}
template<typename T> T *HashTable<T>::WalkFirst() const
{
for (int bucket = 0; bucket < mTableSize; bucket++)
{
HashEntry *entry = mTable[bucket];
if (entry != NULL)
return(&entry->obj);
}
return(NULL);
}
template<typename T> T *HashTable<T>::WalkNext(T *prevResult) const
{
HashEntry *entry = (HashEntry *)(((char *)prevResult) - offsetof(HashEntry, obj));
int bucket = ((unsigned)entry->hashValue) % mTableSize;
entry = entry->nextEntry;
if (entry != NULL)
return(&entry->obj);
bucket++; // go onto next bucket
for (; bucket < mTableSize; bucket++)
{
HashEntry *entry = mTable[bucket];
if (entry != NULL)
return(&entry->obj);
}
return(NULL);
}
template<typename T> void HashTable<T>::Resize(int hashSize)
{
HashEntry **oldTable = mTable;
int oldSize = mTableSize;
// calculate next prime number greater than hashSize.
mTableSize = NextPrime(hashSize);
mTable = new HashEntry*[mTableSize];
memset(mTable, 0, sizeof(HashEntry *) * mTableSize);
mStatUsedSlots = 0;
if (mEntryCount > 0)
{
for (int i = 0; i < oldSize; i++)
{
HashEntry* next = oldTable[i];
while (next != NULL)
{
HashEntry* hold = next;
next = next->nextEntry;
// insert hold into new table
int spot = ((unsigned)hold->hashValue) % mTableSize;
if (mTable[spot] == NULL)
{
hold->nextEntry = NULL;
mTable[spot] = hold;
mStatUsedSlots++;
}
else
{
hold->nextEntry = mTable[spot];
mTable[spot] = hold;
}
}
}
}
delete[] oldTable;
}
template<typename T> void HashTable<T>::GetStatistics(HashTableStatistics *stats) const
{
stats->totalEntries = mEntryCount;
stats->usedSlots = mStatUsedSlots;
stats->tableSize = mTableSize;
}
//////////////////////////////////////////////////////////////////////////////
// ObjectHashTable
//
// similar to basic HashTable object, only this version requires the contents
// be pointers to objects derived from class HashTableMember. If you can use
// this version, it avoids allocations of HashEntry objects.
// making the cost of object inserts/deletes dirt-cheap
//////////////////////////////////////////////////////////////////////////////
class HashTableMember
{
#if defined(_MSC_VER) && (_MSC_VER >= 1300) // MSVC 7.0 is the first version to support friend templates
template<typename T> friend class ObjectHashTable;
protected:
#else
public:
#endif
int mHashValue;
HashTableMember *mHashNextEntry;
};
template<typename T> class ObjectHashTable
{
public:
ObjectHashTable(int hashSize);
~ObjectHashTable();
void Insert(T obj, int hashValue);
bool Remove(T obj, int hashValue);
void Reset(); // removes all entries from the table
T FindFirst(int hashValue) const; // returns NULL if not found
T FindNext(T prevResult) const; // returns NULL if not found
T WalkFirst() const; // returns NULL if not found
T WalkNext(T prevResult) const; // returns NULL if not found
void Resize(int hashSize); // the actual hash size will be rounded up to the next larger prime number (very slow, not recommended)
void GetStatistics(HashTableStatistics *stats) const;
protected:
T *mTable;
int mTableSize;
int mEntryCount;
int mStatUsedSlots;
};
template<typename T> ObjectHashTable<T>::ObjectHashTable(int hashSize)
{
mTable = NULL;
mTableSize = 0;
mEntryCount = 0;
mStatUsedSlots = 0;
Resize(hashSize);
}
template<typename T> ObjectHashTable<T>::~ObjectHashTable()
{
Reset();
delete[] mTable;
}
template<typename T> void ObjectHashTable<T>::Insert(T obj, int hashValue)
{
obj->mHashValue = hashValue;
int spot = ((unsigned)hashValue) % mTableSize;
if (mTable[spot] == NULL)
{
obj->mHashNextEntry = NULL;
mTable[spot] = obj;
mStatUsedSlots++;
}
else
{
obj->mHashNextEntry = mTable[spot];
mTable[spot] = obj;
}
mEntryCount++;
}
template<typename T> bool ObjectHashTable<T>::Remove(T obj, int hashValue)
{
int spot = ((unsigned)hashValue) % mTableSize;
T next = mTable[spot];
T *prev = &mTable[spot];
while (next != NULL)
{
if (next == obj)
{
*prev = (T)next->mHashNextEntry;
next->mHashNextEntry = NULL;
mEntryCount--;
if (mTable[spot] == NULL)
mStatUsedSlots--;
return(true);
break;
}
prev = (T *)&next->mHashNextEntry;
next = (T)next->mHashNextEntry;
}
return(false);
}
template<typename T> void ObjectHashTable<T>::Reset()
{
for (int spot = 0; spot < mTableSize; spot++)
{
T curr = mTable[spot];
if (curr != NULL)
{
while (curr != NULL)
{
T next = (T)curr->mHashNextEntry;
curr->mHashNextEntry = NULL;
mEntryCount--;
curr = next;
}
mTable[spot] = NULL;
mStatUsedSlots--;
}
}
}
template<typename T> T ObjectHashTable<T>::FindFirst(int hashValue) const
{
T entry = mTable[((unsigned)hashValue) % mTableSize];
while (entry != NULL)
{
if (entry->mHashValue == hashValue)
return(entry);
entry = (T)entry->mHashNextEntry;
}
return(NULL);
}
template<typename T> T ObjectHashTable<T>::FindNext(T prevResult) const
{
T entry = prevResult;
int hashValue = entry->mHashValue;
entry = (T)entry->mHashNextEntry;
while (entry != NULL)
{
if (entry->mHashValue == hashValue)
return(entry);
entry = (T)entry->mHashNextEntry;
}
return(NULL);
}
template<typename T> T ObjectHashTable<T>::WalkFirst() const
{
for (int bucket = 0; bucket < mTableSize; bucket++)
{
T entry = mTable[bucket];
if (entry != NULL)
return(entry);
}
return(NULL);
}
template<typename T> T ObjectHashTable<T>::WalkNext(T prevResult) const
{
T entry = prevResult;
int bucket = ((unsigned)entry->mHashValue) % mTableSize;
entry = (T)entry->mHashNextEntry;
if (entry != NULL)
return(entry);
bucket++; // go onto next bucket
for (; bucket < mTableSize; bucket++)
{
entry = mTable[bucket];
if (entry != NULL)
return(entry);
}
return(NULL);
}
template<typename T> void ObjectHashTable<T>::Resize(int hashSize)
{
T *oldTable = mTable;
int oldSize = mTableSize;
// calculate next prime number greater than hashSize.
mTableSize = NextPrime(hashSize);
mTable = new T[mTableSize];
memset(mTable, 0, sizeof(T) * mTableSize);
mStatUsedSlots = 0;
if (mEntryCount > 0)
{
for (int i = 0; i < oldSize; i++)
{
T next = oldTable[i];
while (next != NULL)
{
T hold = next;
next = (T)next->mHashNextEntry;
// insert hold into new table
int spot = ((unsigned)hold->mHashValue) % mTableSize;
if (mTable[spot] == NULL)
{
hold->mHashNextEntry = NULL;
mTable[spot] = hold;
mStatUsedSlots++;
}
else
{
hold->mHashNextEntry = mTable[spot];
mTable[spot] = hold;
}
}
}
}
delete[] oldTable;
}
template<typename T> void ObjectHashTable<T>::GetStatistics(HashTableStatistics *stats) const
{
stats->totalEntries = mEntryCount;
stats->usedSlots = mStatUsedSlots;
stats->tableSize = mTableSize;
}
#endif
@@ -0,0 +1,790 @@
#include "log.h"
#if defined (_MT)
#include "thread.h"
#endif
#include <sys/stat.h>
#include "types.h"
#ifdef WIN32
#include <time.h>
#include <stdarg.h>
#include <io.h>
#include <direct.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#else
#include <errno.h>
#include <assert.h>
#include <sys/errno.h>
#include <pthread.h>
#include <resolv.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#endif
#ifdef WIN32
#define snprintf _snprintf
#endif
using namespace std;
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace soe
{
const long kDateLenAllowance = 256;
#ifdef WIN32
const char file_sep = '\\';
#define LOGGER_GET_CURR_TIME(__tm_struct__, __time_t_var__) \
memcpy(&__tm_struct__, localtime(&__time_t_var__), sizeof(__tm_struct__))
#define LOGGER_MAKE_DIR(__dir_name__, __mode__) mkdir(__dir_name__)
#define vsnprintf _vsnprintf
#else // ifndef WIN32
const char file_sep = '/';
const char *syslogLevels[] = {
"EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG" };
const int numSysLogLevels = sizeof(syslogLevels) / sizeof(char *);
#define LOGGER_GET_CURR_TIME(__tm_struct__, __time_t_var__) \
localtime_r(&__time_t_var__, &__tm_struct__)
#define LOGGER_MAKE_DIR(__dir_name__, __mode__) mkdir(__dir_name__, __mode__)
#endif // WIN32
#ifdef _MT
#define LOGGER_LOCK ScopeLock logLock(rLock);
#else // ifndef _MT
#define LOGGER_LOCK
#endif // _MT
Logger::Logger(const char *prefix,
int level,
unsigned size,
bool rollDate)
: m_defaultLevel(level),
m_defaultSize(size),
m_dirPrefix(prefix),
m_rollDate(rollDate),
m_unlimitedLineSize(false)
{
m_logType = eUseLocalFile;
LoggerInit("UnNamedServer");
}
Logger::Logger(const char *programName,
const ELogType logType,
const char *prefix,
int level,
unsigned size,
bool rollDate)
: m_defaultLevel(level),
m_defaultSize(size),
m_dirPrefix(prefix),
m_rollDate(rollDate),
m_logType(logType),
m_unlimitedLineSize(false)
{
LoggerInit(programName);
}
void Logger::LoggerInit(const char *programName)
{
char buf[1024];
FILE *logDir = NULL;
if (0 != (m_logType & eUseLocalFile))
{
logDir = fopen(m_dirPrefix.c_str(), "r+");
if(errno == ENOENT)
{
cmkdir(m_dirPrefix.c_str(), 0755);
}
else if(logDir != NULL)
{
fclose(logDir);
}
tm now;
time_t t = time(NULL);
LOGGER_GET_CURR_TIME(now, t);
memcpy(&m_lastDateTime, &now, sizeof(tm));
if(m_rollDate)
{
snprintf(buf, sizeof(buf), "%s%c%2.2d-%2.2d-%2.2d", m_dirPrefix.c_str(), file_sep, (now.tm_mon + 1), now.tm_mday, (now.tm_year % 100));
}
else
{
snprintf(buf, sizeof(buf), "%s", m_dirPrefix.c_str());
}
logDir = fopen(buf, "r+");
if(errno == ENOENT)
{
cmkdir(buf, 0755);
}
else if(logDir != NULL)
{
fclose(logDir);
}
m_logPrefix = buf;
m_logRolloverSize = 0x80000000; // Default: 2 GB upper limit on file size
}
// need to do this because syslog does not copy the buffer; it copies the *pointer*.
setProgramName(programName);
#ifndef WIN32
// Open connection to syslog
if (0 != (m_logType & eUseSysLog)) {
openlog(m_programName, LOG_NDELAY | LOG_PID, LOG_LOCAL5);
}
#endif // !WIN32
}
Logger::~Logger()
{
map<unsigned, LogInfo *>::iterator iter;
for(iter = m_logTable.begin(); iter != m_logTable.end(); iter++)
{
logWithSys((*iter).first, LOG_INFO, LOG_FILEONLY, "---=== Log Stopped ===---");
fflush((*iter).second->file);
fclose((*iter).second->file);
delete((*iter).second);
}
m_logTable.clear();
#ifndef WIN32
// close connection to syslog
if (0 != (m_logType & eUseSysLog))
closelog();
#endif // !WIN32
}
void Logger::setProgramName(const char *programName)
{
if (programName)
{
strncpy(m_programName, programName, sizeof(m_programName));
m_programName[sizeof(m_programName) - 1] = '\0';
}
}
void Logger::flush(unsigned logenum)
{
map<unsigned, LogInfo *>::iterator iter = m_logTable.find(logenum);
if(iter != m_logTable.end())
{
LogInfo *info = (*iter).second;
fflush(info->file);
info->used = 0;
}
}
void Logger::flushAll()
{
if (0 != (m_logType & eUseLocalFile))
{
map<unsigned, LogInfo *>::iterator iter;
for(iter = m_logTable.begin(); iter != m_logTable.end(); iter++)
{
LogInfo *info = (*iter).second;
fflush(info->file);
info->used = 0;
}
}
}
void Logger::addLog(const char *id, unsigned logenum, int level, unsigned size)
{
if (0 != (m_logType & eUseLocalFile))
{
LogInfo *newLog = new LogInfo;
newLog->filename = m_logPrefix + file_sep + id + ".log";
newLog->name = id;
newLog->used = 0;
newLog->max = size;
newLog->last = 0;
newLog->level = level;
m_logTable.insert(pair<unsigned, LogInfo *>(logenum, newLog));
if(strcmp("stdout", id) == 0)
{
newLog->file = stdout;
}
else if(strcmp("stderr", id) == 0)
{
newLog->file = stderr;
}
else
{
newLog->file = fopen(newLog->filename.c_str(), "a+");
}
logWithSys(logenum, LOG_INFO, LOG_FILEONLY, "---=== Log Started ===---");
}
}
void Logger::addLog(const char *id, unsigned logenum)
{
if (0 != (m_logType & eUseLocalFile))
{
LogInfo *newLog = new LogInfo;
newLog->filename = m_logPrefix + file_sep + id + ".log";
newLog->name = id;
newLog->used = 0;
newLog->max = m_defaultSize;
newLog->last = 0;
newLog->level = m_defaultLevel;
m_logTable.insert(pair<unsigned, LogInfo *>(logenum, newLog));
if(strcmp("stdout", id) == 0)
{
newLog->file = stdout;
}
else if(strcmp("stderr", id) == 0)
{
newLog->file = stderr;
}
else
{
newLog->file = fopen(newLog->filename.c_str(), "a+");
}
logWithSys(logenum, LOG_INFO, LOG_FILEONLY, "---===Log Started ===---");
}
}
void Logger::updateLog(unsigned logenum, int level, unsigned size)
{
if (0 != (m_logType & eUseLocalFile))
{
map<unsigned, LogInfo *>::iterator iter = m_logTable.find(logenum);
if(iter != m_logTable.end())
{
(*iter).second->level = level;
(*iter).second->max = size;
}
}
}
void Logger::removeLog(unsigned logenum)
{
if (0 != (m_logType & eUseLocalFile))
{
map<unsigned, LogInfo *>::iterator iter = m_logTable.find(logenum);
if(iter != m_logTable.end())
{
#ifdef WIN32
logWithSys((*iter).first, LOG_INFO, LOG_FILEONLY, "---=== Log Stopped ===---");
#else // ifndef WIN32
logWithSys((*iter).first, LOG_INFO, LOG_ALWAYS, "---=== Log Stopped ===---");
#endif // WIN32
fflush((*iter).second->file);
fclose((*iter).second->file);
delete((*iter).second);
}
}
}
void Logger::logSimple(unsigned logenum, int level, const char *message)
{
map<unsigned, LogInfo *>::iterator iter = m_logTable.find(logenum);
if(iter == m_logTable.end())
{
return;
}
time_t t = time(NULL);
LogInfo *info = (*iter).second;
if(level >= info->level)
{
return;
}
#ifndef WIN32
if(level == LOG_FILEONLY && ((info->file == stderr) || (info->file == stdout)))
{
return;
}
#endif // !WIN32
if(info->last != t)
{
memcpy(&info->ts, localtime(&t), sizeof(tm));
info->last = t;
}
if(m_rollDate && info->ts.tm_mday != m_lastDateTime.tm_mday)
{
if(info->ts.tm_mday != m_lastDateTime.tm_mday)
{
memcpy(&m_lastDateTime, &info->ts, sizeof(tm));
rollDate(t);
}
}
if(iter != m_logTable.end())
{
if(info->max > 0)
{
info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, message);
info->used += fputc('\n', info->file);
if(info->used > info->max)
{
fflush(info->file);
info->used = 0;
}
}
else
{
fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, message);
fputc('\n', info->file);
fflush(info->file);
}
}
}
void Logger::logSimpleWithSys(unsigned logenum, unsigned priority, int level, const char *message)
{
#ifndef WIN32
if (0 != (m_logType & eUseSysLog))
syslog(priority, "%s: %s", syslogLevels[priority % numSysLogLevels], message);
#endif // !WIN32
if (0 != (m_logType & eUseLocalFile))
{
map<unsigned, LogInfo *>::iterator iter = m_logTable.find(logenum);
if(iter == m_logTable.end())
{
return;
}
time_t t = time(NULL);
LogInfo *info = (*iter).second;
if(level >= info->level)
{
return;
}
#ifndef WIN32
if(level == LOG_FILEONLY && ((info->file == stderr) || (info->file == stdout)))
{
return;
}
#endif // !WIN32
if(info->last != t)
{
memcpy(&info->ts, localtime(&t), sizeof(tm));
info->last = t;
}
if(m_rollDate && info->ts.tm_mday != m_lastDateTime.tm_mday)
{
if(info->ts.tm_mday != m_lastDateTime.tm_mday)
{
memcpy(&m_lastDateTime, &info->ts, sizeof(tm));
rollDate(t);
}
}
if(iter != m_logTable.end())
{
if (m_logRolloverSize> 0)
checkLogRoll(info, (unsigned long)::strlen(message) + kDateLenAllowance);
if(info->max > 0)
{
info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, message);
info->used += fputc('\n', info->file);
if(info->used > info->max)
{
fflush(info->file);
info->used = 0;
}
}
else
{
fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, message);
fputc('\n', info->file);
fflush(info->file);
}
}
}
}
void Logger::log(unsigned logenum, int level, const char *message, ...)
{
va_list varg;
va_start(varg, message);
vlogWithSys(logenum, LOG_NOTICE, level, message, varg);
va_end(varg);
}
void Logger::logWithSys(unsigned logenum, unsigned priority, int level, const char *message, ...)
{
char buf[2048];
va_list varg;
va_start(varg, message);
vsnprintf(buf, 2047, message, varg);
va_end(varg);
buf[2047] = 0;
#ifndef WIN32
if (0 != (m_logType & eUseSysLog))
syslog(priority, "%s: %s", syslogLevels[priority % numSysLogLevels], buf);
#endif // !WIN32
if (0 != (m_logType & eUseLocalFile))
{
map<unsigned, LogInfo *>::iterator iter = m_logTable.find(logenum);
if(iter == m_logTable.end())
{
return;
}
time_t t = time(NULL);
LogInfo *info = (*iter).second;
if(level >= info->level)
{
return;
}
if(level == LOG_FILEONLY && ((info->file == stderr) || (info->file == stdout)))
{
return;
}
if(info->last != t)
{
LOGGER_GET_CURR_TIME(info->ts, t);
info->last = t;
}
if(m_rollDate && info->ts.tm_mday != m_lastDateTime.tm_mday)
{
if(info->ts.tm_mday != m_lastDateTime.tm_mday)
{
memcpy(&m_lastDateTime, &info->ts, sizeof(tm));
rollDate(t);
}
}
if(iter != m_logTable.end())
{
if (m_logRolloverSize> 0)
checkLogRoll(info, (unsigned long)::strlen(buf) + kDateLenAllowance);
if(info->max > 0)
{
if (m_unlimitedLineSize) {
info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] ", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec);
va_start(varg, message);
info->used += vfprintf(info->file, message, varg);
va_end(varg);
} else {
info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, buf);
}
info->used += fputc('\n', info->file);
if(info->used > info->max)
{
fflush(info->file);
info->used = 0;
}
}
else
{
if (m_unlimitedLineSize) {
info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] ", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec);
va_start(varg, message);
info->used += vfprintf(info->file, message, varg);
va_end(varg);
} else {
info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, buf);
}
fputc('\n', info->file);
fflush(info->file);
}
}
}
}
void Logger::vlogWithSys(unsigned logenum, unsigned priority, int level, const char *message, va_list argptr)
{
char buf[2048];
vsnprintf(buf, 2047, message, argptr);
buf[2047] = 0;
#ifndef WIN32
if (0 != (m_logType & eUseSysLog))
syslog(priority, "%s: %s", syslogLevels[priority % numSysLogLevels], buf);
#endif // !WIN32
if (0 != (m_logType & eUseLocalFile))
{
map<unsigned, LogInfo *>::iterator iter = m_logTable.find(logenum);
if(iter == m_logTable.end())
{
return;
}
time_t t = time(NULL);
LogInfo *info = (*iter).second;
if(level >= info->level)
{
return;
}
if(level == LOG_FILEONLY && ((info->file == stderr) || (info->file == stdout)))
{
return;
}
if(info->last != t)
{
LOGGER_GET_CURR_TIME(info->ts, t);
info->last = t;
}
if(m_rollDate && info->ts.tm_mday != m_lastDateTime.tm_mday)
{
if(info->ts.tm_mday != m_lastDateTime.tm_mday)
{
memcpy(&m_lastDateTime, &info->ts, sizeof(tm));
rollDate(t);
}
}
if(iter != m_logTable.end())
{
if (m_logRolloverSize> 0)
checkLogRoll(info, (unsigned long)::strlen(buf) + kDateLenAllowance);
if(info->max > 0)
{
if (m_unlimitedLineSize) {
info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] ", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec);
info->used += vfprintf(info->file, message, argptr);
} else {
info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, buf);
}
info->used += fputc('\n', info->file);
if(info->used > info->max)
{
fflush(info->file);
info->used = 0;
}
}
else
{
if (m_unlimitedLineSize) {
info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] ", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec);
info->used += vfprintf(info->file, message, argptr);
} else {
info->used += fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s", (info->ts.tm_mon + 1), info->ts.tm_mday, (info->ts.tm_year % 100), info->ts.tm_hour, info->ts.tm_min, info->ts.tm_sec, buf);
}
fputc('\n', info->file);
fflush(info->file);
}
}
}
}
void Logger::vlog(unsigned logenum, int level, const char *message, va_list argptr)
{
vlogWithSys(logenum, LOG_NOTICE, level, message, argptr);
}
// void Logger::vlogWithSys(unsigned logenum, unsigned priority, int level, const char *message, va_list argptr)
void Logger::rollDate(time_t t)
{
char buf[80];
FILE *logDir = NULL;
logDir = fopen(m_dirPrefix.c_str(), "r+");
if(errno == ENOENT)
{
cmkdir(m_dirPrefix.c_str(), 0755);
}
else if(logDir != NULL)
{
fclose(logDir);
}
tm now;
LOGGER_GET_CURR_TIME(now, t);
snprintf(buf, sizeof(buf), "%s%c%2.2d-%2.2d-%2.2d", m_dirPrefix.c_str(), file_sep, (now.tm_mon + 1), now.tm_mday, (now.tm_year % 100));
logDir = fopen(buf, "r+");
if(errno == ENOENT)
{
cmkdir(buf, 0755);
}
else if(logDir != NULL)
{
fclose(logDir);
}
m_logPrefix = buf;
map<unsigned, LogInfo *>::iterator iter;
for(iter = m_logTable.begin(); iter != m_logTable.end(); iter++)
{
(*iter).second->filename = m_logPrefix + file_sep + (*iter).second->name.c_str() + ".log";
fflush((*iter).second->file);
fclose((*iter).second->file);
(*iter).second->file = fopen((*iter).second->filename.c_str(), "a+");
if ((*iter).second->file == 0)
abort();
memcpy(&((*iter).second->ts), &now, sizeof(tm));
}
}
// mkdir function that creates intermediate directories
void Logger::cmkdir(const char *dir, int mode)
{
char dirbuf[128];
strncpy(dirbuf, dir, 127);
dirbuf[127] = 0;
char *j = dirbuf, *i = dirbuf;
int handle;
while(*i)
{
if(*i == file_sep)
{
(*i) = 0;
#ifdef WIN32
handle = open(j, O_EXCL);
if((handle > 0) || (errno != EISDIR && errno != ENOENT && errno != EACCES))
{
perror("Logger::cmkdir():");
abort();
}
#else // ifndef WIN32
// handle = open(j, O_EXCL); // Ben's original code
// if((handle > 0) || (errno != EISDIR && errno != ENOENT))
// {
// perror("Logger::cmkdir():");
// abort();
// }
// This doesnt work under Linux, it returns a valid handle
// Instead: see if file exists. If it doesnt, create directory ok
// If it exists, do stat to see if it is a dir.
// If it is a dir, then ok, create the directory.
// If it is a file, error
// ging 9-16-2002
handle = open(j, O_RDONLY);
if (handle > 0)
{
struct stat stat_buffer;
int ret = fstat(handle,&stat_buffer);
if ((ret == -1) || ((stat_buffer.st_mode | S_IFDIR) == 0))
{
perror("Logger::cmkdir():");
abort();
}
}
#endif // WIN32
LOGGER_MAKE_DIR(j, mode);
close(handle);
(*i) = file_sep;
}
else if(*(i + 1) == 0)
{
LOGGER_MAKE_DIR(j, mode);
}
i++;
}
}
void Logger::rollLog(LogInfo *logInfo)
{
std::string newLogName;
char timeStampBuffer[256];
time_t t = time(NULL);
tm now;
int r;
int nTries = 10;
fflush(logInfo->file);
fclose(logInfo->file);
do
{
LOGGER_GET_CURR_TIME(now, t);
snprintf(timeStampBuffer, sizeof(timeStampBuffer), "-%4.4d-%2.2d-%2.2d-%2.2d-%2.2d-%2.2d.log",
(now.tm_year + 1900), (now.tm_mon + 1), now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec);
newLogName = logInfo->filename.substr(0, logInfo->filename.length() - 4) + timeStampBuffer;
r = rename(logInfo->filename.c_str(), newLogName.c_str());
nTries--;
t++;
}
while ((r != 0) && (nTries > 0));
logInfo->file = fopen(logInfo->filename.c_str(), "a+");
memcpy(&(logInfo->ts), &now, sizeof(tm));
}
void Logger::checkLogRoll(LogInfo *logInfo, unsigned long lenToAdd)
{
unsigned long logSize = ftell(logInfo->file);
if ((logSize + lenToAdd) > m_logRolloverSize)
{
rollLog(logInfo);
}
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,149 @@
#ifndef __LOGGER_H__
#define __LOGGER_H__
// make the compiler shut up
#pragma warning (disable : 4786)
#include <string>
#include <stdio.h>
#include <map>
#if defined (_MT) || defined(_REENTRANT)
# include "thread.h"
#endif
#ifndef WIN32
#include <syslog.h>
#endif
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace soe
{
#define LOG_ALWAYS -1
#define LOG_FILEONLY -2
struct LogInfo
{
FILE *file;
unsigned used;
tm ts;
time_t last;
unsigned max;
int level;
std::string filename;
std::string name;
};
/* Use these flags defined in syslog.h for the priority level
LOG_EMERG,
LOG_ALERT,
LOG_CRIT,
LOG_ERR,
LOG_WARNING,
LOG_NOTICE,
LOG_INFO,
LOG_DEBUG
*/
//-----------------------------------------------
// Windows doesn't have syslog (?) so we define the
// syslog warning levels here to satisfy the compiler
// but then ignore them in log() and logSimple()
//-----------------------------------------------
#ifdef WIN32
enum _WIN32_LOG_LEVELS_
{
LOG_EMERG = 0,
LOG_ALERT,
LOG_CRIT,
LOG_ERR,
LOG_WARNING,
LOG_NOTICE,
LOG_INFO,
LOG_DEBUG
};
#endif
enum ELogType
{
eUseNone = 0,
eUseLocalFile = 1,
eUseSysLog = 2,
eUseBoth = 3
};
#define MAX_LOG_BUFFER 10240
class Logger
{
public:
Logger(const char *programName,
const ELogType logType = eUseLocalFile,
const char *prefix = "logs",
int level = 10,
unsigned size = 0,
bool rollDate = true);
Logger(const char *prefix,
int level,
unsigned size,
bool rollDate = true); // Backwards compatibility
void LoggerInit(const char *programName);
~Logger();
void addLog(const char *id, unsigned logenum, int level, unsigned size);
void addLog(const char *id, unsigned logenum);
void removeLog(unsigned logenum);
void updateLog(unsigned logenum, int level, unsigned size);
void logSimple(unsigned logenum, int level, const char *message);
void logSimpleWithSys(unsigned logenum, unsigned priority, int level, const char *message);
void logWithSys(unsigned logenum, unsigned priority, int level, const char *message, ...);
void log(unsigned logenum, int level, const char *message, ...);
void vlogWithSys(unsigned logenum, unsigned priority, int level, const char *message, va_list argptr);
void vlog(unsigned logenum, int level, const char *message, va_list argptr);
void flushAll();
void flush(unsigned logenum);
unsigned long getLogRolloverSize() { return m_logRolloverSize; }
void setLogRolloverSize(unsigned long maxLogSize) { m_logRolloverSize = maxLogSize; }
void setUnlimitedLineSize(bool isUnlimited) { m_unlimitedLineSize = isUnlimited; }
void setProgramName(const char *programName);
#if defined (_MT) || defined(_REENTRANT)
Mutex & getMutex() { return rLock; }
#endif
private:
void rollDate(time_t now);
void cmkdir(const char *dir, int mode);
void rollLog(LogInfo *logInfo);
void checkLogRoll(LogInfo *logInfo, unsigned long lenToAdd);
unsigned m_defaultLevel;
unsigned m_defaultSize;
std::string m_lastDateText;
tm m_lastDateTime;
std::map<unsigned, LogInfo *> m_logTable;
std::string m_logPrefix;
std::string m_dirPrefix;
#if defined (_MT) || defined(_REENTRANT)
Mutex rLock;
#endif
bool m_rollDate;
ELogType m_logType;
unsigned long m_logRolloverSize;
bool m_unlimitedLineSize;
char m_programName[2048];
};
extern const char file_sep;
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif
@@ -0,0 +1,608 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "monitorAPI.h"
//**********************************************************************************************
//**********************************************************************************************
//********************************** DO NOT EDIT THIS FILE ***********************************
//**********************************************************************************************
//**********************************************************************************************
void set_bit( unsigned char p[], int bit){ p[bit >> 3] |= 1 << (bit & 0x7); }
void unset_bit(unsigned char p[], int bit){ p[bit >> 3] &= ~(1 << (bit & 0x7)); }
int get_bit( unsigned char p[], int bit){ return (p[bit >> 3] >> (bit & 0x7)) & 1; }
////////////////////////////////////////
// Player implementation
////////////////////////////////////////
MonitorObject::MonitorObject(UdpConnection *con,CMonitorData *_gamedata, char *passwd, char **addressList,bool _bprint)
{
mbprint = _bprint;
mMonitorData = _gamedata;
mbAuthenticated = false;
mPasswd = passwd;
mAddressList = addressList;
mHierarchySent = false;
mSequence = 1;
mlastUpdateTime = 0 ;
mConnection = con;
mConnection->AddRef();
mConnection->SetHandler(this);
// Flag all the descriptions
mMark = new unsigned char [ (mMonitorData->DataMax()/8)+2];
memset(mMark,0,(mMonitorData->DataMax()/8)+2);
char hold[256];
if( mbprint )
{
fprintf(stderr,"MONITOR API CONNECTED: %s:%d\n",
mConnection->GetDestinationIp().GetAddress(hold),
mConnection->GetDestinationPort());
}
}
MonitorObject::~MonitorObject()
{
if( mMark )
delete [] mMark;
if( mConnection )
{
mConnection->SetHandler(NULL);
mConnection->Disconnect();
mConnection->Release();
}
}
void MonitorObject::OnTerminated( UdpConnection * /* con */)
{
char hold[214];
if( mConnection )
{
if( mbprint )
{
mConnection->GetDestinationIp().GetAddress(hold);
if( mbprint )
{
fprintf(stderr,"MONITOR API TERMINATE %s:%d %s - %s\n",
hold,
mConnection->GetDestinationPort(),
UdpConnection::DisconnectReasonText( mConnection->GetDisconnectReason()),
UdpConnection::DisconnectReasonText( mConnection->GetOtherSideDisconnectReason()));
}
}
mConnection->SetHandler(NULL);
mConnection->Disconnect();
mConnection->Release();
mConnection = NULL;
}
}
void MonitorObject::OnRoutePacket(UdpConnection * con, const uchar *data, int dataLen)
{
if( dataLen < 6 )
{
if( mbprint )
fprintf(stderr,"MONITOR API: This should not happen, line %d\n",__LINE__);
}
simpleMessage msg(data);
if( con == NULL )
{
if( mbprint)
fprintf(stderr,"MONITOR API: MonitorObject.OnRoutePacket, recived a NULL connection.?\n");
return;
}
//************************* Login Process ***************************
if ( mbAuthenticated == false )
{
if ( msg.getCommand() != MON_MSG_AUTH )
return;
if( processAuthRequest(data, dataLen) == false )
return;
mbAuthenticated = true;
return;
}
//************************* Process Commands ***********************
switch(msg.getCommand())
{
// *********************** Game Server Processing ******************
case MON_MSG_QUERY_ELEMENTS:
if( mHierarchySent == true )
{
if( mMonitorData->processElementsRequest(con,mSequence,(char *)&data[6],dataLen,mlastUpdateTime ))
mlastUpdateTime = time(NULL);
break;
}
// NOTE: if mHierarchy is not sent or changed, then send it.
case MON_MSG_QUERY_HIERARCHY:
if( mMonitorData->processHierarchyRequest(con,mSequence) == false)
{
break;
}
mHierarchySent = true;
break;
case MON_MSG_QUERY_DESCRIPTION:
mMonitorData->processDescriptionRequest(con,mSequence,(char *)&data[6], dataLen,mMark);
break;
case MON_MSG_ERROR:
processError(data);
break;
default:
fprintf(stderr,"MONITOR API: unknown message type received from client [%x]\n",msg.getCommand());
break;
}
}
bool MonitorObject::checkAddress(const char * address)
{
int x = 0;
while( mAddressList[x] )
{
if (strncmp(mAddressList[x], address, strlen(mAddressList[x]))== 0)
return true;
x++;
}
return false;
}
bool MonitorObject::checkPasswd( const char *passwd)
{
if (strcmp(mPasswd,passwd)== 0 )
return true;
return false;
}
bool MonitorObject::processAuthRequest(const unsigned char * data, int /* dataLen */)
{
char reply;
stringMessage strMsg(data);
char addBuff[16] = {0};
char sendBuf[32];
int len;
reply = '1';
if ( checkAddress(mConnection->GetDestinationIp().GetAddress(addBuff)) == false)
{
reply = '3';
}
else if (checkPasswd(strMsg.getData()) == false)
{
reply = '2';
}
memset(sendBuf, 0, sizeof(sendBuf));
len = 0;
packShort( sendBuf + len, len,(short)MON_MSG_AUTHREPLY);
packShort( sendBuf + len, len, mSequence);
packShort( sendBuf + len, len,(short)3);
packShort( sendBuf + len, len,(short)CURRENT_API_VERSION);
packByte( sendBuf + len, len, reply);
mConnection->Send(cUdpChannelReliable1, sendBuf, 9 );
return true;
}
void MonitorObject::DescriptionMark(int x,int mode)
{
if( mode == 0 ) set_bit(mMark,x); else unset_bit(mMark,x);
}
char * getErrorString(unsigned short errorCode)
{
if (errorCode == 0)
{
return "none";
}
else
{
switch (errorCode)
{
case INVALID_HEADER:
case INVALID_SEQUENCE:
case INVALID_MSG_LENGTH:
case INVALID_MSG_TYPE:
return "Invalid message";
case INVALID_AUTH_REQUEST:
return "Invalid authorization request";
case INVALID_ELEMENT_REQUEST:
case INVALID_HIERARCHY_REQUEST:
return "Invalid data request";
case INVALID_AUTH_REPLY:
return "Invalid reply to authentication request";
case INVALID_ELEMENT_REPLY:
case INVALID_HIERARCHY_REPLY:
return "Badly formatted data in dataReplyMessage";
case INVALID_ERROR_CODE:
return "Received invalid error message";
}
}
return "Undefined error code";
}
bool MonitorObject::processError(const unsigned char * data)
{
stringMessage strMsg(data);
unsigned short errCode = (unsigned short)atoi(strMsg.getData());
fprintf(stderr,"MONITOR API Error: %s\n", getErrorString(errCode));
return true;
}
///////////////////////////////////////
// MonitorManager implementation
////////////////////////////////////////
MonitorManager::MonitorManager(char *configFile, CMonitorData *_gamedata, UdpManager *manager, bool _bprint)
{
mManager = manager;
mbprint = _bprint;
passString = NULL;
mMonitorData = _gamedata;
mObjectCount = 0;
for(int x=0;x<AUTHADDRESS_MAX;x++)
allowedAddressList[x] = 0;
loadAuthData(configFile);
}
MonitorManager::~MonitorManager()
{
int x;
x=0;
while( allowedAddressList[x])
free(allowedAddressList[x++]);
if( passString )
free( passString );
for (int i =0; i < mObjectCount; i++ )
delete mObject[i];
}
void MonitorManager::OnConnectRequest(UdpConnection *con)
{
if( mObjectCount == CONNECTION_MAX )
{
if( con )
{
con->SetHandler(NULL);
con->Disconnect();
con->Release();
}
if( mbprint )
fprintf(stderr,"MonitorAPI: Collector connection reached max (%d).\n",CONNECTION_MAX);
return;
}
AddObject(new MonitorObject(con,mMonitorData,passString,allowedAddressList,mbprint));
}
void MonitorManager::AddObject(MonitorObject *Object)
{
mObject[mObjectCount++] = Object;
}
void MonitorManager::GiveTime()
{
// check if the monitor object is no longer connected
for (int i = 0; i < mObjectCount; i++)
{
if( mObject[i]->mConnection == NULL ||
mObject[i]->mConnection->GetStatus() == UdpConnection::cStatusDisconnected )
{
MonitorObject *o = mObject[i];
mObjectCount--;
memmove(&mObject[i], &mObject[i + 1], (mObjectCount - i) * sizeof(MonitorObject *));
i--;
delete o;
}
}
}
void MonitorManager::HierarchyChanged()
{
for (int i = 0; i < mObjectCount; i++)
mObject[i]->HeirarchyChanged();
}
void MonitorManager::DescriptionMark(int x ,int mode)
{
for (int i = 0; i < mObjectCount; i++)
mObject[i]->DescriptionMark(x,mode);
}
bool MonitorManager::loadAuthData(const char * filename)
{
int nline;
int len;
int x;
char buffer[1024];
FILE *fp = fopen(filename,"r");
if (fp == NULL)
{
fprintf(stderr,"Monitor API: could not open %s file\nTHIS FILE IS REQUIRED.\n", filename);
return false;
}
if( passString )
free(passString);
for(x=0;x<AUTHADDRESS_MAX;x++)
{
if( allowedAddressList[x] )
{
free(allowedAddressList[x]);
allowedAddressList[x] = 0;
}
}
nline = 0;
x = 0;
while(!feof(fp))
{
fgets( buffer, 1023, fp);
// get rid of '\n' and '\r' for comparisons
strtok(buffer,"\r\n");
len = strlen(buffer);
if( len > 0 )
{
if( nline == 0 )
{
passString = (char *)malloc( len + 1 );
strcpy(passString,buffer);
}
else
{
allowedAddressList[x] = (char *)malloc( len + 1 );
strcpy(allowedAddressList[x],buffer);
x++;
}
}
nline++;
}
// clean up
fclose(fp);
return true;
}
//******************************************************************************************************
//******************************************************************************************************
//******************************************************************************************************
//******************************************************************************************************
CMonitorAPI::CMonitorAPI( char *configFile, unsigned short Port, bool _bprint , char *address, UdpManager * mang )
{
mbprint = _bprint;
mPort = Port;
mAddress = NULL;
if( address )
{
mAddress = (char *)malloc(strlen(address)+1);
strcpy(mAddress,address);
}
if( mang == NULL )
{
UdpManager::Params params;
params.handler = NULL;
params.maxConnections = CONNECTION_MAX;
params.outgoingBufferSize = 1000000;
params.noDataTimeout = 130000;
params.oldestUnacknowledgedTimeout = 120000;
params.processIcmpErrors = false;
params.port = mPort;
mManager = new UdpManager(&params);
mMonitorData = new CMonitorData();
}
mObjectManager = new MonitorManager(configFile,mMonitorData,mManager,mbprint);
mManager->SetHandler(mObjectManager);
if( mbprint )
fprintf(stderr,"MonitorAPI: started on port->%d\n",mPort);
}
CMonitorAPI::~CMonitorAPI()
{
if( mAddress )
free(mAddress);
if( mObjectManager )
delete mObjectManager;
mManager->Release();
if( mMonitorData )
delete mMonitorData;
}
void CMonitorAPI::Update()
{
if( mManager )
mManager->GiveTime();
if( mObjectManager )
mObjectManager->GiveTime();
}
void CMonitorAPI::add(const char *label, int id, int ping, char *des )
{
if( mMonitorData->add(label,id,ping,des))
mObjectManager->HierarchyChanged();
}
void CMonitorAPI::remove(int Id)
{
mMonitorData->remove(Id);
mObjectManager->HierarchyChanged();
}
void CMonitorAPI::setDescription( int Id, const char *Description )
{
int x;
int mode;
x = mMonitorData->setDescription(Id,Description,mode);
if( x == -1 )
return;
mObjectManager->DescriptionMark(x,mode);
}
void CMonitorAPI::dump(){ mMonitorData->dump(); }
//----------------------------------------------------------------
monMessage::monMessage():command(0),sequence(0),size(0){}
//----------------------------------------------------------------
monMessage::monMessage(short cmd,short seq,short s):command(cmd),sequence(seq),size(s){}
//----------------------------------------------------------------
monMessage::monMessage(const unsigned char * source):command(0),sequence(0),size(0)
{
int len;
len = 0;
unpackShort( (char *)source + len, len,command);
unpackShort( (char *)source + len, len,sequence);
unpackShort( (char *)source + len, len,size);
}
//----------------------------------------------------------------
monMessage::monMessage(const monMessage &copy):command(copy.command),sequence(copy.sequence),size(copy.size){}
//----------------------------------------------------------------
monMessage::~monMessage(){}
//----------------------------------------------------------------
stringMessage::stringMessage(const unsigned char * source):monMessage(source)
{
int size;
size = strlen((char *)source+6) +1;
data = new char [ size ];
strcpy(data,(char *)source+6); // Add six for the size of the header
}
//----------------------------------------------------------------
stringMessage::stringMessage(const unsigned short command,const unsigned short sequence,const unsigned short size,char * newData):
monMessage(command, sequence, size)
{
data = new char [strlen(newData) + 1];
if (data)
strncpy(data, newData, strlen(newData + 1));
else
data = NULL;
}
//----------------------------------------------------------------
stringMessage::~stringMessage()
{
if(data)
delete [] data;
data = 0;
}
//----------------------------------------------------------------
authReplyMessage::authReplyMessage(const unsigned char * source) :
monMessage(source)
{
int len = 6;
unpackShort((char *)source+len,len,version);
unpackByte((char *)source+len,len,data);
}
//----------------------------------------------------------------
authReplyMessage::authReplyMessage(const unsigned short command,
const unsigned short sequence,
const unsigned short size,
unsigned char newData):
monMessage(command, sequence, size),data(newData){}
//----------------------------------------------------------------
authReplyMessage::~authReplyMessage(){}
//----------------------------------------------------------------
dataReplyMessage::dataReplyMessage(const unsigned char * source) :
monMessage(source)
{
data = new unsigned char[getSize()+1];
if (data)
{
memcpy(data, source + 6, getSize());
data[getSize()] = 0;
}
else
data = NULL;
}
//----------------------------------------------------------------
dataReplyMessage::dataReplyMessage(const unsigned short command,
const unsigned short sequence,
const unsigned short size,
unsigned char * newData,
int newDataLen):
monMessage(command, sequence, size)
{
data = new unsigned char[newDataLen];
if (data)
memcpy(data, newData, newDataLen);
else
data = NULL;
}
//----------------------------------------------------------------
dataReplyMessage::~dataReplyMessage()
{
if (data)
{
delete [] data;
data = 0;
}
}
//----------------------------------------------------------------
simpleMessage::simpleMessage(const unsigned char * source):monMessage(source){}
//----------------------------------------------------------------
simpleMessage::simpleMessage(const unsigned short command,
const unsigned short sequence,
const unsigned short size):
monMessage(command, sequence, size){}
//----------------------------------------------------------------
simpleMessage::~simpleMessage(){}
//----------------------------------------------------------------
@@ -0,0 +1,105 @@
#ifndef __MONITOR_API__
#define __MONITOR_API__
//**********************************************************************************************
//**********************************************************************************************
//********************************** DO NOT EDIT THIS FILE ***********************************
//**********************************************************************************************
//**********************************************************************************************
#include "UdpLibrary/UdpHandler.hpp"
#include "UdpLibrary/UdpLibrary.hpp"
#include "monitorData.h"
#define AUTHADDRESS_MAX 30
#define CONNECTION_MAX 8
class MonitorObject : public UdpConnectionHandler
{
CMonitorData *mMonitorData;
short mSequence;
char *mPasswd;
char **mAddressList;
unsigned char *mMark;
int mbAuthenticated;
bool mHierarchySent;
bool mbprint;
long mlastUpdateTime;
bool checkAddress(const char * address);
bool checkPasswd( const char *passwd);
public:
UdpConnection *mConnection;
MonitorObject(UdpConnection *con, CMonitorData *, char *passwd, char **addressList ,bool _bprint );
virtual ~MonitorObject();
virtual void OnRoutePacket(UdpConnection *con, const uchar *data, int dataLen);
virtual void OnTerminated( UdpConnection *con);
bool processAuthRequest(const unsigned char * data, int dataLen);
bool processError(const unsigned char * data);
void HeirarchyChanged(){ mHierarchySent = false; }
void DescriptionMark(int x,int mode);
};
class MonitorManager : public UdpManagerHandler
{
bool mbprint;
CMonitorData *mMonitorData;
char *passString;
char *allowedAddressList[AUTHADDRESS_MAX];
bool loadAuthData(const char * filename);
public:
MonitorManager(char *configFile, CMonitorData *gamedata, UdpManager *manager , bool _bprint = false);
virtual ~MonitorManager();
void AddObject(MonitorObject *player);
void GiveTime();
void HierarchyChanged();
void DescriptionMark(int x,int mode);
virtual void OnConnectRequest(UdpConnection *con);
protected:
MonitorObject *mObject[CONNECTION_MAX];
int mObjectCount;
UdpManager *mManager;
};
class CMonitorAPI {
bool mbprint;
public:
CMonitorAPI( char *configFile, unsigned short Port, bool _bprint = false , char * address = NULL, UdpManager * mang = NULL );
~CMonitorAPI();
void Update();
void add( const char *label, int id, int ping = MON_PING_5MIN, char *des = NULL );
void setDescription( int Id, const char *Description ) ;
int PingValue(int p){ return mMonitorData->pingValue(p); }
void set(int Id, int value){ mMonitorData->set(Id,value); }
void remove(int Id);
void dump();
private:
CMonitorData *mMonitorData;
UdpManager *mManager;
MonitorManager *mObjectManager;
char *mAddress;
unsigned short mPort;
};
#endif
@@ -0,0 +1,598 @@
// #include <varargs.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "monitorData.h"
#ifdef WIN32
#define snprintf _snprintf
#endif
//**********************************************************************************************
//**********************************************************************************************
//********************************** DO NOT EDIT THIS FILE ***********************************
//**********************************************************************************************
//**********************************************************************************************
#define ELEMENT_START_VALUE 600
#define BUFFER_SIZE_START 2048
#define BUFFER_RESIZE_VALUE 1024
extern void set_bit( unsigned char p[], int bit);
extern void unset_bit(unsigned char p[], int bit);
extern int get_bit( unsigned char p[], int bit);
// ------------------ Support Routine -----------------------------
//////////////////////////////////////////////////////////////////////
// qsort compare routine
//////////////////////////////////////////////////////////////////////
int compar( const void *e1, const void *e2 )
{
MON_ELEMENT *data1,*data2;
data1 = (MON_ELEMENT *)e1;
data2 = (MON_ELEMENT *)e2;
#ifdef _WIN32
return stricmp(data1->label, data2->label);
#else
return strcasecmp(data1->label,data2->label);
#endif
}
// ------------------ Game Data Object ----------------------------
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMonitorData::CMonitorData()
{
m_sequence = 1;
m_buffer = NULL;
m_nbuffer = 0;
m_count = 0;
m_max = ELEMENT_START_VALUE;
m_data = new MON_ELEMENT[m_max];
for(int x=0;x<m_max;x++)
{
memset(&m_data[x],0,sizeof(MON_ELEMENT));
}
resize_buffer(BUFFER_SIZE_START);
}
CMonitorData::~CMonitorData()
{
int x;
for(x=0;x<m_count;x++)
{
if( m_data[x].discription )
delete m_data[x].discription;
if( m_data[x].label )
delete m_data[x].label;
}
if(m_buffer)
delete m_buffer;
if( m_data )
delete [] m_data;
}
void CMonitorData::resize_buffer(int new_size)
{
char *temp;
if( m_buffer != NULL )
{
temp = m_buffer;
m_buffer = new char[ new_size];
memcpy(m_buffer,temp,m_nbuffer);
m_nbuffer = new_size;
delete [] temp;
}
else
{
m_buffer = new char[ new_size];
m_nbuffer = new_size;
}
}
void CMonitorData::send(UdpConnection *con,short & sequence,short msg,char *data )
{
int len;
int size;
char *p;
size = strlen(data)+1;
p = (char *)malloc(size+6);
len = 0;
packShort(p+len, len, msg);
packShort(p+len, len, m_sequence);
packShort(p+len, len, size);
memcpy( p+len, data, size );
con->Send(cUdpChannelReliable1, p, size + 6);
free(p);
sequence++;
}
bool CMonitorData::processHierarchyRequest( UdpConnection *con, short & sequence )
{
int x,size;
char temp[215];
if( m_count == 0 )
{
send(con,sequence,MON_MSG_REPLY_HIERARCHY,"NOTREADY");
return 0;
}
if( m_sort )
{
qsort(m_data,m_count,sizeof(MON_ELEMENT),compar);
m_sort = 0;
}
memset(m_buffer,0, 16);
size = 0;
for(x=0;x<m_count;x++)
{
snprintf(temp, sizeof(temp), "%s,%X,%d|", m_data[x].label, m_data[x].id, m_data[x].ping);
size += strlen(temp);
if( size >= m_nbuffer )
resize_buffer(size+BUFFER_RESIZE_VALUE);
strcat(m_buffer,temp);
}
send(con,sequence,MON_MSG_REPLY_HIERARCHY,m_buffer);
return 1;
}
bool CMonitorData::processElementsRequest(UdpConnection *con, short & sequence, char * data, int /* dataLen */ , long lastUpdateTime )
{
char tmp[200];
int x,id;
int size;
int count;
char **list;
memset(m_buffer,0,16);
if( !strcmp(data,"-1") )
{
size = 0;
for (x=0;x<m_count;x++)
{
snprintf(tmp, sizeof(tmp), "%d %x|", m_data[x].id, m_data[x].value);
size += strlen(tmp);
if( size >= m_nbuffer )
resize_buffer(size+BUFFER_RESIZE_VALUE);
strcat(m_buffer,tmp);
}
send(con,sequence,MON_MSG_REPLY_ELEMENTS,m_buffer);
return 1;
}
if( !strcmp(data,"-2") )
{
size = 0;
count = 0;
for (x=0;x<m_count;x++)
{
if( lastUpdateTime <= m_data[x].ChangedTime )
{
snprintf(tmp, sizeof(tmp), "%d %x|",m_data[x].id,m_data[x].value);
size += strlen(tmp);
if( size >= m_nbuffer )
resize_buffer(size+BUFFER_RESIZE_VALUE);
strcat(m_buffer,tmp);
count++;
}
}
if ( count )
{
send(con,sequence,MON_MSG_REPLY_ELEMENTS,m_buffer);
return 1;
}
return 0;
}
list = new char * [ELEMENT_MAX];
count = parseList( list, data,'|',ELEMENT_MAX);
memset(m_buffer,0,16);
size = 0;
for(x=0;x<count;x++)
{
id = atoi(list[x]);
for(x=0;x<m_count;x++)
if( m_data[x].id == id )
{
snprintf(tmp, sizeof(tmp), "%d %x|", m_data[x].id, m_data[x].value);
size += strlen(tmp);
if( size >= m_nbuffer )
resize_buffer(size+BUFFER_RESIZE_VALUE);
strcat(m_buffer,tmp);
}
}
delete [] list;
if( count > 0 )
send(con,sequence,MON_MSG_REPLY_ELEMENTS,m_buffer);
return 0;
}
bool CMonitorData::processDescriptionRequest(UdpConnection *con, short & sequence, char * userData, int dataLen, unsigned char *mark)
{
char line[4096];
char tmp[400];
int x,id,size;
int flag;
char *p;
size = 0;
memset(m_buffer,0,16);
strcpy(line,userData);
p = strtok(line,"|");
flag = 0;
if( strstr(p,"next") )
{
for(x=0;x<m_count;x++)
{
if( get_bit(mark,x) == 0 )
{
if( m_data[x].discription != NULL )
snprintf(tmp, sizeof(tmp), "%d,%s|", m_data[x].id, m_data[x].discription);
else
snprintf(tmp, sizeof(tmp), "%d, |", m_data[x].id);
set_bit( mark, x );
size += strlen(tmp);
if( size >= m_nbuffer )
resize_buffer(size+BUFFER_RESIZE_VALUE);
strcat(m_buffer,tmp);
send(con,sequence,MON_MSG_REPLY_DESCRIPTION,m_buffer);
return 1;
}
}
}
else
{
if( p )
{
size = 0;
flag = 0;
id = atoi(p);
for(x=0;x<m_count;x++)
{
if( flag == 0 && id == m_data[x].id )
flag = 1;
if( flag )
{
flag = 2;
if( m_data[x].discription != NULL )
snprintf(tmp, sizeof(tmp), "%d,%s|", m_data[x].id, m_data[x].discription);
else
snprintf(tmp, sizeof(tmp), "%d, |", m_data[x].id);
set_bit(mark,x);
size += strlen(tmp);
if( size >= m_nbuffer )
resize_buffer(size+BUFFER_RESIZE_VALUE);
strcat(m_buffer,tmp);
if( size >= 2000 || m_data[x].discription )
{
send(con,sequence,MON_MSG_REPLY_DESCRIPTION,m_buffer);
return 1;
}
}
}
}
}
if( flag == 2 )
send(con,sequence,MON_MSG_REPLY_DESCRIPTION,m_buffer);
send(con,sequence,MON_MSG_REPLY_DESCRIPTION,"none");
return 0;
}
int CMonitorData::add(const char *label, int id, int ping, char *des )
{
int x;
if( strlen(label) >= 127 )
{
printf("MonAPI Error: add() label exceeds length of 127. ->%s\n",label);
return 0;
}
for(x=0;x<m_count;x++)
{
if( id == m_data[x].id )
{
printf("MonAPI: assign new Id (%d) %s -> %s\n",id,m_data[x].label,label);
m_data[x].ping = pingValue( ping );
m_data[x].value = 0;
m_data[x].id = id;
//******* Label ***********
if( m_data[x].label )
delete m_data[x].label;
m_data[x].label = new char [strlen(label)+1];
strcpy(m_data[x].label,label);
//******* Discription ******
if( m_data[x].discription != NULL )
delete [] m_data[x].discription;
m_data[x].discription = NULL;
if( des )
{
m_data[x].discription = new char [strlen(des)+1];
strcpy(m_data[x].discription,des);
}
m_sort = 1;
return 1;
}
if( !strcmp(label,m_data[x].label) )
{
printf("MonAPI ERROR: Label already found %s Id: old(%d) new(%d).\n",label,m_data[x].id,id);
return 0;
}
}
if( m_max == m_count + 1 )
{
printf("MonitorObject: max element reached [%d].\n%s\nContact David Taylor (858) 577-3155.\n",m_max,label);
return 0;
}
m_data[m_count].ping = pingValue( ping );
m_data[m_count].value = 0;
m_data[m_count].id = id;
m_data[m_count].label = new char [strlen(label)+1];
strcpy(m_data[m_count].label,label);
if( des )
{
if( m_data[x].discription )
delete [] m_data[x].discription;
m_data[x].discription = new char [strlen(des)+1];
strcpy(m_data[x].discription,des);
}
m_count++;
m_sort = 1;
return 1;
}
int CMonitorData::setDescription( int Id, const char *Description , int & mode)
{
int x;
for(x=0;x<m_count;x++)
{
if( Id == m_data[x].id )
{
if( Description == NULL )
{
if( m_data[x].discription )
delete [] m_data[x].discription;
m_data[x].discription = NULL;
mode = 0;
return x;
}
if( m_data[x].discription && !strcmp( m_data[x].discription, Description ) )
return -1;
if( m_data[x].discription )
delete [] m_data[x].discription;
m_data[x].discription = new char [ strlen(Description) +1 ];
strcpy(m_data[x].discription,Description);
mode = 1;
return x;
}
}
return -1;
}
int CMonitorData::pingValue(int p)
{
switch(p)
{
case MON_PING_15: return 15;
case MON_PING_30: return 30;
case MON_PING_60: return 60;
case MON_PING_5MIN: return (60 * 5);
default:
printf("MonAPI ERROR: add() function is not using defined constances.\n");
printf("Please use one of the following:\n");
printf("\tMON_PING_15\n\tMON_PING_30\n\tMON_PING_60\n\tMON_PING_5MIN\n");
break;
}
return 0;
}
void CMonitorData::set(int Id, int value)
{
for(int x=0;x<m_count;x++)
if( Id == m_data[x].id )
{
if( m_data[x].ChangedTime == 0 || m_data[x].value != value )
m_data[x].ChangedTime = time(NULL);
m_data[x].value = value;
return;
}
}
void CMonitorData::remove(int Id)
{
int x;
if( m_count == 1 )
{
if( m_data[0].label )
delete [] m_data[0].label;
m_data[0].label = 0;
m_data[0].id = 0;
m_data[0].value = 0;;
m_data[0].ping = 0;;
m_sort = 1;
m_count--;
return;
}
for(x=0;x<m_count;x++)
{
if( Id == m_data[x].id )
{
if( m_data[x].label )
delete [] m_data[x].label;
m_data[x].label = 0;
if( x < m_count -1 )
{
memcpy(&m_data[x],&m_data[m_count-1],sizeof(MON_ELEMENT));
}
memset(&m_data[m_count-1],0,sizeof(MON_ELEMENT));
m_sort = 1;
m_count--;
return;
}
}
}
int CMonitorData::parseList( char **list, char *data, char tok , int max )
{
int count;
int cnt;
if( data == NULL )
return 0;
list[0] = data;
count = 1;
cnt =0;
while( cnt < max && *data > 0 )
{
if( *data == tok )
{
*data = 0;
data++;
cnt++;
list[count] = data;
if( *data ) count++;
}
cnt++;
if( *data ) data++;
}
return count;
}
void CMonitorData::dump()
{
if( m_sort )
{
qsort(m_data,m_count,sizeof(MON_ELEMENT),compar);
m_sort = 0;
}
printf("********** Monitor API Dump *******************\n");
printf(" Version: %d\n",CURRENT_API_VERSION);
printf("\ncount: %d\n", m_count);
printf("\t%-40s %8s\t%s\t%s\n","Label","Id","Ping","Value");
for(int x=0;x<m_count;x++)
{
printf("\t%-40s % 8d\t%d\t%d\n",
m_data[x].label,
m_data[x].id,
m_data[x].ping,
m_data[x].value);
}
printf("***********************************************\n");
}
//////////////////////////////////////////////////////////////////////////////
// ------------------ Pack and unpack Routine -----------------------------
///////////////////////////////////////////////////////////////////////////////
int packString(char *buffer, int & len, char * value)
{
int size;
size = strlen(value)+1;
memcpy(buffer,value, size);
len += size;
return size;
}
int packByte(char *buffer, int & len, char value)
{
buffer[0] = value;
len++;
return 1;
}
int packShort(char *buffer, int & len, short value)
{
char *p;
p = (char *)&value;
#ifdef _sun
buffer[0] = p[1];
buffer[1] = p[0];
#else
buffer[0] = p[0];
buffer[1] = p[1];
#endif
len += 2;
return 2;
}
int unpackShort(char *buffer, int & len, short & value)
{
char *p;
p = (char *)&value;
#ifdef _sun
p[1] = buffer[0];
p[0] = buffer[1];
#else
p[0] = buffer[0];
p[1] = buffer[1];
#endif
len += 2;
return 2;
}
int unpackByte( char *buffer, int & len, char &value)
{
value = buffer[0];
len++;
return 1;
}
@@ -0,0 +1,252 @@
#ifndef __MONITOR_DATA__
#define __MONITOR_DATA__
//**********************************************************************************************
//**********************************************************************************************
//********************************** DO NOT EDIT THIS FILE ***********************************
//**********************************************************************************************
//**********************************************************************************************
#include "UdpLibrary/UdpHandler.hpp"
#include "UdpLibrary/UdpLibrary.hpp"
#define CURRENT_API_VERSION 2
#define MON_PING_15 1 // This will ping every 15 sec.
#define MON_PING_30 2 // This will ping every 30 sec.
#define MON_PING_60 3 // This will ping every 30 sec. and report max of 60 sec
#define MON_PING_5MIN 4 // This will ping every 30 sec. and report max of 5 min.
#define MON_ONLY_SHOW 5 // This will not store data. WILL NOT GRAPH
#define STATUS_LOCKED -1 // Server is locking out players
#define STATUS_DOWN -2 // Server is down.
#define STATUS_NOCONNECT -3 // Server is not connected
#define STATUS_LOADING -4 // Server is in a loading state
#define ELEMENT_MAX 1000
/*
Provide binary data packing and unpacking functions
Usage
Format strings are as follows:
'c' - char (1)
'l' - long int (4)
'L' - long long int (8)
'i' - int (4)
's' - short int (2)
'S' - C-style, null-terminated string (n + null)
'Bn' - buffer, of size n. Used for non-terminated strings, or
other binary data.
*/
extern int packString(char *buffer, int & len, char * value);
extern int packByte(char *buffer, int & len, char value);
extern int packShort(char *buffer, int & len, short value);
extern int unpackShort(char *buffer, int & len, short & value);
extern int unpackByte( char *buffer, int & len, char & value);
//----------------------------------------------------------------
typedef unsigned char byte;
//----------------------------------------------------------------
// Define the message types that are understood via the Monitoring API
enum MON_MESSAGES
{
MON_MSG_AUTH = 1, // client sends auth info during connect request
MON_MSG_AUTHREPLY, // server responds to auth request
MON_MSG_QUERY_ELEMENTS, // client asking for element data
MON_MSG_QUERY_HIERARCHY, // client asking for hierarchy data
MON_MSG_REPLY_ELEMENTS, // server returns element data
MON_MSG_REPLY_HIERARCHY, // server returns element data
MON_MSG_QUERY_DESCRIPTION, // client asking for Description of element
MON_MSG_REPLY_DESCRIPTION, // server returns element Description of element
MON_MSG_ERROR = 99 // one of many errors, defined elsewhere
};
//----------------------------------------------------------------
// define error codes that can be sent and received via MON_MSG_ERROR types
enum MON_ERRORS
{
INVALID_HEADER = 10, // could not read the header data reliably
INVALID_SEQUENCE = 20, // out of range or unknown sequence number
INVALID_MSG_LENGTH = 30, // message length field is incorrect
INVALID_AUTH_REQUEST = 101, // could not read the entire request
INVALID_ELEMENT_REQUEST = 102, // could not read the entire request
INVALID_HIERARCHY_REQUEST = 103, // could not read the entire request
INVALID_AUTH_REPLY = 105, // the data reply was incorrectly formatted
INVALID_ELEMENT_REPLY = 106, // the data reply was incorrectly formatted
INVALID_HIERARCHY_REPLY = 107, // the data reply was incorrectly formatted
INVALID_ERROR_CODE = 108, // an error was sent, but it isn't recognized
INVALID_MSG_TYPE = 109, // an invalid message type was sent
INVALID_CONFIG_FILE = 110 // Error in reading config file
};
//----------------------------------------------------------------
// monMessage
// The base message class for the Monitor API
// This message should not be used explicitly. Use simpleMessage for basic tasks.
// monMessage does not contain the etx field as required by the monitoring protocol.
class monMessage
{
public:
explicit monMessage(short command, short sequence, short size);
explicit monMessage(const unsigned char * source);
monMessage(const monMessage &copy);
monMessage();
~monMessage();
inline const unsigned short getCommand() const {return command;}
inline const unsigned short getSequence() const {return sequence;}
inline const unsigned short getSize() const {return size;}
private:
short command;
short sequence;
short size;
};
//----------------------------------------------------------------
// stringMessage
// This message type is used for passing messages that can consist of a NULL terminated string
class stringMessage : public monMessage
{
public:
explicit stringMessage(const unsigned short command, const unsigned short sequence, const unsigned short size, char * data);
explicit stringMessage(const unsigned char * source);
~stringMessage();
inline const char * getData() const {return data;};
private:
char * data;
};
//----------------------------------------------------------------
// authReplyMessage
// This message is used exclusively to tell the client whether or not they were successfully
// authenticated. This message is sent in reply to a MON_MSG_AUTH request.
class authReplyMessage : public monMessage
{
public:
explicit authReplyMessage(const unsigned short command, const unsigned short sequence, const unsigned short size, byte data);
explicit authReplyMessage(const unsigned char * source);
~authReplyMessage();
inline const unsigned char getData() const {return data;};
inline const short getVersion() const { return version; };
inline void setData(const unsigned char newData) {data = newData;}
private:
char data;
short version;
};
//----------------------------------------------------------------
// dataReplyMessage
// This message type is sent for Element and Hierarchy data requests
// The data is stored and retrieved as a byte array, internally represented as a std::vector<byte>
class dataReplyMessage : public monMessage
{
public:
explicit dataReplyMessage(const unsigned short command, const unsigned short sequence, const unsigned short size, unsigned char *data, int dataLen);
explicit dataReplyMessage(const unsigned char * source);
~dataReplyMessage();
inline const unsigned char * getData() const {return data;};
private:
unsigned char * data;
};
//----------------------------------------------------------------
// simpleMessage
// This is the most basic monitor API message. It can be created from an
// Archive::ByteStream in order to discover the message type for more complex messages,
// or it could be sent explicitly for query message types.
class simpleMessage : public monMessage
{
public:
explicit simpleMessage(const unsigned short command, const unsigned short sequence, const unsigned short size);
explicit simpleMessage(const unsigned char * source);
~simpleMessage();
private:
};
//*************** Internal Struct ***************************
typedef struct {
int value; // Value of the element
int id; // Id for users, user control, could be any value, must be unique
int ping; // Ping time, use one of the API defined values, MON_PING_15,...
char *label; // Label of element, use periods to make sub labels, last name sperated
// by periods is the name of the element.
//
// Example: "Universe.Planet.Zone1.count"
// Universe.Planet.Zone1 = Tree name
// count = element name
//
// NOTE: This label is the name of the data element, change the label name
// and a new history of data is started. You will not be able to change
// the name at run time.
//
char *discription; // Discription of element. This can be changed at will.
long ChangedTime;
} MON_ELEMENT;
class CMonitorData {
MON_ELEMENT *m_data; // Pointer to MON_DATA elements
int m_ndata;
int m_count;
int m_max;
int m_sort;
char *m_buffer;
int m_nbuffer;
short m_sequence;
int parseList( char **list, char *data, char tok , int max );
void resize_buffer(int new_size);
void send( UdpConnection *mConnection,short & sequence, short msg,char *data );
public:
CMonitorData();
~CMonitorData();
int getCount(){ return m_ndata; }
int DataMax(){ return m_max; }
bool processHierarchyRequest(UdpConnection *con, short & sequence);
bool processElementsRequest( UdpConnection *con, short & sequence, char * userData, int dataLen , long lastUpdateTime);
bool processDescriptionRequest(UdpConnection *con, short & sequence, char * userData, int dataLen,unsigned char *mark);
int add(const char *label, int id, int ping, char *des );
int setDescription( int Id, const char *Description , int & mode);
char *getDescription(int x){ if( m_ndata >= x ) return NULL; return m_data[x].discription;}
int pingValue(int p);
void set(int Id, int value);
void remove(int Id);
void dump();
};
#endif
@@ -0,0 +1,57 @@
#include "pid.h"
#ifdef WIN32
#include <Winsock2.h>
#else
#include <errno.h>
extern int errno;
#endif
#include <cstdio>
#define NAME_SIZE 256
#ifdef WIN32
std::string soegethostname()
{
std::string hn = "";
WORD wVersionRequested;
WSADATA wsaData;
char name[NAME_SIZE];
wVersionRequested = MAKEWORD( 2, 0 );
if ( WSAStartup( wVersionRequested, &wsaData ) == 0 )
{
if( gethostname ( name, sizeof(name)) != 0)
{
int err = WSAGetLastError();
printf("gethostname error: %d\n", err);
}
WSACleanup( );
}
hn = name;
return hn;
}
#else
std::string soegethostname()
{
char res[NAME_SIZE];
memset(res, 0, NAME_SIZE);
std::string retVal;
int error = gethostname(res, NAME_SIZE-1);
int errdetail;
if(error !=0)
{
errdetail = errno;
}
retVal = res;
return retVal;
}
#endif
@@ -0,0 +1,23 @@
#ifndef SOE_PID_H
#define SOE_PID_H
#ifndef WIN32
#include <sys/types.h>
#include <unistd.h>
#define soegetpid() (long)getpid()
#endif
#ifdef WIN32
// include winsock 2 before windows to not have winsock 1 included . . .
#include <WinSock2.h>
#include <winbase.h>
#define soegetpid() (long)GetCurrentProcessId()
#endif
#include <string>
std::string soegethostname();
#endif
@@ -0,0 +1,225 @@
#ifndef PRIORITY_HPP
#define PRIORITY_HPP
template<typename T, typename P> class PriorityQueue;
// classes that wish to be members of the priority queue below must derive themselves from this class
// in order to pull in the two member variables. Unlike normal priority queue classes which don't
// have this restriction, it is required in order to support Remove and reprioritize functionality
// in a timely manner (otherwise, in order to remove an entry that is not at the top, you would have
// to linearly scan the entire queue). This is accomplished by having the member itself contain
// a pointer to it's position in the queue (mPriorityQueuePosition).
// note: a restriction of this ability is that an object cannot participate in more than one priority
// queue at a time.
class PriorityQueueMember
{
public:
PriorityQueueMember();
#if defined(_MSC_VER) && (_MSC_VER >= 1300) // MSVC 7.0 is the first version to support friend templates
template<typename T, typename P> friend class PriorityQueue;
protected:
#else
public:
#endif
int mPriorityQueuePosition; // -1=not in queue
};
// this class provides a priority queue that is capable of reprioritizing/removing entries. The
// compiler will ensure that objects stored in this class are derived from PriorityQueueMember.
// We don't really need this to be a template class, since we could just treat everything as a
// PriorityQueueMember, but then the application would lose some type checking. We don't use references
// in the api as most priority queue templates do as we can't support non pointer types anyways.
template<typename T, typename P> class PriorityQueue
{
public:
PriorityQueue(int queueSize);
~PriorityQueue();
T* Top(); // returns NULL if queue is empty
T* TopRemove(); // returns NULL if queue is empty
T* TopRemove(P priority); // removes item from queue if it has a lower priority value, otherwise return NULL
T* Add(T* entry, P priority); // reprioritizes if already in queue, returns entry always
T* Remove(T* entry); // returns entry always (even if it was not in the queue)
P *GetPriority(T* entry); // returns NULL if entry is not in the queue
int QueueUsed(); // returns how many entries are in the queue
protected:
struct QueueEntry
{
T* entry;
P priority;
};
QueueEntry* mQueue;
int mQueueSize;
int mQueueEnd;
void Refloat(T* entry);
};
//////////////////////////////////////////////////////////////////////////
// PriorityQueueMember implementation
//////////////////////////////////////////////////////////////////////////
inline PriorityQueueMember::PriorityQueueMember()
{
mPriorityQueuePosition = -1;
}
//////////////////////////////////////////////////////////////////////////
// PriorityQueue implementation
//////////////////////////////////////////////////////////////////////////
template<typename T, typename P> PriorityQueue<T, P>::PriorityQueue(int queueSize)
{
mQueueEnd = 0;
mQueueSize = queueSize;
mQueue = new QueueEntry[mQueueSize];
memset(mQueue, 0, sizeof(mQueue));
}
template<typename T, typename P> PriorityQueue<T, P>::~PriorityQueue()
{
delete[] mQueue;
}
template<typename T, typename P> T* PriorityQueue<T, P>::Top()
{
if (mQueueEnd == 0)
return(NULL);
return(mQueue[0].entry);
}
template<typename T, typename P> T* PriorityQueue<T, P>::TopRemove()
{
if (mQueueEnd == 0)
return(NULL);
T* top = mQueue[0].entry;
Remove(top);
return(top);
}
template<typename T, typename P> T* PriorityQueue<T, P>::TopRemove(P priority)
{
if (mQueueEnd > 0 && mQueue[0].priority <= priority)
return(Remove(mQueue[0].entry));
return(NULL);
}
template<typename T, typename P> P* PriorityQueue<T, P>::GetPriority(T* entry)
{
if (entry->mPriorityQueuePosition >= 0)
return(&mQueue[entry->mPriorityQueuePosition].priority);
return(NULL);
}
template<typename T, typename P> T* PriorityQueue<T, P>::Add(T* entry, P priority)
{
if (entry->mPriorityQueuePosition == -1)
{
// not in queue, so add it to the bottom
if (mQueueEnd >= mQueueSize)
return(NULL);
mQueue[mQueueEnd].entry = entry;
mQueue[mQueueEnd].priority = priority;
mQueue[mQueueEnd].entry->mPriorityQueuePosition = mQueueEnd;
mQueueEnd++;
}
else
{
// see if priority has actually changed, if not, just return, otherwise change priority and fall through to refloat it
if (mQueue[entry->mPriorityQueuePosition].priority == priority)
return(entry);
mQueue[entry->mPriorityQueuePosition].priority = priority;
}
Refloat(entry);
return(entry);
}
template<typename T, typename P> T* PriorityQueue<T, P>::Remove(T* entry)
{
if (entry->mPriorityQueuePosition == -1)
return(entry);
// move end entry into place of one being removed
mQueueEnd--;
int spot = entry->mPriorityQueuePosition;
if (spot != mQueueEnd) // don't remove last item in queue (bottom of tree), so no need to copy bottom one up and refloat it (we would be refloating our own removed entry)
{
mQueue[spot] = mQueue[mQueueEnd];
mQueue[spot].entry->mPriorityQueuePosition = spot;
Refloat(mQueue[spot].entry);
}
entry->mPriorityQueuePosition = -1;
return(entry);
}
template<typename T, typename P> void PriorityQueue<T, P>::Refloat(T* entry)
{
// float upward
int spot = entry->mPriorityQueuePosition;
bool tryDown = true;
while (spot > 0 && mQueue[spot].priority < mQueue[(spot - 1) / 2].priority)
{
int newSpot = (spot - 1) / 2;
QueueEntry hold = mQueue[spot];
mQueue[spot] = mQueue[newSpot];
mQueue[newSpot] = hold;
mQueue[spot].entry->mPriorityQueuePosition = spot;
mQueue[newSpot].entry->mPriorityQueuePosition = newSpot;
spot = newSpot;
tryDown = false;
}
if (tryDown)
{
// if we didn't manage to float up at all, then we need to try floating down
for (;;)
{
// pick smallest child
int downSpot1 = (spot * 2) + 1;
if (downSpot1 >= mQueueEnd)
break;
int downSpot2 = (spot * 2) + 2;
if (downSpot2 >= mQueueEnd || mQueue[downSpot1].priority < mQueue[downSpot2].priority)
{
if (mQueue[downSpot1].priority < mQueue[spot].priority)
{
QueueEntry hold = mQueue[spot];
mQueue[spot] = mQueue[downSpot1];
mQueue[downSpot1] = hold;
mQueue[spot].entry->mPriorityQueuePosition = spot;
mQueue[downSpot1].entry->mPriorityQueuePosition = downSpot1;
spot = downSpot1;
}
else
break;
}
else
{
if (mQueue[downSpot2].priority < mQueue[spot].priority)
{
QueueEntry hold = mQueue[spot];
mQueue[spot] = mQueue[downSpot2];
mQueue[downSpot2] = hold;
mQueue[spot].entry->mPriorityQueuePosition = spot;
mQueue[downSpot2].entry->mPriorityQueuePosition = downSpot2;
spot = downSpot2;
}
else
break;
}
}
}
}
template<typename T, typename P> int PriorityQueue<T, P>::QueueUsed()
{
return(mQueueEnd);
}
#endif
@@ -0,0 +1,454 @@
#ifdef WIN32
#pragma warning (disable: 4786)
#endif
#include <stdio.h>
#include <time.h>
#include "profile.h"
#include "timer.h"
#ifdef WIN32
#define snprintf _snprintf
#endif
Profiler globalProfiler;
Profiler::NodeData::NodeData() :
mStartTimer(0),
mTotalLatency(0),
mChildLatency(0),
mTotalChildLatency(0),
mMaxLatency(0),
mMinLatency(0),
mTotalCalls(0)
{
}
Profiler::Profiler() :
mActive(false),
mStartTime(0),
mStartTimer(0),
mDataMap(),
mDataStack(),
mNodeMap(),
mNodeStack()
{
mStartTime = (unsigned)time(0);
mStartTimer = soe::GetTimer();
}
Profiler::~Profiler()
{
}
void Profiler::AddNode(Node & lhs, const Node & rhs)
{
lhs.mData.mTotalLatency += rhs.mData.mTotalLatency;
lhs.mData.mTotalChildLatency += rhs.mData.mTotalChildLatency;
lhs.mData.mTotalCalls += rhs.mData.mTotalCalls;
if (rhs.mData.mMaxLatency > lhs.mData.mMaxLatency)
lhs.mData.mMaxLatency = rhs.mData.mMaxLatency;
if (lhs.mData.mMinLatency == 0 || rhs.mData.mMinLatency < lhs.mData.mMinLatency)
lhs.mData.mMinLatency = rhs.mData.mMinLatency;
NodeMap_t::const_iterator iter;
for (iter = rhs.mNodeMap.begin(); iter != rhs.mNodeMap.end(); iter++)
{
Node & node = lhs.mNodeMap[iter->first];
AddNode(node, iter->second);
}
}
void Profiler::AddData(const Profiler & rhs, bool hierarchy)
{
if (hierarchy)
{
NodeMap_t::const_iterator nodeIter;
for (nodeIter = rhs.mNodeMap.begin(); nodeIter != rhs.mNodeMap.end(); nodeIter++)
{
Node & node = mNodeMap[nodeIter->first];
AddNode(node, nodeIter->second);
}
}
DataMap_t::const_iterator iter;
for (iter = rhs.mDataMap.begin(); iter != rhs.mDataMap.end(); iter++)
{
NodeData & lhs = mDataMap[iter->first];
const NodeData & rhs = iter->second;
lhs.mTotalLatency += rhs.mTotalLatency;
lhs.mTotalChildLatency += rhs.mTotalChildLatency;
lhs.mTotalCalls += rhs.mTotalCalls;
if (rhs.mMaxLatency > lhs.mMaxLatency)
lhs.mMaxLatency = rhs.mMaxLatency;
if (lhs.mMinLatency == 0 || rhs.mMinLatency < lhs.mMinLatency)
lhs.mMinLatency = rhs.mMinLatency;
}
}
void Profiler::Open(const std::string & description)
{
NodeData & data = mDataMap[description];
data.mStartTimer = soe::GetTimer();
data.mChildLatency = 0;
mDataStack.push_front(&data);
if (mNodeStack.empty())
{
Node & node = mNodeMap[description];
node.mData.mStartTimer = data.mStartTimer;
node.mData.mChildLatency = 0;
mNodeStack.push_front(&node);
}
else
{
Node & node = mNodeStack.front()->mNodeMap[description];
node.mData.mStartTimer = data.mStartTimer;
node.mData.mChildLatency = 0;
mNodeStack.push_front(&node);
}
}
void Profiler::Close()
{
if (mNodeStack.empty() || mDataStack.empty())
return;
double latency;
double trueLatency;
NodeData & data = *mDataStack.front();
Node & node = *mNodeStack.front();
mDataStack.pop_front();
mNodeStack.pop_front();
latency = soe::GetTimerLatency(data.mStartTimer);
trueLatency = latency - data.mChildLatency;
if (data.mMaxLatency < trueLatency)
data.mMaxLatency = trueLatency;
if (data.mMinLatency == 0 || data.mMinLatency > trueLatency)
data.mMinLatency = trueLatency;
data.mTotalLatency += latency;
data.mTotalCalls++;
trueLatency = latency - node.mData.mChildLatency;
if (node.mData.mMaxLatency < trueLatency)
node.mData.mMaxLatency = trueLatency;
if (node.mData.mMinLatency == 0 || node.mData.mMinLatency > trueLatency)
node.mData.mMinLatency = trueLatency;
node.mData.mTotalLatency += latency;
node.mData.mTotalCalls++;
if (!mNodeStack.empty() && !mDataStack.empty())
{
NodeData & parentData = *mDataStack.front();
Node & parentNode = *mNodeStack.front();
parentData.mChildLatency += latency;
parentData.mTotalChildLatency += latency;
parentNode.mData.mChildLatency += latency;
parentNode.mData.mTotalChildLatency += latency;
}
}
void Profiler::Clear()
{
mStartTime = (unsigned)time(0);
mStartTimer = soe::GetTimer();
mDataMap.clear();
mDataStack.clear();
mNodeMap.clear();
mNodeStack.clear();
}
void Profiler::GetOutput(std::string & output, bool hierarchy)
{
char buffer[256];
double profileDuration = soe::GetTimerLatency(mStartTimer);
// print header
struct tm timeStruct = *localtime((time_t *)&mStartTime);
strftime(buffer,128,"%m/%d/%Y %H:%M:%S", &timeStruct);
output = buffer;
snprintf(buffer, sizeof(buffer), " profile duration: %.1fms\n", profileDuration*1000);
output += buffer;
if (hierarchy && !mNodeMap.empty())
{
// print legend
snprintf(buffer, sizeof(buffer), "prcnt latency max min avg count prcnt latency description\n");
output += buffer;
// recursively print node map (hierarchical call profile)
GetNodeOutput(output, mNodeMap, profileDuration);
}
// print legend
snprintf(buffer, sizeof(buffer), "prcnt latency max min avg count prcnt latency description\n");
output += buffer;
// print data map (linear call profile)
DataMap_t::const_iterator iter;
for (iter = mDataMap.begin(); iter != mDataMap.end(); iter++)
{
const NodeData & data = iter->second;
double trueLatency = data.mTotalLatency-data.mTotalChildLatency;
snprintf(buffer, sizeof(buffer), "%5.1f %9.3f %7.3f %7.3f %7.3f %5u %5.1f %9.3f ", trueLatency/profileDuration*100, trueLatency*1000, data.mMaxLatency*1000, data.mMinLatency*1000, trueLatency/data.mTotalCalls*1000, data.mTotalCalls, data.mTotalLatency/profileDuration*100, data.mTotalLatency*1000);
output += buffer;
snprintf(buffer, sizeof(buffer), "%s\n", iter->first.c_str());
output += buffer;
}
}
void Profiler::GetXmlOutput(std::string & output, bool hierarchy)
{
char buffer[256];
double profileDuration = soe::GetTimerLatency(mStartTimer);
output += "<General>";
// print header
struct tm timeStruct = *localtime((time_t *)&mStartTime);
strftime(buffer,128,"%m/%d/%Y %H:%M:%S", &timeStruct);
output += "<DateTime>";
output += buffer;
output += "</DateTime>";
snprintf(buffer, sizeof(buffer), "%.1f\n", profileDuration*1000);
output += "<Duration>";
output += buffer;
output += "</Duration>";
output += "</General>";
if (hierarchy && !mNodeMap.empty())
{
// print legend
//sprintf(buffer,"prcnt latency max min avg count prcnt latency description\n");
//output += buffer;
// recursively print node map (hierarchical call profile)
//GetNodeOutput(output, mNodeMap, profileDuration);
output += "<DataMapNested>";
GetXmlNodeOutput(output, mNodeMap, profileDuration);
output += "</DataMapNested>";
}
// print legend
//sprintf(buffer,"prcnt latency max min avg count prcnt latency description\n");
//output += buffer;
output += "<DataMap>";
output += "<DataMapCount>";
snprintf(buffer, sizeof(buffer), "%u", mDataMap.size());
output += buffer;
output += "</DataMapCount>";
// print data map (linear call profile)
int i = 1;
DataMap_t::const_iterator iter;
for (iter = mDataMap.begin(); iter != mDataMap.end(); iter++)
{
const NodeData & data = iter->second;
double trueLatency = data.mTotalLatency-data.mTotalChildLatency;
/*
sprintf(buffer, "%5.1f %9.3f %7.3f %7.3f %7.3f %5u %5.1f %9.3f ",
trueLatency/profileDuration*100,
trueLatency*1000,
data.mMaxLatency*1000,
data.mMinLatency*1000,
trueLatency/data.mTotalCalls*1000,
data.mTotalCalls,
data.mTotalLatency/profileDuration*100,
data.mTotalLatency*1000);
*/
snprintf(buffer, sizeof(buffer), "<DataMap%u>", i);
output += buffer;
output += "<Description>";
output += iter->first;
output += "</Description>";
snprintf(buffer, sizeof(buffer), "%5.1f", trueLatency/profileDuration*100);
output += "<Percent>";
output += buffer;
output += "</Percent>";
snprintf(buffer, sizeof(buffer), "%9.3f", trueLatency*1000);
output += "<Latency>";
output += buffer;
output += "</Latency>";
snprintf(buffer, sizeof(buffer), "%7.3f", data.mMaxLatency*1000);
output += "<Max>";
output += buffer;
output += "</Max>";
snprintf(buffer, sizeof(buffer), "%7.3f", data.mMinLatency*1000);
output += "<Min>";
output += buffer;
output += "</Min>";
snprintf(buffer, sizeof(buffer), "%7.3f", trueLatency/data.mTotalCalls*1000);
output += "<Average>";
output += buffer;
output += "</Average>";
snprintf(buffer, sizeof(buffer), "%5u", data.mTotalCalls);
output += "<Count>";
output += buffer;
output += "</Count>";
snprintf(buffer, sizeof(buffer), "%5.1f", data.mTotalLatency/profileDuration*100);
output += "<TotalPercent>";
output += buffer;
output += "</TotalPercent>";
snprintf(buffer, sizeof(buffer), "%9.3f", data.mTotalLatency*1000);
output += "<TotalLatency>";
output += buffer;
output += "</TotalLatency>";
//sprintf(buffer,"%s\n",iter->first.c_str());
//output += buffer;
snprintf(buffer, sizeof(buffer), "</DataMap%u>", i++);
output += buffer;
}
output += "</DataMap>";
}
void Profiler::GetNodeOutput(std::string & output, const NodeMap_t & nodeMap, double profileDuration, int level)
{
char buffer[256];
// recursively print node map
NodeMap_t::const_iterator iter;
for (iter = nodeMap.begin(); iter != nodeMap.end(); iter++)
{
// output node description
const Node & node = iter->second;
double trueLatency = node.mData.mTotalLatency-node.mData.mTotalChildLatency;
snprintf(buffer, sizeof(buffer), "%5.1f %9.3f %7.3f %7.3f %7.3f %5u %5.1f %9.3f ", trueLatency/profileDuration*100, trueLatency*1000, node.mData.mMaxLatency*1000, node.mData.mMinLatency*1000, trueLatency/node.mData.mTotalCalls*1000, node.mData.mTotalCalls, node.mData.mTotalLatency/profileDuration*100, node.mData.mTotalLatency*1000);
output += buffer;
for (int i=0; i<level; i++)
output += " ";
snprintf(buffer, sizeof(buffer), "+%s\n", iter->first.c_str());
output += buffer;
// recursively print node's node map
GetNodeOutput(output, node.mNodeMap, profileDuration, level+1);
}
}
void Profiler::GetXmlNodeOutput(std::string & output, const NodeMap_t & nodeMap, double profileDuration, int level)
{
char buffer[256];
output += "<NodeCount>";
snprintf(buffer, sizeof(buffer), "%u", nodeMap.size());
output += buffer;
output += "</NodeCount>";
// recursively print node map
int i = 1;
NodeMap_t::const_iterator iter;
for (iter = nodeMap.begin(); iter != nodeMap.end(); iter++)
{
snprintf(buffer, sizeof(buffer), "<Node%d>", i);
output += buffer;
output += "<Description>";
output += iter->first;
output += "</Description>";
// output node description
const Node & node = iter->second;
double trueLatency = node.mData.mTotalLatency-node.mData.mTotalChildLatency;
/*
sprintf(buffer, "%5.1f %9.3f %7.3f %7.3f %7.3f %5u %5.1f %9.3f ",
trueLatency/profileDuration*100,
trueLatency*1000,
node.mData.mMaxLatency*1000,
node.mData.mMinLatency*1000,
trueLatency/node.mData.mTotalCalls*1000,
node.mData.mTotalCalls,
node.mData.mTotalLatency/profileDuration*100,
node.mData.mTotalLatency*1000);
*/
snprintf(buffer, sizeof(buffer), "%5.1f", trueLatency/profileDuration*100);
output += "<Percent>";
output += buffer;
output += "</Percent>";
snprintf(buffer, sizeof(buffer), "%9.3f", trueLatency*1000);
output += "<Latency>";
output += buffer;
output += "</Latency>";
snprintf(buffer, sizeof(buffer), "%7.3f", node.mData.mMaxLatency*1000);
output += "<Max>";
output += buffer;
output += "</Max>";
snprintf(buffer, sizeof(buffer), "%7.3f", node.mData.mMinLatency*1000);
output += "<Min>";
output += buffer;
output += "</Min>";
snprintf(buffer, sizeof(buffer), "%7.3f", trueLatency/node.mData.mTotalCalls*1000);
output += "<Average>";
output += buffer;
output += "</Average>";
snprintf(buffer, sizeof(buffer), "%5u", node.mData.mTotalCalls);
output += "<Count>";
output += buffer;
output += "</Count>";
snprintf(buffer, sizeof(buffer), "%5.1f", node.mData.mTotalLatency/profileDuration*100);
output += "<TotalPercent>";
output += buffer;
output += "</TotalPercent>";
snprintf(buffer, sizeof(buffer), "%9.3f", node.mData.mTotalLatency*1000);
output += "<TotalLatency>";
output += buffer;
output += "</TotalLatency>";
// recursively print node's node map
GetXmlNodeOutput(output, node.mNodeMap, profileDuration, level+1);
snprintf(buffer, sizeof(buffer), "</Node%d>", i++);
output += buffer;
}
}
Profile::Profile(const char * description, Profiler & profile) :
mProfiler(profile)
{
if (mProfiler.IsActive())
{
mProfiler.Open(description);
}
}
Profile::~Profile()
{
if (mProfiler.IsActive())
{
mProfiler.Close();
}
}
@@ -0,0 +1,82 @@
#ifndef SERVER_PROFILE_H
#define SERVER_PROFILE_H
#include <string>
#include <list>
#include <map>
#include "types.h"
class Profiler
{
struct NodeData;
struct Node;
typedef std::map<std::string,NodeData> DataMap_t;
typedef std::map<std::string,Node> NodeMap_t;
typedef std::list<NodeData *> DataStack_t;
typedef std::list<Node *> NodeStack_t;
struct NodeData
{
NodeData();
soe::uint64 mStartTimer;
double mTotalLatency;
double mChildLatency;
double mTotalChildLatency;
double mMaxLatency;
double mMinLatency;
unsigned mTotalCalls;
};
struct Node
{
NodeData mData;
NodeMap_t mNodeMap;
};
public:
Profiler();
~Profiler();
void AddNode(Node & lhs, const Node & rhs);
void AddData(const Profiler & rhs, bool hierarchy=true);
bool IsActive() { return mActive; }
void Start() { mActive = true; }
void Stop() { mActive = false; }
void Open(const std::string & description);
void Close();
void Clear();
void GetOutput(std::string & output, bool hierarchy=true);
void GetXmlOutput(std::string & output, bool hierarchy=true);
private:
void GetNodeOutput(std::string & output, const NodeMap_t & nodeMap, double profileDuration, int level = 0);
void GetXmlNodeOutput(std::string & output, const NodeMap_t & nodeMap, double profileDuration, int level = 0);
void MakeValidXmlTag(std::string& tag);
private:
bool mActive;
unsigned mStartTime;
soe::uint64 mStartTimer;
DataMap_t mDataMap; // stores linear call totals
DataStack_t mDataStack; // stores linear call stack
NodeMap_t mNodeMap; // stores hierarchical call totals
NodeStack_t mNodeStack; // stores hierarchical call stack
};
extern Profiler globalProfiler;
class Profile
{
public:
Profile(const char * description, Profiler & profile = globalProfiler);
~Profile();
private:
Profiler & mProfiler;
};
#endif
@@ -0,0 +1,22 @@
#ifndef __RATE_LIMIT_H__
#define __RATE_LIMIT_H__
namespace soe
{
typedef long limit_t;
typedef long interval_t;
struct RateLimit
{
RateLimit()
: mLimit(0)
, mInterval(0)
{ }
limit_t mLimit;
interval_t mInterval;
};
typedef std::vector<RateLimit> RateLimits_t;
};
#endif // __RATE_LIMIT_H__
@@ -0,0 +1,106 @@
#ifndef UTIL_H
#define UTIL_H
#include <list>
#include <vector>
template<typename T>
class ref_ptr
{
private:
struct Node
{
T object;
unsigned refCount;
};
struct Allocator
{
public:
static std::vector<void *> & getBlockArray()
{
static std::vector<void *> * blockArray = new std::vector<void *>;
return *blockArray;
}
static std::list<T *> & getBlockList()
{
static std::list<T *> * blockList = new std::list<T *>;
return *blockList;
}
static T * allocate()
{
if (getBlockList().empty())
grow();
T * ptr = getBlockList().front();
getBlockList().pop_front();
_blocksAvailable--;
return new (ptr) T;
}
static T * allocate(const T & copy)
{
if (getBlockList().empty())
grow();
T * ptr = getBlockList().front();
getBlockList().pop_front();
_blocksAvailable--;
return new (ptr) T(copy);
}
static void release(T * ptr)
{
ptr->~T();
getBlockList().push_front(ptr);
_blocksAvailable++;
if (_blocksAvailable == _blocksTotal)
{
for (unsigned i=0; i<getBlockArray().size(); i++)
delete [] static_cast<unsigned *>(getBlockArray()[i]);
getBlockArray().clear();
getBlockList().clear();
_blocksAvailable = _blocksTotal = 0;
}
}
private:
static void grow()
{
unsigned blockCount = (unsigned)(getBlockArray().size()+1)*32;
unsigned blockSize = (unsigned)blockCount * sizeof(Node)/sizeof(unsigned);
getBlockArray().push_back(new unsigned[blockSize]);
Node * ptr = static_cast<Node *>(getBlockArray().back());
for (size_t i=0; i<blockCount; i++)
getBlockList().push_back(&ptr[i].object);
_blocksAvailable += blockCount;
_blocksTotal += blockCount;
}
private:
static unsigned _blocksAvailable;
static unsigned _blocksTotal;
};
public:
ref_ptr() : ptr(0) {}
//explicit ref_ptr(T * p) : ptr(p) { addRef(); }
ref_ptr(const ref_ptr<T> & copy) { copy.checkRef(); ptr = copy.ptr; addRef(); }
~ref_ptr() { unref(); }
//ref_ptr<T> & operator=(T * p) { unref(); ptr = p; addRef(); return *this; }
ref_ptr<T> & operator=(const ref_ptr<T> & rhs) { rhs.checkRef(); if (&rhs != this && rhs.ptr != ptr) { unref(); ptr = rhs.ptr; addRef(); } return *this; }
T & operator*() const { checkRef(); return *ptr; }
T * operator->() const { checkRef(); return ptr; }
operator bool() const { return ptr != 0; }
bool unique() const { return (!ptr || node()->refCount == 1); }
void clone() { if (!unique()) { T * temp = Allocator::allocate(*ptr); unref(); ptr = temp; node()->refCount = 1; } }
private:
Node * node() const { return static_cast<Node *>((void *)ptr); }
void checkRef() const { if (!ptr) { ptr = Allocator::allocate(); node()->refCount = 1; } }
void addRef() const { if (ptr) { node()->refCount++; } }
void unref() { if (ptr && !--(node()->refCount)) Allocator::release(ptr); }
private:
mutable T * ptr;
};
template<typename T>
unsigned ref_ptr<T>::Allocator::_blocksAvailable = 0;
template<typename T>
unsigned ref_ptr<T>::Allocator::_blocksTotal = 0;
#endif
@@ -0,0 +1,16 @@
#ifndef SOE__SERIALIZE_H
#define SOE__SERIALIZE_H
// this file has been split into two sections
// to enable separate inclusion in problematic cases
// with GCC 3.4.4
#include "serializeClasses.h"
#ifdef USE_SERIALIZE_STRING_VECTOR
#include "serializeStringVector.h"
#endif
#include "serializeTemplates.h"
#endif
@@ -0,0 +1,934 @@
#ifndef SOE__SERIALIZE_CLASSES_H
#define SOE__SERIALIZE_CLASSES_H
#include <assert.h>
#include <string>
#include <list>
#include <vector>
#ifdef PRINTABLE_MESSAGES
# include <stdio.h>
# include <time.h>
# if defined(WIN32) && !defined(snprintf)
# define snprintf _snprintf
# endif
#endif
#ifdef TRACK_READ_WRITE_FAILURES
# include "trackMessageFailures.h"
# define MESSAGE_FAILURE_TRACE_GENERIC \
soe::PushMessageFailure(soe::PrintToString("%s, %s:%u - failed to transmit, size = %u", __FUNCTION__, __FILE__, __LINE__, size))
# define MESSAGE_FAILURE_TRACE_LABEL(__label__) \
soe::PushMessageFailure(soe::PrintToString("%s, %s:%u - failed to transmit %s, size = %u", __FUNCTION__, __FILE__, __LINE__, __label__, size))
# define MESSAGE_FAILURE_TRACE_INDEX(__index__) \
soe::PushMessageFailure(soe::PrintToString("%s, %s:%u - failed to transmit item #%u, size = %u", __FUNCTION__, __FILE__, __LINE__, __index__, size))
# define MESSAGE_FAILURE_TRACE_LABEL_INDEX(__label__, __index__) \
soe::PushMessageFailure(soe::PrintToString("%s, %s:%u - failed to transmit %s, item #%u, size = %u", __FUNCTION__, __FILE__, __LINE__, __label__, __index__, size))
#else
# define MESSAGE_FAILURE_TRACE_GENERIC
# define MESSAGE_FAILURE_TRACE_LABEL(__label__)
# define MESSAGE_FAILURE_TRACE_INDEX(__index__)
#endif
#define DefineClassScribe(ClassName) \
inline unsigned Read(const unsigned char * stream, unsigned size, ClassName & data, unsigned maxLen, unsigned version = 0) \
{ \
return data.Read(stream, size, version); \
} \
inline unsigned Write(unsigned char * stream, unsigned size, const ClassName & data, unsigned version = 0) \
{ \
return data.Write(stream, size, version); \
} \
inline int Print(char * stream, unsigned size, const ClassName & data, unsigned maxDepth = INT_MAX) \
{ \
return data.Print(stream, size, maxDepth); \
}
#define DECLARE_SCRIBE_MEMBERS_INTERNAL \
unsigned Read(const unsigned char * stream, unsigned size, unsigned version = 0); \
unsigned Write(unsigned char * stream, unsigned size, unsigned version = 0) const; \
int Print(char * stream, unsigned size, unsigned maxDepth = INT_MAX) const; \
class Scribe; \
static Scribe & GetScribe();
#define DECLARE_VIRTUAL_SCRIBE_MEMBERS_INTERNAL \
virtual unsigned Read(const unsigned char * stream, unsigned size, unsigned version = 0); \
virtual unsigned Write(unsigned char * stream, unsigned size, unsigned version = 0) const; \
virtual int Print(char * stream, unsigned size, unsigned maxDepth = INT_MAX) const; \
class Scribe; \
static Scribe & GetScribe();
#define DECLARE_SCRIBE_MEMBERS \
unsigned Read(const unsigned char * stream, unsigned size, unsigned version = 0); \
unsigned Write(unsigned char * stream, unsigned size, unsigned version = 0) const; \
int Print(char * stream, unsigned size, unsigned maxDepth = INT_MAX) const;
#define DECLARE_VIRTUAL_SCRIBE_MEMBERS \
virtual unsigned Read(const unsigned char * stream, unsigned size, unsigned version = 0); \
virtual unsigned Write(unsigned char * stream, unsigned size, unsigned version = 0) const; \
virtual int Print(char * stream, unsigned size, unsigned maxDepth = INT_MAX) const;
#ifdef PRINTABLE_MESSAGES
# define PrintEnum(EnumName) \
long lData = data; \
return snprintf(stream, size, "('%s')%d", #EnumName, lData);
#else
# define PrintEnum(EnumName) \
return 0;
#endif
#define SCRIBE_ENUM(EnumName) \
inline unsigned Write( unsigned char * stream, unsigned size, const EnumName & data, unsigned version = 0) \
{ \
unsigned dataSize = sizeof(EnumName); \
if (size < dataSize) \
return 0; \
memcpy(stream, (void*)&data, dataSize); \
return dataSize; \
} \
inline unsigned Read( const unsigned char * stream, unsigned size, EnumName & data, unsigned, unsigned version = 0) \
{ \
unsigned dataSize = sizeof(EnumName); \
if (size < dataSize) \
return 0; \
memcpy((void*)&data, stream, dataSize); \
return dataSize; \
} \
inline int Print( char * stream, unsigned size, const EnumName & data, unsigned maxDepth = 0) \
{ \
PrintEnum(EnumName) \
}
#ifdef WIN32
# define mapped_type referent_type
#endif
#define DefineMapScribe(MapName) \
unsigned Read(const unsigned char * stream, unsigned size, MapName & data, unsigned maxLen, unsigned version = 0);
#define ImplementMapScribeMember(MapName, KeyName) \
unsigned Read(const unsigned char * stream, unsigned size, MapName & data, unsigned maxLen, unsigned version) \
{ \
return Read(stream, size, data, MapName::mapped_type::KeyName, maxLen, version); \
}
#define ImplementMapScribeAccessor(MapName, KeyName) \
unsigned Read(const unsigned char * stream, unsigned size, MapName & data, unsigned maxLen, unsigned version) \
{ \
return Read(stream, size, data, &MapName::mapped_type::KeyName, maxLen, version); \
}
#ifdef API_NAMESPACE
// forward/extern declarations
namespace soe { class ClassScribeBase; }
namespace API_NAMESPACE { void AddClassScribeToGlobalSet(soe::ClassScribeBase * pScribe); }
// macro to add scribe to global set for APIs
# define AddScribeToResetSet API_NAMESPACE::AddClassScribeToGlobalSet(&classScribe);
#else
# define AddScribeToResetSet // NOP - nothing to do in this case
#endif
#define ImplementClassScribeBeginInternal(ClassName) \
class ClassName::Scribe : public soe::ClassScribe<ClassName> \
{ \
public: \
Scribe(); \
void Initialize(); \
}; \
ClassName::Scribe & ClassName::GetScribe() \
{ \
static ClassName::Scribe classScribe; \
if (!classScribe.IsInitialized()) { \
classScribe.ClearMembers(); \
classScribe.Initialize(); \
} \
return classScribe; \
} \
unsigned ClassName::Read(const unsigned char * stream, unsigned size, unsigned version) \
{ \
return GetScribe().Read(stream, size, *this, version); \
} \
unsigned ClassName::Write(unsigned char * stream, unsigned size, unsigned version) const \
{ \
return GetScribe().Write(stream, size, *this, version); \
} \
int ClassName::Print(char * stream, unsigned size, unsigned maxDepth) const \
{ \
return GetScribe().Print(stream, size, *this, maxDepth); \
} \
ClassName::Scribe::Scribe() \
: soe::ClassScribe<ClassName>(#ClassName) \
{ \
Initialize(); \
} \
void ClassName::Scribe::Initialize() \
{ \
typedef ClassName ScribedClass_t; \
Scribe & classScribe = *this; \
ClearMembers();
#define ImplementClassScribeBegin(ClassName) \
soe::ClassScribe<ClassName> & GetScribe(const ClassName & object); \
unsigned ClassName::Read(const unsigned char * stream, unsigned size, unsigned version) \
{ \
return GetScribe(*this).Read(stream, size, *this, version); \
} \
unsigned ClassName::Write(unsigned char * stream, unsigned size, unsigned version) const \
{ \
return GetScribe(*this).Write(stream, size, *this, version); \
} \
int ClassName::Print(char * stream, unsigned size, unsigned maxDepth) const \
{ \
return GetScribe(*this).Print(stream, size, *this, maxDepth); \
} \
soe::ClassScribe<ClassName> & GetScribe(const ClassName & object) \
{ \
typedef ClassName ScribedClass_t; \
static soe::ClassScribe<ClassName> classScribe(#ClassName); \
if (!classScribe.IsInitialized()) { \
classScribe.ClearMembers();
#define ImplementClassScribeBeginEx(ClassName, ParentClassName) \
soe::ClassScribe<ClassName> & GetScribe(const ClassName & object); \
unsigned ClassName::Read(const unsigned char * stream, unsigned size, unsigned version) \
{ \
unsigned bytesTotal = 0; \
unsigned bytes = 0; \
bytesTotal += (bytes = GetScribe((const ParentClassName &)*this).Read(stream, size, *this, version)); \
if (!bytes && (GetScribe((const ParentClassName &)*this).CountMembers() > 0)) { return 0; } \
bytesTotal += (bytes = GetScribe(*this).Read(stream+bytesTotal, size-bytesTotal , *this, version)); \
if (!bytes && (GetScribe(*this).CountMembers() > 0)) { return 0; } \
return bytesTotal; \
} \
unsigned ClassName::Write(unsigned char * stream, unsigned size, unsigned version) const \
{ \
unsigned bytesTotal = 0; \
unsigned bytes = 0; \
bytesTotal += (bytes = GetScribe((const ParentClassName &)*this).Write(stream, size, *this, version)); \
if (!bytes && (GetScribe((const ParentClassName &)*this).CountMembers() > 0)) { return 0; } \
bytesTotal += (bytes = GetScribe(*this).Write(stream+bytesTotal, size-bytesTotal , *this, version)); \
if (!bytes && (GetScribe(*this).CountMembers() > 0)) { return 0; } \
return bytesTotal; \
} \
int ClassName::Print(char * stream, unsigned size, unsigned maxDepth) const \
{ \
int bytesTotal = 0; \
int bytes = 0; \
bytesTotal += (bytes = GetScribe((const ParentClassName &)*this).Print(stream, size, *this, maxDepth)); \
if (soe::FailedToPrint(bytes, size)) { return bytes; } \
bytesTotal += (bytes = GetScribe(*this).Print(stream+bytesTotal , size-bytesTotal, *this, maxDepth)); \
if (soe::FailedToPrint(bytes, size-bytesTotal)) { return bytes; } \
return bytesTotal; \
} \
soe::ClassScribe<ClassName> & GetScribe(const ClassName & object) \
{ \
typedef ClassName ScribedClass_t; \
static soe::ClassScribe<ClassName> classScribe(#ClassName); \
if (!classScribe.IsInitialized()) { \
classScribe.ClearMembers();
#define ImplementClassScribeMember(MemberName) \
classScribe.AddMember(#MemberName, &ScribedClass_t::MemberName, 1, 0, eNoEffect);
#define ImplementClassScribeMemberEx(MemberName,MaxLen) \
classScribe.AddMember(#MemberName, &ScribedClass_t::MemberName, MaxLen, 0, eNoEffect);
#define ImplementClassScribeMemberContainerEx(MemberName,MaxLen,MaxElementLen) \
classScribe.AddMemberContainer(#MemberName, &ScribedClass_t::MemberName, MaxLen, MaxElementLen, 0, eNoEffect);
#define ImplementVersionAddedClassScribeMember(MemberName,Version) \
classScribe.AddMember(#MemberName, &ScribedClass_t::MemberName, 1, Version, eAdded);
#define ImplementVersionAddedClassScribeMemberEx(MemberName,MaxLen,Version) \
classScribe.AddMember(#MemberName, &ScribedClass_t::MemberName, MaxLen, Version, eAdded);
#define ImplementVersionAddedClassScribeMemberContainerEx(MemberName,MaxLen,MaxElementLen,Version) \
classScribe.AddMemberContainer(#MemberName, &ScribedClass_t::MemberName, MaxLen, MaxElementLen, Version, eAdded);
#define ImplementVersionDroppedClassScribeMember(MemberName,Version) \
classScribe.AddMember(#MemberName, &ScribedClass_t::MemberName, 1, Version, eDropped);
#define ImplementVersionDroppedClassScribeMemberEx(MemberName,MaxLen,Version) \
classScribe.AddMember(#MemberName, &ScribedClass_t::MemberName, MaxLen, Version, eDropped);
#define ImplementVersionDroppedClassScribeMemberContainerEx(MemberName,MaxLen,MaxElementLen,Version) \
classScribe.AddMemberContainer(#MemberName, &ScribedClass_t::MemberName, MaxLen, MaxElementLen, Version, eDropped);
#define ImplementClassScribeEndInternal \
SetInitialized(true); \
AddScribeToResetSet \
}
#define ImplementClassScribeEnd \
classScribe.SetInitialized(true); \
AddScribeToResetSet \
} \
return classScribe; \
}
#include "types.h"
#if (defined(WIN32) || defined(linux)) && !defined(NETWORK_BIG_ENDIAN)
#define BYTE1 0
#define BYTE2 1
#define BYTE3 2
#define BYTE4 3
#define BYTE5 4
#define BYTE6 5
#define BYTE7 6
#define BYTE8 7
#elif defined(sparc) || defined(NETWORK_BIG_ENDIAN)
#define BYTE1 7
#define BYTE2 6
#define BYTE3 5
#define BYTE4 4
#define BYTE5 3
#define BYTE6 2
#define BYTE7 1
#define BYTE8 0
#endif
////////////////////////////////////////////////////////////////////////////////
namespace soe
{
////////////////////////////////////////////////////////////////////////////////
// 388 ns (50 bytes)
inline unsigned Write(unsigned char * stream, unsigned size, const unsigned char * data, unsigned dataLen, unsigned version = 0)
{
if (size < dataLen)
return 0;
memcpy(stream, data, dataLen);
return dataLen;
}
// 353 ns
inline unsigned Write(unsigned char * stream, unsigned size, bool data, unsigned version = 0)
{
if (size < sizeof(uint8))
return 0;
stream[BYTE1] = data;
return sizeof(uint8);
}
// 362 ns
inline unsigned Write(unsigned char * stream, unsigned size, int8 data, unsigned version = 0)
{
if (size < sizeof(int8))
return 0;
stream[BYTE1] = data;
return sizeof(int8);
}
// 362 ns
inline unsigned Write(unsigned char * stream, unsigned size, uint8 data, unsigned version = 0)
{
if (size < sizeof(uint8))
return 0;
stream[BYTE1] = data;
return sizeof(uint8);
}
// 355 ns
inline unsigned Write(unsigned char * stream, unsigned size, int16 data, unsigned version = 0)
{
if (size < sizeof(int16))
return 0;
stream[BYTE1] = data&0xff;
stream[BYTE2] = (data>>8)&0xff;
return sizeof(int16);
}
// 360 ns
inline unsigned Write(unsigned char * stream, unsigned size, uint16 data, unsigned version = 0)
{
if (size < sizeof(uint16))
return 0;
stream[BYTE1] = data&0xff;
stream[BYTE2] = (data>>8)&0xff;
return sizeof(uint16);
}
// 360 ns
inline unsigned Write(unsigned char * stream, unsigned size, int32 data, unsigned version = 0)
{
if (size < sizeof(int32))
return 0;
stream[BYTE1] = data&0xff;
stream[BYTE2] = (data>>8)&0xff;
stream[BYTE3] = (data>>16)&0xff;
stream[BYTE4] = (data>>24)&0xff;
return sizeof(int32);
}
// 360 ns
inline unsigned Write(unsigned char * stream, unsigned size, uint32 data, unsigned version = 0)
{
if (size < sizeof(uint32))
return 0;
stream[BYTE1] = data&0xff;
stream[BYTE2] = (data>>8)&0xff;
stream[BYTE3] = (data>>16)&0xff;
stream[BYTE4] = (data>>24)&0xff;
return sizeof(uint32);
}
// 370 ns
inline unsigned Write(unsigned char * stream, unsigned size, int64 data, unsigned version = 0)
{
if (size < sizeof(int64))
return 0;
#if (defined(WIN32) || defined(linux))
uint32 low = *(uint32 *)(&data);
uint32 high = *((uint32 *)&data+1);
#elif defined(sparc)
uint32 low = *((uint32 *)&data+1);
uint32 high = *(uint32 *)(&data);
#endif
stream[BYTE1] = (unsigned char)low&0xff;
stream[BYTE2] = (unsigned char)(low>>8)&0xff;
stream[BYTE3] = (unsigned char)(low>>16)&0xff;
stream[BYTE4] = (unsigned char)(low>>24)&0xff;
stream[BYTE5] = (unsigned char)high&0xff;
stream[BYTE6] = (unsigned char)(high>>8)&0xff;
stream[BYTE7] = (unsigned char)(high>>16)&0xff;
stream[BYTE8] = (unsigned char)(high>>24)&0xff;
return sizeof(int64);
}
// 370 ns
inline unsigned Write(unsigned char * stream, unsigned size, uint64 data, unsigned version = 0)
{
if (size < sizeof(uint64))
return 0;
#if (defined(WIN32) || defined(linux))
uint32 low = *(uint32 *)(&data);
uint32 high = *((uint32 *)&data+1);
#elif defined(sparc)
uint32 low = *((uint32 *)&data+1);
uint32 high = *(uint32 *)(&data);
#endif
stream[BYTE1] = (unsigned char)low&0xff;
stream[BYTE2] = (unsigned char)(low>>8)&0xff;
stream[BYTE3] = (unsigned char)(low>>16)&0xff;
stream[BYTE4] = (unsigned char)(low>>24)&0xff;
stream[BYTE5] = (unsigned char)high&0xff;
stream[BYTE6] = (unsigned char)(high>>8)&0xff;
stream[BYTE7] = (unsigned char)(high>>16)&0xff;
stream[BYTE8] = (unsigned char)(high>>24)&0xff;
return sizeof(uint64);
}
// 360 ns
inline unsigned Write(unsigned char * stream, unsigned size, float data, unsigned version = 0)
{
uint32 & dataRef = *(uint32 *)(&data);
if (size < sizeof(float))
return 0;
stream[BYTE1] = dataRef&0xff;
stream[BYTE2] = (dataRef>>8)&0xff;
stream[BYTE3] = (dataRef>>16)&0xff;
stream[BYTE4] = (dataRef>>24)&0xff;
return sizeof(float);
}
// 370 ns
inline unsigned Write(unsigned char * stream, unsigned size, double data, unsigned version = 0)
{
if (size < sizeof(double))
return 0;
#if (defined(WIN32) || defined(linux))
uint32 low = *(uint32 *)(&data);
uint32 high = *((uint32 *)&data+1);
#elif defined(sparc)
uint32 low = *((uint32 *)&data+1);
uint32 high = *(uint32 *)(&data);
#endif
stream[BYTE1] = (unsigned char)low&0xff;
stream[BYTE2] = (unsigned char)(low>>8)&0xff;
stream[BYTE3] = (unsigned char)(low>>16)&0xff;
stream[BYTE4] = (unsigned char)(low>>24)&0xff;
stream[BYTE5] = (unsigned char)high&0xff;
stream[BYTE6] = (unsigned char)(high>>8)&0xff;
stream[BYTE7] = (unsigned char)(high>>16)&0xff;
stream[BYTE8] = (unsigned char)(high>>24)&0xff;
return sizeof(double);
}
// 361 ns
inline unsigned WriteEncoded(unsigned char * stream, unsigned size, uint32 data)
{
unsigned encoded = ((data & 0xffffffc0) << 2) | (data & 0x3f);
if (data > 0x3fffffff)
{
return 0;
}
else if (data > 0x3fffff && size >= 4)
{
encoded |= 0xc0;
stream[BYTE1] = encoded & 0xff;
stream[BYTE2] = (encoded>>8) & 0xff;
stream[BYTE3] = (encoded>>16) & 0xff;
stream[BYTE4] = (encoded>>24) & 0xff;
return 4;
}
else if (data > 0x3fff)
{
encoded |= 0x80;
stream[BYTE1] = encoded & 0xff;
stream[BYTE2] = (encoded>>8) & 0xff;
stream[BYTE3] = (encoded>>16) & 0xff;
return 3;
}
else if (data > 0x3f)
{
encoded |= 0x40;
stream[BYTE1] = encoded & 0xff;
stream[BYTE2] = (encoded>>8) & 0xff;
return 2;
}
else if (size >= 1)
{
stream[BYTE1] = encoded & 0xff;
return 1;
}
return 0;
}
// 630 ns
inline unsigned Write(unsigned char * stream, unsigned size, const std::string & data, unsigned version = 0)
{
unsigned lengthBytes = 0;
unsigned bytes = 0;
lengthBytes += WriteEncoded(stream, size, (soe::uint32)data.length());
if (!lengthBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to write length (%u bytes)", __FUNCTION__, __FILE__, __LINE__, sizeof(soe::uint32)));
#endif
return 0;
}
if (data.length())
{
bytes = Write(stream+lengthBytes, size-lengthBytes, reinterpret_cast<const unsigned char *>(data.data()), (soe::uint32)data.length());
if (!bytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to write %u string bytes.", __FUNCTION__, __FILE__, __LINE__, data.length()));
#endif
return 0;
}
}
return lengthBytes + bytes;
}
inline unsigned Read(const unsigned char * stream, unsigned size, unsigned char * data, unsigned dataLen, unsigned version = 0)
{
if (size < dataLen)
return 0;
memcpy(data, stream, dataLen);
return dataLen;
}
// 355 ns
inline unsigned Read(const unsigned char * stream, unsigned size, bool & data, unsigned = 1/*unused*/, unsigned version = 0)
{
if (size < sizeof(uint8))
return 0;
data = stream[BYTE1] != 0;
return sizeof(uint8);
}
// 355 ns
inline unsigned Read(const unsigned char * stream, unsigned size, int8 & data, unsigned = 1/*unused*/, unsigned version = 0)
{
if (size < sizeof(int8))
return 0;
data = stream[BYTE1];
return sizeof(int8);
}
// 355 ns
inline unsigned Read(const unsigned char * stream, unsigned size, uint8 & data, unsigned = 1/*unused*/, unsigned version = 0)
{
if (size < sizeof(uint8))
return 0;
data = stream[BYTE1];
return sizeof(uint8);
}
// 355 ns
inline unsigned Read(const unsigned char * stream, unsigned size, int16 & data, unsigned = 1/*unused*/, unsigned version = 0)
{
if (size < sizeof(int16))
return 0;
data = stream[BYTE1];
data |= stream[BYTE2]<<8;
return sizeof(int16);
}
// 355 ns
inline unsigned Read(const unsigned char * stream, unsigned size, uint16 & data, unsigned = 1/*unused*/, unsigned version = 0)
{
if (size < sizeof(uint16))
return 0;
data = stream[BYTE1];
data |= stream[BYTE2]<<8;
return sizeof(uint16);
}
// 360 ns
inline unsigned Read(const unsigned char * stream, unsigned size, int32 & data, unsigned = 1/*unused*/, unsigned version = 0)
{
if (size < sizeof(int32))
return 0;
data = stream[BYTE1];
data |= stream[BYTE2]<<8;
data |= stream[BYTE3]<<16;
data |= stream[BYTE4]<<24;
return sizeof(int32);
}
// 360 ns
inline unsigned Read(const unsigned char * stream, unsigned size, uint32 & data, unsigned = 1/*unused*/, unsigned version = 0)
{
if (size < sizeof(uint32))
return 0;
data = stream[BYTE1];
data |= stream[BYTE2]<<8;
data |= stream[BYTE3]<<16;
data |= stream[BYTE4]<<24;
return sizeof(uint32);
}
// 380 ns
inline unsigned Read(const unsigned char * stream, unsigned size, int64 & data, unsigned = 1/*unused*/, unsigned version = 0)
{
if (size < sizeof(int64))
return 0;
#if (defined(WIN32) || defined(linux))
uint32 & low = *(uint32 *)(&data);
uint32 & high = *((uint32 *)&data+1);
#elif defined(sparc)
uint32 & low = *(uint32 *)(&data+1);
uint32 & high = *(uint32 *)(&data);
#endif
low = stream[BYTE1];
low |= stream[BYTE2]<<8;
low |= stream[BYTE3]<<16;
low |= stream[BYTE4]<<24;
high = stream[BYTE5];
high |= stream[BYTE6]<<8;
high |= stream[BYTE7]<<16;
high |= stream[BYTE8]<<24;
return sizeof(int64);
}
// 380 ns
inline unsigned Read(const unsigned char * stream, unsigned size, uint64 & data, unsigned = 1/*unused*/, unsigned version = 0)
{
if (size < sizeof(uint64))
return 0;
#if (defined(WIN32) || defined(linux))
uint32 & low = *(uint32 *)(&data);
uint32 & high = *((uint32 *)&data+1);
#elif defined(sparc)
uint32 & low = *(uint32 *)(&data+1);
uint32 & high = *(uint32 *)(&data);
#endif
low = stream[BYTE1];
low |= stream[BYTE2]<<8;
low |= stream[BYTE3]<<16;
low |= stream[BYTE4]<<24;
high = stream[BYTE5];
high |= stream[BYTE6]<<8;
high |= stream[BYTE7]<<16;
high |= stream[BYTE8]<<24;
return sizeof(uint64);
}
// 370 ns
inline unsigned Read(const unsigned char * stream, unsigned size, float & data, unsigned = 1/*unused*/, unsigned version = 0)
{
assert(sizeof(float) == 4);
uint32 & dataRef = *(uint32 *)(&data);
if (size < sizeof(float))
return 0;
dataRef = stream[BYTE1];
dataRef |= stream[BYTE2]<<8;
dataRef |= stream[BYTE3]<<16;
dataRef |= stream[BYTE4]<<24;
return sizeof(float);
}
// 380 ns
inline unsigned Read(const unsigned char * stream, unsigned size, double & data, unsigned = 1/*unused*/, unsigned version = 0)
{
assert(sizeof(double) == 8);
if (size < sizeof(double))
return 0;
#if (defined(WIN32) || defined(linux))
uint32 & low = *(uint32 *)(&data);
uint32 & high = *((uint32 *)&data+1);
#elif defined(sparc)
uint32 & low = *(uint32 *)(&data+1);
uint32 & high = *(uint32 *)(&data);
#endif
low = stream[BYTE1];
low |= stream[BYTE2]<<8;
low |= stream[BYTE3]<<16;
low |= stream[BYTE4]<<24;
high = stream[BYTE5];
high |= stream[BYTE6]<<8;
high |= stream[BYTE7]<<16;
high |= stream[BYTE8]<<24;
return sizeof(double);
}
// 360 ns
inline unsigned ReadEncoded(const unsigned char * stream, unsigned size, uint32 & data)
{
if (size < 1)
return 0;
unsigned encoded = stream[BYTE1];
unsigned mask = encoded & 0xc0;
if (mask == 0)
{
data = encoded & 0x3f;
return 1;
}
else if (mask == 0x40 && size >=2)
{
data = (stream[BYTE2]<<6) | (encoded & 0x3f);
return 2;
}
else if (mask == 0x80 && size >=3)
{
data = (stream[BYTE3]<<14) | (stream[BYTE2]<<6) | (encoded & 0x3f);
return 3;
}
else if (mask == 0xc0 && size >=4)
{
data = (stream[BYTE4]<<22) | (stream[BYTE3]<<14) | (stream[BYTE2]<<6) | (encoded & 0x3f);
return 4;
}
return 0;
}
inline unsigned Read(const unsigned char * stream, unsigned size, std::string & data, unsigned maxLen, unsigned version = 0)
{
unsigned bytes = 0;
unsigned length = 0;
bytes += ReadEncoded(stream, size, length);
if (!bytes || size < bytes+length || length > maxLen) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read string, length = %u, maxLen = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, length, maxLen, size));
#endif
return 0;
}
data.assign((const char *)stream+bytes, (const char *)stream+bytes+length); // assign would be dangerous if unicode, single-byte characters are ok
return bytes + length;
}
#ifdef _USE_32BIT_TIME_T
// Seems that VC8 has switched time_t to __int64 so this becomes a signature clash
inline unsigned Read(const unsigned char * stream, unsigned size, time_t & data, unsigned maxLen = 1, unsigned version = 0)
{
soe::uint32 wordData = 0;
unsigned bytesRead = Read(stream, size, wordData, maxLen);
data = (time_t)wordData;
return bytesRead;
}
inline unsigned Write(unsigned char * stream, unsigned size, time_t data, unsigned version = 0)
{
return Write(stream, size, (soe::uint32)data);
}
#endif
inline bool FailedToPrint(int bytesPrinted, unsigned maxBytes)
{
return ( (bytesPrinted < 0) || (bytesPrinted > (int)maxBytes) );
}
#ifdef PRINTABLE_MESSAGES
inline int Print(char * stream, unsigned size, time_t data, unsigned maxDepth=INT_MAX)
{
tm *timeStruct = localtime(&data);
if (timeStruct) {
size_t bytes = strftime(stream, size, "%Y-%m-%d %H:%M:%S", timeStruct);
if (bytes > 0) {
return (int)bytes;
} else {
return -1;
}
} else {
return snprintf(stream, size, "(time_t)%u)", (unsigned)data);
}
}
inline int Print(char * stream, unsigned size, const unsigned char * data, unsigned dataLen, unsigned maxDepth=INT_MAX)
{
int bytes = 0;
int moreBytes = snprintf(stream, size, "[[%u]]", dataLen);
if ((maxDepth == 0) || (FailedToPrint(moreBytes, size))) {
return moreBytes;
} else {
bytes += moreBytes;
}
moreBytes = snprintf(stream+bytes, size-bytes, "0x");
if (FailedToPrint(moreBytes, size-bytes)) {
return moreBytes;
} else {
bytes += moreBytes;
}
for (unsigned index = 0; index < dataLen; index++)
{
moreBytes = snprintf(stream+bytes, size-bytes, "%x", data[index]);
if (FailedToPrint(moreBytes, size-bytes)) { break; }
bytes += moreBytes;
}
return FailedToPrint(moreBytes, size-bytes) ? moreBytes : bytes;
}
inline int Print(char * stream, unsigned size, bool data, unsigned maxDepth=INT_MAX)
{
return snprintf(stream, size, "%s", data ? "TRUE" : "FALSE");
}
inline int Print(char * stream, unsigned size, int8 data, unsigned maxDepth=INT_MAX)
{
return snprintf(stream, size, "%d", data);
}
inline int Print(char * stream, unsigned size, uint8 data, unsigned maxDepth=INT_MAX)
{
return snprintf(stream, size, "%u", data);
}
inline int Print(char * stream, unsigned size, int16 data, unsigned maxDepth=INT_MAX)
{
return snprintf(stream, size, "%d", data);
}
inline int Print(char * stream, unsigned size, uint16 data, unsigned maxDepth=INT_MAX)
{
return snprintf(stream, size, "%u", data);
}
inline int Print(char * stream, unsigned size, int32 data, unsigned maxDepth=INT_MAX)
{
return snprintf(stream, size, "%d", data);
}
inline int Print(char * stream, unsigned size, uint32 data, unsigned maxDepth=INT_MAX)
{
return snprintf(stream, size, "%u", data);
}
inline int Print(char * stream, unsigned size, int64 data, unsigned maxDepth=INT_MAX)
{
# ifdef WIN32
return snprintf(stream, size, "%I64d", data);
# else
return snprintf(stream, size, "%lld", data);
# endif
}
inline int Print(char * stream, unsigned size, uint64 data, unsigned maxDepth=INT_MAX)
{
# ifdef WIN32
return snprintf(stream, size, "%I64u", data);
# else
return snprintf(stream, size, "%llu", data);
# endif
}
inline int Print(char * stream, unsigned size, float data, unsigned maxDepth=INT_MAX)
{
return snprintf(stream, size, "%f", data);
}
inline int Print(char * stream, unsigned size, double data, unsigned maxDepth=INT_MAX)
{
return snprintf(stream, size, "%f", data);
}
inline int Print(char * stream, unsigned size, const std::string & data, unsigned maxDepth=INT_MAX)
{
return snprintf(stream, size, "%s", data.c_str());
}
#endif
////////////////////////////////////////////////////////////////////////////////
class DECLSPEC AutoVariableBase
{
public:
AutoVariableBase() {}
virtual ~AutoVariableBase() {}
virtual void Copy(AutoVariableBase *pSource) = 0;
virtual unsigned Write(unsigned char * stream, unsigned size, unsigned version = 0) const = 0;
virtual unsigned Read(const unsigned char * stream, unsigned size, unsigned maxLen = 1, unsigned version = 0) = 0;
#ifdef PRINTABLE_MESSAGES
virtual int Print(char * stream, unsigned size, unsigned maxDepth=INT_MAX) const = 0;
#endif
#if defined(PRINTABLE_MESSAGES) || defined(TRACK_READ_WRITE_FAILURES)
virtual const char * VariableName() const { return "(Unknown)"; }
#endif
};
////////////////////////////////////////////////////////////////////////////////
enum EVersionEffect
{
eNoEffect,
eDropped,
eAdded,
};
inline bool IsMemberIncluded(unsigned messageVersion, unsigned memberVersion, EVersionEffect memberVersionEffect)
{
bool isIncluded = true;
if (messageVersion) {
switch(memberVersionEffect)
{
case eAdded:
isIncluded = (messageVersion >= memberVersion);
break;
case eDropped:
isIncluded = (messageVersion < memberVersion);
break;
case eNoEffect:
default:
break;
}
}
return isIncluded;
}
////////////////////////////////////////////////////////////////////////////////
}
#endif
@@ -0,0 +1,14 @@
#include "serializeClasses.h"
#include "serializeStringVector.h"
namespace soe
{
/* This file is here for backwards compatability.
*/
}
@@ -0,0 +1,245 @@
#ifndef SERIALIZESTRINGVECTOR_H
#define SERIALIZESTRINGVECTOR_H
#ifdef SOE__SERIALIZE_TEMPLATES_H
#error wrong odering, serialzeTemplates.h must be included after this file.
#endif
#include <list>
#include <vector>
#include <string>
#include "serializeClasses.h"
#define DEFAULT_MAX_LENGTH_STRING 1000
#define DEFAULT_MAX_NUMBER_ELEMENTS 1000
namespace soe
{
///////////////////////////////////////////////////////////////////////////////////////////
// SerializeStringVector
// This class is just a std::vector<std::string> with extra serialization routines.
//
// This class is designed to handle the serialization of a vector of strings. This was necessary
// because the default serialization routines did not handle the length of the string properly, and
// there was more risk involved in modifying all the serialization routines to handle the
// extra length property for the string as well as the vector.
//
// this is intenede to be used with the serialization macros
// Ex:
// DefineMessageMember(myStringVector, SerializeStringVector)
// ImplementMessageMember(paymentInstrument, SerializeStringVector(DEFAULT_MAX_LENGTH_STRING, DEFAULT_MAX_NUMBER_ELEMENTS))
///////////////////////////////////////////////////////////////////////////////////////////
typedef std::list<std::string> stringList_t;
typedef std::vector<std::string> stringVector_t;
class SerializeStringList : public stringList_t
{
private:
unsigned mMaxStringLength;
unsigned mMaxListLength;
protected:
public:
SerializeStringList()
: mMaxStringLength(DEFAULT_MAX_LENGTH_STRING), mMaxListLength(DEFAULT_MAX_NUMBER_ELEMENTS)
{};
// writing will use the default values and assume that the vector is valid
//SerializeStringList(stringList_t vStrings);
SerializeStringList(unsigned maxStringLength, unsigned maxListLength)
: mMaxStringLength(maxStringLength), mMaxListLength(maxListLength)
{
}
SerializeStringList::SerializeStringList(stringList_t vStrings)
: mMaxStringLength(DEFAULT_MAX_LENGTH_STRING), mMaxListLength(DEFAULT_MAX_NUMBER_ELEMENTS)
{
for(stringList_t::iterator i = vStrings.begin(); i != vStrings.end(); i++)
{
push_back(*i);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
unsigned SerializeStringList::Read(const unsigned char * stream, unsigned size)
{
// fix this:
std::string element;
unsigned bytes = 0;
unsigned elementBytes = 0;
unsigned length = 0;
clear();
bytes += ReadEncoded(stream, size, length);
if (!bytes || length > mMaxListLength) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read StringList, length = %u, mMaxListLength = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, length, mMaxListLength, size));
#endif
return 0;
}
for (unsigned i=0; i<length; i++)
{
elementBytes = soe::Read(stream+bytes, size-bytes, element, mMaxStringLength);
if (!elementBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read StringList element, index = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, i, size));
#endif
return 0;
}
push_back(element);
bytes += elementBytes;
}
return bytes;
}
///////////////////////////////////////////////////////////////////////////////////////////
unsigned SerializeStringList::Write(unsigned char * stream, unsigned size) const
{
unsigned index = 0;
unsigned bytes = 0;
unsigned elementBytes = 0;
bytes += WriteEncoded(stream, size, (soe::uint32)this->size());
if (!bytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to write StringList length (%u bytes)", __FUNCTION__, __FILE__, __LINE__, sizeof(soe::uint32)));
#endif
return 0;
}
for (stringList_t::const_iterator iter = begin(); iter != end(); iter++, index++)
{
elementBytes = soe::Write(stream+bytes, size-bytes, *iter);
if (!elementBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to write StringList element, index = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, index, size));
#endif
return 0;
}
bytes += elementBytes;
}
return bytes;
}
//operator stringList_t () { return *this; }
//unsigned Read(const unsigned char * stream, unsigned size);
//DECLARE_SCRIBE_MEMBERS
};
///////////////////////////////////////////////////////////////////////////////////////////
inline unsigned Write(unsigned char * stream, unsigned size, const SerializeStringList & data, unsigned version = 0)
{
return data.Write(stream, size);
}
///////////////////////////////////////////////////////////////////////////////////////////
inline unsigned Read(const unsigned char * stream, unsigned size, SerializeStringList & data, unsigned, unsigned version = 0)
{
return data.Read(stream, size);
}
class SerializeStringVector : public stringVector_t
{
private:
unsigned mMaxStringLength;
unsigned mMaxVectorLength;
protected:
public:
SerializeStringVector()
: mMaxStringLength(DEFAULT_MAX_LENGTH_STRING), mMaxVectorLength(DEFAULT_MAX_NUMBER_ELEMENTS)
{};
// writing will use the default values and assume that the vector is valid
//SerializeStringVector(stringVector_t vStrings);
SerializeStringVector(unsigned maxStringLength, unsigned maxVectorLength)
: mMaxStringLength(maxStringLength), mMaxVectorLength(maxVectorLength)
{
}
SerializeStringVector::SerializeStringVector(stringVector_t vStrings)
: mMaxStringLength(DEFAULT_MAX_LENGTH_STRING), mMaxVectorLength(DEFAULT_MAX_NUMBER_ELEMENTS)
{
for(stringVector_t::iterator i = vStrings.begin(); i != vStrings.end(); i++)
{
push_back(*i);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
unsigned SerializeStringVector::Read(const unsigned char * stream, unsigned size)
{
// fix this:
std::string element;
unsigned bytes = 0;
unsigned elementBytes = 0;
unsigned length = 0;
clear();
bytes += ReadEncoded(stream, size, length);
if (!bytes || length > mMaxVectorLength) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read StringVector, length = %u, mMaxListLength = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, length, mMaxVectorLength, size));
#endif
return 0;
}
for (unsigned i=0; i<length; i++)
{
elementBytes = soe::Read(stream+bytes, size-bytes, element, mMaxStringLength);
if (!elementBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read StringVector element, index = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, i, size));
#endif
return 0;
}
push_back(element);
bytes += elementBytes;
}
return bytes;
}
///////////////////////////////////////////////////////////////////////////////////////////
unsigned SerializeStringVector::Write(unsigned char * stream, unsigned size) const
{
unsigned index = 0;
unsigned bytes = 0;
unsigned elementBytes = 0;
bytes += WriteEncoded(stream, size, (soe::uint32)this->size());
if (!bytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to write StringVector length (%u bytes)", __FUNCTION__, __FILE__, __LINE__, sizeof(soe::uint32)));
#endif
return 0;
}
for (stringVector_t::const_iterator iter = begin(); iter != end(); iter++, index++)
{
elementBytes = soe::Write(stream+bytes, size-bytes, *iter);
if (!elementBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to write StringVector element, index = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, index, size));
#endif
return 0;
}
bytes += elementBytes;
}
return bytes;
}
operator stringVector_t () { return *this; }
//unsigned Read(const unsigned char * stream, unsigned size);
//DECLARE_SCRIBE_MEMBERS
};
///////////////////////////////////////////////////////////////////////////////////////////
inline unsigned Write(unsigned char * stream, unsigned size, const SerializeStringVector & data, unsigned version = 0)
{
return data.Write(stream, size);
}
///////////////////////////////////////////////////////////////////////////////////////////
inline unsigned Read(const unsigned char * stream, unsigned size, SerializeStringVector & data, unsigned, unsigned version = 0)
{
return data.Read(stream, size);
}
} // namespace soe
#endif //SERIALIZESTRINGVECTOR_H
@@ -0,0 +1,784 @@
#ifndef SOE__SERIALIZE_TEMPLATES_H
#define SOE__SERIALIZE_TEMPLATES_H
#ifdef TRACK_READ_WRITE_FAILURES
# include "trackMessageFailures.h"
#endif
#include <map>
namespace soe
{
////////////////////////////////////////////////////////////////////////////////
template<typename K, class T>
inline unsigned Write(unsigned char * stream, unsigned size, const std::map<K, T> & data, unsigned version = 0)
{
unsigned bytes = 0;
unsigned elementBytes = 0;
bytes += WriteEncoded(stream, size, (soe::uint32)data.size());
if (!bytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to write vector length (%u bytes)", __FUNCTION__, __FILE__, __LINE__, sizeof(soe::uint32)));
#endif
return 0;
}
size_t index = 0;
for (typename std::map<K, T>::const_iterator iter = data.begin(); iter != data.end(); iter++, index++)
{
elementBytes = Write(stream+bytes, size-bytes, iter->second, version);
if (!elementBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to write map element, index = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, index, size));
#endif
return 0;
}
bytes += elementBytes;
}
return bytes;
}
template<typename K, class T>
inline unsigned Read(const unsigned char * stream, unsigned size, std::map<K, T> & data, K T::*dataKey, unsigned maxLen, unsigned version = 0)
{
unsigned bytes = 0;
unsigned elementBytes = 0;
unsigned length = 0;
data.clear();
bytes += ReadEncoded(stream, size, length);
if (!bytes || length > maxLen) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read vector, length = %u, maxLen = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, length, maxLen, size));
#endif
return 0;
}
for (unsigned i=0; i<length; i++)
{
T element;
elementBytes = Read(stream+bytes, size-bytes, element, 1, version);
if (!elementBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read vector element, index = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, i, size));
#endif
return 0;
}
data[element.*dataKey] = element;
data.push_back(element);
bytes += elementBytes;
}
return bytes;
}
template<typename K, class T>
inline unsigned Read(const unsigned char * stream, unsigned size, std::map<K, T> & data, const K & (T::*dataKeyAccessor)() const, unsigned maxLen, unsigned version = 0)
{
unsigned bytes = 0;
unsigned elementBytes = 0;
unsigned length = 0;
data.clear();
bytes += ReadEncoded(stream, size, length);
if (!bytes || length > maxLen) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read vector, length = %u, maxLen = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, length, maxLen, size));
#endif
return 0;
}
for (unsigned i=0; i<length; i++)
{
T element;
elementBytes = Read(stream+bytes, size-bytes, element, 1, version);
if (!elementBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read vector element, index = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, i, size));
#endif
return 0;
}
data[(element.*dataKeyAccessor)()] = element;
bytes += elementBytes;
}
return bytes;
}
template<typename K, class T>
inline unsigned Read(const unsigned char * stream, unsigned size, std::map<K, T> & data, K (T::*dataKeyAccessor)() const, unsigned maxLen, unsigned version = 0)
{
unsigned bytes = 0;
unsigned elementBytes = 0;
unsigned length = 0;
data.clear();
bytes += ReadEncoded(stream, size, length);
if (!bytes || length > maxLen) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read vector, length = %u, maxLen = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, length, maxLen, size));
#endif
return 0;
}
for (unsigned i=0; i<length; i++)
{
T element;
elementBytes = Read(stream+bytes, size-bytes, element, 1, version);
if (!elementBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read vector element, index = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, i, size));
#endif
return 0;
}
data[element.*dataKeyAccessor()] = element;
data.push_back(element);
bytes += elementBytes;
}
return bytes;
}
////////////////////////////////////////////////////////////////////////////////
template<class T>
inline unsigned Write(unsigned char * stream, unsigned size, const std::list<T> & data, unsigned version = 0)
{
unsigned bytes = 0;
unsigned elementBytes = 0;
bytes += WriteEncoded(stream, size, (soe::uint32)data.size());
if (!bytes)
return 0;
for (typename std::list<T>::const_iterator iter = data.begin(); iter != data.end(); iter++)
{
elementBytes = Write(stream+bytes, size-bytes, *iter, version);
if (!elementBytes)
return 0;
bytes += elementBytes;
}
return bytes;
}
template<class T>
inline unsigned ReadContainer(const unsigned char * stream, unsigned size, std::list<T> & data, unsigned maxLen, unsigned maxElementLen, unsigned version = 0)
{
unsigned bytes = 0;
unsigned elementBytes = 0;
unsigned length = 0;
data.clear();
bytes += ReadEncoded(stream, size, length);
if (!bytes || length > maxLen)
return 0;
for (unsigned i=0; i<length; i++)
{
T element;
elementBytes = Read(stream+bytes, size-bytes, element, maxElementLen, version);
if (!elementBytes)
return 0;
data.push_back(element);
bytes += elementBytes;
}
return bytes;
}
template<class T>
inline unsigned Read(const unsigned char * stream, unsigned size, std::list<T> & data, unsigned maxLen, unsigned version = 0)
{
return ReadContainer(stream, size, data, maxLen, 1, version);
}
////////////////////////////////////////////////////////////////////////////////
template<class T>
inline unsigned Write(unsigned char * stream, unsigned size, const std::vector<T> & data, unsigned version = 0)
{
unsigned bytes = 0;
unsigned elementBytes = 0;
bytes += WriteEncoded(stream, size, (soe::uint32)data.size());
if (!bytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to write vector length (%u bytes)", __FUNCTION__, __FILE__, __LINE__, sizeof(soe::uint32)));
#endif
return 0;
}
for (size_t index = 0; index < data.size(); index++)
{
elementBytes = Write(stream+bytes, size-bytes, data[index], version);
if (!elementBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to write vector element, index = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, index, size));
#endif
return 0;
}
bytes += elementBytes;
}
return bytes;
}
template<class T>
inline unsigned ReadContainer(const unsigned char * stream, unsigned size, std::vector<T> & data, unsigned maxLen, unsigned maxElementLen, unsigned version = 0)
{
unsigned bytes = 0;
unsigned elementBytes = 0;
unsigned length = 0;
data.clear();
bytes += ReadEncoded(stream, size, length);
if (!bytes || length > maxLen) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read vector, length = %u, maxLen = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, length, maxLen, size));
#endif
return 0;
}
for (unsigned i=0; i<length; i++)
{
T element;
elementBytes = Read(stream+bytes, size-bytes, element, maxElementLen, version);
if (!elementBytes) {
#ifdef TRACK_READ_WRITE_FAILURES
PushMessageFailure(PrintToString("%s, %s:%u - failed to read vector element, index = %u, size = %u", __FUNCTION__, __FILE__, __LINE__, i, size));
#endif
return 0;
}
data.push_back(element);
bytes += elementBytes;
}
return bytes;
}
template<class T>
inline unsigned Read(const unsigned char * stream, unsigned size, std::vector<T> & data, unsigned maxLen, unsigned version = 0)
{
return ReadContainer(stream, size, data, maxLen, 1, version);
}
#ifdef PRINTABLE_MESSAGES
template<typename K, class T>
inline int Print(char * stream, unsigned size, const std::map<K, T> & data, unsigned maxDepth=INT_MAX)
{
int bytes = 0;
int elementBytes = 0;
if (maxDepth == 0) {
bytes = snprintf(stream, size, "{size(%u)}", data.size());
return bytes;
}
elementBytes = snprintf(stream+bytes, size-bytes, "{");
if (FailedToPrint(elementBytes, size-bytes)) {
bytes = elementBytes;
return bytes;
} else {
bytes += elementBytes;
}
bool printedOne = false;
size_t index = 0;
for (typename std::map<K, T>::const_iterator iter = data.begin(); iter != data.end(); iter++, index++)
{
if (printedOne) {
elementBytes = snprintf(stream+bytes, size-bytes, ", ");
if (FailedToPrint(elementBytes, size-bytes)) {
bytes = elementBytes;
return bytes;
} else {
bytes += elementBytes;
}
} else {
printedOne = true;
}
elementBytes = snprintf(stream+bytes, size-bytes, "[%u]", index);
if (FailedToPrint(elementBytes, size-bytes)) {
return elementBytes;
}
bytes += elementBytes;
elementBytes = Print(stream+bytes, size-bytes, *iter, maxDepth-1);
if (FailedToPrint(elementBytes, size-bytes)) {
return elementBytes;
}
bytes += elementBytes;
}
elementBytes = snprintf(stream+bytes, size-bytes, "}");
if (FailedToPrint(elementBytes, size-bytes)) {
bytes = elementBytes;
return bytes;
} else {
bytes += elementBytes;
}
return bytes;
}
template<class T>
inline int Print(char * stream, unsigned size, const std::list<T> & data, unsigned maxDepth=INT_MAX)
{
int bytes = 0;
int elementBytes = 0;
if (maxDepth == 0) {
bytes = snprintf(stream, size, "{size(%u)}", data.size());
return bytes;
}
elementBytes = snprintf(stream+bytes, size-bytes, "{");
if (FailedToPrint(elementBytes, size-bytes)) {
bytes = elementBytes;
return bytes;
} else {
bytes += elementBytes;
}
bool printedOne = false;
size_t index = 0;
for (typename std::list<T>::const_iterator iter = data.begin(); iter != data.end(); iter++, index++)
{
if (printedOne) {
elementBytes = snprintf(stream+bytes, size-bytes, ", ");
if (FailedToPrint(elementBytes, size-bytes)) {
bytes = elementBytes;
return bytes;
} else {
bytes += elementBytes;
}
} else {
printedOne = true;
}
elementBytes = snprintf(stream+bytes, size-bytes, "[%u]", index);
if (FailedToPrint(elementBytes, size-bytes)) {
return elementBytes;
}
bytes += elementBytes;
elementBytes = Print(stream+bytes, size-bytes, *iter, maxDepth-1);
if (FailedToPrint(elementBytes, size-bytes)) {
return elementBytes;
}
bytes += elementBytes;
}
elementBytes = snprintf(stream+bytes, size-bytes, "}");
if (FailedToPrint(elementBytes, size-bytes)) {
bytes = elementBytes;
return bytes;
} else {
bytes += elementBytes;
}
return bytes;
}
template<class T>
inline int Print(char * stream, unsigned size, const std::vector<T> & data, unsigned maxDepth=INT_MAX)
{
int bytes = 0;
int elementBytes = 0;
if (maxDepth == 0) {
bytes = snprintf(stream, size, "{size(%u)}", data.size());
return bytes;
}
elementBytes = snprintf(stream+bytes, size-bytes, "{");
if (FailedToPrint(elementBytes, size-bytes)) {
bytes = elementBytes;
return bytes;
} else {
bytes += elementBytes;
}
bool printedOne = false;
size_t index = 0;
for (typename std::vector<T>::const_iterator iter = data.begin(); iter != data.end(); iter++, index++)
{
if (printedOne) {
elementBytes = snprintf(stream+bytes, size-bytes, ", ");
if (FailedToPrint(elementBytes, size-bytes)) {
bytes = elementBytes;
return bytes;
} else {
bytes += elementBytes;
}
} else {
printedOne = true;
}
elementBytes = snprintf(stream+bytes, size-bytes, "[%u]", index);
if (FailedToPrint(elementBytes, size-bytes)) {
return elementBytes;
}
bytes += elementBytes;
elementBytes = Print(stream+bytes, size-bytes, *iter, maxDepth-1);
if (FailedToPrint(elementBytes, size-bytes)) {
return elementBytes;
}
bytes += elementBytes;
}
elementBytes = snprintf(stream+bytes, size-bytes, "}");
if (FailedToPrint(elementBytes, size-bytes)) {
bytes = elementBytes;
return bytes;
} else {
bytes += elementBytes;
}
return bytes;
}
#endif
////////////////////////////////////////////////////////////////////////////////
template<class ValueType>
class DECLSPEC AutoVariable : public AutoVariableBase
{
public:
//AutoVariable() : AutoVariableBase(), mValue() {}
AutoVariable() : AutoVariableBase() {} // rls - removed redundant default constructor for mValue
explicit AutoVariable(const ValueType & source) : AutoVariableBase(), mValue(source) {}
AutoVariable(const AutoVariable & copy) : AutoVariableBase(), mValue(copy.mValue) {}
virtual ~AutoVariable() {}
const ValueType & Get() const { return mValue; }
ValueType & Get() { return mValue; }
void Set(const ValueType & rhs) { mValue = rhs; }
virtual void Copy(AutoVariableBase *pSource) { AutoVariable<ValueType> *pOther = static_cast<AutoVariable<ValueType> *>(pSource); mValue = pOther->mValue; }
virtual unsigned Write(unsigned char * stream, unsigned size, unsigned version = 0) const { return soe::Write(stream, size, mValue, version); }
virtual unsigned Read(const unsigned char * stream, unsigned size, unsigned maxLen, unsigned version = 0) { return soe::Read(stream, size, mValue, maxLen, version); }
#ifdef PRINTABLE_MESSAGES
virtual int Print(char * stream, unsigned size, unsigned maxDepth=INT_MAX) const
{
int bytes = snprintf(stream, size, "%s(", this->VariableName());
int bytesTotal = 0;
if (FailedToPrint(bytes, size)) {
return bytes;
}
bytesTotal += bytes;
bytes = soe::Print(stream+bytesTotal, size-bytesTotal, mValue, maxDepth);
if (FailedToPrint(bytes, size-bytesTotal)) {
return bytes;
}
bytesTotal += bytes;
bytes = snprintf(stream+bytesTotal, size-bytesTotal, ")");
if (FailedToPrint(bytes, size-bytesTotal)) {
return bytes;
}
bytesTotal += bytes;
return bytesTotal;
}
#endif
private:
ValueType mValue;
};
////////////////////////////////////////////////////////////////////////////////
template<typename ClassType>
class DECLSPEC MemberScribeBase
{
public:
MemberScribeBase(const char * variableName, unsigned version = 0, EVersionEffect effect = eNoEffect)
: mVariableName(variableName)
, mVersion(version)
, mEffect(effect)
{}
virtual ~MemberScribeBase() {}
virtual unsigned Read(const unsigned char * stream, unsigned size, ClassType & data, unsigned version = 0) const = 0;
virtual unsigned Write(unsigned char * stream, unsigned size, const ClassType & data, unsigned version = 0) const = 0;
virtual int Print(char * stream, unsigned size, const ClassType & data, unsigned maxDepth=INT_MAX) const = 0;
inline const char * VariableName() const { return mVariableName; }
inline unsigned Version() const { return mVersion; }
inline EVersionEffect Effect() const { return mEffect; }
protected:
const char *mVariableName;
unsigned mVersion;
EVersionEffect mEffect;
};
////////////////////////////////////////////////////////////////////////////////
template<typename ClassType, typename MemberType>
class DECLSPEC MemberScribe : public MemberScribeBase<ClassType>
{
public:
typedef MemberType ClassType::*MemberPointer_t;
MemberScribe(const char * variableName, MemberPointer_t memberPointer, unsigned size, unsigned version, EVersionEffect effect)
: MemberScribeBase<ClassType>(variableName, version, effect)
, mMemberPointer(memberPointer)
, mSize(size)
{}
virtual ~MemberScribe() {}
virtual unsigned Read(const unsigned char * stream, unsigned size, ClassType & data, unsigned version = 0) const
{
return soe::Read(stream, size, data.*mMemberPointer, mSize, version);
}
virtual unsigned Write(unsigned char * stream, unsigned size, const ClassType & data, unsigned version = 0) const
{
return soe::Write(stream, size, data.*mMemberPointer, version);
}
virtual int Print(char * stream, unsigned size, const ClassType & data, unsigned maxDepth=INT_MAX) const
{
#ifdef PRINTABLE_MESSAGES
return soe::Print(stream, size, data.*mMemberPointer, maxDepth);
#else
return 0;
#endif
}
protected:
MemberPointer_t mMemberPointer;
unsigned mSize;
};
// For use with list/vector reading with string/vector/list (anything with maxSize) elements
template<typename ClassType, typename MemberType>
class DECLSPEC MemberScribeWithElements : public MemberScribe<ClassType, MemberType>
{
public:
MemberScribeWithElements(const char * variableName, typename MemberScribe<ClassType, MemberType>::MemberPointer_t memberPointer, unsigned size, unsigned elementSize, unsigned version = 0, EVersionEffect effect = eNoEffect)
: MemberScribe<ClassType, MemberType>(variableName, memberPointer, size, version, effect)
, mElementSize(elementSize)
{}
virtual ~MemberScribeWithElements() {}
// overrides read function *only*; parent behavior OK for others
virtual unsigned Read(const unsigned char * stream, unsigned size, ClassType & data, unsigned version = 0) const
{
return soe::ReadContainer(stream, size, data.*MemberScribe<ClassType, MemberType>::mMemberPointer, MemberScribe<ClassType, MemberType>::mSize, mElementSize, version);
}
protected:
unsigned mElementSize;
};
class DECLSPEC ClassScribeBase
{
public:
ClassScribeBase(const char * className) : mClassName(className), mInitialized(false) { }
virtual ~ClassScribeBase() { }
inline bool IsInitialized() const { return mInitialized; }
inline void SetInitialized(bool initialized) { mInitialized = initialized; }
const char * ClassName() const { return mClassName; }
virtual void ClearMembers() = 0;
virtual size_t CountMembers() const = 0;
protected:
const char * mClassName;
private:
bool mInitialized;
};
template<typename ClassType>
class DECLSPEC ClassScribe : public ClassScribeBase
{
protected:
typedef MemberScribeBase<ClassType> MemberScribe_t;
typedef std::vector<MemberScribe_t *> MemberScribeVector_t;
public:
ClassScribe(const char * className) : ClassScribeBase(className) { }
~ClassScribe() { }
unsigned Read(const unsigned char * stream, unsigned size, ClassType & data, unsigned version) const;
unsigned Write(unsigned char * stream, unsigned size, const ClassType & data, unsigned version) const;
int Print(char * stream, unsigned size, const ClassType & data, unsigned maxDepth) const;
virtual void ClearMembers()
{
typename MemberScribeVector_t::const_iterator memberIter;
for (memberIter = mMemberScribes.begin(); memberIter != mMemberScribes.end(); memberIter++)
{
MemberScribe_t * pMemberScribe = *memberIter;
delete pMemberScribe;
}
mMemberScribes.clear();
}
virtual size_t CountMembers() const { return mMemberScribes.size(); }
template<typename MemberType>
void AddMember(const char * variableName, MemberType ClassType:: * memberPointer, unsigned size, unsigned version, EVersionEffect effect)
{
MemberScribeBase<ClassType> * pMemberScribe = new MemberScribe<ClassType, MemberType>(variableName, memberPointer, size, version, effect);
mMemberScribes.push_back(pMemberScribe);
}
template<typename MemberType>
void AddMemberContainer(const char * variableName, MemberType ClassType:: * memberPointer, unsigned size , unsigned elementSize, unsigned version, EVersionEffect effect)
{
MemberScribeBase<ClassType> * pMemberScribe = new MemberScribeWithElements<ClassType, MemberType>(variableName, memberPointer, size, elementSize, version, effect);
mMemberScribes.push_back(pMemberScribe);
}
private:
MemberScribeVector_t mMemberScribes;
};
template<typename ClassType>
unsigned ClassScribe<ClassType>::Read(const unsigned char * stream, unsigned size, ClassType & data, unsigned version) const
{
unsigned bytesTotal = 0;
typename MemberScribeVector_t::const_iterator memberIter;
for (memberIter = mMemberScribes.begin(); memberIter != mMemberScribes.end(); memberIter++)
{
MemberScribe_t * pMemberScribe = *memberIter;
if (IsMemberIncluded(version, pMemberScribe->Version(), pMemberScribe->Effect()))
{
unsigned bytes = pMemberScribe->Read(stream, size, data, version);
if (bytes == 0)
{
#ifdef TRACK_READ_WRITE_FAILURES
soe::PushMessageFailure(soe::PrintToString("%s, %s:%u - failed to read %s.%s, size = %u, version = %u", __FUNCTION__, __FILE__, __LINE__, ClassName(), pMemberScribe->VariableName(), size, version));
#endif
bytesTotal = 0;
break;
}
else
{
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
}
}
return bytesTotal;
}
template<typename ClassType>
unsigned ClassScribe<ClassType>::Write(unsigned char * stream, unsigned size, const ClassType & data, unsigned version) const
{
unsigned bytesTotal = 0;
typename MemberScribeVector_t::const_iterator memberIter;
for (memberIter = mMemberScribes.begin(); memberIter != mMemberScribes.end(); memberIter++)
{
const MemberScribe_t * pMemberScribe = *memberIter;
if (IsMemberIncluded(version, pMemberScribe->Version(), pMemberScribe->Effect()))
{
unsigned bytes = pMemberScribe->Write(stream, size, data, version);
if (bytes == 0)
{
#ifdef TRACK_READ_WRITE_FAILURES
soe::PushMessageFailure(soe::PrintToString("%s, %s:%u - failed to read %s.%s, size = %u, version = %u", __FUNCTION__, __FILE__, __LINE__, ClassName(), pMemberScribe->VariableName(), size, version));
#endif
bytesTotal = 0;
break;
}
else
{
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
}
}
return bytesTotal;
}
template<typename ClassType>
int ClassScribe<ClassType>::Print(char * stream, unsigned size, const ClassType & data, unsigned maxDepth) const
{
int bytesTotal = 0;
int bytes = 0;
#ifdef PRINTABLE_MESSAGES
if (maxDepth == 0) {
bytes = snprintf(stream, size, "%s{mMembers(%u)}", ClassName(), mMemberScribes.size());
return bytes;
}
bytes = snprintf(stream, size, "{");
if (soe::FailedToPrint(bytes, size)) {
bytesTotal = bytes;
return bytesTotal;
} else {
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
bool printedOne = false;
typename MemberScribeVector_t::const_iterator memberIter;
for (memberIter = mMemberScribes.begin(); memberIter != mMemberScribes.end(); memberIter++)
{
int bytes = 0;
if (printedOne) {
bytes = snprintf(stream, size, ", ");
if (soe::FailedToPrint(bytes, size)) {
bytesTotal = bytes;
return bytesTotal;
} else {
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
} else {
printedOne = true;
}
const MemberScribe_t * pMemberScribe = *memberIter;
bytes = pMemberScribe->Print(stream, size, maxDepth-1);
if (soe::FailedToPrint(bytes, size))
{
bytesTotal = bytes;
return bytesTotal;
}
else
{
stream += bytes;
size -= bytes;
bytesTotal += bytes;
}
}
#endif
return bytesTotal;
}
////////////////////////////////////////////////////////////////////////////////
}
#endif
@@ -0,0 +1,174 @@
#ifdef WIN32
#pragma warning (disable: 4786)
#endif
#include "stringutils.h"
#include <cctype>
#include <algorithm>
using namespace std;
#define transform std::transform
namespace soe
{
void makeupper(std::string& str)
{
transform(str.begin(), str.end(), str.begin(), toupper);
}
std::string touppercase(const std::string& str)
{
std::string tmp = str;
transform(tmp.begin(), tmp.end(), tmp.begin(), toupper);
return tmp;
}
void makelower(std::string& str)
{
transform(str.begin(), str.end(), str.begin(), tolower);
}
std::string tolowercase(const std::string& str)
{
std::string tmp = str;
transform(tmp.begin(), tmp.end(), tmp.begin(), tolower);
return tmp;
}
bool isEqualNoCase(const std::string& left, const std::string& right)
{
std::string tmp1 = left;
makeupper(tmp1);
std::string tmp2 = right;
makeupper(tmp2);
return tmp1 == tmp2;
}
void rtrim(std::string& str)
{
size_t pos;
pos = str.find_last_not_of (" ");
str = str.substr(0, pos + 1);
}
void ltrim(std::string& str)
{
size_t pos;
pos = str.find_first_not_of (" ");
if (pos != std::string::npos)
str = str.substr(pos);
}
void trim(std::string& str)
{
rtrim(str);
ltrim(str);
}
// crack(dest, base, tok) takes a string and breaks it at the first instance of the token (tok)
// if the token does not exist it is considerd to be past the end of the string.
// dest will contain the portion before the token, base will containe the after the token, the token is discarded
// I want the caller to provide the dest, so we are not at fault if it leaks
// NBM - This is code that I have developed many times before (FYI)
void crack(std::string * dest, std::string * base, const std::string& tok)
{
size_t pos = base->find(tok);
if (pos == std::string::npos)
{
// tok not found take the whole thing
if (dest != NULL) { dest->assign(*base);}
base->clear();
return;
}
if (dest != NULL) {dest->assign(base->substr(0,pos));}
base->erase(0,pos + tok.length());
}
}
//*********************************************************************
//
// Unit Tests
//
//*********************************************************************
#ifdef ENABLE_UNIT_TESTS
#include <UnitTest++.h>
#include <TestReporterStdout.h>
SUITE(stringUtilsSuite)
{
struct stringUtilsFixture
{
stringUtilsFixture()
{
s1 = "AbcD 1&";
s2 = "";
s3 = " abcd 1& ";
}
~stringUtilsFixture()
{
}
std::string s1, s2, s3;
};
TEST_FIXTURE(stringUtilsFixture, MakeUpper)
{
soe::makeupper(s1);
CHECK_EQUAL("ABCD 1&", s1);
soe::makeupper(s2);
CHECK_EQUAL("", s2);
}
TEST_FIXTURE(stringUtilsFixture, toppercase)
{
CHECK_EQUAL("ABCD 1&", soe::touppercase(s1));
CHECK_EQUAL("", soe::touppercase(s2));
}
TEST_FIXTURE(stringUtilsFixture, MakeLower)
{
soe::makelower(s1);
CHECK_EQUAL("abcd 1&", s1);
soe::makelower(s2);
CHECK_EQUAL("", s2);
}
TEST_FIXTURE(stringUtilsFixture, tolowercase)
{
CHECK_EQUAL("abcd 1&", soe::tolowercase(s1));
CHECK_EQUAL("", soe::tolowercase(s2));
}
TEST(isEqualNoCase)
{
CHECK(soe::isEqualNoCase("aBcD", "AbCd"));
CHECK(!(soe::isEqualNoCase("aBcD", "AbCx")));
CHECK(!(soe::isEqualNoCase("aBcD", "AbCx")));
CHECK(!(soe::isEqualNoCase("aBcD", "AbCdE")));
CHECK(!(soe::isEqualNoCase("aBcD", "")));
CHECK(!(soe::isEqualNoCase("", "AbCdE")));
}
TEST_FIXTURE(stringUtilsFixture, rtrim)
{
soe::rtrim(s3);
CHECK_EQUAL(" abcd 1&", s3);
}
TEST_FIXTURE(stringUtilsFixture, ltrim)
{
soe::ltrim(s3);
CHECK_EQUAL("abcd 1& ", s3);
}
TEST_FIXTURE(stringUtilsFixture, trim)
{
soe::trim(s3);
CHECK_EQUAL("abcd 1&", s3);
}
} // End of stringutils
#endif // ENABLE_UINIT_TESTS
@@ -0,0 +1,64 @@
#ifndef __STRINGUTILS_H__
#define __STRINGUTILS_H__
#include <string>
#define LOWER_CASE_STRING_COMPARISON_OPERATOR(__oper_type__) \
bool operator __oper_type__(const lowerCaseString & rhs) const { return mString __oper_type__ rhs.mString; }
#define UPPER_CASE_STRING_COMPARISON_OPERATOR(__oper_type__) \
bool operator __oper_type__(const upperCaseString & rhs) const { return mString __oper_type__ rhs.mString; }
namespace soe
{
void makeupper(std::string& str);
std::string touppercase(const std::string& str);
void makelower(std::string& str);
std::string tolowercase(const std::string& str);
bool isEqualNoCase(const std::string& left, const std::string& right);
void rtrim(std::string& str);
void ltrim(std::string& str);
void trim(std::string& str);
void crack(std::string * dest, std::string * base, const std::string& tok);
void inline crack(std::string& dest, std::string& base, const std::string& tok) {crack(&dest, &base, tok);}
void inline crack(std::string& base, const std::string& tok) {crack(NULL, &base, tok);}
class lowerCaseString
{
public:
lowerCaseString() {}
lowerCaseString(const std::string & src) : mString(src) { makelower(mString); }
lowerCaseString(const char * src) : mString(src ? src : "") { makelower(mString); }
operator std::string() const { return mString; }
LOWER_CASE_STRING_COMPARISON_OPERATOR(<)
LOWER_CASE_STRING_COMPARISON_OPERATOR(<=)
LOWER_CASE_STRING_COMPARISON_OPERATOR(==)
LOWER_CASE_STRING_COMPARISON_OPERATOR(>=)
LOWER_CASE_STRING_COMPARISON_OPERATOR(>)
private:
std::string mString;
};
class upperCaseString
{
public:
upperCaseString() {}
upperCaseString(const std::string & src) : mString(src) { makeupper(mString); }
upperCaseString(const char * src) : mString(src ? src : "") { makeupper(mString); }
operator std::string() const { return mString; }
UPPER_CASE_STRING_COMPARISON_OPERATOR(<)
UPPER_CASE_STRING_COMPARISON_OPERATOR(<=)
UPPER_CASE_STRING_COMPARISON_OPERATOR(==)
UPPER_CASE_STRING_COMPARISON_OPERATOR(>=)
UPPER_CASE_STRING_COMPARISON_OPERATOR(>)
private:
std::string mString;
};
}
#endif
@@ -0,0 +1,795 @@
#ifndef _SUBSTRING_SEARCH_TREE_H_
#define _SUBSTRING_SEARCH_TREE_H_
#include <algorithm>
#include <list>
#include <vector>
template<typename letter_t, typename data_t>
class stringTree
{
public:
typedef std::basic_string<letter_t> string_t;
stringTree();
stringTree(const stringTree & src);
virtual ~stringTree();
stringTree & operator=(const stringTree & rhs);
private:
class letterNode;
typedef typename std::vector<const letterNode *> nodeVector_t;
public:
class const_iterator
{
public:
friend class stringTree;
const_iterator() { }
virtual ~const_iterator() { }
void getKey(string_t & key) const;
inline string_t key() const { string_t value; getKey(value); return value; }
const_iterator & operator=(const const_iterator & rhs) { mBranch = rhs.mBranch; return *this; }
const_iterator & operator++();
const_iterator operator++(int) { const_iterator tmp = *this; ++*this; return tmp; }
const_iterator & operator--();
const_iterator operator--(int) { const_iterator tmp = *this; --*this; return tmp; }
bool operator==(const const_iterator & rhs) const;
bool operator!=(const const_iterator & rhs) const;
const data_t & operator*() const;
const data_t * operator->() const;
protected:
bool advance();
bool retreat();
nodeVector_t mBranch;
};
class iterator : public const_iterator
{
public:
friend class stringTree;
iterator() { }
virtual ~iterator() { }
iterator & operator=(const iterator & rhs) { *((const_iterator *)this) = rhs; return *this; }
data_t & operator*() const;
data_t * operator->() const;
};
inline const iterator & begin() { if(mBeginDirty) { setBegin(); } return mBegin; }
inline const const_iterator & begin() const { if(mBeginDirty) { setBegin(); } return mBegin; }
inline const iterator & end() { return mEnd; }
inline const const_iterator & end() const { return mEnd; }
template<typename iter_t>
iterator find(const iter_t & start, const iter_t & stop);
template<typename iter_t>
const_iterator find(const iter_t & start, const iter_t & stop) const;
template<typename container_t>
inline iterator find(const container_t & key) { return find(key.begin(), key.end()); }
template<typename container_t>
inline const_iterator find(const container_t & key) const { return find(key.begin(), key.end()); }
template<typename iter_t>
bool seek(iter_t & start, const iter_t & stop, iterator & position);
template<typename iter_t>
bool seek(iter_t & start, const iter_t & stop, const_iterator & position) const;
template<typename iter_t>
bool search(iter_t & start, iter_t & middle, const iter_t & stop, typename stringTree::const_iterator & position) const;
template<typename iter_t>
bool insert(const iter_t & start, const iter_t & stop, data_t data);
inline bool insert(const string_t & key, data_t data) { return insert(key.begin(), key.end(), data); }
data_t & operator[](const string_t & key);
template<typename iter_t>
bool erase(const iter_t & start, const iter_t & stop);
bool erase(const iterator & position);
inline bool erase(const string_t & key) { return erase(key.begin(), key.end()); }
void clear();
size_t merge(const const_iterator & start, const const_iterator & stop);
inline size_t merge(const stringTree & src) { return merge(src.begin(), src.end()); }
size_t size() const { return mSize; }
bool empty() const { return (mSize == 0); }
size_t nodeCount() const { return mNodeCount; }
size_t depth() const { return mDepthVector.size(); }
size_t width(size_t level) const { return mDepthVector[level]; }
template<typename iter_t>
class finder
{
public:
finder(const stringTree & dictionary, const iter_t & start, const iter_t & end)
: mDictionary(dictionary)
, mTextStart(start)
, mTextMiddle(start)
, mTextEnd(end)
{ }
template<typename container_t>
finder(const stringTree & dictionary, const container_t & text)
: mDictionary(dictionary)
, mTextStart(text.begin())
, mTextMiddle(text.begin())
, mTextEnd(text.end())
{ }
virtual ~finder() { }
bool next();
const data_t * data() const;
inline const iter_t & start() const { return mTextStart; }
inline const iter_t & middle() const { return mTextMiddle; }
inline const iter_t & end() const { return mTextEnd; }
inline const iter_t & match() const { return mMatchStart; }
private:
iter_t mTextStart;
iter_t mTextMiddle;
iter_t mTextEnd;
iter_t mMatchStart;
const stringTree & mDictionary;
typename stringTree::const_iterator mDictionaryIter;
};
private:
class letterNode
{
public:
letterNode() : mpData(NULL), mpChildren(NULL), mNumChildren(0) { }
letterNode(const letter_t & letter) : mLetter(letter), mpData(NULL), mpChildren(NULL), mNumChildren(0) { }
~letterNode();
inline bool hasData() const { return (mpData != NULL); }
inline data_t & getData() { return *mpData; }
inline const data_t & getData() const { return *mpData; }
inline void setData(const data_t & data) { if (mpData) { *mpData = data; } else { mpData = new data_t(data); } }
inline void removeData() { delete mpData; mpData = NULL; }
letterNode * get(letter_t index) const;
bool put(letter_t index, letterNode ** tree);
bool take(letter_t index, bool deallocate = true);
letterNode * firstChild() const;
letterNode * lastChild() const;
letterNode * nextChild(const letterNode * child) const;
letterNode * previousChild(const letterNode * child) const;
inline bool operator<(const letter_t & rhs) const { return mLetter < rhs; }
friend inline bool operator<(const const_iterator & lhs, const letter_t & rhs) { return lhs.mLetter < rhs; }
inline bool operator==(const letter_t & rhs) const { return mLetter == rhs; }
friend inline bool operator==(const const_iterator & lhs, const letter_t & rhs) { return lhs.mLetter == rhs; }
inline letter_t & letter() { return mLetter; }
inline const letter_t & letter() const { return mLetter; }
inline bool hasNoChildren() const { return (mpChildren == NULL) || (mNumChildren == 0); }
private:
letter_t mLetter;
data_t * mpData;
letterNode * mpChildren;
size_t mNumChildren;
};
private:
void setBegin() const;
size_t mSize;
size_t mNodeCount;
std::vector<size_t> mDepthVector;
letterNode mRoot;
mutable iterator mBegin;
mutable iterator mEnd;
mutable bool mBeginDirty;
bool mIsClearing;
};
template<typename letter_t, typename data_t>
stringTree<letter_t, data_t>::stringTree()
: mSize(0)
, mNodeCount(0)
, mBeginDirty(true)
, mIsClearing(false)
{
setBegin();
mEnd.mBranch.push_back(&mRoot);
}
template<typename letter_t, typename data_t>
stringTree<letter_t, data_t>::stringTree(const stringTree & src)
: mSize(0)
, mNodeCount(0)
, mBeginDirty(true)
, mIsClearing(false)
{
setBegin();
mEnd.mBranch.push_back(&mRoot);
merge(src);
}
template<typename letter_t, typename data_t>
stringTree<letter_t, data_t> & stringTree<letter_t, data_t>::operator=(const stringTree<letter_t, data_t> & rhs)
{
clear();
merge(rhs);
return *this;
}
template<typename letter_t, typename data_t>
stringTree<letter_t, data_t>::~stringTree()
{
clear();
}
template<typename letter_t, typename data_t>
template<typename iter_t>
bool stringTree<letter_t, data_t>::search(iter_t & start, iter_t & middle, const iter_t & stop, typename stringTree::const_iterator & position) const
{
if (seek(middle, stop, position)) {
start++;
} else {
for (;
(position == end()) && (start!= stop);
start++)
{
position = end();
middle = start;
seek(middle, stop, position);
}
}
return (position != end());
}
template<typename letter_t, typename data_t>
template<typename iter_t>
bool stringTree<letter_t, data_t>::seek(iter_t & start, const iter_t & stop, typename stringTree::iterator & position)
{
bool found = false;
if (position.mBranch.empty()) {
position.mBranch.push_back(&mRoot);
}
const letterNode * pnode = (start != stop) ? position.mBranch.back() : NULL;
for (; (start != stop) && ((pnode = pnode->get(*start)) != NULL); start++)
{
position.mBranch.push_back(pnode);
if (pnode->hasData()) {
start++;
break;
}
}
found = pnode && pnode->hasData();
if (!found) { position = end(); }
return found;
}
template<typename letter_t, typename data_t>
template<typename iter_t>
bool stringTree<letter_t, data_t>::seek(iter_t & start, const iter_t & stop, typename stringTree::const_iterator & position) const
{
bool found = false;
if (position.mBranch.empty()) {
position.mBranch.push_back(&mRoot);
}
const letterNode * pnode = (start != stop) ? position.mBranch.back() : NULL;
for (; (start != stop) && ((pnode = pnode->get(*start)) != NULL); start++)
{
position.mBranch.push_back(pnode);
if (pnode->hasData()) {
start++;
break;
}
}
found = pnode && pnode->hasData();
if (!found) { position = end(); }
return found;
}
template<typename letter_t, typename data_t>
template<typename iter_t>
typename stringTree<letter_t, data_t>::iterator stringTree<letter_t, data_t>::find(const iter_t & start, const iter_t & stop)
{
iter_t iter = start;
iterator pos;
for (seek(iter, stop, pos);
(iter != stop) && (pos != end());
seek(iter, stop, pos))
{ }
return pos;
}
template<typename letter_t, typename data_t>
template<typename iter_t>
typename stringTree<letter_t, data_t>::const_iterator stringTree<letter_t, data_t>::find(const iter_t & start, const iter_t & stop) const
{
iter_t iter = start;
const_iterator pos;
for (seek(iter, stop, pos);
(iter != stop) && (pos != end());
seek(iter, stop, pos))
{ }
return pos;
}
template<typename letter_t, typename data_t>
template<typename iter_t>
bool stringTree<letter_t, data_t>::insert(const iter_t & start, const iter_t & stop, data_t data)
{
letterNode * pnode = &mRoot;
bool added = false;
size_t depth = 0;
for (iter_t iter = start; iter != stop; iter++, depth++)
{
bool justAdded = pnode->put(*iter, &pnode);
if (justAdded) {
if (mDepthVector.size() <= depth) {
mDepthVector.push_back(0);
}
mDepthVector[depth]++;
mNodeCount++;
}
added = added || justAdded;
}
added = added || !pnode->hasData();
if (added) { mSize++; mBeginDirty = true; }
pnode->setData(data);
return added;
}
template<typename letter_t, typename data_t>
template<typename iter_t>
bool stringTree<letter_t, data_t>::erase(const iter_t & start, const iter_t & stop)
{
iterator position = find(start, stop);
bool removed = erase(position);
return removed;
}
template<typename letter_t, typename data_t>
bool stringTree<letter_t, data_t>::erase(const iterator & position)
{
bool removed = false;
size_t depth = position.mBranch.size();
if (depth > 1) {
const nodeVector_t & trace = position.mBranch;
typename nodeVector_t::const_reverse_iterator trIter;
letter_t lastLetter;
bool lastWasEmpty = false;
depth--;
const_cast<letterNode *>(position.mBranch.back())->removeData();
for (trIter = trace.rbegin(); trIter != trace.rend(); trIter++, depth--)
{
if (lastWasEmpty) {
const_cast<letterNode *>(*trIter)->take(lastLetter, !mIsClearing);
mNodeCount--;
mDepthVector[depth]--;
if (mDepthVector[depth] == 0) {
mDepthVector.pop_back();
}
}
lastLetter = (*trIter)->letter();
lastWasEmpty = (*trIter)->hasNoChildren() && !(*trIter)->hasData();
}
removed = true;
}
if (removed) { mSize--; mBeginDirty = true; }
return removed;
}
template<typename letter_t, typename data_t>
data_t & stringTree<letter_t, data_t>::operator[](const string_t & key)
{
iterator iter = find(key);
if (iter == end()) {
insert(key, data_t());
iter = find(key);
}
return *iter;
}
template<typename letter_t, typename data_t>
stringTree<letter_t, data_t>::letterNode::~letterNode()
{
/*
does not free any memory; that is left up to the owner
*/
}
template<typename letter_t, typename data_t>
typename stringTree<letter_t, data_t>::letterNode * stringTree<letter_t, data_t>::letterNode::get(letter_t index) const
{
letterNode * tree = NULL;
letterNode * end = mpChildren + mNumChildren;
letterNode * place = std::lower_bound<letterNode *>(mpChildren, mpChildren + mNumChildren, index);
if (place && (place < end) && (place->mLetter == index)) {
tree = place;
}
return tree;
}
template<typename letter_t, typename data_t>
bool stringTree<letter_t, data_t>::letterNode::put(letter_t index, typename stringTree::letterNode ** tree)
{
letterNode * end = mpChildren + mNumChildren;
letterNode * place = std::lower_bound<letterNode *>(mpChildren, mpChildren + mNumChildren, index);
bool added = false;
if (place && (place < end) && (place->mLetter == index)) {
*tree = place;
} else {
mNumChildren++;
letterNode * children = new letterNode[mNumChildren];
size_t before = place - mpChildren;
size_t after = end - place;
letterNode * post = children + before + 1;
memcpy(children, mpChildren, before * sizeof(letterNode));
memcpy(post, place, after * sizeof(letterNode));
place = children + before;
place->mLetter = index;
delete [] mpChildren;
mpChildren = children;
*tree = place;
added = true;
}
return added;
}
template<typename letter_t, typename data_t>
bool stringTree<letter_t, data_t>::letterNode::take(letter_t index, bool deallocate)
{
letterNode * end = mpChildren + mNumChildren;
letterNode * place = std::lower_bound<letterNode *>(mpChildren, end, index);
bool removed = false;
if (place && (place < end) && (place->mLetter == index)) {
mNumChildren--;
if (!mNumChildren) { deallocate = true; }
letterNode * children = NULL;
if (deallocate) {
children = mNumChildren ? new letterNode[mNumChildren] : NULL;
} else {
children = mpChildren;
}
size_t before = place - mpChildren;
size_t after = end - place - 1;
letterNode * post = children + before;
if (deallocate) { memcpy(children, mpChildren, before * sizeof(letterNode)); }
memcpy(post, place + 1, after * sizeof(letterNode));
if (deallocate) { delete [] mpChildren; }
mpChildren = children;
removed = true;
}
return removed;
}
template<typename letter_t, typename data_t>
void stringTree<letter_t, data_t>::const_iterator::getKey(string_t & key) const
{
typename nodeVector_t::const_iterator iter = mBranch.begin();
if (iter != mBranch.end()) {
// skip the root
iter++;
}
for (; iter != mBranch.end(); iter++)
{
key.append(1, (*iter)->letter());
}
}
template<typename letter_t, typename data_t>
typename stringTree<letter_t, data_t>::letterNode * stringTree<letter_t, data_t>::letterNode::firstChild() const
{
letterNode * child = NULL;
if (mpChildren) {
child = mpChildren;
}
return child;
}
template<typename letter_t, typename data_t>
typename stringTree<letter_t, data_t>::letterNode * stringTree<letter_t, data_t>::letterNode::lastChild() const
{
letterNode * child = NULL;
if (mpChildren) {
child = mpChildren + mNumChildren - 1;
}
return child;
}
template<typename letter_t, typename data_t>
typename stringTree<letter_t, data_t>::letterNode * stringTree<letter_t, data_t>::letterNode::nextChild(const letterNode * child) const
{
letterNode * next = NULL;
if (mpChildren) {
size_t index = child - mpChildren;
index++;
if (index < mNumChildren) {
next = mpChildren + index;
}
}
return next;
}
template<typename letter_t, typename data_t>
typename stringTree<letter_t, data_t>::letterNode * stringTree<letter_t, data_t>::letterNode::previousChild(const letterNode * child) const
{
letterNode * previous = NULL;
if (mpChildren) {
size_t index = child - mpChildren;
if (index > 0) {
index--;
previous = mpChildren + index;
}
}
return previous;
}
template<typename letter_t, typename data_t>
typename stringTree<letter_t, data_t>::const_iterator& stringTree<letter_t, data_t>::const_iterator::operator++()
{
while (advance() && !mBranch.back()->hasData())
{ }
if (!mBranch.back()->hasData()) {
mBranch.resize(1);
}
return *this;
}
template<typename letter_t, typename data_t>
typename stringTree<letter_t, data_t>::const_iterator & stringTree<letter_t, data_t>::const_iterator::operator--()
{
while (retreat() &&
!mBranch.back()->hasData() &&
(mBranch.size() > 1))
{ }
if (!mBranch.back()->hasData()) {
mBranch.resize(1);
}
return *this;
}
template<typename letter_t, typename data_t>
bool stringTree<letter_t, data_t>::const_iterator::advance()
{
bool wentForward = false;
const letterNode * terminal = NULL;
const letterNode * penultimate = NULL;
const letterNode * next = NULL;
if (mBranch.back()->hasNoChildren()) {
// go forward
while ((mBranch.size() >= 2) && (next == NULL))
{
penultimate = mBranch[mBranch.size() - 2];
terminal = mBranch[mBranch.size() - 1];
next = penultimate->nextChild(terminal);
mBranch.pop_back();
}
} else {
// go down
terminal = mBranch[mBranch.size() - 1];
next = terminal->firstChild();
}
if (next) {
mBranch.push_back(next);
wentForward = true;
}
return wentForward;
}
template<typename letter_t, typename data_t>
bool stringTree<letter_t, data_t>::const_iterator::retreat()
{
bool wentBack = false;
const letterNode * terminal = NULL;
const letterNode * penultimate = NULL;
const letterNode * next = NULL;
if (mBranch.size() >= 2) {
// go backwards
penultimate = mBranch[mBranch.size() - 2];
terminal = mBranch[mBranch.size() - 1];
next = penultimate->previousChild(terminal);
mBranch.pop_back();
wentBack = true;
} else {
next = mBranch.back();
mBranch.pop_back();
}
// go to leaf
for (; next != NULL; next = next->lastChild())
{
mBranch.push_back(next);
if (next->hasData() && next->hasNoChildren()) {
wentBack = true;
break;
}
}
return wentBack;
}
template<typename letter_t, typename data_t>
bool stringTree<letter_t, data_t>::const_iterator::operator==(const typename stringTree<letter_t, data_t>::const_iterator & rhs) const
{
bool isEqual = (mBranch.size() == rhs.mBranch.size()) &&
(mBranch.empty() || (mBranch.back() == rhs.mBranch.back()));
return isEqual;
}
template<typename letter_t, typename data_t>
bool stringTree<letter_t, data_t>::const_iterator::operator!=(const typename stringTree<letter_t, data_t>::const_iterator & rhs) const
{
return (mBranch != rhs.mBranch);
}
template<typename letter_t, typename data_t>
const data_t & stringTree<letter_t, data_t>::const_iterator::operator*() const
{
return mBranch.back()->getData();
}
template<typename letter_t, typename data_t>
const data_t * stringTree<letter_t, data_t>::const_iterator::operator->() const
{
return &(mBranch.back()->getData());
}
template<typename letter_t, typename data_t>
data_t & stringTree<letter_t, data_t>::iterator::operator*() const
{
return ((data_t &)**(const_iterator *)this);
}
template<typename letter_t, typename data_t>
data_t * stringTree<letter_t, data_t>::iterator::operator->() const
{
return (&**this);
}
template<typename letter_t, typename data_t>
void stringTree<letter_t, data_t>::setBegin() const
{
mBegin.mBranch.clear();
const letterNode * leaf = NULL;
for (leaf = &mRoot; leaf != NULL; leaf = leaf->firstChild())
{
mBegin.mBranch.push_back(leaf);
if (leaf->hasData()) {
break;
}
}
if (!mBegin.mBranch.back()->hasData()) {
mBegin.mBranch.resize(1);
}
mBeginDirty = false;
}
template<typename letter_t, typename data_t>
void stringTree<letter_t, data_t>::clear()
{
mIsClearing = true;
while (!empty())
{
setBegin();
erase(mBegin);
}
mIsClearing = false;
}
template<typename letter_t, typename data_t>
size_t stringTree<letter_t, data_t>::merge(const const_iterator & start, const const_iterator & stop)
{
const_iterator iter;
size_t numberInserted = 0;
for (iter = start; iter != stop; iter++)
{
if (insert(iter.key(), *iter)) {
numberInserted++;
}
}
}
template<typename letter_t, typename data_t>
template<typename iter_t>
bool stringTree<letter_t, data_t>::finder<iter_t>::next()
{
bool found = mDictionary.search(mTextStart, mTextMiddle, mTextEnd, mDictionaryIter);
if (found) {
mMatchStart = mTextStart - 1;
}
return found;
}
template<typename letter_t, typename data_t>
template<typename iter_t>
const data_t * stringTree<letter_t, data_t>::finder<iter_t>::data() const
{
const data_t * pData = NULL;
if (mDictionaryIter != mDictionary.end()) {
pData = &(*mDictionaryIter);
}
return pData;
}
#endif // _SUBSTRING_SEARCH_TREE_H_
@@ -0,0 +1,174 @@
#ifdef WIN32
#pragma warning (disable: 4786)
#endif
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include "systemLog.h"
#include "profile.h"
#ifdef linux
#include <syslog.h>
#endif
const char * SysLogPriority[] =
{
"EMERG ",
"ALERT ",
"CRIT ",
"ERR ",
"WARNING",
"NOTICE ",
"INFO ",
"DEBUG "
};
SysLog::SysLog(const char * identity, bool systemOutput, bool localOutput, int logopt, int facility) :
mIdentity(),
mSystemOutput(systemOutput),
mLocalOutput(localOutput),
mLogFile(0),
mFileTimeout(0),
mTimeStamp(),
mStampTimeout(0),
mFlushOnEveryLocalWrite(false)
{
Profile profile("SysLog::SysLog()");
strncpy((char *)mIdentity, identity, 64); mIdentity[63] = 0;
mTimeStamp[0] = 0;
#ifdef linux
if (logopt == DEFAULT_LOGOPT)
{
logopt = LOG_NDELAY|LOG_PID;
}
if (facility == DEFAULT_FACILITY)
{
facility = LOG_LOCAL5;
}
openlog(mIdentity, logopt, facility);
#endif
}
SysLog::~SysLog()
{
Profile profile("SysLog::~SysLog()");
#ifdef linux
closelog();
#endif
if (mLogFile)
{
fprintf(mLogFile, "SysLog closed\n");
fclose(mLogFile);
}
}
void SysLog::CheckLocalFile(unsigned currentTime)
{
Profile profile("SysLog::CheckLocalFile()");
if (mLogFile && mFileTimeout < currentTime)
{
fprintf(mLogFile, "SysLog closed (continue in new file)\n");
fclose(mLogFile);
mLogFile = 0;
}
if (!mLogFile)
{
char filename[64];
struct tm timeStruct = *localtime((time_t *)&currentTime);
strftime(filename, 64, "log-%b%d-%H.txt", &timeStruct);
timeStruct.tm_sec = 59;
timeStruct.tm_min = 59;
//timeStruct.tm_hour = 23;
mFileTimeout = mktime(&timeStruct);
mLogFile = fopen(filename, "a+t");
if (!mLogFile)
{
mLocalOutput = false;
}
else
{
fprintf(mLogFile, "\nSysLog opened\n");
}
}
}
// 4975 ns
void SysLog::Log(int priority, const char *message)
{
Profile profile("SysLog::Log()");
if (priority > LOG_DEBUG)
priority = LOG_DEBUG;
#ifdef linux
if (mSystemOutput)
{
Profile profile("syslog()");
syslog(priority, "%s : %s", SysLogPriority[priority], message);
}
#endif
if (mLocalOutput)
{
unsigned currentTime = (unsigned)time(0);
CheckLocalFile(currentTime);
if (mLogFile)
{
if (mStampTimeout < currentTime)
{
struct tm timeStruct = *localtime((time_t *)&currentTime);
strftime(mTimeStamp, 64, "%b %d %H:%M:%S", &timeStruct);
mStampTimeout = currentTime;
}
Profile profile("fprintf()");
fprintf(mLogFile, "%s %s: %s : %s\n", mTimeStamp, mIdentity, SysLogPriority[priority], message);
if (mFlushOnEveryLocalWrite)
fflush(mLogFile);
}
}
}
void SysLog::Log(int priority, const char *message, va_list args)
{
Profile profile("SysLog::Log(...)");
if (priority > LOG_DEBUG)
priority = LOG_DEBUG;
#ifdef linux
if (mSystemOutput)
{
char buffer[10240];
snprintf(buffer, 10240, "%s : %s", SysLogPriority[priority], message);
Profile profile("vsyslog()");
vsyslog(priority, buffer, args);
}
#endif
if (mLocalOutput)
{
unsigned currentTime = (unsigned)time(0);
CheckLocalFile(currentTime);
if (mLogFile)
{
if (mStampTimeout < currentTime)
{
struct tm timeStruct = *localtime((time_t *)&currentTime);
strftime(mTimeStamp, 64, "%b %d %H:%M:%S", &timeStruct);
mStampTimeout = currentTime;
}
Profile profile("fprintf()");
fprintf(mLogFile, "%s %s: %s : ", mTimeStamp, mIdentity, SysLogPriority[priority]);
vfprintf(mLogFile, message, args);
fprintf(mLogFile, "\n");
if (mFlushOnEveryLocalWrite)
fflush(mLogFile);
}
}
}
void SysLog::vLog(int priority, const char *message, ...)
{
Profile profile("SysLog::vLog()");
va_list args;
va_start(args, message);
Log(priority, message, args);
va_end(args);
}
@@ -0,0 +1,37 @@
#ifndef SERVER__SYSTEMLOG_H
#define SERVER__SYSTEMLOG_H
#include <stdio.h>
class SysLog
{
public:
enum { LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG };
enum { DEFAULT_LOGOPT = -1, DEFAULT_FACILITY = -1 };
SysLog(const char * identity, bool systemOutput = true, bool localOutput = false, int logopt = DEFAULT_LOGOPT, int facility = DEFAULT_FACILITY);
~SysLog();
void Log(int priority, const char *message);
void Log(int priority, const char *message, va_list argptr);
void vLog(int priority, const char *message, ...);
void EnableFlushOnEveryLocalWrite(bool bEnable=true) { mFlushOnEveryLocalWrite=bEnable; }
private:
void CheckLocalFile(unsigned currentTime);
private:
char mIdentity[64];
bool mSystemOutput;
bool mLocalOutput;
bool mFlushOnEveryLocalWrite;
FILE * mLogFile;
unsigned mFileTimeout;
char mTimeStamp[64];
unsigned mStampTimeout;
};
#endif // #ifndef SERVER__SYSTEMLOG_H
@@ -0,0 +1,413 @@
#ifdef WIN32
#pragma warning (disable: 4514 4786)
#endif
#if !defined(_MT) && !defined(_REENTRANT)
#pragma message ("excluding thread.cpp - requires multi-threaded compile")
#else
#include "timer.h"
#include "thread.h"
#include <time.h>
#include <assert.h>
#ifdef WIN32
#include <process.h>
#endif
#ifdef NAMESPACE
namespace NAMESPACE
{
#endif
ThreadId_t BeginThread(ThreadProc_t threadproc, void *arglist)
{
ThreadId_t threadId;
#ifdef WIN32
threadId = _beginthread(*threadproc,0,arglist);
#else
pthread_create(&threadId,0,threadproc,arglist);
#endif
return threadId;
}
ThreadId_t GetThreadId()
{
unsigned threadId;
#ifdef WIN32
threadId = GetCurrentThreadId();
#else
threadId = pthread_self();
#endif
return threadId;
}
Mutex::Mutex()
{
#ifdef WIN32
InitializeCriticalSection(&mMutex);
#else
pthread_mutex_init(&mMutex, 0);
#endif
}
Mutex::~Mutex()
{
#ifdef WIN32
DeleteCriticalSection(&mMutex);
#else
pthread_mutex_destroy(&mMutex);
#endif
}
void Mutex::Lock()
{
#ifdef WIN32
EnterCriticalSection(&mMutex);
#else
pthread_mutex_lock(&mMutex);
#endif
}
bool Mutex::TryLock()
{
#ifdef WIN32
Lock();
return false;
#else
return pthread_mutex_trylock(&mMutex) != EBUSY;
#endif
}
void Mutex::Unlock()
{
#ifdef WIN32
LeaveCriticalSection(&mMutex);
#else
pthread_mutex_unlock(&mMutex);
#endif
}
ScopeLock::ScopeLock(Mutex & mutex) :
mMutex(mutex)
{
mMutex.Lock();
}
ScopeLock::~ScopeLock()
{
mMutex.Unlock();
}
SwitchableScopeLock::SwitchableScopeLock(Mutex & mutex, bool isOn) :
mMutex(mutex),
mIsOn(isOn)
{
if(mIsOn) { mMutex.Lock(); }
}
SwitchableScopeLock::~SwitchableScopeLock()
{
if(mIsOn) { mMutex.Unlock(); }
}
const int EVENT_SIGNALED = -1;
Event::Event(bool signaled) :
#ifndef WIN32
mMutex(),
mThreadCount(signaled ? EVENT_SIGNALED : 0),
#endif
mEvent()
{
#ifdef WIN32
mEvent = CreateEvent(NULL, FALSE, signaled ? TRUE : FALSE, NULL);
#else
pthread_mutex_init(&mMutex, NULL);
pthread_cond_init(&mCond, NULL);
#endif
}
Event::~Event()
{
#ifdef WIN32
CloseHandle(mEvent);
#else
pthread_cond_destroy(&mCond);
pthread_mutex_destroy(&mMutex);
#endif
}
// return: true if signaled, false if timeout/error
bool Event::Wait(unsigned timeoutMilliseconds)
{
#ifdef WIN32
return WaitForSingleObjectEx(mEvent, timeoutMilliseconds ? timeoutMilliseconds : INFINITE, FALSE) == WAIT_OBJECT_0;
#else
pthread_mutex_lock(&mMutex);
if (mThreadCount == EVENT_SIGNALED)
{
mThreadCount = 0;
pthread_mutex_unlock(&mMutex);
return true; // signaled
}
if (!timeoutMilliseconds)
{
mThreadCount++;
pthread_cond_wait(&mCond, &mMutex);
mThreadCount--;
pthread_mutex_unlock(&mMutex);
return true; // signaled
}
else
{
struct timeval now;
struct timespec abs_timeout;
gettimeofday(&now, NULL);
abs_timeout.tv_sec = now.tv_sec + timeoutMilliseconds/1000;
abs_timeout.tv_nsec = now.tv_usec * 1000 + (timeoutMilliseconds%1000)*1000000;
abs_timeout.tv_sec += abs_timeout.tv_nsec / 1000000000;
abs_timeout.tv_nsec %= 1000000000;
mThreadCount++;
int waitResult = pthread_cond_timedwait(&mCond, &mMutex, &abs_timeout);
mThreadCount--;
pthread_mutex_unlock(&mMutex);
return (waitResult == 0 || waitResult == EINTR);
}
#endif
}
void Event::Signal()
{
#ifdef WIN32
SetEvent(mEvent);
#else
pthread_mutex_lock(&mMutex);
if (mThreadCount == 0)
mThreadCount = EVENT_SIGNALED;
pthread_cond_signal(&mCond);
pthread_mutex_unlock(&mMutex);
#endif
}
EventLock::EventLock(bool locked) :
#ifndef WIN32
mMutex(),
mLocked(locked),
#endif
mEvent()
{
#ifdef WIN32
mEvent = CreateEvent(NULL, TRUE, locked ? FALSE : TRUE, NULL);
#else
pthread_mutex_init(&mMutex, NULL);
pthread_cond_init(&mCond, NULL);
#endif
}
EventLock::~EventLock()
{
#ifdef WIN32
CloseHandle(mEvent);
#else
pthread_cond_destroy(&mCond);
pthread_mutex_destroy(&mMutex);
#endif
}
bool EventLock::IsLocked()
{
#ifdef WIN32
return WaitForSingleObjectEx(mEvent, 0, FALSE) != WAIT_OBJECT_0;
#else
return mLocked;
#endif
}
bool EventLock::Wait(unsigned timeoutMilliseconds)
{
#ifdef WIN32
return WaitForSingleObjectEx(mEvent, timeoutMilliseconds ? timeoutMilliseconds : INFINITE, FALSE) == WAIT_OBJECT_0;
#else
pthread_mutex_lock(&mMutex);
if (mLocked)
{
if (!timeoutMilliseconds)
{
pthread_cond_wait(&mCond, &mMutex);
pthread_mutex_unlock(&mMutex);
return true; // signaled
}
else
{
struct timeval now;
struct timespec abs_timeout;
gettimeofday(&now, NULL);
abs_timeout.tv_sec = now.tv_sec + timeoutMilliseconds/1000;
abs_timeout.tv_nsec = now.tv_usec * 1000 + (timeoutMilliseconds%1000)*1000000;
abs_timeout.tv_sec += abs_timeout.tv_nsec / 1000000000;
abs_timeout.tv_nsec %= 1000000000;
int waitResult = pthread_cond_timedwait(&mCond, &mMutex, &abs_timeout);
pthread_mutex_unlock(&mMutex);
return (waitResult == 0 || waitResult == EINTR);
}
} else {
pthread_mutex_unlock(&mMutex);
}
return true;
#endif
}
void EventLock::Lock()
{
#ifdef WIN32
ResetEvent(mEvent);
#else
pthread_mutex_lock(&mMutex);
mLocked = true;
pthread_mutex_unlock(&mMutex);
#endif
}
void EventLock::Unlock()
{
#ifdef WIN32
SetEvent(mEvent);
#else
pthread_mutex_lock(&mMutex);
mLocked = false;
pthread_cond_broadcast(&mCond);
pthread_mutex_unlock(&mMutex);
#endif
}
RWLock::RWLock() :
mWriteMutex(),
mReadMutex(),
mReadCount(0),
mReadLock(),
mReadEvent()
{
}
RWLock::~RWLock()
{
}
void RWLock::ReadLock()
{
mReadMutex.Lock();
unsigned short readCount = mReadCount++;
mReadMutex.Unlock();
if (readCount == 0)
{
mReadEvent.Wait();
mReadLock.Unlock();
}
mReadLock.Wait();
}
void RWLock::ReadUnlock()
{
assert(mReadCount);
mReadMutex.Lock();
unsigned short readCount = --mReadCount;
mReadMutex.Unlock();
if (readCount == 0)
{
mReadLock.Lock();
mReadEvent.Signal();
}
}
void RWLock::WriteLock()
{
mWriteMutex.Lock();
mReadEvent.Wait();
}
void RWLock::WriteUnlock()
{
mReadEvent.Signal();
mWriteMutex.Unlock();
}
Thread::Thread() :
mThreadId(0),
mActive(false),
mContinue(false)
{
}
Thread::~Thread()
{
Stop();
}
#ifdef WIN32
void _threadProc(void *threadPtr)
{
Thread & thread = *((Thread*)threadPtr);
thread.mActive = true;
thread.ThreadProc();
thread.mActive = false;
}
#else
void* _threadProc(void *threadPtr)
{
Thread & thread = *((Thread*)threadPtr);
thread.mActive = true;
thread.ThreadProc();
thread.mActive = false;
return 0;
}
#endif
void Thread::Start()
{
mContinue = true;
mThreadId = BeginThread(_threadProc,this);
}
// return true if thread became inactive before the timeout
bool Thread::Stop(unsigned timeoutSeconds)
{
mContinue = false;
timeoutSeconds += time(0);
while (mActive && (unsigned)time(0)<timeoutSeconds)
soe::Sleep(100);
return (!mActive);
}
bool Thread::Active() const
{
return mActive;
}
bool Thread::GetId(ThreadId_t & threadId) const
{
/*
if (!mActive)
return false;
*/
threadId = mThreadId;
return true;
}
bool Thread::Continue() const
{
return mContinue;
}
#ifdef NAMESPACE
}
#endif
#endif
@@ -0,0 +1,148 @@
#ifndef BASE__THREAD_H
#define BASE__THREAD_H
#if !defined(_MT) && !defined(_REENTRANT)
#error thread.h - requires multi-threaded compile
#endif
#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/errno.h>
#include <pthread.h>
#endif
#ifdef NAMESPACE
namespace NAMESPACE
{
#endif
#ifdef WIN32
typedef unsigned ThreadId_t;
typedef CRITICAL_SECTION Mutex_t;
typedef HANDLE Event_t;
typedef void (*ThreadProc_t)(void *);
void _threadProc(void *);
#else
typedef pthread_t ThreadId_t;
typedef pthread_mutex_t Mutex_t;
typedef pthread_cond_t Event_t;
typedef void* (*ThreadProc_t)(void *);
void* _threadProc(void *);
#endif
ThreadId_t BeginThread(ThreadProc_t threadproc, void *arglist);
ThreadId_t GetThreadId();
class Mutex
{
public:
Mutex();
~Mutex();
void Lock();
bool TryLock();
void Unlock();
private:
Mutex_t mMutex;
};
class ScopeLock
{
public:
ScopeLock(Mutex & mutex);
~ScopeLock();
private:
Mutex & mMutex;
};
class SwitchableScopeLock
{
public:
SwitchableScopeLock(Mutex & mutex, bool isOn);
~SwitchableScopeLock();
private:
Mutex & mMutex;
bool mIsOn;
};
class Event
{
public:
Event(bool signaled = false);
~Event();
bool Wait(unsigned timeoutMilliseconds = 0);
void Signal();
private:
#ifndef WIN32
Mutex_t mMutex;
int mThreadCount;
pthread_cond_t mCond;
#endif
Event_t mEvent;
};
class EventLock
{
public:
EventLock(bool locked = true);
~EventLock();
bool Wait(unsigned timeoutMilliseconds = 0);
void Lock();
void Unlock();
bool IsLocked();
private:
#ifndef WIN32
Mutex_t mMutex;
bool mLocked;
pthread_cond_t mCond;
#endif
Event_t mEvent;
};
class RWLock
{
public:
RWLock();
~RWLock();
void ReadLock();
void ReadUnlock();
void WriteLock();
void WriteUnlock();
private:
Mutex mWriteMutex;
Mutex mReadMutex;
unsigned short mReadCount;
EventLock mReadLock;
Event mReadEvent;
};
class Thread
{
#ifdef WIN32
friend void _threadProc(void *);
#else
friend void* _threadProc(void *);
#endif
public:
Thread();
virtual ~Thread();
void Start();
bool Stop(unsigned timeoutSeconds=0);
bool Active() const;
bool GetId(ThreadId_t & threadId) const;
protected:
virtual void ThreadProc() = 0;
bool Continue() const; // query for ThreadProc to continue or exit
bool mContinue;
private:
ThreadId_t mThreadId;
bool mActive;
};
#ifdef NAMESPACE
}
#endif
#endif
@@ -0,0 +1,93 @@
#ifndef SOE__TIMER_H
#define SOE__TIMER_H
#ifdef WIN32
#include <winsock2.h>
#elif linux
#include <sys/time.h>
#include <unistd.h>
#endif
#include "types.h"
namespace soe
{
#ifdef WIN32
inline uint64 GetTimer(void)
{
uint64 result;
if (!QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&result)))
result = 0;
return result;
}
inline int64 GetTimerFrequency(void)
{
int64 result;
if (!QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&result)))
result = 0;
return result;
}
inline void Sleep(uint32 ms)
{
::Sleep(ms);
}
#elif linux
inline uint64 GetTimer(void)
{
uint64 t;
struct timeval tv;
gettimeofday(&tv, 0);
t = tv.tv_sec;
t = t * 1000000;
t += tv.tv_usec;
return t;
}
inline int64 GetTimerFrequency(void)
{
int64 f = 1000000;
return f;
}
inline void Sleep(uint32 ms)
{
usleep(static_cast<unsigned long>(ms * 1000));
}
#endif
inline double GetTimerLatency(soe::uint64 startTime, soe::uint64 finishTime=0)
{
soe::int64 requestAge;
soe::uint64 finish = (finishTime ? finishTime : soe::GetTimer());
if (finish < startTime)
requestAge = (0 - 1) - (startTime - finish) + 1;
else
requestAge = finish - startTime;
return (double)requestAge/soe::GetTimerFrequency();
}
}
#endif
@@ -0,0 +1,114 @@
#include "trackMessageFailures.h"
#ifdef TRACK_READ_WRITE_FAILURES
# include <stdarg.h>
# include <stdio.h>
# if defined(_MT) || defined(_REENTRANT)
# include "thread.h"
# endif
# ifdef WIN32
# define vsnprintf _vsnprintf
# endif
# include <list>
namespace soe
{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////
// Variables for tracking read/write failure
typedef std::list<std::string> stringList_t;
stringList_t messageFailureList;
bool serializeMessageFailures = false;
#if defined(_MT) || defined(_REENTRANT)
class SwitchableScopeLock
{
public:
SwitchableScopeLock()
{
if (serializeMessageFailures)
{ msMutex.Lock(); }
}
~SwitchableScopeLock()
{
if (serializeMessageFailures)
{ msMutex.Unlock(); }
}
private:
static Mutex msMutex;
};
Mutex SwitchableScopeLock::msMutex;
#else
class SwitchableScopeLock
{
public:
SwitchableScopeLock() {}
~SwitchableScopeLock() {}
};
#endif
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////
// Functions for tracking read/write failure
std::string PrintToString(const char * format, ...)
{
va_list arg;
va_start(arg, format);
char buffer[2048];
vsnprintf((char *)buffer, sizeof(buffer), format, arg);
va_end(arg);
return buffer;
}
void SetSerializeMessageFailures(bool serialize)
{
serializeMessageFailures = serialize;
}
void PushMessageFailure(const std::string & failureDescription)
{
SwitchableScopeLock s;
messageFailureList.push_front(failureDescription);
}
void GetMessageFailureStack(std::vector<std::string> & failureDescriptions)
{
SwitchableScopeLock s;
size_t index = 0;
failureDescriptions.resize(messageFailureList.size());
for (stringList_t::const_iterator lit = messageFailureList.begin(); lit != messageFailureList.end(); lit++, index++)
{
failureDescriptions[index] = *lit;
}
}
void ClearMessageFailureStack()
{
SwitchableScopeLock s;
messageFailureList.clear();
}
////////////////////////////////////////////////////////////////////////////////
}
#endif // TRACK_READ_WRITE_FAILURES
@@ -0,0 +1,29 @@
#ifndef TRACK_MESSAGE_FAILURES_H
#define TRACK_MESSAGE_FAILURES_H
/////////////////////////////////////////////////////////////////////////////
// Define the preprocessor directive below (TRACK_READ_WRITE_FAILURES) //
// in *.vcproj/make file to enable tracking of message read/write failures //
/////////////////////////////////////////////////////////////////////////////
#ifdef TRACK_READ_WRITE_FAILURES
#include <string>
#include <vector>
namespace soe
{
std::string PrintToString(const char * format, ...);
void PushMessageFailure(const std::string & failureDescription);
void GetMessageFailureStack(std::vector<std::string> & failureDescriptions);
void ClearMessageFailureStack();
void SetSerializeMessageFailures(bool serialize);
};
#endif // TRACK_READ_WRITE_FAILURES
#endif // TRACK_MESSAGE_FAILURES_H
@@ -0,0 +1,79 @@
#ifndef SOE__TYPES_H
#define SOE__TYPES_H
#define XSTRINGIFY(S) STRINGIFY(S)
#define STRINGIFY(S) #S
#ifdef linux
#include <sys/bitypes.h>
#endif
#if 0
# pragma warning (disable: 4251)
# ifndef DECLSPEC
# if defined (IMPORT_DLL)
# define DECLSPEC __declspec(dllimport)
# elif defined (EXPORT_DLL)
# define DECLSPEC __declspec(dllexport)
# else
# define DECLSPEC
# endif
# endif
# define DECLIMPORT __declspec(dllimport)
#else
# define DECLSPEC
# define DECLIMPORT extern
#endif
#ifdef WIN32
# define FILENAME (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#else
# define FILENAME __FILE__
#endif
// printf format specifier for 64 bit number since Windows and Linux differ
#ifdef WIN32
#define FMT_INT64 "%I64d"
#define FMT_UINT64 "%I64u"
#define atoi64(x) _atoi64(x)
#elif linux
#define FMT_INT64 "%lld"
#define FMT_UINT64 "%llu"
#define atoi64(x) atoll(x)
#endif
namespace soe
{
typedef char int8;
typedef unsigned char uint8;
typedef short int16;
typedef unsigned short uint16;
#ifdef WIN32
typedef int int32;
typedef unsigned uint32;
typedef __int64 int64;
typedef unsigned __int64 uint64;
#elif linux
typedef int32_t int32;
typedef u_int32_t uint32;
typedef int64_t int64;
typedef u_int64_t uint64;
//! the previous seem erroneous
// typedef signed int int32;
// typedef unsigned int uint32;
// typedef signed long long int64;
// typedef unsigned long long uint64;
#endif
}
#endif
@@ -0,0 +1,312 @@
#include <string.h>
#include "utf8.h"
namespace soe
{
/*
A little bit about UTF8...
UTF8 stands for UCS Tranfer Format, while UCS stands for Universal Character Set. In
essence, UTF8 is a way to encode all the characters in the UCS. UTF8 attempts to
describe all the characters in the UCS using from 1 to 6 bytes per character. If the
first byte's high bit is not set, then the character is 1 byte long, and corresponds to
the US-ASCII character of the same number. In this way, all current US-ASCII strings are
already UTF8 compatible. If the the first byte's high bit is set, then the number of
high bits set until the first 0 describes the number of bytes in the character, e.g. a
first byte who's bits are 1110xxxx will be followed by 2 more "data bytes" that look like
10yyyyyy 10zzzzzz, so that the entire character's descriptive ID is x xxxxyyyy yyzzzzzz.
With this method, all characters in the UCS-4 character space can be mapped to <=6 bytes of
data, and all characters int the UCS-2 character space can be mapped in <=3 bytes
maximum. Since only UCS-2 actually contains character assignments from known languages,
it is expected that a maximum of 3 bytes will be needed for any character encountered
during translation.
Unfortunately, this method also means that there are sequences of bytes that do not form
valid UTF8 characters/strings.
In this file, we've placed some string and character validation functions, as well as
replacements for functions where the standard <string.h> function will not behave
properly on a UTF8 string.
*/
// array of character byte-lengths. Index into the array with the first byte of the character & 0x3C then shift down twice.
// NOTE: this only works for multi-byte characters (up to 6).
static char UTF8_charSizeArray[16] = { 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6 };
// UTF8_charSize returns the length of a UTF8 character in bytes (1-6).
// The array UTF8_size has 0's where an invalid header byte is detected.
// This is a "fast" function, so no error checking is done.
size_t UTF8_charSize( char * ptr )
{
// temp hold of "header" byte
unsigned char ct = *ptr;
// if high bit not set, it's just a normal character, length 1
if (( ct & 0x80 ) == 0 )
{
return 1;
}
return (size_t)UTF8_charSizeArray[ ( ct & 0x3C ) >> 2 ];
}
// takes a pointer to a UTF8 character and fills the 2nd arg with the 16-bit UTF16 corresponding char.
// return value is the length of the UTF8 char converted.
size_t UTF8_convertCharToUTF16( char * ptr , UTF16 * ret )
{
size_t len = UTF8_charSize( ptr );
if ( len == 1 )
{
*ret = *ptr;
}
else if ( len == 2 )
{
*ret = (UTF16)(((UTF16)( *ptr & 0x1F ) << 6 ) + ( *(ptr+1) & 0x3F ));
}
else if ( len == 3 )
{
*ret = (UTF16)(((UTF16)( *ptr & 0x0F ) << 12 ) + ((UTF16)( *(ptr+1) & 0x3F ) << 6 ) + (( *(ptr+2) & 0x3F )));
}
return len;
}
// takes a pointer to a UTF8 String and fills the 2nd array with the corresponding UTF16 string, up to
// the limit number of characters.
// return value is the length of the UTF16 string converted.
size_t UTF8_convertToUTF16( char * ptr , UTF16 * ret, size_t limit )
{
size_t len = 0;
while (( *ptr != 0 ) && ( len < ( limit - 1 ) ))//we use limit -1 to leave room for the null terminator
{
size_t clen = UTF8_convertCharToUTF16( ptr, ret );
ptr += clen;
ret++;
len++;
}
*ret = 0;
return len;
}
// takes a UTF16 character and fills the 2nd arg with the UTF8 corresponding char.
// return value is the size of the UTF8 char converted.
// return value is 0 if the size of the UTF8 char would be bigger than the limit allowed. In this
// case, the return string is not filled.
size_t UTF16_convertCharToUTF8( UTF16 char16, char * ret, size_t limit )
{
size_t len = 0;
if ( char16 <= 0x0080 )
{
if ( limit >= 1 )
{
*ret = (char)char16;
len = 1;
}
}
else if ( char16 <= 0x07FF )
{
if ( limit >= 2 )
{
*(ret) = (char)( 0xC0 + (( char16 & 0x07C0 ) >> 6 ));
*(ret+1) = (char)(0x80 + (char)( char16 & 0x003F ));
len = 2;
}
}
else
{
if ( limit >= 3 )
{
*ret = (char)(0xE0 + (( char16 & 0xF000 ) >> 12 ));
*(ret+1) = (char)(0x80 + (( char16 & 0x0FC0 ) >> 6 ));
*(ret+2) = (char)(0x80 + ( char16 & 0x003F ));
len = 3;
}
}
return len;
}
// takes a pointer to a UTF16 String and fills the 2nd array with the corresponding UTF8 string, up to
// the limit number of bytes.
// return value is the size of the UTF8 string converted.
size_t UTF16_convertToUTF8( UTF16 *ptr, char * ret, size_t limit )
{
size_t len = 0;
while (( *ptr != 0 ) && ( limit != 0 ))
{
size_t clen = UTF16_convertCharToUTF8( *ptr, ret, limit );
if ( clen == 0 )
{
break;
}
ret += clen;
ptr++;
limit -= clen;
}
*ret = 0;
return len;
}
void EnglishToFakeUtf8(char *fakeDestination, char *englishSource, size_t destinationSize)
{
UTF16 utf16[8192];
UTF16 *d = utf16;
char *s = englishSource;
bool afterPercent = false;
while (*s != 0)
{
if (afterPercent)
{
*d = *s;
if (*s == ' ') // assuming everthing between % and white-space is formatting and don't shift it, this may not be the case all the time, but the worst that will happen is we won't shift everything we possibly could have
afterPercent = false;
}
else
{
if ((*s >= 'a' && *s <= 'k') || (*s >= 'A' && *s <= 'Z'))
*d = (UTF16)(*s + 0xfee0);
else
*d = *s;
if (*s == '%') // we can't be shifting formatting tokens or else sprintf won't work
afterPercent = true;
}
d++;
s++;
}
*d = 0;
UTF16_convertToUTF8(utf16, fakeDestination, destinationSize);
}
void FakeUtf8ToEnglish(char *englishDestination, char *fakeSource, size_t destinationSize)
{
UTF16 utf16[8192];
UTF8_convertToUTF16(fakeSource, utf16, sizeof(utf16));
UTF16 *s = utf16;
char *d = englishDestination;
char *endDest = d + destinationSize - 1;
while (*s != 0 && d < endDest)
{
if (*s >= 0xfee0)
*d = (char)(*s - 0xfee0);
else
*d = (char)*s;
d++;
s++;
}
*d = 0;
}
size_t UTF16_strlen( UTF16 * ptr )
{
size_t count(0);
while(*ptr != 0)
{
ptr++;
count++;
}
return count;
}
static const int utf8_lengths[16]=
{
1,1,1,1,1,1,1,1, // 0000 to 0111 : 1 byte (plain ASCII)
0,0,0,0, // 1000 to 1011 : not valid
2,2, // 1100, 1101 : 2 bytes
3, // 1110 : 3 bytes
4 // 1111 :4 bytes
};
int UTF8_strlen(const char * source)
{
int wchar_length=0;
int code_size;
unsigned char byte;
if (source)
{
int byte_length = (int)strlen(source);
while (byte_length > 0)
{
byte=(unsigned char)*source;
// Use lookup table to determine sequence
// length based on upper 4 bits of first byte
if ((byte <= 0xF7) && (0 != (code_size=utf8_lengths[ byte >> 4])))
{
// 1 sequence == 1 character
wchar_length++;
if (code_size==4)
{
wchar_length++;
}
source+=code_size; // increment pointer
byte_length-=code_size; // decrement counter
}
else
{
// invalid character encountered
return -1;
}
}
}
return wchar_length;
}
int UTF8_truncate(char *output, const char *source, size_t limit)
{
int wchar_length=0; //number of utf-8 characters
int code_size; //number of bytes each wchar
int cur_bytes_count = 0;
unsigned char byte;
char *pout = output;
if(limit <= 0)
return -1;
if (source)
{
int byte_length = (int)strlen(source);
while (byte_length > 0)
{
byte=(unsigned char)*source;
// Use lookup table to determine sequence
// length based on upper 4 bits of first byte
if ((byte <= 0xF7) && (0 != (code_size=utf8_lengths[ byte >> 4])))
{
// 1 sequence == 1 character
cur_bytes_count+=code_size;
if(cur_bytes_count <= limit)
{
strncpy(pout, source, code_size);
} else {
break;
}
wchar_length++;
if (code_size==4)
{
wchar_length++;
}
source+=code_size; // increment pointer
pout+=code_size;
byte_length-=code_size; // decrement counter
}
else
{
// invalid character encountered
return -1;
}
}
}
return wchar_length;
}
};
@@ -0,0 +1,33 @@
#ifndef UTF8_H
#define UTF8_H
#include <stdio.h>
//#include "Unicode.h"
namespace soe
{
typedef char UTF8;
typedef unsigned short int UTF16;
size_t UTF8_charSize( char * );
size_t UTF8_convertCharToUTF16( char * ptr , UTF16 * ret );
size_t UTF8_convertToUTF16( char * ptr , UTF16 * ret, size_t limit );
size_t UTF16_convertCharToUTF8( UTF16 ret, char * ptr , size_t limit );
size_t UTF16_convertToUTF8( UTF16 * ret, char * ptr , size_t limit );
void EnglishToFakeUtf8(char *fakeDestination, char *englishSource, size_t destinationSize);
void FakeUtf8ToEnglish(char *englishDestination, char *fakeSource, size_t destinationSize);
//Plat_Unicode::String UTF8ToUnicode(const char *source);
//void UnicodeToUTF8(Plat_Unicode::String &source, char *dest, int limit);
size_t UTF16_strlen( UTF16 * ptr );
int UTF8_strlen( const char * );
//truncate UTF-8
int UTF8_truncate( char *, const char*, size_t limit);
};
#endif
@@ -0,0 +1,119 @@
#include "Clock.h"
#include <time.h>
#ifdef WIN32
#include <winsock.h>
#else //WIN32
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#endif
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
Clock::Clock()
: m_lastStart(0),
m_totalRunTime(0)
{
}
ClockStamp Clock::getCurTime()
{
#if defined(WIN32)
static int sClockHigh = 0;
static ClockStamp sClockLast = 0;
int high = sClockHigh;
DWORD low = GetTickCount();
ClockStamp holdLast = sClockLast; // this should be interlocked too
ClockStamp ret = ((ClockStamp)high << 32) | low;
// crazy trick to allow threading to work, by putting in a 1000 second fudge factor, we effective say
// that it is ok to time-slice us at a bad point and we will still handle it, provided that our thread
// gets processing time again within 1000 seconds
if (ret < holdLast - 1000000)
{
sClockHigh = high + 1;
ret = ((ClockStamp)high << 32) | low;
}
sClockLast = ret; // this really should be interlocked to be totally safe since it is a 64 bit value, but I don't see a way to do that and am not sure it would mess up anything but the one call anyways
return ret;
#else
struct timeval tv;
int err;
err = gettimeofday(&tv, NULL);
return (static_cast<ClockStamp>(tv.tv_sec) * 1000 + static_cast<ClockStamp>(tv.tv_usec / 1000));
#endif
}
ClockStamp Clock::getElapsedSinceLastStart()
{
if (m_lastStart == 0)
{
//hasn't been started
return 0;
}
ClockStamp elapsed = getCurTime() - m_lastStart;
if (elapsed > 2000000000) // only time differences up to 23 days can be measured with this function
elapsed = 2000000000;
return elapsed;
}
void Clock::start()
{
if (m_lastStart != 0)
{
//already started
return;
}
//set last start to curtime
m_lastStart = getCurTime();
}
void Clock::stop()
{
if (m_lastStart == 0)
{
//need to start before stoping
return;
}
m_totalRunTime += (unsigned)getElapsedSinceLastStart(); //rlsmith - explicit cast to prevent compiler warning
m_lastStart = 0;
}
bool Clock::isDone(unsigned runTime)
{
if (m_lastStart == 0)
{
//never started, so say no
return false;
}
ClockStamp totalElapsed = getElapsedSinceLastStart() + m_totalRunTime;
return (totalElapsed >= runTime);
}
void Clock::reset()
{
m_lastStart = 0;
m_totalRunTime = 0;
}
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,71 @@
#ifndef CLOCK_H
#define CLOCK_H
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
#if defined(WIN32)
typedef __int64 ClockStamp;
#else
typedef long long ClockStamp;
#endif
/**
* @brief A Clock can be used as a millisecond timer.
*/
class Clock
{
public:
/**
* @brief Creates a clock, must still be started with Clock::start method.
*
* Once created, a clock can be started, and stoped as often as possible.
*/
Clock();
/**
* @brief Starts the timer running.
*/
void start();
/**
* @brief Stops the timer from running (note: can still be started again later).
*/
void stop();
/**
* @brief Tells you if the timer has been in the started state for longer than runTime.
*
* @param runTime The amount of time to test if this timer has ran longer than.
*
* @return 'true' if timer has ran for longer than or equal to runTime, false otherwise.
*/
bool isDone(unsigned runTime);
/**
* @brief Resets this clock (as if it were never started).
*/
void reset();
private:
ClockStamp m_lastStart;
unsigned m_totalRunTime;
ClockStamp getCurTime();
ClockStamp getElapsedSinceLastStart();
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif //CLOCK_H
@@ -0,0 +1,33 @@
#include "IPAddress.h"
#if defined(WIN32)
#include <winsock2.h>
typedef int socklen_t;
#else // for non-windows platforms (linux)
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#endif
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
IPAddress::IPAddress(unsigned int ip)
: m_IP(ip)
{
}
char *IPAddress::GetAddress(char *buffer) const
{
struct sockaddr_in addr;
addr.sin_addr.s_addr = m_IP;
strcpy(buffer, inet_ntoa(addr.sin_addr));
return(buffer);
}
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,51 @@
#ifndef TCPIPADDRESS_H
#define TCPIPADDRESS_H
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
/**
* @brief Container object for IP Address.
*/
class IPAddress
{
public:
/**
* @brief Constructor, sets the ip address if specified.
*/
IPAddress(unsigned int ip = 0);
/**
* @brief Sets the ip address.
*/
void SetAddress(unsigned int ip){ m_IP = ip; }
/**
* @brief Returns the unsigned int representation of this address.
*/
unsigned int GetAddress() const { return m_IP; }
/**
* @brief Used to retreive the the dot-notation represenatatiion of this address.
*
* @param buffer A pointer to the buffer to place the ip address into.
* Must be at least 17 characters long, will be null terminated.
*
* @return A pointer to the buffer the address was placed into.
*/
char *GetAddress(char *buffer) const;
private:
unsigned int m_IP;
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif //TCPIPADDRESS_H
@@ -0,0 +1,94 @@
#include "TcpBlockAllocator.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
TcpBlockAllocator::TcpBlockAllocator(const unsigned initSize, const unsigned initCount)
: m_freeHead(NULL), m_blockCount(initCount), m_blockSize(initSize), m_numAvailBlocks(0)
{
realloc();
}
TcpBlockAllocator::~TcpBlockAllocator()
{
while(m_freeHead)
{
data_block *tmp = m_freeHead;
m_freeHead = m_freeHead->m_next;
delete[] tmp->m_data;
delete tmp;m_numAvailBlocks--;
}
}
data_block *TcpBlockAllocator::getBlock()
{
data_block *tmp;
if(!m_freeHead)
{
realloc();
}
tmp = m_freeHead;
m_freeHead = m_freeHead->m_next;
tmp->m_next = NULL;
m_numAvailBlocks--;
return(tmp);
}
void TcpBlockAllocator::returnBlock(data_block *b)
{
b->m_usedSize = 0;
b->m_sentSize = 0;
if (m_numAvailBlocks >= m_blockCount)
{
delete[] b->m_data;
delete b;
return;
}
b->m_next = m_freeHead;
m_freeHead = b; m_numAvailBlocks++;
}
void TcpBlockAllocator::realloc()
{
data_block *tmp = NULL, *cursor = NULL;
tmp = new data_block; m_numAvailBlocks++;
cursor = tmp;
memset(cursor, 0, sizeof(data_block));
cursor->m_data = new char[m_blockSize];
cursor->m_totalSize = m_blockSize;
for(unsigned i = 1; i < m_blockCount; i++)
{
cursor->m_next = new data_block; m_numAvailBlocks++;
cursor = cursor->m_next;
memset(cursor, 0, sizeof(data_block));
cursor->m_data = new char[m_blockSize];
cursor->m_totalSize = m_blockSize;
}
if(m_freeHead)
{
cursor->m_next = m_freeHead;
m_freeHead = tmp;
}
else
{
m_freeHead = tmp;
}
}
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,44 @@
#ifndef TCPBLOCKALLOCATOR_H
#define TCPBLOCKALLOCATOR_H
#include <string.h>
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
struct data_block
{
unsigned m_usedSize;
unsigned m_sentSize;
unsigned m_totalSize;
char *m_data;
data_block *m_next;
};
class TcpBlockAllocator
{
public:
TcpBlockAllocator(const unsigned initSize, const unsigned initCount);
~TcpBlockAllocator();
data_block *getBlock();
void returnBlock(data_block *);
private:
void realloc();
data_block *m_freeHead;
unsigned m_blockCount;
unsigned m_blockSize;
unsigned m_numAvailBlocks;
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif //TCPBLOCKALLOCATOR_H
@@ -0,0 +1,792 @@
#include "TcpConnection.h"
#include "TcpManager.h"
#include "Clock.h"
#include <errno.h>
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
//used when want to open new connection with this socket
TcpConnection::TcpConnection(TcpManager *tcpManager, TcpBlockAllocator *sendAlloc, TcpManager::TcpParams &params, const IPAddress &destIP, unsigned short destPort, unsigned timeout)
: m_nextConnection(NULL),
m_prevConnection(NULL),
m_socket(INVALID_SOCKET),
m_nextKeepAliveConnection(NULL),
m_prevKeepAliveConnection(NULL),
m_aliveListId(tcpManager->m_aliveList.m_listID),
m_nextRecvDataConnection(NULL),
m_prevRecvDataConnection(NULL),
m_recvDataListId(tcpManager->m_dataList.m_listID),
m_manager(tcpManager),
m_status(StatusNegotiating),
m_handler(NULL),
m_destIP(destIP),
m_destPort(destPort),
m_refCount(0),
m_sendAllocator(sendAlloc),
m_head(NULL),
m_tail(NULL),
m_bytesRead(0),
m_bytesNeeded(0),
m_params(params),
m_recvBuff(NULL),
m_connectTimeout(timeout),
m_connectTimer(),
m_wasConRemovedFromMgr(false),
m_connectionRefused(false)
{
//start connection timer
m_connectTimer.start();
memset(&m_addr, 0, sizeof(m_addr));
if (m_params.maxRecvMessageSize != 0)
{
m_recvBuff = new char[m_params.maxRecvMessageSize];
}
m_socket = socket(AF_INET, SOCK_STREAM, 0);
setOptions();
m_addr.sin_family = AF_INET;
m_addr.sin_port = htons(m_destPort);
m_addr.sin_addr.s_addr = m_destIP.GetAddress();
int err = connect(m_socket, (sockaddr *)&m_addr, sizeof(m_addr));
if(err == SOCKET_ERROR)
{
#ifdef WIN32
int sockerr = WSAGetLastError();
if(sockerr != WSAEWOULDBLOCK)
{
//a real error
m_status = StatusDisconnected;
}
else
{
m_status = StatusNegotiating;
}
#else // UNIX
if (errno != EINPROGRESS)
{
m_status = StatusDisconnected;
}
else
{
m_status = StatusNegotiating;
}
#endif
}
else
{
//we are connected, wow
m_status = StatusConnected;
}
}
//used when server mode creates new connection object representing a connect request
TcpConnection::TcpConnection(TcpManager *tcpManager, TcpBlockAllocator *sendAlloc, TcpManager::TcpParams &params, SOCKET socket, const IPAddress &destIP, unsigned short destPort)
: m_nextConnection(NULL),
m_prevConnection(NULL),
m_socket(socket),
m_nextKeepAliveConnection(NULL),
m_prevKeepAliveConnection(NULL),
m_aliveListId(tcpManager->m_aliveList.m_listID),
m_nextRecvDataConnection(NULL),
m_prevRecvDataConnection(NULL),
m_recvDataListId(tcpManager->m_dataList.m_listID),
m_manager(tcpManager),
m_status(StatusConnected),
m_handler(NULL),
m_destIP(destIP),
m_destPort(destPort),
m_refCount(0),
m_sendAllocator(sendAlloc),
m_head(NULL),
m_tail(NULL),
m_bytesRead(0),
m_bytesNeeded(0),
m_params(params),
m_recvBuff(NULL),
m_connectTimeout(0),
m_connectTimer(),
m_wasConRemovedFromMgr(false)
{
memset(&m_addr, 0, sizeof(m_addr));
if (m_params.maxRecvMessageSize != 0)
{
m_recvBuff = new char[m_params.maxRecvMessageSize];
}
setOptions();
}
void TcpConnection::setOptions()
{
if (m_socket != INVALID_SOCKET)
{
#if defined(WIN32)
unsigned long isNonBlocking = 1;
int outBufSize = m_params.outgoingBufferSize;
int inBufSize = m_params.incomingBufferSize;
int keepAlive = 1;
int reuseAddr = 1;
struct linger ld;
ld.l_onoff = 0;
ld.l_linger = 0;
if (ioctlsocket(m_socket, FIONBIO, &isNonBlocking) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, (char *)&outBufSize, sizeof(outBufSize)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char *)&inBufSize, sizeof(inBufSize)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepAlive, sizeof(keepAlive)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseAddr, sizeof(reuseAddr)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_LINGER, (char *)&ld, sizeof(ld)) != 0 )
{
//bummer, but no need to crash now.... ?
}
#else // linux is to remain the default compile mode
unsigned long isNonBlocking = 1;
unsigned long keepAlive = 1;
unsigned long outBufSize = m_params.outgoingBufferSize;
unsigned long inBufSize = m_params.incomingBufferSize;
unsigned long reuseAddr = 1;
struct linger ld;
ld.l_onoff = 0;
ld.l_linger = 0;
if (ioctl(m_socket, FIONBIO, &isNonBlocking) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, &outBufSize, sizeof(outBufSize)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, &inBufSize, sizeof(inBufSize)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(keepAlive)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_LINGER, &ld, sizeof(ld)) != 0)
{
//bummer, but no need to crash now.... ?
}
#endif
}
}
int TcpConnection::finishConnect()
{
AddRef();
int returnVal = 0;
m_connectionRefused = false;
/**< returns < 0 if fatal error and connect will not work, =0 if need more time, >0 if connect completed */
switch (m_status)
{
case StatusDisconnected:
{
//something went wrong
Disconnect(false);
returnVal = -1;
}
break;
case StatusNegotiating:
{
#ifdef WIN32
//try to finish connection
fd_set wrSet;
FD_ZERO(&wrSet);
FD_SET(m_socket, &wrSet);
timeval t;
t.tv_sec = 0;
t.tv_usec = 0;
int err = select(m_socket + 1, NULL, &wrSet, NULL, &t);
if (err == 0)
{
//needs more time
returnVal = 0;
}
else if (err == SOCKET_ERROR)
{
//huhoh, let's hope it needs more time
int sockerr = WSAGetLastError();
if (sockerr == WSAEINPROGRESS
|| sockerr == WSAEWOULDBLOCK
|| sockerr == WSAEALREADY
|| sockerr == WSAEINVAL)
{
//yep
returnVal = 0;
}
else
{
Disconnect(false);
returnVal = -1;
}
}
else
{
//check if write bit set for socket
if (FD_ISSET(m_socket, &wrSet))
{
//connection complete
m_status = StatusConnected;
returnVal = 1;
}
else
{
//give it more time??
returnVal = 0;
}
}
#else // not WIN32
int err = connect(m_socket, (sockaddr *)&m_addr, sizeof(m_addr));
if(err == SOCKET_ERROR)
{
m_connectionRefused = (errno == ECONNREFUSED);
if (errno != EINPROGRESS && errno != EALREADY)
{
/* if (errno == ECONNREFUSED) */ Disconnect(true);
/* else Disconnect(false); -- Don't do this here; bad! */
returnVal = -1;//failure
}
else
{
returnVal = 0;//need to wait
}
}
else
{
m_status = StatusConnected;
returnVal = 1;//connect success
}
#endif
}
break;
case StatusConnected:
{
//wierd, shouldn't be trying to do this here
Disconnect(true);
returnVal = -1;
}
break;
}
if (returnVal == 0 && m_connectTimeout != 0 && m_connectTimer.isDone(m_connectTimeout))
{
Disconnect(true);
returnVal = -1;
}
else if (returnVal ==1/* && m_connectTimeout != 0*/)
{
//need to give, onConnect callback
if (m_handler)
m_handler->OnConnectRequest(this);
}
Release();
return returnVal;
}
TcpConnection::~TcpConnection()
{
if (m_recvBuff != NULL)
{
delete [] m_recvBuff;
}
while(m_head != NULL)
{
data_block *tmp = m_head;
m_head = m_head->m_next;
m_sendAllocator->returnBlock(tmp);
}
//TODO: need to notify app if are currently connected
}
void TcpConnection::Send(const char *data, unsigned int dataLen)
{
//add msg to buf
int totalLen = dataLen + sizeof(int);
if(m_status == StatusDisconnected)
{
return;
}
if (m_params.keepAliveDelay > 0 && m_aliveListId == m_manager->m_aliveList.m_listID)
{
m_aliveListId = m_manager->m_keepAliveList.m_listID;
if (m_prevKeepAliveConnection != NULL)
m_prevKeepAliveConnection->m_nextKeepAliveConnection = m_nextKeepAliveConnection;
if (m_nextKeepAliveConnection != NULL)
m_nextKeepAliveConnection->m_prevKeepAliveConnection = m_prevKeepAliveConnection;
if (m_manager->m_keepAliveList.m_beginList == this)
m_manager->m_keepAliveList.m_beginList = m_nextKeepAliveConnection;
m_nextKeepAliveConnection = m_manager->m_aliveList.m_beginList;
m_prevKeepAliveConnection = NULL;
if (m_manager->m_aliveList.m_beginList != NULL)
m_manager->m_aliveList.m_beginList->m_prevKeepAliveConnection = this;
m_manager->m_aliveList.m_beginList = this;
}
data_block *work = NULL;
// this connection has no send buffer. Get a block
if(!m_tail)
{
m_head = m_sendAllocator->getBlock();
m_tail = m_head;
}
work = m_tail;
//send message len first
unsigned nLen = htonl(totalLen);
unsigned lenLength = sizeof(int);
unsigned lenIndex = 0;
while(lenIndex < lenLength)
{
if ((lenLength - lenIndex) <= (work->m_totalSize - work->m_usedSize))
{
//size will fit in this block
memcpy(work->m_data + work->m_usedSize, (char *)(&nLen) + lenIndex, lenLength - lenIndex);
work->m_usedSize += (lenLength - lenIndex);
lenIndex += (lenLength - lenIndex);
}
else
{
//size will not fit in this block
memcpy(work->m_data + work->m_usedSize, (char *)(&nLen) + lenIndex, work->m_totalSize - work->m_usedSize);
lenIndex += work->m_totalSize - work->m_usedSize;
work->m_usedSize += work->m_totalSize - work->m_usedSize;
work->m_next = m_sendAllocator->getBlock();
work = work->m_next;
m_tail = work;
}
}
//now send message payload
unsigned messageIndex = 0;
while(messageIndex < dataLen)
{
if((dataLen - messageIndex) <= (work->m_totalSize - work->m_usedSize))
{
// data will fit in this block
memcpy(work->m_data + work->m_usedSize, data + messageIndex, (dataLen - messageIndex));
work->m_usedSize += (dataLen - messageIndex);
messageIndex += (dataLen - messageIndex);
}
else
{
// data will not fit in this block. Fill this block and get another block
memcpy(work->m_data + work->m_usedSize, data + messageIndex, work->m_totalSize - work->m_usedSize);
messageIndex += work->m_totalSize - work->m_usedSize;
work->m_usedSize += work->m_totalSize - work->m_usedSize;
work->m_next = m_sendAllocator->getBlock();
work = work->m_next;
m_tail = work;
}
}
return;
}
void TcpConnection::Disconnect(bool notifyApplication)
{
AddRef();
m_status = StatusDisconnected;
if (!m_wasConRemovedFromMgr)
{
m_manager->removeConnection(this);
m_wasConRemovedFromMgr = true;
}
if(m_socket != INVALID_SOCKET)
{
#if defined(WIN32)
closesocket(m_socket);
#else
close(m_socket);
#endif
m_socket = INVALID_SOCKET;
}
if (notifyApplication && m_handler)
m_handler->OnTerminated(this);
Release();
}
void TcpConnection::AddRef()
{
m_refCount++;
}
void TcpConnection::Release()
{
if (--m_refCount == 0)
{
//make sure manager knows I'm gone
if (m_status != StatusDisconnected)
{
m_refCount = 1;
Disconnect(false);
m_refCount = 0;
}
delete this;
}
}
int TcpConnection::processIncoming()
{
/**< returns < 0 if fatal error and socket has been closed,
=0 if read anything (full or partial message),
>0 if nothing to read now, or would block so shouldn't try again immediately. */
if (m_status != StatusConnected)
{
//wait until connect succeeds
return 1;
}
if (m_params.noDataTimeout > 0 && m_recvDataListId == m_manager->m_dataList.m_listID)
{
m_recvDataListId = m_manager->m_noDataList.m_listID;
if (m_prevRecvDataConnection != NULL)
m_prevRecvDataConnection->m_nextRecvDataConnection = m_nextRecvDataConnection;
if (m_nextRecvDataConnection != NULL)
m_nextRecvDataConnection->m_prevRecvDataConnection = m_prevRecvDataConnection;
if (m_manager->m_noDataList.m_beginList == this)
m_manager->m_noDataList.m_beginList = m_nextRecvDataConnection;
m_nextRecvDataConnection = m_manager->m_dataList.m_beginList;
m_prevRecvDataConnection = NULL;
if (m_manager->m_dataList.m_beginList != NULL)
m_manager->m_dataList.m_beginList->m_prevRecvDataConnection = this;
m_manager->m_dataList.m_beginList = this;
}
int newMsg = 0;
if (m_bytesRead < sizeof(int))
{
//new msg
newMsg = 1;
//printf("socket: %d\n", m_socket);
int ret = recv(m_socket, ((char *)(&m_bytesNeeded) + m_bytesRead),
4 - m_bytesRead, 0);
//fprintf(stderr, "READ: %d\n", ret);
if (ret == 0)
{
//We did a select, so there should be data. Socket was closed.
Disconnect();
return -1;
}
else if (ret == -1)
{
if (translateRecvSocketEror())
{
//fatal error
return -1;
}
else
{
//need to wait
return 1;
}
}
else
{
m_bytesRead += ret;
if (m_bytesRead < 4)
{
return 1;//need to wait
}
else
{
m_bytesNeeded = ntohl(m_bytesNeeded);
//printf("m_bytesNeeded = %i\n", m_bytesNeeded);
if (m_bytesNeeded == sizeof(int))
{
//keepalive, ignore
m_bytesRead = 0;
m_bytesNeeded = 0;
return 0;
}
else if (m_bytesNeeded < sizeof(int))
{
//major protocol violation
Disconnect();
return -1;
}
else if (m_params.maxRecvMessageSize == 0)
{
if (m_recvBuff!=NULL)
delete [] m_recvBuff;
m_recvBuff = new char[m_bytesNeeded-4];
}
else if (m_params.maxRecvMessageSize != 0 && (m_bytesNeeded-4) > m_params.maxRecvMessageSize)
{
//error, maxRecvMeessageSize exceeded, Disconnect
Disconnect();
return -1;
}
}
}
}
int msgBytesRead = m_bytesRead - 4;
int msgBytesNeeded = m_bytesNeeded - 4;
int ret = recv(m_socket, (char *)(m_recvBuff + msgBytesRead),
msgBytesNeeded - msgBytesRead, 0);
if (ret == 0 && !newMsg)
{
//We did a select, so there should be data. Socket was closed.
Disconnect();
return -1;
}
if (ret == -1)
{
if (translateRecvSocketEror())
{
//fatal error
return -1;
}
else
{
//need to wait
return 1;
}
} else
{
m_bytesRead += ret;
}
if (m_bytesRead == m_bytesNeeded)
{
m_bytesRead = 0;
m_bytesNeeded = 0;
if (m_handler)
{
AddRef();//could get deleted during this callback
m_handler->OnRoutePacket(this, (unsigned char *)m_recvBuff, msgBytesNeeded);
if (m_status == StatusDisconnected)
{
Release();
return -1;
}
Release();
}
//entire message received
return 0;
}
else
{
return 1;//couldn't get entire msg
}
}
int TcpConnection::processOutgoing()
{
/**< returns < 0 if fatal error and socket has been closed,
=0 if sent data, call again immediately if want to,
>0 may have sent data, but calling again would do no good because there is either no more data to send, or would block. */
if (m_status != StatusConnected)
{
//wait until connect succeeds
return 0;
}
int sendError = 1;
// If m_head is not null, then this connection has something to send
if(m_head)
{
int amt = ::send(m_socket, m_head->m_data + m_head->m_sentSize, m_head->m_usedSize - m_head->m_sentSize, 0);
if(amt < 0)
{
#ifdef WIN32
switch(WSAGetLastError())
{
case WSAEWOULDBLOCK:
case WSAEINTR:
case WSAEINPROGRESS:
case WSAEALREADY:
case WSA_IO_PENDING:
case WSA_NOT_ENOUGH_MEMORY:
case WSATRY_AGAIN:
//try again
sendError = 1;
break;
default:
//assume broken, Disconnect
Disconnect();
sendError = -1;
break;
}
#else //not WIN32
// error condition, EAGAIN is recoverable, otherwise raise an error condition. Break from loop
switch(errno)
{
case EAGAIN:
//try again
sendError = 1;
break;
default:
//assume broken, Disconnect
Disconnect();
sendError = -1;
break;
}
#endif
}
else if(static_cast<unsigned>(amt) < (m_head->m_usedSize - m_head->m_sentSize))
{
// partial send: trying to do anything more now would be a waste of time. Break from loop
m_head->m_sentSize += amt;
sendError = 1;
}
else if(amt == 0)
{
Disconnect();
sendError = -1;
// client closed connection
}
else
{
// everything was sent from this block. Return it to the pool, advance m_head. Attempt to continue
// sending
data_block *tmp = m_head;
if(m_tail == m_head)
{
m_tail = m_tail->m_next;
m_head = m_head->m_next;
}
else
{
m_head = m_head->m_next;
}
m_sendAllocator->returnBlock(tmp);
sendError = 0;
}
}
return sendError;
}
bool TcpConnection::translateRecvSocketEror()
{
/**< returns false if fatal error and socket has been closed,
true if should try again. */
bool fatalError=false;
#ifdef WIN32
int lastErr = WSAGetLastError();
switch(lastErr)
{
case WSAENOBUFS:
case WSAEINPROGRESS:
case WSAEINTR:
case WSAEWOULDBLOCK:
case WSABASEERR:
fatalError=false;
break;
case WSANOTINITIALISED:
case WSAENETDOWN:
case WSAEFAULT:
case WSAENOTCONN:
case WSAENETRESET:
case WSAENOTSOCK:
case WSAEOPNOTSUPP:
case WSAESHUTDOWN:
case WSAEMSGSIZE:
case WSAEINVAL:
case WSAECONNABORTED:
case WSAETIMEDOUT:
case WSAECONNRESET:
default:
//fatal
fatalError=true;
Disconnect();
break;
}
#else //not WIN32
switch(errno)
{
case EWOULDBLOCK:
case EINTR:
case ETIMEDOUT:
case ENOBUFS:
//try later
fatalError=false;
break;
case EBADF:
case ECONNRESET:
case EFAULT:
case EINVAL:
case ENOTCONN:
case ENOTSOCK:
case EOPNOTSUPP:
case EPIPE:
case EIO:
case ENOMEM:
case ENOSR:
default:
//fatal
fatalError=true;
Disconnect();
break;
}
#endif
return fatalError;
}
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,160 @@
#ifndef TCPCONNECTION_H
#define TCPCONNECTION_H
#include "TcpHandlers.h"
#include "TcpManager.h"
#include "IPAddress.h"
#include "TcpBlockAllocator.h"
#include "Clock.h"
#if defined(WIN32)
#include <winsock2.h>
typedef int socklen_t;
#else // for non-windows platforms (linux)
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
/**
* @brief Manages a single connection.
*/
class TcpConnection
{
public:
/**
* @brief The connection status.
*/
enum Status {
StatusNegotiating, /**< Currently attempting to connect. */
StatusConnected, /**< Currently connected. */
StatusDisconnected /**< Currently disconnected. */
};
/**
* @brief Sets the handler object which will receive callback methods.
*
* To have the TcpConnection call your object directly when packets are received, and when the
* connection is disconnected, you simply need to derive your class
* (multiply if necessary) from TcpConnectionHandler, then you can use
* this method to set the object the TcpConnection will call as appropriate.
* default = NULL (no callbacks made)
*
* @param handler The object which will be called for notifications.
*/
void SetHandler(TcpConnectionHandler *handler){ m_handler = handler; }
/**
* @brief Returns the handler associated with this object.
*/
TcpConnectionHandler *GetHandler(){ return m_handler; }
/**
* @brief Returns the current status of this connection.
*/
Status GetStatus(){ return m_status; }
/**
* @brief Queues a message to be sent on this connection.
*/
void Send(const char *data, unsigned dataLen);
/**
* @brief Disconnects and recycles the socket.
*
* @param notifyApplication primarily used internally, but when set to 'true', it will cause the application
* to be called back via the onTerminated handler due to this call (the callback will not occur if the connection was
* already disconnected)
*/
void Disconnect(bool notifyApplication=true);
/**
* @brief Returns the ip on the other side of this connection.
*/
IPAddress GetDestinationIp(){ return m_destIP; }
/**
* @brief Returns the port on the other side of this conection.
*/
unsigned short GetDestinationPort(){ return m_destPort; }
/**
* @brief Standard AddRef/Release scheme
*/
void AddRef();
/**
* @brief Standard AddRef/Release scheme
*/
void Release();
bool wasRemovedFromMgr() { return m_wasConRemovedFromMgr; }
void setRemovedFromMgr() { m_wasConRemovedFromMgr = true; }
bool isConnectionRefused() const { return m_connectionRefused; }
protected:
friend class TcpManager;
TcpConnection(TcpManager *tcpManager, TcpBlockAllocator *sendAlloc, TcpManager::TcpParams &params, const IPAddress &destIP, unsigned short destPort, unsigned timeout);
int finishConnect();/**< returns < 0 if fatal error and connect will not work, =0 if need more time, >0 if connect completed */
TcpConnection(TcpManager *tcpManager, TcpBlockAllocator *sendAlloc, TcpManager::TcpParams &params, SOCKET socket, const IPAddress &destIP, unsigned short destPort);
TcpConnection *m_nextConnection; /**< Double linked list imp. */
TcpConnection *m_prevConnection; /**< Double linked list imp. */
SOCKET m_socket;
int processOutgoing();/**< returns < 0 if fatal error and socket has been closed, =0 if sent data, call again immediately if want to, >0 may have sent data, but calling again would do no good because there is either no more data to send, or would block. */
int processIncoming();/**< returns < 0 if fatal error and socket has been closed, =0 if read anything (full or partial message), >0 if nothing to read now, or would block so shouldn't try again immediately. */
TcpConnection *m_nextKeepAliveConnection; /**< Double linked list imp. */
TcpConnection *m_prevKeepAliveConnection; /**< Double linked list imp. */
int m_aliveListId;
TcpConnection *m_nextRecvDataConnection;
TcpConnection *m_prevRecvDataConnection;
int m_recvDataListId;
private:
~TcpConnection();
void setOptions();
TcpManager *m_manager;
bool translateRecvSocketEror();
Status m_status;
TcpConnectionHandler *m_handler;
IPAddress m_destIP;
unsigned short m_destPort;
unsigned m_refCount;
TcpBlockAllocator *m_sendAllocator;
data_block *m_head;
data_block *m_tail;
unsigned m_bytesRead;
unsigned m_bytesNeeded;
TcpManager::TcpParams m_params;
char *m_recvBuff;
sockaddr_in m_addr;
unsigned m_connectTimeout;
Clock m_connectTimer;
bool m_connectionRefused;
bool m_wasConRemovedFromMgr;
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif //TCPCONNECTION_H
@@ -0,0 +1,52 @@
#ifndef TCPHANDLERS_H
#define TCPHANDLERS_H
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
class TcpConnection;
/**
* @brief Interface used by TcpManager class for notification to application of connection state/etc.
*
* Note: these callbacks will only be made when during a call to TcpManager::giveTime.
*/
class TcpManagerHandler
{
public:
/**
* @brief Callback made when a new connection has been established by the manager.
*/
virtual void OnConnectRequest(TcpConnection *con)=0;
};
/**
* @brief Interface used by TcpConnection class for notification to application of connection state/etc.
*
* Note: these callbacks will only be made when during a call to TcpManager::giveTime.
*/
class TcpConnectionHandler
{
public:
/**
* @brief Callback made when a new message has been received on the specified connection.
*/
virtual void OnRoutePacket(TcpConnection *con, const unsigned char *data, int dataLen)=0;
/**
* @brief Callback made when the specified connection has closed, or been closed.
*/
virtual void OnTerminated(TcpConnection *con)=0;
virtual void OnConnectRequest(TcpConnection *con)=0;
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif //TCPHANDLERS_H
@@ -0,0 +1,435 @@
//This code is not used by anything intentionally
//The Connection class was getting mistakenly linked in
//instead of the SWG Connection class that is used for
//all of our connections. Removing the whole thing
//to prevent the issue from coming up again.
#if 0
#ifdef WIN32
#pragma warning (disable: 4786)
#endif
#include <stdio.h>
#include "TcpConnection.h"
#include "TcpListener.h"
#ifdef WIN32
#define snprintf _snprintf
#endif
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
////////////////////////////////////////////////////////////////////////////////
Listener::QueueNode::QueueNode() :
connection(0),
request(0)
{
}
Listener::QueueNode::QueueNode(Connection * con, RequestBase * req) :
connection(con),
request(req)
{
}
Listener::Listener() :
mParams(),
mTcpManager(0),
mConnections(),
mConnectionCount(0),
mClosedConnections(),
mQueuedRequests(),
mActiveRequests(),
mActiveCount(0),
mActiveMax(0),
mAcceptingNewConnections(true)
{
//printf("ctor 0x%x Listener\n",this);
}
Listener::~Listener()
{
std::set<Connection *>::iterator iterator;
for (iterator = mConnections.begin(); iterator != mConnections.end(); iterator++)
{
Connection * connection = *iterator;
delete connection;
}
mConnections.clear();
if (mTcpManager != 0)
{
mTcpManager->Release();
mTcpManager = 0;
}
//printf("dtor 0x%x Listener\n",this);
}
void Listener::RequestSleep(RequestBase * request)
{
mSleepingRequests.insert(request);
}
void Listener::RequestWake(RequestBase * request)
{
if (mSleepingRequests.erase(request))
{
QueueNode node(request->mConnection, request);
mActiveRequests.push_front(node);
}
}
void Listener::OnConnectRequest(TcpConnection * connection)
{
if (IsAcceptingNewConnections())
{
Connection * connectionObject = new Connection(*this, connection);
mConnections.insert(connectionObject);
mConnectionCount++;
OnConnectionOpened(connectionObject);
}
}
void Listener::QueueRequest(Connection * connection, RequestBase * request)
{
if (connection)
{
// normal request, internal requests have no connection
connection->NotifyQueuedRequest(request);
}
mQueuedRequests.push_back(QueueNode(connection,request));
}
bool Listener::IsIdle() const
{
return (!IsActive() && !mTcpManager && mQueuedRequests.empty() && !mActiveCount);
}
bool Listener::IsAcceptingNewConnections() const
{
return (IsActive() && mAcceptingNewConnections);
}
unsigned Listener::Process()
{
//Profile profile("Listener::Process");
////////////////////////////////////////
// handle inactive state (with UdpManager)
if (!IsActive() && mTcpManager)
{
// check all connections to see if they are idle
std::set<Connection *>::iterator iterator;
for (iterator = mConnections.begin(); iterator != mConnections.end(); iterator++)
{
Connection * connection = *iterator;
if (connection->IsConnected())
connection->Disconnect();
}
// close the UdpManager if all the connections are closed
if (!mConnectionCount)
{
mTcpManager->Release();
mTcpManager = 0;
OnShutdown();
}
}
////////////////////////////////////////
// handle active state (without UdpManager)
else if (IsActive() && !mTcpManager)
{
mParams = GetConnectionParams();
mActiveMax = GetActiveRequestMax();
mTcpManager = new TcpManager(mParams);
mTcpManager->SetHandler(this);
if (mTcpManager->BindAsServer()){
OnStartup();
}else{
OnFailedStartup();
return 0;
}
}
////////////////////////////////////////
// process the TcpManager
if (mTcpManager)
{
//Profile subProfile("TcpManager::GiveTime()");
mTcpManager->GiveTime();
}
// check all closed connections to see if they are idle
std::list<Connection *>::iterator closedIterator = mClosedConnections.begin();
while (closedIterator != mClosedConnections.end())
{
//Profile profile("Listener::Process (cleanup connection)");
std::list<Connection *>::iterator current = closedIterator++;
Connection * connection = *current;
if (!connection->GetActiveRequests() &&
!connection->GetQueuedRequests())
{
mClosedConnections.erase(current);
mConnections.erase(connection);
mConnectionCount--;
OnConnectionDestroyed(connection);
delete connection;
}
}
////////////////////////////////////////
// process request queue
while (!mQueuedRequests.empty() && (!mActiveMax || mActiveCount < mActiveMax))
{
//Profile profile("Listener::Process (activate queued request)");
QueueNode & node = mQueuedRequests.front();
if (!IsActive())
{
// If not active, discard queued request
if (node.connection)
{
// normal request, internal requests have no connection
node.connection->NotifyDiscardRequest(node.request);
}
DestroyRequest(node.request);
}
else
{
// Move request to active list
if (node.connection)
{
// normal request, internal requests have no connection
node.connection->NotifyBeginRequest(node.request);
}
mActiveRequests.push_back(node);
mActiveCount++;
}
mQueuedRequests.pop_front();
}
////////////////////////////////////////
// Process active requests
unsigned requestsProcessed = 0;
std::list<QueueNode>::iterator iterator = mActiveRequests.begin();
while (iterator != mActiveRequests.end())
{
//Profile profile("Listener::Process (process request)");
std::list<QueueNode>::iterator current = iterator++;
RequestBase * request = current->request;
Connection * connection = current->connection;
if (request->Process())
{
if (connection)
{
// normal request, internal requests have no connection
connection->NotifyEndRequest(request);
}
DestroyRequest(request);
mActiveRequests.erase(current);
mActiveCount--;
}
else if (mSleepingRequests.find(request) != mSleepingRequests.end())
{
mActiveRequests.erase(current);
}
requestsProcessed++;
}
return requestsProcessed;
}
/*
void Listener::GetStats(UdpManagerStatistics & statsStruct)
{
if (mTcpManager)
mTcpManager->GetStats(&statsStruct);
}
void Listener::ResetStats()
{
if (mTcpManager)
mTcpManager->ResetStats();
}
*/
void Listener::OnStartup()
{
}
void Listener::OnShutdown()
{
}
void Listener::OnFailedStartup()
{
}
void Listener::OnConnectionOpened(Connection * connection)
{
}
void Listener::OnConnectionClosed(Connection * connection, const char * reason)
{
}
void Listener::OnConnectionDestroyed(Connection * connection)
{
}
void Listener::OnCrcReject(Connection *connection, const unsigned char * buffer, unsigned size)
{
}
/*
void Listener::OnPacketCorrupt(Connection *con, const unsigned char *data, int dataLen, UdpCorruptionReason reason)
{
}
*/
////////////////////////////////////////////////////////////////////////////////
Connection::Connection(Listener & listener, TcpConnection * connection) :
mListener(listener),
mConnection(connection),
mHost(),
mHostIp(0),
mDisconnectReason(0),
mQueuedRequests(0),
mActiveRequests(0)
{
mConnection->AddRef();
mConnection->SetHandler(this);
char buffer[256];
char addr[32];
mHostIp = mConnection->GetDestinationIp().GetAddress();
mConnection->GetDestinationIp().GetAddress(addr);
snprintf(buffer, sizeof(buffer), "%s:%u", addr, mConnection->GetDestinationPort());
mHost = buffer;
//printf("ctor 0x%x connection\n",this);
}
Connection::~Connection()
{
Disconnect();
//printf("dtor 0x%x connection\n",this);
}
unsigned Connection::Send(const unsigned char * data, unsigned dataLen)
{
if (mConnection)
{
mConnection->Send((const char*)data, dataLen);
return dataLen;
}
return 0;
}
void Connection::Disconnect()
{
if (mConnection)
OnTerminated(mConnection);
}
bool Connection::IsConnected() const
{
return mConnection != 0;
}
const std::string & Connection::GetHost() const
{
return mHost;
}
const unsigned Connection::GetHostIP() const
{
return mHostIp;
}
unsigned Connection::GetQueuedRequests() const
{
return mQueuedRequests;
}
unsigned Connection::GetActiveRequests() const
{
return mActiveRequests;
}
void Connection::OnTerminated(TcpConnection *con)
{
mConnection->SetHandler(0);
mConnection->Disconnect();
//TcpConnection::DisconnectReason disconnectReason = mConnection->GetDisconnectReason();
mConnection->Release();
mConnection = 0;
mListener.mClosedConnections.push_back(this);
mListener.OnConnectionClosed(this, "Test"/*TcpConnection::DisconnectReasonText(disconnectReason)*/);
}
void Connection::OnRoutePacket(TcpConnection *, const unsigned char * data, int dataLen)
{
mListener.OnReceive(this, data, dataLen);
}
void Connection::OnCrcReject(TcpConnection *, const unsigned char * data, int dataLen)
{
mListener.OnCrcReject(this, data, dataLen);
}
/*
void Connection::OnPacketCorrupt(TcpConnection *, const uchar *data, int dataLen, UdpCorruptionReason reason)
{
mListener.OnPacketCorrupt(this, data, dataLen, reason);
}
*/
void Connection::NotifyQueuedRequest(RequestBase * request)
{
mQueuedRequests++;
}
void Connection::NotifyDiscardRequest(RequestBase * request)
{
mQueuedRequests--;
}
void Connection::NotifyBeginRequest(RequestBase * request)
{
mQueuedRequests--;
mActiveRequests++;
}
void Connection::NotifyEndRequest(RequestBase * request)
{
mActiveRequests--;
}
////////////////////////////////////////////////////////////////////////////////
RequestBase::RequestBase(Connection * connection, bool isInternal) :
mConnection(connection),
mProcessState(0),
mIsInternal(isInternal)
{
}
RequestBase::~RequestBase()
{
}
#ifdef EXTERNAL_DISTRO
}
#endif
#endif
@@ -0,0 +1,160 @@
//This code is not used by anything intentionally
//The Connection class was getting mistakenly linked in
//instead of the SWG Connection class that is used for
//all of our connections. Removing the whole thing
//to prevent the issue from coming up again.
#if 0
#ifndef TCP_LISTENER_H
#define TCP_LISTENER_H
#include <string>
#include <list>
#include <set>
#include "TcpManager.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
////////////////////////////////////////////////////////////////////////////////
class RequestBase;
class Connection;
class Listener : public TcpManagerHandler
{
friend class Connection;
struct QueueNode
{
QueueNode();
QueueNode(Connection * connection, RequestBase * request);
bool operator<(const QueueNode & rhs) { return request < rhs.request; }
Connection * connection;
RequestBase * request;
};
public:
Listener();
virtual ~Listener();
void QueueRequest(Connection * connection, RequestBase * request);
bool IsIdle() const;
bool IsAcceptingNewConnections() const;
unsigned Process();
void SetAcceptingNewConnections(bool value) { mAcceptingNewConnections = value; }
//void GetStats(TcpManagerStatistics & statsStruct);
//void ResetStats();
unsigned GetNumberQueuedRequests() { return (unsigned)mQueuedRequests.size(); }
void RequestSleep(RequestBase * request);
void RequestWake(RequestBase * request);
virtual bool IsActive() const = 0;
virtual unsigned GetActiveRequestMax() = 0;
virtual TcpManager::TcpParams GetConnectionParams() = 0;
virtual void OnStartup();
virtual void OnShutdown();
virtual void OnFailedStartup();
virtual void OnConnectionOpened(Connection * connection);
virtual void OnConnectionClosed(Connection * connection, const char * reason);
virtual void OnConnectionDestroyed(Connection * connection);
virtual void OnReceive(Connection * connection, const unsigned char * data, unsigned dataLen) = 0;
virtual void OnCrcReject(Connection *connection, const unsigned char * data, unsigned dataLen);
//virtual void OnPacketCorrupt(Connection *con, const unsigned char *data, int dataLen, TcpCorruptionReason reason);
virtual void DestroyRequest(RequestBase * request) = 0;
virtual void OnConnectRequest(TcpConnection *con);
protected:
TcpManager::TcpParams mParams;
TcpManager * mTcpManager;
std::set<Connection *> mConnections;
unsigned mConnectionCount;
std::list<Connection *> mClosedConnections;
std::list<QueueNode> mQueuedRequests;
std::list<QueueNode> mActiveRequests;
std::set<RequestBase *> mSleepingRequests;
unsigned mActiveCount;
unsigned mActiveMax;
bool mAcceptingNewConnections;
};
////////////////////////////////////////////////////////////////////////////////
class Connection : public TcpConnectionHandler
{
friend class Listener;
public:
Connection(Listener & listener, TcpConnection * connection);
virtual ~Connection();
unsigned Send(const unsigned char * data, unsigned dataLen);
void Disconnect();
bool IsConnected() const;
const std::string & GetHost() const;
const unsigned GetHostIP() const;
unsigned GetQueuedRequests() const;
unsigned GetActiveRequests() const;
virtual void OnTerminated(TcpConnection *con);
virtual void OnConnectRequest(TcpConnection *con) {};
virtual void OnRoutePacket(TcpConnection *con, const unsigned char *data, int dataLen);
virtual void OnCrcReject(TcpConnection *con, const unsigned char *data, int dataLen);
//virtual void OnPacketCorrupt(TcpConnection *con, const unsigned char *data, int dataLen, TcpCorruptionReason reason);
protected:
void NotifyQueuedRequest(RequestBase * request);
void NotifyDiscardRequest(RequestBase * request);
void NotifyBeginRequest(RequestBase * request);
void NotifyEndRequest(RequestBase * request);
protected:
Listener & mListener;
TcpConnection * mConnection;
std::string mHost;
unsigned mHostIp;
const char * mDisconnectReason;
unsigned mQueuedRequests;
unsigned mActiveRequests;
};
////////////////////////////////////////////////////////////////////////////////
class RequestBase
{
friend class Listener;
public:
RequestBase(Connection * connection, bool isInternal=false);
virtual ~RequestBase();
virtual bool Process() = 0;
Connection * GetConnection() const { return mConnection; }
unsigned GetState() const { return mProcessState; }
protected:
Connection * mConnection;
unsigned mProcessState;
bool mIsInternal;
};
////////////////////////////////////////////////////////////////////////////////
#ifdef EXTERNAL_DISTRO
}
#endif
#endif
#endif
@@ -0,0 +1,761 @@
#include "TcpManager.h"
#include <assert.h>
#include "IPAddress.h"
#include "TcpConnection.h"
#include <time.h>
#ifndef WIN32
#include <sys/poll.h>
#endif
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
const time_t DNS_TIMEOUT = 60 * 5;
TcpManager::TcpParams::TcpParams()
: port(0),
/*
maxConnections(1000),
incomingBufferSize(6*1024),
outgoingBufferSize(64*1024),
allocatorBlockSize(8*1024),
allocatorBlockCount(16),
maxRecvMessageSize(0),
keepAliveDelay(0),
noDataTimeout(0)
*/
maxConnections(1000),
incomingBufferSize(512*1024),
outgoingBufferSize(512*1024),
allocatorBlockSize(8*1024),
allocatorBlockCount(1024),
maxRecvMessageSize(2048*1024),
keepAliveDelay(0),
noDataTimeout(0)
{
memset(bindAddress, 0, sizeof(bindAddress));
}
TcpManager::TcpParams::TcpParams(const TcpParams &cpy)
: port(cpy.port),
maxConnections(cpy.maxConnections),
incomingBufferSize(cpy.incomingBufferSize),
outgoingBufferSize(cpy.outgoingBufferSize),
allocatorBlockSize(cpy.allocatorBlockSize),
allocatorBlockCount(cpy.allocatorBlockCount),
maxRecvMessageSize(cpy.maxRecvMessageSize),
keepAliveDelay(cpy.keepAliveDelay),
noDataTimeout(cpy.noDataTimeout)
{
memset(bindAddress, 0, sizeof(bindAddress));
strncpy(bindAddress, cpy.bindAddress, sizeof(cpy.bindAddress));
}
TcpManager::TcpManager(const TcpParams &params)
: m_handler(NULL),
m_keepAliveList(NULL, 1),
m_aliveList(NULL, 2),
m_noDataList(NULL, 1),
m_dataList(NULL, 2),
m_params(params),
m_refCount(1),
m_connectionList(NULL),
m_connectionListCount(0),
m_socket(INVALID_SOCKET),
m_boundAsServer(false),
m_allocator(params.allocatorBlockSize, params.allocatorBlockCount),
m_keepAliveTimer(),
m_noDataTimer(),
m_dnsMap()
{
if (params.keepAliveDelay > 0)
m_keepAliveTimer.start();
if (params.noDataTimeout > 0)
m_noDataTimer.start();
#if defined(WIN32)
WSADATA wsaData;
WSAStartup(MAKEWORD(1,1), &wsaData);
FD_ZERO(&m_permfds);//select only used on win32
#endif
}
TcpManager::~TcpManager()
{
#if defined(WIN32)
WSACleanup();
#endif
if (m_boundAsServer)
{
#if defined(WIN32)
closesocket(m_socket);
#else
close(m_socket);
#endif
}
while (m_connectionList != NULL)
{
TcpConnection *con = m_connectionList;
con->AddRef();
removeConnection(con);
con->Release();
}
}
bool TcpManager::BindAsServer()
{
m_socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_socket != INVALID_SOCKET)
{
#if defined(WIN32)
FD_SET(m_socket, &m_permfds);//the socket this server is listening on
unsigned long isNonBlocking = 1;
int outBufSize = m_params.outgoingBufferSize;
int inBufSize = m_params.incomingBufferSize;
int keepAlive = 1;
int reuseAddr = 1;
struct linger ld;
ld.l_onoff = 0;
ld.l_linger = 0;
if (ioctlsocket(m_socket, FIONBIO, &isNonBlocking) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, (char *)&outBufSize, sizeof(outBufSize)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, (char *)&inBufSize, sizeof(inBufSize)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepAlive, sizeof(keepAlive)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseAddr, sizeof(reuseAddr)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_LINGER, (char *)&ld, sizeof(ld)) != 0 )
{
return false;
}
#else // linux is to remain the default compile mode
unsigned long isNonBlocking = 1;
unsigned long keepAlive = 1;
unsigned long outBufSize = m_params.outgoingBufferSize;
unsigned long inBufSize = m_params.incomingBufferSize;
unsigned long reuseAddr = 1;
struct linger ld;
ld.l_onoff = 0;
ld.l_linger = 0;
if (ioctl(m_socket, FIONBIO, &isNonBlocking) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, &outBufSize, sizeof(outBufSize)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, &inBufSize, sizeof(inBufSize)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(keepAlive)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)) != 0
|| setsockopt(m_socket, SOL_SOCKET, SO_LINGER, &ld, sizeof(ld)) != 0)
{
return false;
}
#endif
}
else
{
return false;
}
struct sockaddr_in addr_loc;
addr_loc.sin_family = AF_INET;
addr_loc.sin_port = htons(m_params.port);
addr_loc.sin_addr.s_addr = htonl(INADDR_ANY);
if (m_params.bindAddress[0] != 0)
{
unsigned long address = inet_addr(m_params.bindAddress);
if (address == INADDR_NONE)
{
struct hostent * lphp;
lphp = gethostbyname(m_params.bindAddress);
if (lphp != NULL)
addr_loc.sin_addr.s_addr = ((struct in_addr *)(lphp->h_addr))->s_addr;
}
else
{
addr_loc.sin_addr.s_addr = address;
}
}
if (bind(m_socket, (struct sockaddr *)&addr_loc, sizeof(addr_loc)) != 0)
{
return false;
}
if (listen(m_socket, 1000) != 0)
{
return false;
}
m_boundAsServer = true;
return true;
}
TcpConnection *TcpManager::acceptClient()
{
TcpConnection *newConn = NULL;
if (m_boundAsServer && m_connectionListCount < m_params.maxConnections)
{
sockaddr_in addr;
int addrLength = sizeof(addr);
SOCKET sock = ::accept(m_socket, (sockaddr *) &addr, (socklen_t *) &addrLength);
if (sock != INVALID_SOCKET)
{
newConn = new TcpConnection(this, &m_allocator, m_params, sock, IPAddress(addr.sin_addr.s_addr), ntohs(addr.sin_port));
addNewConnection(newConn);
if (m_handler != NULL)
{
m_handler->OnConnectRequest(newConn);
}
}
}
return newConn;
}
void TcpManager::SetHandler(TcpManagerHandler *handler)
{
m_handler = handler;
}
SOCKET TcpManager::getMaxFD()
{
#ifdef WIN32
return 0;//this param is not used on win32 for select, only on unix
#else
SOCKET maxfd = 0;
if (m_boundAsServer)
maxfd = m_socket+1;
TcpConnection *next = NULL;
for (TcpConnection *con = m_connectionList ; con != NULL ; con = next)
{
next = con->m_nextConnection;
if (con->GetStatus() != TcpConnection::StatusDisconnected && con->m_socket > maxfd)
{
maxfd = con->m_socket + 1;
}
}
return maxfd;
#endif
}
TcpConnection *TcpManager::getConnection(SOCKET fd)
{
TcpConnection *next = NULL;
for (TcpConnection *con = m_connectionList ; con != NULL ; con = next)
{
next = con->m_nextConnection;
if (con->m_socket == fd)
{
return con;
}
}
//if get here ,couldn't find it
return NULL;
}
bool TcpManager::GiveTime(unsigned maxTimeAcceptingConnections,unsigned maxSendTimePerConnection, unsigned maxRecvTimePerConnection)
{
bool processedIncoming = false;
if (maxTimeAcceptingConnections == 0 && maxSendTimePerConnection==0 && maxRecvTimePerConnection==0)
{
//they don't want to do anything now
return processedIncoming;
}
AddRef(); //keep a reference to ourself in case we callback to the application and the application releases us.
//first process outgoing on each connection, and finish establishing connections, if params say to
if (m_connectionListCount != 0 && maxSendTimePerConnection != 0)
{
// Send output from last heartbeat
TcpConnection *next = NULL;
for (TcpConnection *con = m_connectionList ; con != NULL ; con = next)
{
con->AddRef();
if (next) next->Release();
next = con->m_nextConnection;
if (next) next->AddRef();
if(con->GetStatus() == TcpConnection::StatusConnected)
{
Clock timer;
timer.start();
while(!timer.isDone(maxSendTimePerConnection))
{
int err = con->processOutgoing();
if (err > 0)
{
//couldn't finish processing last request, don't try more
break;
}
else if (err < 0)
{
break;
}
}
con->Release();
}
else if (con->GetStatus() == TcpConnection::StatusNegotiating)
{
if (con->finishConnect() < 0)
{
con->Release();
continue;
}
con->Release();
}
else //inactive client in client list????
{
removeConnection(con);
con->Release();
continue;
}
}
}
//process incoming messages (including connect requests)
if ((
m_boundAsServer //if in server mode and want to spend time accepting clients
&& maxTimeAcceptingConnections != 0
)
||
(
m_connectionListCount != 0 //if there are connections and want to spend time receiving on them
&& maxRecvTimePerConnection != 0
)
)
{
#ifdef WIN32
SOCKET maxfd = getMaxFD(); //re-calc maxfd every time select on WIN32
//select on all fd's
struct timeval timeout;
fd_set tmpfds;
tmpfds = m_permfds;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
int cnt = select(maxfd, &tmpfds, NULL, NULL, &timeout); // blocks for timeout
if (cnt > 0)
{
if (m_boundAsServer && maxTimeAcceptingConnections != 0)
{//activity on our socket means connect requests
//see if are new incoming clients
if (FD_ISSET(m_socket, &tmpfds))
{
//yep
Clock timer;
timer.start();
while (acceptClient() && !timer.isDone(maxTimeAcceptingConnections))
{
//loop
}
}
}
//process incoming client messages
if (maxRecvTimePerConnection != 0)
{
TcpConnection *next = NULL;
for (TcpConnection *con = m_connectionList ; con != NULL ; con = next)
{
con->AddRef();
if (next) next->Release();
next = con->m_nextConnection;
if (next) next->AddRef();
SOCKET fd = con->m_socket;
if (fd == INVALID_SOCKET)
{
//invalid socket in list?, check if is connecting, otherwise, Disconnect and discard
if (con->GetStatus() != TcpConnection::StatusNegotiating)
{
removeConnection(con);
con->Release();
continue;
}
}
if (FD_ISSET(fd, &tmpfds))
{
Clock timer;
timer.start();
while(!timer.isDone(maxRecvTimePerConnection) && con->GetStatus() == TcpConnection::StatusConnected)
{
int err = con->processIncoming();
if (err >= 0)
{
processedIncoming = true;
}
if (err > 0)
{
//couldn't finish processing last request, don't try more
break;
}
else if (err < 0)
{
break;
}
}//while(!timer...)
}//if (FD_ISSET...)
con->Release();
}//for (...)
} //maxRecvTimePerConnection != 0
}//cnt > 0
#else //on UNIX use poll
int numfds = m_connectionListCount;
int idx = 0;
if (m_boundAsServer)
{
numfds++;
idx++;
}
struct pollfd pollfds[numfds];
if (m_boundAsServer)
{
pollfds[0].fd = m_socket;
pollfds[0].events |= POLLIN;
}
TcpConnection *next = NULL;
for (TcpConnection *con = m_connectionList ; con != NULL ; con = next, idx++)
{
next = con->m_nextConnection;
pollfds[idx].fd = con->m_socket;
pollfds[idx].events |= POLLIN;
pollfds[idx].events |= POLLHUP;
}
int cnt = poll(pollfds, numfds, 1);
if(cnt == SOCKET_ERROR)
{
//poll not working?
//TODO: need to notify client somehow, don't think we can assume a fatal error here
}
else if (cnt > 0)
{
for (idx = 0; idx < numfds; idx++)
{
//find corresponding TcpConnection
//TODO: optimize, seriously, this is takes linear time, every time
TcpConnection *con = getConnection(pollfds[idx].fd);
if (pollfds[idx].revents & POLLIN)
{
if (m_boundAsServer && maxTimeAcceptingConnections != 0 && pollfds[idx].fd == m_socket)
{
//new incoming clients
Clock timer;
timer.start();
while (acceptClient() && !timer.isDone(maxTimeAcceptingConnections))
{
//loop
}
continue;//don't try to readmsgs from listening fd
}
//process regular msg(s)
if (con == NULL)
{
close(pollfds[idx].fd);
continue;
}
Clock timer;
timer.start();
con->AddRef();//so it can't get deleted while we are checking it's status
while(!timer.isDone(maxRecvTimePerConnection) && con->GetStatus() == TcpConnection::StatusConnected)
{
int err = con->processIncoming();
if (err >= 0)
{
processedIncoming = true;
}
if (err > 0)
{
//couldn't finish processing last request, don't try more
break;
}
else if (err < 0)
{
break;
}
}//while(!timer....)
con->Release();
}//if(pollfds[...
else if (pollfds[idx].revents & POLLHUP)
{
if (con == NULL)
{
close(pollfds[idx].fd);
continue;
}
//Disconnect client
con->Disconnect();
}
}//for (idx=0....
}//else if (cnt > 0)
#endif
}//wanted to process incoming messages or connect requests
//now process any keepalives, if time to do that
if (m_params.keepAliveDelay > 0 && m_keepAliveTimer.isDone(m_params.keepAliveDelay))
{
TcpConnection *next = NULL;
for (TcpConnection *con = m_keepAliveList.m_beginList ; con != NULL ; con = next)
{
con->AddRef();
if (next) next->Release();
next = con->m_nextKeepAliveConnection;
if (next) next->AddRef();
con->Send(NULL, 0); //note: this request will move the connection from the keepAliveList to the aliveList
con->Release();
}
//now move the complete alive list over to the keepalive list to reset those timers
m_keepAliveList.m_beginList = m_aliveList.m_beginList;
m_aliveList.m_beginList = NULL;
//switch id's for those connections that were in the alive list last go - around
int tmpID = m_aliveList.m_listID;
m_aliveList.m_listID = m_keepAliveList.m_listID;
m_keepAliveList.m_listID = tmpID;
m_keepAliveTimer.reset();
m_keepAliveTimer.start();
}
//now process any noDataCons, if time to do that
if (m_params.noDataTimeout > 0 && m_noDataTimer.isDone(m_params.noDataTimeout))
{
TcpConnection *next = NULL;
for (TcpConnection *con = m_noDataList.m_beginList ; con != NULL ; con = next)
{
con->AddRef();
if (next) next->Release();
next = con->m_nextRecvDataConnection;
if (next) next->AddRef();
//time to disconnect this guy
con->Disconnect();
con->Release();
}
//now move the complete data list over to the nodata list to reset those timers
m_noDataList.m_beginList = m_dataList.m_beginList;
m_dataList.m_beginList = NULL;
//switch id's for those connections that were in the data list last go - around
int tmpID = m_dataList.m_listID;
m_dataList.m_listID = m_noDataList.m_listID;
m_noDataList.m_listID = tmpID;
m_noDataTimer.reset();
m_noDataTimer.start();
}
Release();
return processedIncoming;
}
TcpConnection *TcpManager::EstablishConnection(const char *serverAddress, unsigned short serverPort, unsigned timeout)
{
if (m_boundAsServer)
{
//can't open outgoing connections when in server mode
// use a different TcpManager to do that
return NULL;
}
if (m_connectionListCount >= m_params.maxConnections)
return(NULL);
// get server address
unsigned long address = inet_addr(serverAddress);
if (address == INADDR_NONE)
{
if (m_dnsMap[serverAddress].timeout >= time(NULL))
{
address = m_dnsMap[serverAddress].addr;
}
else
{
struct hostent * lphp;
lphp = gethostbyname(serverAddress);
if (lphp == NULL)
return(NULL);
address = ((struct in_addr *)(lphp->h_addr))->s_addr;
m_dnsMap[serverAddress].addr = address;
m_dnsMap[serverAddress].timeout = time(NULL)+DNS_TIMEOUT;
}
}
IPAddress destIP(address);
TcpConnection *con = new TcpConnection(this, &m_allocator, m_params, destIP, serverPort, timeout);
con->AddRef();//for the client - to conform to UdpLibrary method
addNewConnection(con);
return con;
}
void TcpManager::addNewConnection(TcpConnection *con)
{
con->AddRef();
#ifdef WIN32 //uses select
if (con->m_socket != INVALID_SOCKET)
FD_SET(con->m_socket, &m_permfds);
#endif
con->m_nextConnection = m_connectionList;
con->m_prevConnection = NULL;
if (m_connectionList != NULL)
m_connectionList->m_prevConnection = con;
m_connectionList = con;
m_connectionListCount++;
con->m_nextKeepAliveConnection = m_aliveList.m_beginList;
con->m_prevKeepAliveConnection = NULL;
if (m_aliveList.m_beginList != NULL)
m_aliveList.m_beginList->m_prevKeepAliveConnection = con;
m_aliveList.m_beginList = con;
con->m_aliveListId = m_keepAliveList.m_listID;//start it out thinking it's already in the alive list, since it is
con->m_nextRecvDataConnection = m_dataList.m_beginList;
con->m_prevRecvDataConnection = NULL;
if (m_dataList.m_beginList != NULL)
m_dataList.m_beginList->m_prevRecvDataConnection = con;
m_dataList.m_beginList = con;
con->m_recvDataListId = m_noDataList.m_listID;//start it out thinking it's already in the data list, since it is
}
void TcpManager::removeConnection(TcpConnection *con)
{
if (!con->wasRemovedFromMgr())
{
con->setRemovedFromMgr();
m_connectionListCount--;
#ifdef WIN32 //select only used on win32
if (con->m_socket != INVALID_SOCKET)
{
FD_CLR(con->m_socket, &m_permfds);
}
#endif
if (con->m_prevConnection != NULL)
con->m_prevConnection->m_nextConnection = con->m_nextConnection;
if (con->m_nextConnection != NULL)
con->m_nextConnection->m_prevConnection = con->m_prevConnection;
if (m_connectionList == con)
m_connectionList = con->m_nextConnection;
con->m_nextConnection = NULL;
con->m_prevConnection = NULL;
if (con->m_prevKeepAliveConnection != NULL)
con->m_prevKeepAliveConnection->m_nextKeepAliveConnection = con->m_nextKeepAliveConnection;
if (con->m_nextKeepAliveConnection != NULL)
con->m_nextKeepAliveConnection->m_prevKeepAliveConnection = con->m_prevKeepAliveConnection;
if (m_aliveList.m_beginList == con)
m_aliveList.m_beginList = con->m_nextKeepAliveConnection;
else if (m_keepAliveList.m_beginList == con)
m_keepAliveList.m_beginList = con->m_nextKeepAliveConnection;
con->m_nextKeepAliveConnection = NULL;
con->m_prevKeepAliveConnection = NULL;
if (con->m_prevRecvDataConnection != NULL)
con->m_prevRecvDataConnection->m_nextRecvDataConnection = con->m_nextRecvDataConnection;
if (con->m_nextRecvDataConnection != NULL)
con->m_nextRecvDataConnection->m_prevRecvDataConnection = con->m_prevRecvDataConnection;
if (m_dataList.m_beginList == con)
m_dataList.m_beginList = con->m_nextRecvDataConnection;
else if (m_noDataList.m_beginList == con)
m_noDataList.m_beginList = con->m_nextRecvDataConnection;
con->m_nextRecvDataConnection = NULL;
con->m_prevRecvDataConnection = NULL;
con->Release();
}
}
void TcpManager::AddRef()
{
m_refCount++;
}
void TcpManager::Release()
{
if (--m_refCount == 0)
delete this;
}
IPAddress TcpManager::GetLocalIp() const
{
struct sockaddr_in addr_self;
memset(&addr_self, 0, sizeof(addr_self));
socklen_t len = sizeof(addr_self);
getsockname(m_socket, (struct sockaddr *)&addr_self, &len);
return(IPAddress(addr_self.sin_addr.s_addr));
}
unsigned int TcpManager::GetLocalPort() const
{
struct sockaddr_in addr_self;
memset(&addr_self, 0, sizeof(addr_self));
socklen_t len = sizeof(addr_self);
getsockname(m_socket, (struct sockaddr *)&addr_self, &len);
return(ntohs(addr_self.sin_port));
}
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,300 @@
#ifndef TCPMANAGER_H
#define TCPMANAGER_H
#ifdef WIN32
#pragma warning (disable: 4786)
#endif
#include "TcpHandlers.h"
#include "TcpBlockAllocator.h"
#include "IPAddress.h"
#include "Clock.h"
#include <map>
#include <string>
#if defined(WIN32)
#include <winsock2.h>
typedef int socklen_t;
#else // for non-windows platforms (linux)
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
const int INVALID_SOCKET = 0xFFFFFFFF;
const int SOCKET_ERROR = 0xFFFFFFFF;
typedef int SOCKET;
#endif
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
class TcpConnection;
struct ConnectionList
{
ConnectionList(TcpConnection *con, int id) : m_beginList(con), m_listID(id) {}
TcpConnection *m_beginList;
int m_listID;
};
/**
* @brief The purpose of the TcpManager is to manage a set of connections that are coming in on a particular port.
*
*/
class TcpManager
{
public:
struct AddrTimeout
{
AddrTimeout() : addr(0), timeout(0) {}
long addr;
time_t timeout;
};
/** @brief Parameters for the TcpManager. */
struct TcpParams
{
/** @brief Simple constructor sets default values for members. */
TcpParams();
/** @brief Simple copy constructor. */
TcpParams(const TcpParams &cpy);
/**
* @brief Connection port number.
*
* this is the port number that this manager will use for all incoming and outgoing data. On the client side
* this is typically set to 0, which causes the manager object to randomly pick an available port. On the server
* side, this port should be set to a specific value as it will represent the port number that clients will use
* to connect to the server (ie. the listening port). It's generally a good idea to give the user on the client
* side the option of fixing this port number at a specific value as well as it is often necessary for them to
* do so in order to navigate company firewalls which may have specific port numbers open to them for this purpose.
* default = 0
*/
unsigned short port;
/**
* @ brief Server bind ip.
*
*/
char bindAddress[64];
/**
* @brief Maximum number of connections that can be established by this manager.
*
* this is the maximum number of connections that can be established by this manager, any incoming/outgoing connections
* over this limit will be refused. On the client side, this typically only needs to be set to 1, though there
* is little harm in setting this number larger.
* default = 10
*/
unsigned maxConnections;
/**
* @brief The size of the incoming socket buffer.
*
* The client will want to set this fairly small (32k or so), but the server
* will want to set this fairly large (512k)
* default = 64k
*/
unsigned incomingBufferSize;
/**
* @brief The size of the outgoing socket buffer.
*
* The client will want to set this fairly small (32k or so), but the server
* will want to set this fairly large (512k)
* default = 64k
*/
unsigned outgoingBufferSize;
/**
* @brief The block size of a single outgoing buffer memory allocator block.
*
* This param should allways be set at least as high as the maximum message size you
* expect to send (performance will suffer otherwise).
* default = 8K
*/
unsigned allocatorBlockSize;
/**
* @brief The number of block memory allocator 'blocks' created at a time.
*
* This is the number of blocks created for the buffer allocator for each
* TcpConnection opened by this manager. Since the block size should be
* the max size of an outgoing message, the recommended setting is: greater
* than the number of concurrent connections you expect to normally have open.
* default = 1024
*/
unsigned allocatorBlockCount;
/**
* @brief The maximum size that a recvd message is allowed to be.
*
* Really only here for protection, not required. If you set this, you can safeguard
* your client/server from receiving stray oversized messages. If a message on the socket
* specifies it's length at larger than this value, then the message is not read, and the connection
* is terminated. If the value is set to 0, then there is no max message size checking
* on incoming messages (this will also cary a performance hit, since every new message
* recieved will have to have a new buffer created if you don't specify a value here). Be careful
* not to set this too small, if you have messages that could exceed the value you set here
* they will be discarded, and the connection will be terminated without warning.
* default = 0
*/
unsigned maxRecvMessageSize;
unsigned keepAliveDelay;
unsigned noDataTimeout;
};
/**
* @brief
*/
TcpManager(const TcpParams &params);
/**
* @brief Use to specify a handler object to receive callbacks.
*
* To have the TcpManager call your object directly when connection requests come in, you
* simply need to derive your class (multiply if necessary) from TcpManagerHandler, then you can use
* this method to set the object the TcpManager will call as appropriate. The TcpConnection object
* also has a handler mechanism that replaces the other callback functions below, see TcpConnection::SetHandler
* default = NULL (no callbacks made)
*
* @param handler The object which will be called for manager related notifications.
*/
void SetHandler(TcpManagerHandler *handler);
/**
* @brief This function MUST be called on a regular basis in order to give the manager object time to service the socket and give time to various connection objects that may need processing time, etc.
*
* @param maxTimeAcceptingConnections The max amount of time in milliseconds to spend accepting new client connections.
* This parameter is only used if this manager has been bound as a server (bindAsServer).
* If you set this param to 0, it will not attempt to accept any new connections.
*
* @param giveConnectionsTime
* True if every connection opened on this manager is given time in this call, false if
* no connections are given time.
*
* @param maxSendTimePerConnection Max amount of time in milliseconds to spend on each client processing outgoing messages.
* A max of the specified amount of time will be spent on each and every individual connection. If you set
* this parametrer to 0, it will not process any outgoing messages on any clients. Note also that when attempting
* to establish new connections (via the EstablishConnection method), this parameter must be > 0 in order to
* complete the connection process for any connections that were still negotiating.
*
* @param maxRecvTimePerConnection Max amount of time in milliseconds to spend on each client processing incoming messages.
* A max of the specified amount of time will be spent on each and every individual connection. If you set
* this param to 0, it will not process any incoming messages on any clients.
* This is a good way to give the manager processing time for outgoing packets in situations
* where the application does not want to have to worry about processing incoming packets.
*
* @return true if any incoming packets were processed during this time slice, otherwise returns false
*/
bool GiveTime(unsigned maxTimeAcceptingConnections = 5, unsigned maxSendTimePerConnection = 5, unsigned maxRecvTimePerConnection = 5);
/**
* @brief Used to establish a connection to a server that is listening at the specified address and port.
*
* The serverAddress will do a DNS lookup as appropriate. This call will block long enough to resolve
* the DNS lookup, but then will return a TcpConnection object that will be in a StatusNegotiating
* state until the connection is actually established. The application must give the manager
* object time after calling EstablishConnection or else the negotiation process to establish the
* connection will never have time to actually occur. Typically the client establishing the connection
* will call EstablishConnection, then sit in a loop calling TcpManager::GiveTime and checking to see
* if the status of the returned TcpConnection object is changed from StatusNegotiating. This allows
* the application to look for the ESC key or timeout an attempted connection.
*
* @param serverAddress The address of the server to open a connection to.
*
* @param serverPort The port of the server to open a connection to.
*
* @param timeout How long to attempt connecting to the server (in milliseconds).
* Setting the timeout value to something greater than 0 will cause the TcpConnection object to change
* from a StatusNegotiating state to a StatusDisconnected state after the timeout has expired. It will also cause
* the connect-complete callback to be called if the connection is succesfull.
*
* @return A pointer to a TcpConnection object.
* NULL if the manager object has exceeded its maximum number of connections
* or if the serverAddress cannot be resolved to an IP address.
*/
TcpConnection *EstablishConnection(const char *serverAddress, unsigned short serverPort, unsigned timeout = 0);
/**
* @brief Binds this manager as a server which will listen for and accept incoming connections.
*
* @return 'true' if manager is able to bind succesfully, false otherwise.
*/
bool BindAsServer();
/**
* @brief Standard AddRef/Release scheme
*/
void AddRef();
/**
* @brief Standard AddRef/Release scheme
*/
void Release();
/**
* @brief Returns the ip address of this machine. If the machine is multi-homed, this value may be blank.
*/
IPAddress GetLocalIp() const;
/**
* @brief Returns the port the manager is actually using. This value will be the same as is specified in
* Params::port (or if Params::port was set to 0, this will be the dynamically assigned port number)
*/
unsigned int GetLocalPort() const;
protected:
friend class TcpConnection;
void removeConnection(TcpConnection *con);
TcpManagerHandler *m_handler;
ConnectionList m_keepAliveList;
ConnectionList m_aliveList;
ConnectionList m_noDataList;
ConnectionList m_dataList;
private:
~TcpManager();
TcpParams m_params;
int m_refCount;
TcpConnection *m_connectionList;
unsigned m_connectionListCount;
#ifdef WIN32
fd_set m_permfds; /**< Used for select on WIN32 if we are in server mode. Keeps track of all clients connected to us. */
#endif //WIN32
SOCKET m_socket;
bool m_boundAsServer;
TcpBlockAllocator m_allocator;
Clock m_keepAliveTimer;
Clock m_noDataTimer;
void addNewConnection(TcpConnection *con);
SOCKET getMaxFD();
TcpConnection *getConnection(SOCKET fd);
TcpConnection *acceptClient();
std::map<std::string, AddrTimeout> m_dnsMap;
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif //TCPMANAGER_H
@@ -0,0 +1,82 @@
#ifndef UDPHANDLER_HPP
#define UDPHANDLER_HPP
class UdpManager;
class UdpConnection;
class LogicalPacket;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
enum UdpCorruptionReason { cUdpCorruptionNone
, cUdpCorruptionMultiPacket
, cUdpCorruptionReliablePacketTooShort
, cUdpCorruptionInternalPacketTooShort
, cUdpCorruptionDecryptFailed
, cCorruptionReasonZeroLengthPacket
, cCorruptionReasonPacketShorterThanCrcBytes
};
class UdpManagerHandler
{
public:
// This function is called when a listening UdpManager receives a new connection request. If the application wishes to
// accept this connection, it is the responsibility of the application to AddRef the UdpConnection object such that it
// doesn't get destroyed upon returning from the callback. Additionally, the application should set the handler object
// for the connection. See sample code in the UdpLibrary.doc file for an example.
virtual void OnConnectRequest(UdpConnection *con);
// The following functions are called when user-supplied encryption is specified. In particular, the functions may wish
// to query the connection object for the encryption-code it is using. The encryption code is simply a randomly generated
// 32-bit value that the client and server negotiated during the connection-establishment. It can be used as a key
// of sorts for encrypting data uniquely on a per-connection basis. (see UdpConnection::GetEncryptCode())
// For the encrypt-functions, the destination buffer will be (sourceLen + userSuppliedEncryptExpansionBytes1) long,
// do not overflow it, the debug version has an assert check that ensures that you do not.
// For the decrypt-functions, the destination buffer is guaranteed to be large enough to hold what the original
// data used to be before it was encrypted.
virtual int OnUserSuppliedEncrypt(UdpConnection *con, uchar *destData, const uchar *sourceData, int sourceLen);
virtual int OnUserSuppliedDecrypt(UdpConnection *con, uchar *destData, const uchar *sourceData, int sourceLen);
virtual int OnUserSuppliedEncrypt2(UdpConnection *con, uchar *destData, const uchar *sourceData, int sourceLen);
virtual int OnUserSuppliedDecrypt2(UdpConnection *con, uchar *destData, const uchar *sourceData, int sourceLen);
};
class UdpConnectionHandler
{
public:
// This function is called whenever an application-packet is ready to be delivered to the application.
// Packets will only ever be delivered to the application during UdpManager::GiveTime calls, so the application
// has complete control of when it willing/able to receive packets.
virtual void OnRoutePacket(UdpConnection *con, const uchar *data, int dataLen) = 0;
// This function is called whenever a UdpManager::EstablishConnection call succeeds in establishing the connection.
// Generally on client-side establishment of a connection, I prefer to sit in a tight loop polling the connection
// to see if it has connected yet or not, rather than using this callback (see sample code)
// note: If it is unable to establish the connection, the OnTerminated callback will be called.
// note: this is a change from previous behavior, see release notes for details.
virtual void OnConnectComplete(UdpConnection *con);
// This function is called anytime the UdpConnection object changes to a cStatusDisconnected state. Every UdpConnection
// object is guaranteed to eventually call this once and only once, even connections that never successfully established.
// note: this is a change from previous behavior, see release notes for details
virtual void OnTerminated(UdpConnection *con);
// This function is called anytime an incoming packet fails the CRC check. Normally these packets are just ignored, as
// corruption does occur from time to time; however, some applications may wish to log these events as often times, they
// are an indication of somebody attempting to hack the data stream.
virtual void OnCrcReject(UdpConnection *con, const uchar *data, int dataLen);
// This function is called anytime a corrupt packet is sensed for some reason.
// The reason we give a callback for it is because you may wish to log it as it could be an early indicator of
// somebody trying to hack the protocol.
virtual void OnPacketCorrupt(UdpConnection *con, const uchar *data, int dataLen, UdpCorruptionReason reason);
};
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,394 @@
//This code is not used by anything intentionally
//The Connection class was getting mistakenly linked in
//instead of the SWG Connection class that is used for
//all of our connections. Removing the whole thing
//to prevent the issue from coming up again.
#if 0
#ifdef WIN32
#pragma warning (disable: 4786)
#endif
#include "Base/timer.h"
#include "UdpListener.h"
#include "Base/profile.h"
#ifdef WIN32
#define snprintf _snprintf
#endif
namespace UdpLibrary
{
////////////////////////////////////////////////////////////////////////////////
Listener::QueueNode::QueueNode() :
connection(0),
request(0)
{
}
Listener::QueueNode::QueueNode(Connection * con, RequestBase * req) :
connection(con),
request(req)
{
}
Listener::Listener() :
mParams(),
mUdpManager(0),
mConnections(),
mConnectionCount(0),
mClosedConnections(),
mQueuedRequests(),
mActiveRequests(),
mActiveCount(0),
mActiveMax(0)
{
//printf("ctor 0x%x Listener\n",this);
}
Listener::~Listener()
{
std::set<Connection *>::iterator iterator;
for (iterator = mConnections.begin(); iterator != mConnections.end(); iterator++)
{
Connection * connection = *iterator;
delete connection;
}
mConnections.clear();
if (mUdpManager != 0)
{
mUdpManager->Release();
mUdpManager = 0;
}
//printf("dtor 0x%x Listener\n",this);
}
void Listener::RequestSleep(RequestBase * request)
{
mSleepingRequests.insert(request);
}
void Listener::RequestWake(RequestBase * request)
{
if (mSleepingRequests.erase(request))
{
QueueNode node(request->mConnection, request);
mActiveRequests.push_front(node);
}
}
void Listener::OnConnectRequest(UdpConnection * connection)
{
if (IsActive())
{
Connection * connectionObject = new Connection(*this, connection);
mConnections.insert(connectionObject);
mConnectionCount++;
OnConnectionOpened(connectionObject);
}
}
void Listener::QueueRequest(Connection * connection, RequestBase * request)
{
connection->NotifyQueuedRequest(request);
mQueuedRequests.push_back(QueueNode(connection,request));
}
bool Listener::IsIdle() const
{
return (!IsActive() && !mUdpManager && mQueuedRequests.empty() && !mActiveCount);
}
unsigned Listener::Process()
{
Profile profile("Listener::Process");
////////////////////////////////////////
// handle inactive state (with UdpManager)
if (!IsActive() && mUdpManager)
{
// check all connections to see if they are idle
std::set<Connection *>::iterator iterator;
for (iterator = mConnections.begin(); iterator != mConnections.end(); iterator++)
{
Connection * connection = *iterator;
if (connection->IsConnected())
connection->Disconnect();
}
// close the UdpManager if all the connections are closed
if (!mConnectionCount)
{
mUdpManager->Release();
mUdpManager = 0;
OnShutdown();
}
}
////////////////////////////////////////
// handle active state (without UdpManager)
else if (IsActive() && !mUdpManager)
{
mParams = GetConnectionParams();
mParams.handler = this;
mActiveMax = GetActiveRequestMax();
mUdpManager = new UdpManager(&mParams);
OnStartup();
}
////////////////////////////////////////
// process the UdpManager
if (mUdpManager)
{
Profile subProfile("UdpManager::GiveTime()");
mUdpManager->GiveTime();
}
// check all closed connections to see if they are idle
std::list<Connection *>::iterator closedIterator = mClosedConnections.begin();
while (closedIterator != mClosedConnections.end())
{
Profile profile("Listener::Process (cleanup connection)");
std::list<Connection *>::iterator current = closedIterator++;
Connection * connection = *current;
if (!connection->GetActiveRequests() &&
!connection->GetQueuedRequests())
{
mClosedConnections.erase(current);
mConnections.erase(connection);
mConnectionCount--;
OnConnectionDestroyed(connection);
delete connection;
}
}
////////////////////////////////////////
// process request queue
while (!mQueuedRequests.empty() && (!mActiveMax || mActiveCount < mActiveMax))
{
Profile profile("Listener::Process (activate queued request)");
QueueNode & node = mQueuedRequests.front();
if (!IsActive())
{
// If not active, discard queued request
node.connection->NotifyDiscardRequest(node.request);
DestroyRequest(node.request);
}
else
{
// Move request to active list
node.connection->NotifyBeginRequest(node.request);
mActiveRequests.push_back(node);
mActiveCount++;
}
mQueuedRequests.pop_front();
}
////////////////////////////////////////
// Process active requests
unsigned requestsProcessed = 0;
std::list<QueueNode>::iterator iterator = mActiveRequests.begin();
while (iterator != mActiveRequests.end())
{
Profile profile("Listener::Process (process request)");
std::list<QueueNode>::iterator current = iterator++;
RequestBase * request = current->request;
Connection * connection = current->connection;
if (request->Process())
{
connection->NotifyEndRequest(request);
DestroyRequest(request);
mActiveRequests.erase(current);
mActiveCount--;
}
else if (mSleepingRequests.find(request) != mSleepingRequests.end())
{
mActiveRequests.erase(current);
}
requestsProcessed++;
}
return requestsProcessed;
}
void Listener::GetStats(UdpManagerStatistics & statsStruct)
{
if (mUdpManager)
mUdpManager->GetStats(&statsStruct);
}
void Listener::ResetStats()
{
if (mUdpManager)
mUdpManager->ResetStats();
}
void Listener::OnStartup()
{
}
void Listener::OnShutdown()
{
}
void Listener::OnConnectionOpened(Connection * connection)
{
}
void Listener::OnConnectionClosed(Connection * connection, const char * reason)
{
}
void Listener::OnConnectionDestroyed(Connection * connection)
{
}
void Listener::OnCrcReject(Connection *connection, const unsigned char * buffer, unsigned size)
{
}
void Listener::OnPacketCorrupt(Connection *con, const unsigned char *data, int dataLen, UdpCorruptionReason reason)
{
}
////////////////////////////////////////////////////////////////////////////////
Connection::Connection(Listener & listener, UdpConnection * connection) :
mListener(listener),
mConnection(connection),
mHost(),
mHostIp(0),
mDisconnectReason(0),
mQueuedRequests(0),
mActiveRequests(0)
{
mConnection->AddRef();
mConnection->SetHandler(this);
char buffer[256];
char addr[32];
mHostIp = mConnection->GetDestinationIp().GetAddress();
mConnection->GetDestinationIp().GetAddress(addr);
snprintf(buffer, sizeof(buffer), "%s:%u", addr, mConnection->GetDestinationPort());
mHost = buffer;
//printf("ctor 0x%x connection\n",this);
}
Connection::~Connection()
{
Disconnect();
//printf("dtor 0x%x connection\n",this);
}
unsigned Connection::Send(const unsigned char * data, unsigned dataLen)
{
if (mConnection)
{
mConnection->Send(cUdpChannelReliable1, data, dataLen);
return dataLen;
}
return 0;
}
void Connection::Disconnect()
{
if (mConnection)
OnTerminated(mConnection);
}
bool Connection::IsConnected() const
{
return mConnection != 0;
}
const std::string & Connection::GetHost() const
{
return mHost;
}
const unsigned Connection::GetHostIP() const
{
return mHostIp;
}
unsigned Connection::GetQueuedRequests() const
{
return mQueuedRequests;
}
unsigned Connection::GetActiveRequests() const
{
return mActiveRequests;
}
void Connection::OnTerminated(UdpConnection *con)
{
mConnection->SetHandler(0);
mConnection->Disconnect();
UdpConnection::DisconnectReason disconnectReason = mConnection->GetDisconnectReason();
mConnection->Release();
mConnection = 0;
mListener.mClosedConnections.push_back(this);
mListener.OnConnectionClosed(this, UdpConnection::DisconnectReasonText(disconnectReason));
}
void Connection::OnRoutePacket(UdpConnection *, const unsigned char * data, int dataLen)
{
mListener.OnReceive(this, data, dataLen);
}
void Connection::OnCrcReject(UdpConnection *, const unsigned char * data, int dataLen)
{
mListener.OnCrcReject(this, data, dataLen);
}
void Connection::OnPacketCorrupt(UdpConnection *, const uchar *data, int dataLen, UdpCorruptionReason reason)
{
mListener.OnPacketCorrupt(this, data, dataLen, reason);
}
void Connection::NotifyQueuedRequest(RequestBase * request)
{
mQueuedRequests++;
}
void Connection::NotifyDiscardRequest(RequestBase * request)
{
mQueuedRequests--;
}
void Connection::NotifyBeginRequest(RequestBase * request)
{
mQueuedRequests--;
mActiveRequests++;
}
void Connection::NotifyEndRequest(RequestBase * request)
{
mActiveRequests--;
}
////////////////////////////////////////////////////////////////////////////////
RequestBase::RequestBase(Connection * connection) :
mConnection(connection),
mProcessState(0)
{
}
RequestBase::~RequestBase()
{
}
}
#endif
@@ -0,0 +1,145 @@
//This code is not used by anything intentionally
//The Connection class was getting mistakenly linked in
//instead of the SWG Connection class that is used for
//all of our connections. Removing the whole thing
//to prevent the issue from coming up again.
#if 0
#ifndef COMMON_SERVER__LISTENER_H
#define COMMON_SERVER__LISTENER_H
#include <string>
#include <list>
#include <set>
#include "UdpLibrary.hpp"
namespace UdpLibrary
{
////////////////////////////////////////////////////////////////////////////////
class RequestBase;
class Connection;
class Listener : public UdpManagerHandler
{
friend class Connection;
struct QueueNode
{
QueueNode();
QueueNode(Connection * connection, RequestBase * request);
bool operator<(const QueueNode & rhs) { return request < rhs.request; }
Connection * connection;
RequestBase * request;
};
public:
Listener();
virtual ~Listener();
void QueueRequest(Connection * connection, RequestBase * request);
bool IsIdle() const;
unsigned Process();
void GetStats(UdpManagerStatistics & statsStruct);
void ResetStats();
void RequestSleep(RequestBase * request);
void RequestWake(RequestBase * request);
virtual bool IsActive() const = 0;
virtual unsigned GetActiveRequestMax() = 0;
virtual UdpManager::Params GetConnectionParams() = 0;
virtual void OnStartup();
virtual void OnShutdown();
virtual void OnConnectionOpened(Connection * connection);
virtual void OnConnectionClosed(Connection * connection, const char * reason);
virtual void OnConnectionDestroyed(Connection * connection);
virtual void OnReceive(Connection * connection, const unsigned char * data, unsigned dataLen) = 0;
virtual void OnCrcReject(Connection *connection, const unsigned char * data, unsigned dataLen);
virtual void OnPacketCorrupt(Connection *con, const unsigned char *data, int dataLen, UdpCorruptionReason reason);
virtual void DestroyRequest(RequestBase * request) = 0;
virtual void OnConnectRequest(UdpConnection *con);
protected:
UdpManager::Params mParams;
UdpManager * mUdpManager;
std::set<Connection *> mConnections;
unsigned mConnectionCount;
std::list<Connection *> mClosedConnections;
std::list<QueueNode> mQueuedRequests;
std::list<QueueNode> mActiveRequests;
std::set<RequestBase *> mSleepingRequests;
unsigned mActiveCount;
unsigned mActiveMax;
};
////////////////////////////////////////////////////////////////////////////////
class Connection : public UdpConnectionHandler
{
friend class Listener;
public:
Connection(Listener & listener, UdpConnection * connection);
virtual ~Connection();
unsigned Send(const uchar * data, unsigned dataLen);
void Disconnect();
bool IsConnected() const;
const std::string & GetHost() const;
const unsigned GetHostIP() const;
unsigned GetQueuedRequests() const;
unsigned GetActiveRequests() const;
virtual void OnTerminated(UdpConnection *con);
virtual void OnRoutePacket(UdpConnection *con, const uchar *data, int dataLen);
virtual void OnCrcReject(UdpConnection *con, const uchar *data, int dataLen);
virtual void OnPacketCorrupt(UdpConnection *con, const uchar *data, int dataLen, UdpCorruptionReason reason);
protected:
void NotifyQueuedRequest(RequestBase * request);
void NotifyDiscardRequest(RequestBase * request);
void NotifyBeginRequest(RequestBase * request);
void NotifyEndRequest(RequestBase * request);
protected:
Listener & mListener;
UdpConnection * mConnection;
std::string mHost;
unsigned mHostIp;
const char * mDisconnectReason;
unsigned mQueuedRequests;
unsigned mActiveRequests;
};
////////////////////////////////////////////////////////////////////////////////
class RequestBase
{
friend class Listener;
public:
RequestBase(Connection * connection);
virtual ~RequestBase();
virtual bool Process() = 0;
protected:
Connection * mConnection;
unsigned mProcessState;
};
////////////////////////////////////////////////////////////////////////////////
}
#endif
#endif