Added CSAssist library

This commit is contained in:
Anonymous
2014-01-21 09:18:08 -07:00
parent 697893f7d6
commit eba7ff525c
127 changed files with 46691 additions and 1 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
add_subdirectory(ChatAPI)
add_subdirectory(CSAssist)
add_subdirectory(CTServiceGameAPI)
add_subdirectory(ChatAPI)
add_subdirectory(VChatAPI)
@@ -0,0 +1,4 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/utils)
add_subdirectory(projects)
@@ -0,0 +1,2 @@
add_subdirectory(CSAssist)
@@ -0,0 +1,2 @@
add_subdirectory(CSAssistgameapi)
@@ -0,0 +1,112 @@
set(SHARED_SOURCES
CSAssistgameapi.cpp
CSAssistgameapi.h
CSAssistgameapicore.cpp
CSAssistgameapicore.h
CSAssistgameobjects.cpp
CSAssistgameobjects.h
CSAssistreceiver.cpp
CSAssistreceiver.h
packdata.cpp
packdata.h
request.cpp
request.h
response.cpp
response.h
../../../utils/Base/Archive.cpp
../../../utils/Base/Archive.h
../../../utils/Base/AutoLog.cpp
../../../utils/Base/AutoLog.h
../../../utils/Base/Base.cpp
../../../utils/Base/Base.h
../../../utils/Base/BlockAllocator.h
../../../utils/Base/Config.cpp
../../../utils/Base/Config.h
../../../utils/Base/Event.h
../../../utils/Base/Logger.cpp
../../../utils/Base/Logger.h
../../../utils/Base/MD5.cpp
../../../utils/Base/MD5.h
../../../utils/Base/Mutex.h
../../../utils/Base/Platform.h
../../../utils/Base/ScopeLock.cpp
../../../utils/Base/ScopeLock.h
../../../utils/Base/Statistics.cpp
../../../utils/Base/Statistics.h
../../../utils/Base/TemplateBlockAllocator.h
../../../utils/Base/TemplateObjectAllocator.h
../../../utils/Base/Thread.h
../../../utils/Base/Types.h
../../../utils/Base/WideString.h
../../../utils/Base/serialize.h
../../../utils/TcpLibrary/Clock.cpp
../../../utils/TcpLibrary/Clock.h
../../../utils/TcpLibrary/IPAddress.cpp
../../../utils/TcpLibrary/IPAddress.h
../../../utils/TcpLibrary/TcpBlockAllocator.cpp
../../../utils/TcpLibrary/TcpBlockAllocator.h
../../../utils/TcpLibrary/TcpConnection.cpp
../../../utils/TcpLibrary/TcpConnection.h
../../../utils/TcpLibrary/TcpHandlers.h
../../../utils/TcpLibrary/TcpManager.cpp
../../../utils/TcpLibrary/TcpManager.h
../../../utils/Unicode/FirstUnicode.cpp
../../../utils/Unicode/FirstUnicode.h
../../../utils/Unicode/Unicode.cpp
../../../utils/Unicode/Unicode.h
../../../utils/Unicode/UnicodeBlocks.cpp
../../../utils/Unicode/UnicodeBlocks.h
../../../utils/Unicode/UnicodeCharacterData.cpp
../../../utils/Unicode/UnicodeCharacterData.h
../../../utils/Unicode/UnicodeCharacterDataMap.cpp
../../../utils/Unicode/UnicodeCharacterDataMap.h
../../../utils/Unicode/UnicodeUtils.cpp
../../../utils/Unicode/UnicodeUtils.h
../../../utils/Unicode/utf8.cpp
../../../utils/Unicode/utf8.h
)
if(WIN32)
set(PLATFORM_SOURCES
../../../utils/Base/win32/Archive.h
../../../utils/Base/win32/BlockAllocator.cpp
../../../utils/Base/win32/Event.cpp
../../../utils/Base/win32/Event.h
../../../utils/Base/win32/File.cpp
../../../utils/Base/win32/File.h
../../../utils/Base/win32/Mutex.cpp
../../../utils/Base/win32/Mutex.h
../../../utils/Base/win32/Platform.cpp
../../../utils/Base/win32/Thread.cpp
../../../utils/Base/win32/Thread.h
../../../utils/Base/win32/Types.h
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../utils/Base/win32)
else()
set(PLATFORM_SOURCES
../../../utils/Base/linux/Archive.h
../../../utils/Base/linux/BlockAllocator.cpp
../../../utils/Base/linux/Event.cpp
../../../utils/Base/linux/Event.h
../../../utils/Base/linux/Mutex.cpp
../../../utils/Base/linux/Mutex.h
../../../utils/Base/linux/Platform.cpp
../../../utils/Base/linux/Thread.cpp
../../../utils/Base/linux/Thread.h
../../../utils/Base/linux/Types.h
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../../utils/Base/linux)
endif()
add_definitions(-DEXTERNAL_DISTRO -DNAMESPACE=CSAssist)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_library(CSAssist
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
@@ -0,0 +1,42 @@
// CSAssistGameAPIDll.cpp : Defines the entry point for the DLL application.
//
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <cstdio>
//#include "stdafx.h"
#include "CSAssistGameAPIDll.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// This is an example of an exported variable
//CSASSISTGAMEAPIDLL_API int nCSAssistGameAPIDll=0;
// This is an example of an exported function.
//CSASSISTGAMEAPIDLL_API int fnCSAssistGameAPIDll(void)
//{
// return 42;
//}
// This is the constructor of a class that has been exported.
// see CSAssistGameAPIDll.h for the class definition
//CCSAssistGameAPIDll::CCSAssistGameAPIDll()
//{
// return;
//}
@@ -0,0 +1,31 @@
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the CSASSISTGAMEAPIDLL_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// CSASSISTGAMEAPIDLL_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
/*
#ifdef USE_CSADLL
#ifdef CSASSISTGAMEAPIDLL_EXPORTS
#define CSASSISTGAMEAPIDLL_API __declspec(dllexport)
#else
#define CSASSISTGAMEAPIDLL_API __declspec(dllimport)
#endif
#else
#define CSASSISTGAMEAPIDLL_API
#endif
*/
#define CSASSISTGAMEAPIDLL_API __declspec(dllexport)
// This class is exported from the CSAssistGameAPIDll.dll
//class CSASSISTGAMEAPIDLL_API CCSAssistGameAPIDll {
//public:
// CCSAssistGameAPIDll(void);
// TODO: add your methods here.
//};
//extern CSASSISTGAMEAPIDLL_API int nCSAssistGameAPIDll;
//CSASSISTGAMEAPIDLL_API int fnCSAssistGameAPIDll(void);
@@ -0,0 +1,735 @@
#include "test.h"
#include "Base/Base.h"
#include "Unicode/UnicodeUtils.h"
#include "request.h"
#include <iostream>
#include <time.h>
#include <string.h>
#ifdef WIN32
#include <conio.h>
#endif
#include <queue>
//#define WARP_SPEED true // set this for BRIEF std::cout printing
#define AUTO_RUN true
using namespace std;
using namespace CSAssist;
using namespace Plat_Unicode;
apiTest *api;
int received = 0;
int submitted = 0;
unsigned packetsRx = 0;
bool ready = false;
bool createdTicket = false;
bool loginFailed = true;
unsigned firstTicketID = 0;
unsigned lastTicketID = 0;
unsigned uid = 0;
unsigned testUID = 623259672;//99709401;
unsigned track(0);
int numberFunctionsToRun(0);
bool doBug(false);
std::queue<unsigned> register_list;
Plat_Unicode::String game;
Plat_Unicode::String server;
Plat_Unicode::String character;
Plat_Unicode::String lang;
Plat_Unicode::String comment;
Plat_Unicode::String id;
Plat_Unicode::String search;
Plat_Unicode::String hierarchy = narrowToWide("test");
unsigned numberFunctions = 16;
unsigned functionCount[16];
unsigned functionID[] =
{
CSASSIST_CALL_NEWTICKETACTIVITY, // 2
CSASSIST_CALL_REGISTERCHARACTER, // 3
CSASSIST_CALL_GETISSUEHIERARCHY, // 6
CSASSIST_CALL_CREATETICKET, // 7
CSASSIST_CALL_APPENDCOMMENT, // 8
CSASSIST_CALL_GETTICKETBYID, // 9
CSASSIST_CALL_GETTICKETCOMMENTS, // 10
CSASSIST_CALL_GETTICKET, // 11
CSASSIST_CALL_MARKREAD, // 12
CSASSIST_CALL_CANCELTICKET, // 13
CSASSIST_CALL_COMMENTCOUNT, // 14
CSASSIST_CALL_GETDOCUMENTLIST, // 16
CSASSIST_CALL_GETDOCUMENT, // 17
CSASSIST_CALL_GETTICKETXMLBLOCK, // 18
CSASSIST_CALL_GETKBARTICLE, // 19
CSASSIST_CALL_SEARCHKB // 20
};
char *functionName[] =
{
"CSASSIST_CALL_NEWTICKETACTIVITY", // 2
"CSASSIST_CALL_REGISTERCHARACTER", // 3
"CSASSIST_CALL_GETISSUEHIERARCHY", // 6
"CSASSIST_CALL_CREATETICKET", // 7
"CSASSIST_CALL_APPENDCOMMENT", // 8
"CSASSIST_CALL_GETTICKETBYID", // 9
"CSASSIST_CALL_GETTICKETCOMMENTS", // 10
"CSASSIST_CALL_GETTICKET", // 11
"CSASSIST_CALL_MARKREAD", // 12
"CSASSIST_CALL_CANCELTICKET", // 13
"CSASSIST_CALL_COMMENTCOUNT", // 14
"CSASSIST_CALL_GETDOCUMENTLIST", // 16
"CSASSIST_CALL_GETDOCUMENT", // 17
"CSASSIST_CALL_GETTICKETXMLBLOCK", // 18
"CSASSIST_CALL_GETKBARTICLE", // 19
"CSASSIST_CALL_SEARCHKB" // 20
};
void ResetGlobals()
{
received = 0;
submitted = 0;
packetsRx = 0;
ready = false;
createdTicket = false;
loginFailed = true;
firstTicketID = 0;
lastTicketID = 0;
uid = 0;
float max = 500.0;
//srand(time(0));
//numberFunctionsToRun = 2+(int) (max*rand()/(RAND_MAX+1.0));
numberFunctionsToRun = 2000;
}
//---------------------------------------------
apiTest::apiTest(const char *host, const unsigned port, const unsigned timeout = 0, const unsigned flags = 0)
: CSAssistGameAPI(host, port, timeout, flags)
//---------------------------------------------
{
}
//---------------------------------------------
apiTest::~apiTest()
//---------------------------------------------
{
}
//---------------------------------------------
void apiTest::OnConnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nConnect: " << result;
#endif
if (result == CSASSIST_RESULT_SUCCESS)
ready = true;
else
loginFailed = true;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnDisconnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nDisConnect: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nRegister: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnUnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nUnRegister: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnMarkTicketRead(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nMark Read: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnCancelTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nUCancel: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnGetTicketCommentsCount(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket, const unsigned count)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nComment Count: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnRequestGameLocation(const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID CSRUID)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nGame Location: " << uid;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnGetDocumentList(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIDocumentHeader *docList, const unsigned numberRead)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nDoc List: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnGetDocument(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistUnicodeChar *documentBody)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nDocument: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnGetTicketXMLBlock(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML XMLBody)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nGet XML Block: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnSearchKB(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPISearchResult *results, const unsigned numberRead)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nSearch KB: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnGetKBArticle(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML articleBody)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nGet KB Article: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnIssueHierarchyChanged(const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nHierarchy Changed";
#endif
packetsRx++;
}
//---------------------------------------------
void apiTest::OnNewTicketActivity(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NewActivityFlag, const unsigned HasTickets)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nNewActivity: " << result << " " << HasTickets;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnGetIssueHierarchy(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML hierarchyBody, const unsigned modifyDate)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nHierarchy: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnCreateTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nCreate Ticket: " << result << " "<<flush;
#endif
if (firstTicketID == 0)
firstTicketID = ticket;
if (ticket > lastTicketID)
lastTicketID = ticket;
received++;
packetsRx++;
createdTicket = true;
}
//---------------------------------------------
void apiTest::OnAppendTicketComment(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nAppend Comment: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnGetTicketByID(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicket *ticketBody)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nGet Ticket: " << result;
#endif
received++;
packetsRx++;
}
//---------------------------------------------
void apiTest::OnGetTicketComments(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketComment *comments, const unsigned numberRead)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nGet Ticket Comments: " << result;
if (comments == 0)
std::cout << "\nNo Comment data";
#endif
received++;
packetsRx += numberRead;
}
//---------------------------------------------
void apiTest::OnGetTicketByCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NumberReturned, const unsigned TotalNumber, const CSAssistGameAPITicket *tickets)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nGet Ticket: " << result;
if (tickets == 0)
std::cout << "\nNo Ticket data";
#endif
received++;
packetsRx += NumberReturned;
}
//---------------------------------------------
void apiTest::OnTicketChange(const CSAssistGameAPITicketID ticketID, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character)
//---------------------------------------------
{
#ifndef WARP_SPEED
std::cout << "\nTicket Change: " << ticketID;
#endif
packetsRx++;
}
//---------------------------------------------
void createTicket()
//---------------------------------------------
{
CSAssistGameAPITicket t;
t.setUID(testUID);
t.setGame(game.c_str());
t.setServer(server.c_str());
t.setCharacter(character.c_str());
t.setCategory(0,4000);
t.setCategory(1,4001);
t.setCategory(2,2);
t.setCategory(3,1);
if (doBug) t.setBug();
Plat_Unicode::String details = narrowToWide("Stress Test Ticket details here.");
Plat_Unicode::String location = narrowToWide("Stress Test Location");
Plat_Unicode::String xml = narrowToWide("Stress Test XML here");
t.setDetails(details.c_str());
t.setLocation(location.c_str());
track = api->requestCreateTicket(NULL, &t, NULL, t.uid);
//track = api->requestCreateTicket(NULL, &t, xml.c_str(), t.uid);
submitted++;
printf("creating ticket\n");
createdTicket = false;
if (firstTicketID ==0) // if no tickets created yet, wait for one
{
while (!createdTicket) // wait for create ticket to return, so we know ticket number we created
{
Base::sleep(50);
api->Update();
}
}
}
//---------------------------------------------
unsigned randomTicketID()
//---------------------------------------------
{
if (firstTicketID == 0)
createTicket(); // create at least one ticket first
unsigned r = firstTicketID;
if (r != lastTicketID)
r += rand() % (lastTicketID - firstTicketID);
#ifndef WARP_SPEED
printf(" (%d) ", r);
#endif
return r;
}
//-----------------------------------------------
std::string GetHostName(unsigned port)
//-----------------------------------------------
{
const short hostLen(512);
char hostName[hostLen] = {0};
char hostAndPort[hostLen+10] = {0};
std::string serverID;
#ifdef WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(1,1), &wsaData);
#endif
if (gethostname(hostName, hostLen) < 0)
{
// Bad error - the serverID must be unique between CSA servers.
// Attempt to use IP Address ?. // TODO:rlsmith
sprintf(hostName,"localhost-%u", port);
}
//#endif
std::string shortName = hostName;
unsigned dot = shortName.find_first_of(".");
if (dot != std::string::npos)
{
shortName = shortName.substr(0,dot);
}
#ifdef WIN32
_snprintf(hostAndPort, hostLen+10, "%s", shortName.c_str());
#else
snprintf(hostAndPort, hostLen+10, "%s", shortName.c_str());
#endif
return (std::string)hostAndPort;
}
//---------------------------------------------
int main(int argc, char **argv)
//---------------------------------------------
{
unsigned i = 0;
unsigned tid = 0;
// ----- validate and strip command line parameters -----
char *serverhost;
int serverport;
char *gamep;
char *gameserver;
#ifdef AUTO_RUN
ResetGlobals();
serverhost = "sdplatdev2.station.sony.com";
//serverhost = "64.37.152.161";
//serverport = 3018;
//serverhost = "64.37.153.15";
serverport = 3009;
if (argc > 1)
gamep = argv[1];
else
gamep = "PS";
if (argc> 2 && !strcmp(argv[2],"bug")) doBug=true;
std::string gs = GetHostName(numberFunctionsToRun);
gameserver = (char*)gs.c_str();
#else
if (argc < 6)
{
std::cout << "CSAssistStressTest Game Version: Syntax:\nCSAssistStressTest <hostname> <port> <number_funcs_to_run> <game> <gameserver>\n";
return 0;
}
serverhost = argv[1];
serverport = atoi(argv[2]);
numberFunctionsToRun = atoi(argv[3]);
gamep = argv[4];
gameserver = argv[5];
if (serverhost == NULL || strlen(serverhost) == 0)
{
std::cout << "Missing hostname!\n";
return 0;
}
if (serverport < 3000 || serverport > 3020)
{
std::cout << "Missing or invalid serverport!\n";
return 0;
}
if (numberFunctionsToRun <= 0)
{
std::cout << "Missing or invalid number of functions to run!\n";
return 0;
}
if (gamep == NULL || strlen(gamep) == 0)
{
std::cout << "Missing game name!\n";
return 0;
}
if (gameserver == NULL || strlen(gameserver) == 0)
{
std::cout << "Missing game server name!\n";
return 0;
}
#endif
game = narrowToWide(gamep);
server = narrowToWide(gameserver);
character = narrowToWide("Sabinia");
// ----- connect to API -----
while(1)
{
ResetGlobals();
unsigned updateDelay(100);
unsigned loginWait(500);
unsigned loginAttempts(0);
//api = new apiTest(serverhost, serverport, 60, CSASSIST_APIFLAG_ASSUME_RECONNECT); //, 0, CSASSIST_APIFLAG_ASSUME_RECONNECT);
//api->connectCSAssist(NULL, game.c_str(), server.c_str());
//while (!ready)
// api->Update();
cerr<<"numberFunctionsToRun="<< numberFunctionsToRun <<endl;
while (!ready)
{
if (loginFailed)
{
// Here we try a different set of credintials...if we have a set.
if (api) delete api;
//api = new apiTest(serverhost, serverport, 60, CSASSIST_APIFLAG_ASSUME_RECONNECT);
api = new apiTest(serverhost, serverport, 60, CSASSIST_APIFLAG_ASSUME_RECONNECT|CSASSIST_APIFLAG_NO_REDIRECT);
track = api->connectCSAssist(NULL, game.c_str(), server.c_str());
loginFailed = false;
std::cout <<"Trying to connect..."<<endl;
Base::sleep(loginWait+=500);
if (loginWait > 5000) loginWait=500;
}
if (loginAttempts++ > 30)
{
loginAttempts = 0;
loginFailed = true;
delete api;
api = NULL;
continue;
}
std::cout <<"Waiting for login: track:" << track<<" ..."<<endl;
Base::sleep(updateDelay);
api->Update();
}
for (i=0; i < numberFunctions; i++)
functionCount[i] = 0;
createTicket(); // works better if we do this before timing starts
time_t now = time(0);
srand(now);
// ----- submit random packets -----
for (i=0; i < (unsigned)numberFunctionsToRun; i++)
{
//unsigned randomFunction = 3; // to generate dummy tickets use this line
unsigned randomFunction = 3;//rand() % numberFunctions;
functionCount[randomFunction]++;
#ifndef WARP_SPEED
std::cout << " " << i << " ";
#endif
std::cout << " calling: "<<functionName[randomFunction] << ": " << functionCount[randomFunction] << endl;
track = 0;
switch (functionID[randomFunction])
{
case CSASSIST_CALL_NEWTICKETACTIVITY:
character = narrowToWide("Fippy");
if ((rand() % 10) < 5)
track = api->requestNewTicketActivity(NULL, testUID, 0);
else
track = api->requestNewTicketActivity(NULL, testUID, character.c_str());
submitted++;
break;
case CSASSIST_CALL_REGISTERCHARACTER:
uid = rand();
track = api->requestRegisterCharacter(NULL, uid, 0, 0);
register_list.push(uid);
submitted++;
break;
case CSASSIST_CALL_GETISSUEHIERARCHY:
lang = narrowToWide("en");
track = api->requestGetIssueHierarchy(NULL, hierarchy.c_str(), lang.c_str());
submitted++;
break;
case CSASSIST_CALL_CREATETICKET:
createTicket();
break;
case CSASSIST_CALL_APPENDCOMMENT:
comment = narrowToWide("Unicode comment by player.");
tid = randomTicketID();
track = api->requestAppendTicketComment(NULL, tid, testUID, character.c_str(), comment.c_str());
submitted++;
break;
case CSASSIST_CALL_GETTICKETBYID:
tid = randomTicketID();
track = api->requestGetTicketByID(NULL, tid, 1);
submitted++;
break;
case CSASSIST_CALL_GETTICKETCOMMENTS:
tid = randomTicketID();
track = api->requestGetTicketComments(NULL, tid, 0, (rand() % 100)+1, CSASSIST_OFFSET_START);
submitted++;
break;
case CSASSIST_CALL_GETTICKET:
track = api->requestGetTicketByCharacter(NULL, testUID, character.c_str(), 0, (rand() % 100)+1, 1);
submitted++;
break;
case CSASSIST_CALL_MARKREAD:
tid = randomTicketID();
track = api->requestMarkTicketRead(NULL, tid);
submitted++;
break;
case CSASSIST_CALL_CANCELTICKET:
if (firstTicketID != 0)
{
comment = narrowToWide("Ticket closed by player");
track = api->requestCancelTicket(NULL, firstTicketID, testUID, comment.c_str());
if (++firstTicketID > lastTicketID)
{
firstTicketID = 0;
lastTicketID = 0;
}
submitted++;
}
break;
case CSASSIST_CALL_COMMENTCOUNT:
tid = randomTicketID();
track = api->requestGetTicketCommentsCount(NULL, tid);
submitted++;
break;
case CSASSIST_CALL_GETDOCUMENTLIST:
// lang = narrowToWide("en");
// track = api->requestGetDocumentList(NULL, hierarchy.c_str(), lang.c_str());
// submitted++;
break;
case CSASSIST_CALL_GETDOCUMENT:
// track = api->requestGetDocument(NULL, 1);
// submitted++;
break;
case CSASSIST_CALL_GETTICKETXMLBLOCK:
tid = randomTicketID();
track = api->requestGetTicketXMLBlock(NULL, tid);
submitted++;
break;
case CSASSIST_CALL_GETKBARTICLE:
/*id = narrowToWide("soe1401");
lang = narrowToWide("en");
track = api->requestGetKBArticle(NULL, id.c_str(), lang.c_str());
submitted++;
*/break;
case CSASSIST_CALL_SEARCHKB:
/*Plat_Unicode::String searchStr = narrowToWide("video drivers");
lang = narrowToWide("en");
track = api->requestSearchKB(NULL, searchStr.c_str(), lang.c_str());
submitted++;
*/break;
}
Base::sleep(5);
//api->Update();
if (track)
std::cout << "called: "<< functionName[randomFunction] << ": " << functionCount[randomFunction] << " track:" <<track<< endl;
if (submitted - received > 50)
{
while (submitted > received)
{
Base::sleep(50);
api->Update();
}
}
}
// ----- Wait for final packet -----
cout<<"Waiting for last packet..."<<endl;
while (submitted > received) // make sure everything is complete before disconnecting
{
Base::sleep(50);
api->Update();
}
// ----- unregister any registered characters ----
while (register_list.size())
{
uid = register_list.front();
register_list.pop();
api->requestUnRegisterCharacter(NULL, uid, 0);
submitted++;
}
cout<<"Waiting for unregisters..."<<endl;
while (submitted > received) // make sure everything is complete before disconnecting
{
Base::sleep(50);
api->Update();
}
// ----- and clean up -----
time_t elapsed = time(0) - now;
if (elapsed == 0)
elapsed = 1;
cout<<"Going to disconnect now."<<endl;
api->disconnectCSAssist(NULL);
submitted++;
while (submitted > received)
{
api->Update();
}
cout<<"Going to delete API now."<<endl;
delete api;
api = NULL;
// ----- report findings -----
for (i=0; i < numberFunctions; i++)
std::cout << "\n" << functionName[i] << ": " << functionCount[i];
std::cout << "\n\nSubmitted: " << submitted << "\nReceived: " << received << "\nData Packets Rx: " << packetsRx;
std::cout << "\nElapsed time = " << elapsed << " seconds.\n" << (received / elapsed) << " req/sec.\n" << (packetsRx / elapsed) << " pkts/sec.\n";
// getchar();
} //while(1)
return(0);
}
@@ -0,0 +1,49 @@
#ifndef TEST_H
#define TEST_H
#include "CSAssistgameapi.h"
#include "CSAssistgameobjects.h"
extern "C" {
#include <stdio.h>
};
using namespace CSAssist;
//---------------------------------------------
class apiTest : public CSAssistGameAPI
//---------------------------------------------
{
public:
apiTest(const char *, const unsigned, const unsigned, const unsigned);
virtual ~apiTest();
void OnConnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnDisconnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnNewTicketActivity(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NewActivityFlag, const unsigned HasTickets);
void OnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnUnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnGetIssueHierarchy(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML hierarchyBody, const unsigned modifyDate);
void OnCreateTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket);
void OnAppendTicketComment(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket);
void OnGetTicketByID(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicket *ticketBody);
void OnGetTicketComments(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketComment *comments, const unsigned numberRead);
void OnGetTicketByCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NumberReturned, const unsigned TotalNumber, const CSAssistGameAPITicket *ticketBody);
void OnTicketChange(const CSAssistGameAPITicketID ticketID, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character);
void OnMarkTicketRead(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnCancelTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket);
void OnGetTicketCommentsCount(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket, const unsigned count);
void OnRequestGameLocation(const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID CSRUID);
void OnGetDocumentList(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIDocumentHeader *docList, const unsigned numberRead);
void OnGetDocument(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistUnicodeChar *documentBody);
void OnGetTicketXMLBlock(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML XMLBody);
void OnSearchKB(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPISearchResult *results, const unsigned numberRead);
void OnGetKBArticle(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML articleBody);
void OnIssueHierarchyChanged(const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language);
private:
};
#endif
@@ -0,0 +1,396 @@
//------------------------------------------------------------------------------
//
// CSAssistgameapi.cpp
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// Users layer for API
//
//------------------------------------------------------------------------------
#pragma warning (disable: 4786)
#include "CSAssistgameapi.h"
#include "CSAssistgameapicore.h"
namespace CSAssist
{
//---------------------------
CSAssistGameAPI::CSAssistGameAPI(const char *host, const unsigned port, const unsigned timeout, const unsigned flags)
//---------------------------
{
core = new CSAssistGameAPIcore(this, host, port, timeout, flags);
}
//---------------------------
CSAssistGameAPI::CSAssistGameAPI(const char *serverList, const unsigned timeout, const unsigned flags)
//---------------------------
{
core = new CSAssistGameAPIcore(this, serverList, timeout, flags);
}
//---------------------------
CSAssistGameAPI::~CSAssistGameAPI()
//---------------------------
{
delete core;
}
//---------------------------
void CSAssistGameAPI::Update()
//---------------------------
{
core->Update();
}
//---------------------------
const char *CSAssistGameAPI::getErrorString(const CSAssistGameAPIResult result)
//---------------------------
{
switch (result)
{
case CSASSIST_RESULT_SUCCESS: return "CSASSIST_RESULT_SUCCESS";
case CSASSIST_RESULT_TIMEOUT: return "CSASSIST_RESULT_TIMEOUT";
case CSASSIST_RESULT_FAIL: return "CSASSIST_RESULT_FAIL";
case CSASSIST_RESULT_BADPARAMS: return "CSASSIST_RESULT_BADPARAMS";
case CSASSIST_RESULT_OUTOFMEMORY: return "CSASSIST_RESULT_OUTOFMEMORY";
case CSASSIST_RESULT_NOTICKET: return "CSASSIST_RESULT_NOTICKET";
case CSASSIST_RESULT_NOCREATE_TICKET: return "CSASSIST_RESULT_NOCREATE_TICKET";
case CSASSIST_RESULT_UNKNOWN_USER: return "CSASSIST_RESULT_UNKNOWN_USER";
case CSASSIST_RESULT_NOCREATE_COMMENT: return "CSASSIST_RESULT_NOCREATE_COMMENT";
case CSASSIST_RESULT_TICKETLOCKED: return "CSASSIST_RESULT_TICKETLOCKED";
case CSASSIST_RESULT_DBERROR: return "CSASSIST_RESULT_DBERROR";
case CSASSIST_RESULT_TOOMANYOBJECTS: return "CSASSIST_RESULT_TOOMANYOBJECTS";
case CSASSIST_RESULT_INVALID_ACCOUNT: return "CSASSIST_RESULT_INVALID_ACCOUNT";
case CSASSIST_RESULT_ACCOUNT_CLOSED: return "CSASSIST_RESULT_ACCOUNT_CLOSED";
case CSASSIST_RESULT_INVALID_DOCUMENTID:return "CSASSIST_RESULT_INVALID_DOCUMENTID";
case CSASSIST_RESULT_TICKET_XMLFAILED: return "CSASSIST_RESULT_TICKET_XMLFAILED";
case CSASSIST_RESULT_ALREADY_REGISTERED:return "CSASSIST_RESULT_ALREADY_REGISTERED";
case CSASSIST_RESULT_PRIMUS_ERROR: return "CSASSIST_RESULT_PRIMUS_ERROR";
case CSASSIST_RESULT_TOOMANY_FILTERS: return "CSASSIST_RESULT_TOOMANY_FILTERS";
case CSASSIST_RESULT_ALREADY_LOGGEDIN: return "CSASSIST_RESULT_ALREADY_LOGGEDIN";
case CSASSIST_RESULT_UNKNOWN_FILTER: return "CSASSIST_RESULT_UNKNWON_FILTER";
case CSASSIST_RESULT_BAD_VERSION: return "CSASSIST_RESULT_BAD_VERSION";
case CSASSIST_RESULT_SERVER_DISCONNECT: return "CSASSIST_RESULT_SERVER_DISCONNECT";
}
return "CSASSIST_RESULT_UNKNOWN";
}
//----------------------------------------------------
//
// Override API calls here! **** ADD CODE HERE ****
//
//----------------------------------------------------
//---------------------------
void CSAssistGameAPI::setMaxPacketsPerSecond(const unsigned n)
//---------------------------
{
core->setMaxPacketsPerSecond(n);
}
//------------------------------------------------------
const char *CSAssistGameAPI::GetConnectedHost()
//------------------------------------------------------
{
return core->GetConnectedHost();
}
//------------------------------------------------------
int CSAssistGameAPI::GetConnectedPort()
//------------------------------------------------------
{
return core->GetConnectedPort();
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::connectCSAssist(const void *userData, const CSAssistUnicodeChar *GameName, const CSAssistUnicodeChar *ServerName)
//---------------------------
{
return(core->connectCSAssist(userData, GameName, ServerName));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::disconnectCSAssist(const void *userData)
//---------------------------
{
return(core->disconnectCSAssist(userData));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestNewTicketActivity(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character)
//---------------------------
{
return(core->requestNewTicketActivity(userData, uid, character));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestRegisterCharacter(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const unsigned avaconID)
//---------------------------
{
return(core->requestRegisterCharacter(userData, uid, character, avaconID));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestUnRegisterCharacter(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character)
//---------------------------
{
return(core->requestUnRegisterCharacter(userData, uid, character));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestGetIssueHierarchy(const void *userData, const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language)
//---------------------------
{
return(core->requestGetIssueHierarchy(userData, version, language));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestCreateTicket(const void *userData, const CSAssistGameAPITicket *ticketBody, const CSAssistUnicodeChar *XMLBody, const CSAssistGameAPIUID uid)
//---------------------------
{
return(core->requestCreateTicket(userData, ticketBody, XMLBody, uid));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestAppendTicketComment(const void *userData, const CSAssistGameAPITicketID ticket, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistUnicodeChar *comment)
//---------------------------
{
return(core->requestAppendTicketComment(userData, ticket, uid, character, comment));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestGetTicketByID(const void *userData, const CSAssistGameAPITicketID ticket, const unsigned FlagAsRead)
//---------------------------
{
return(core->requestGetTicketByID(userData, ticket, FlagAsRead));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestGetTicketComments(const void *userData, const CSAssistGameAPITicketID ticket, const unsigned Start, const unsigned Count, const CSAssistGameAPIOffset offset)
//---------------------------
{
return(core->requestGetTicketComments(userData, ticket, Start, Count, offset));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestGetTicketByCharacter(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar * character, const unsigned Start, const unsigned Count, const unsigned FlagAsRead)
//---------------------------
{
return(core->requestGetTicketByCharacter(userData, uid, character, Start, Count, FlagAsRead));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestMarkTicketRead(const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------
{
return(core->requestMarkTicketRead(userData, ticket));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestCancelTicket(const void *userData, const CSAssistGameAPITicketID ticket, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *comment)
//---------------------------
{
return(core->requestCancelTicket(userData, ticket, uid, comment));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestGetTicketCommentsCount(const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------
{
return(core->requestGetTicketCommentsCount(userData, ticket));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::replyGameLocation(const void *userData, const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID csruid, const CSAssistUnicodeChar *locationString)
//---------------------------
{
return(core->replyGameLocation(userData, sourceTrack, uid, character, csruid, locationString));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestGetDocumentList(const void *userData, const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language)
//---------------------------
{
return(core->requestGetDocumentList(userData, version, language));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestGetDocument(const void *userData, const unsigned id)
//---------------------------
{
return(core->requestGetDocument(userData, id));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestGetTicketXMLBlock(const void *userData, const CSAssistGameAPITicketID id)
//---------------------------
{
return(core->requestGetTicketXMLBlock(userData, id));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestGetKBArticle(const void *userData, const CSAssistUnicodeChar *id, const CSAssistUnicodeChar *language, const CSAssistGameAPIUID uid)
//---------------------------
{
return(core->requestGetKBArticle(userData, id, language, uid));
}
//---------------------------
CSAssistGameAPITrack CSAssistGameAPI::requestSearchKB(const void *userData, const CSAssistUnicodeChar *searchstring, const CSAssistUnicodeChar *language, const CSAssistGameAPIUID uid)
//---------------------------
{
return(core->requestSearchKB(userData, searchstring, language, uid));
}
//----------------------------------------------------
//
// Override API callbacks here! **** ADD CODE HERE ****
//
//----------------------------------------------------
//---------------------------
void CSAssistGameAPI::OnConnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnConnectRejectedCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnDisconnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnNewTicketActivity(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NewActivityFlag, const unsigned HasTickets)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnUnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnGetIssueHierarchy(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML hierarchyBody, const unsigned modifyDate)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnCreateTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnAppendTicketComment(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnGetTicketByID(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicket *ticketBody)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnGetTicketComments(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketComment *comments, const unsigned numberRead)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnGetTicketByCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NumberReturned, const unsigned TotalNumber, const CSAssistGameAPITicket *ticketBody)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnTicketChange(const CSAssistGameAPITicketID ticketID, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnMarkTicketRead(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnCancelTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnGetTicketCommentsCount(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket, const unsigned count)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnRequestGameLocation(const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID CSRUID)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnGetDocumentList(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIDocumentHeader *docList, const unsigned numberRead)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnGetDocument(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistUnicodeChar *documentBody)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnGetTicketXMLBlock(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML XMLBody)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnGetKBArticle(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML articleBody, const CSAssistUnicodeChar *articleTitle)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnSearchKB(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPISearchResult *results, const unsigned numberRead)
//---------------------------
{
}
//---------------------------
void CSAssistGameAPI::OnIssueHierarchyChanged(const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language, const CSAssistGameAPIHierarchyChangeType type)
//---------------------------
{
}
} // namespace CSAssist
@@ -0,0 +1,239 @@
#ifndef __CSASSISTGAMEAPI_H
#define __CSASSISTGAMEAPI_H
//------------------------------------------------------------------------------
//
// CSAssistgameapi.h
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// Main Header file for use by the API client
//
//------------------------------------------------------------------------------
#if defined(BUILD_CSADLL)
#define CSADLL_EXPORT __declspec(dllexport)
#elif defined(USE_CSADLL)
#define CSADLL_EXPORT __declspec(dllimport)
#else
#define CSADLL_EXPORT
#endif
#include "time.h"
namespace CSAssist
{
//------------------------------------------------------------------------------
// Define some API types here to identify CSAssist variables
//------------------------------------------------------------------------------
typedef unsigned CSAssistGameAPITrack; // An API tracking number
typedef unsigned CSAssistGameAPIUID; // A station UID
typedef unsigned CSAssistGameAPITicketID; // A ticket ID
typedef unsigned short CSAssistUnicodeChar; // base type for unicode strings (uint16)
typedef CSAssistUnicodeChar *CSAssistGameAPIXML;// A pointer to an XML block
//------------------------------------------------------------------------------
// Most API callbacks will return one of these result codes
// be sure to check for CSASSIST_RESULT_SUCCESS
//------------------------------------------------------------------------------
CSADLL_EXPORT enum CSAssistGameAPIResult // Result codes from all API calls
{
CSASSIST_RESULT_SUCCESS = 0, // 0 operation was successful
CSASSIST_RESULT_TIMEOUT, // 1 operation resulted in an API side timeout
CSASSIST_RESULT_FAIL, // 2 general failure
CSASSIST_RESULT_BADPARAMS, // 3 Client passed in bad parameters (strings too long etc)
CSASSIST_RESULT_OUTOFMEMORY, // 4 failed to allocate some memory somehow
CSASSIST_RESULT_NOTICKET, // 5 ticket not found, probably illegal ticket ID
CSASSIST_RESULT_NOCREATE_TICKET, // 6 failed to create ticket
CSASSIST_RESULT_UNKNOWN_USER, // 7 request cannot be made by an anonymous user (user connectCSAssist)
CSASSIST_RESULT_NOCREATE_COMMENT, // 8 failed to create ticket comment
CSASSIST_RESULT_TICKETLOCKED, // 9 ticked locked by another CSR
CSASSIST_RESULT_DBERROR, // 10 operation failed due to a database problem
CSASSIST_RESULT_TOOMANYOBJECTS, // 11 trying to obtain too many tickets/comments!
CSASSIST_RESULT_INVALID_ACCOUNT, // 12 unvalidated user, probably wrong login name and/or password
CSASSIST_RESULT_ACCOUNT_CLOSED, // 13 validated account but marked closed/banned
CSASSIST_RESULT_INVALID_DOCUMENTID, // 14 document ID requested does not exist
CSASSIST_RESULT_TICKET_XMLFAILED, // 15 failed to write XML block when creating a ticket.
// main ticket was still created, so this error *could* be ignored
CSASSIST_RESULT_ALREADY_REGISTERED, // 16 player character/UID was already registered for this game/server
// he will remain registered, but this indicates a potential application bug
CSASSIST_RESULT_PRIMUS_ERROR, // 17 Primus Knowledge Base returned an error, or malformed XML returned
CSASSIST_RESULT_TOOMANY_FILTERS, // 18 CSR cannot have any more filters
CSASSIST_RESULT_ALREADY_LOGGEDIN, // 19 CSR or game server is already connected and cannot have multiple connections
CSASSIST_RESULT_UNKNOWN_FILTER, // 20 Tried to manipulate or remove a filter that does not exist
CSASSIST_RESULT_BAD_VERSION, // 21 Incorrect API for this server, probably an old API!
CSASSIST_RESULT_SERVER_DISCONNECT // 22 The API was disconnected from the backend. Not a user requested disconnect.
};
CSADLL_EXPORT enum CSAssistGameAPIOffset // offset for First/Last type commands
{
CSASSIST_OFFSET_START = 0,
CSASSIST_OFFSET_END = 1
};
CSADLL_EXPORT enum CSAssistTicketStatus
{
TICKET_STATUS_NEWTICKET = 0,
TICKET_STATUS_UNUSED, // pad
TICKET_STATUS_WAIT_PLAYER, // waiting for response from player
TICKET_STATUS_WAIT_CSR, // waiting for response from CSR
TICKET_STATUS_PENDING_CLOSED, // CSR has closed ticket, awaiting final read by player first
TICKET_STATUS_CLOSED // closed MUST remain at 5 for DB stored procs!
};
CSADLL_EXPORT enum CSAssistBugStatus
{
BUG_STATUS_NONE = 0, // not a bug
BUG_STATUS_BUG, // A bug but not assigned another category yet
BUG_STATUS_REPEATABLE,
BUG_STATUS_UNREPEATABLE,
BUG_STATUS_PENDING,
BUG_STATUS_DUPE,
BUG_STATUS_CLOSED
};
CSADLL_EXPORT enum CSAssistGameAPICommentType
{
CSASSIST_COMMENT_NONE = 0,
CSASSIST_COMMENT_FROM_CSR,
CSASSIST_COMMENT_FROM_PLAYER
};
CSADLL_EXPORT enum CSAssistGameAPIHierarchyChangeType
{
CSASSIST_HIERARCHY_NONE = 0,
CSASSIST_HIERARCHY_ADDED,
CSASSIST_HIERARCHY_UPDATED,
CSASSIST_HIERARCHY_DELETED
};
//------------------------------------------------------------------------------
// Flags passed to the instantiation of the API
//------------------------------------------------------------------------------
static const unsigned CSASSIST_APIFLAG_ASSUME_RECONNECT = 0x001;
// If communication is lost with the server, the API may have already queued
// up many requests. This flag determines whether they will be immediately
// returned as an error to the calling application, or left on their original
// timeout, to see if a server reconnect occurs quickly.
// Set this flag to let the reconnect try to happen. Connection to the server
// may reoccur with 5 seconds which is substantially less than the usual
// timeout values of 60 secs or more.
// Default is for this flag NOT to be set. All queued requests will be
// immediately timed out.
static const unsigned CSASSIST_APIFLAG_NO_REDIRECT = 0x002;
// This flag will not make the API make one hop via a RedirectServer to connect
// to the actual CSAssist backend. If the RECONNECT flag above is set and this is not,
// the API will always try to first connect to a RedirectServer to re-connect
// to CSAssist.
// Defailt is for this flag NOT to be set. All connect requests will attempt
// to connect to a RedirectServer initially.
//------------------------------------------------------------------------------
// String lengths within objects
//------------------------------------------------------------------------------
static const unsigned CSASSIST_TICKET_LENGTH_GAME = 25;
static const unsigned CSASSIST_TICKET_LENGTH_SERVER = 50;
static const unsigned CSASSIST_TICKET_LENGTH_CHARACTER = 64;
static const unsigned CSASSIST_TICKET_LENGTH_DETAILS = 4000;
static const unsigned CSASSIST_TICKET_LENGTH_LANGUAGE = 2;
static const unsigned CSASSIST_TICKET_LENGTH_COMMENT = 4000;
static const unsigned CSASSIST_TICKET_LENGTH_NAME = 64;
static const unsigned CSASSIST_TICKET_LENGTH_LOCATION = 128;
static const short CSASSIST_NUM_CATEGORIES = 4;
static const unsigned CSASSIST_DOCUMENT_LENGTH_NAME = 25;
static const unsigned CSASSIST_DOCUMENT_LENGTH_LANGUAGE = 2;
static const unsigned CSASSIST_DOCUMENT_LENGTH_TITLE = 64;
static const unsigned CSASSIST_DOCUMENT_LENGTH_GAMESUBCODE = 50;
static const unsigned CSASSIST_KBSEARCH_LENGTH_TITLE = 255;
static const unsigned CSASSIST_KBSEARCH_LENGTH_ID = 64;
class CSAssistGameAPIcore;
class CSAssistGameAPITicket;
class CSAssistGameAPITicketComment;
class CSAssistGameAPIDocumentHeader;
class CSAssistGameAPISearchResult;
//---------------------------
class CSADLL_EXPORT CSAssistGameAPI
//---------------------------
{
public:
CSAssistGameAPI(const char *host, const unsigned port, const unsigned timeout, const unsigned flags);
CSAssistGameAPI(const char *serverList, const unsigned timeout = 0, const unsigned flags = CSASSIST_APIFLAG_ASSUME_RECONNECT);
virtual ~CSAssistGameAPI();
// **** ADD CODE HERE ****
CSAssistGameAPITrack connectCSAssist(const void *userData, const CSAssistUnicodeChar *GameName, const CSAssistUnicodeChar *ServerName);
CSAssistGameAPITrack disconnectCSAssist(const void *userData);
CSAssistGameAPITrack requestNewTicketActivity(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character);
CSAssistGameAPITrack requestRegisterCharacter(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const unsigned avaconID);
CSAssistGameAPITrack requestUnRegisterCharacter(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character);
CSAssistGameAPITrack requestGetIssueHierarchy(const void *userData, const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language);
CSAssistGameAPITrack requestCreateTicket(const void *userData, const CSAssistGameAPITicket *ticketBody, const CSAssistUnicodeChar *XMLBody, const CSAssistGameAPIUID uid);
CSAssistGameAPITrack requestAppendTicketComment(const void *userData, const CSAssistGameAPITicketID ticket, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistUnicodeChar *comment);
CSAssistGameAPITrack requestGetTicketByID(const void *userData, const CSAssistGameAPITicketID ticket, const unsigned FlagAsRead);
CSAssistGameAPITrack requestGetTicketComments(const void *userData, const CSAssistGameAPITicketID ticket, const unsigned Start, const unsigned Count, const CSAssistGameAPIOffset offset);
CSAssistGameAPITrack requestGetTicketByCharacter(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const unsigned Start, const unsigned Count, const unsigned FlagAsRead);
CSAssistGameAPITrack requestMarkTicketRead(const void *userData, const CSAssistGameAPITicketID ticket);
CSAssistGameAPITrack requestCancelTicket(const void *userData, const CSAssistGameAPITicketID ticket, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *comment);
CSAssistGameAPITrack requestGetTicketCommentsCount(const void *userData, const CSAssistGameAPITicketID ticket);
CSAssistGameAPITrack replyGameLocation(const void *userData, const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID csruid, const CSAssistUnicodeChar *locationString);
CSAssistGameAPITrack requestGetDocumentList(const void *userData, const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language);
CSAssistGameAPITrack requestGetDocument(const void *userData, const unsigned id);
CSAssistGameAPITrack requestGetTicketXMLBlock(const void *userData, const CSAssistGameAPITicketID id);
CSAssistGameAPITrack requestGetKBArticle(const void *userData, const CSAssistUnicodeChar *id, const CSAssistUnicodeChar *language, const CSAssistGameAPIUID uid);
CSAssistGameAPITrack requestSearchKB(const void *userData, const CSAssistUnicodeChar *searchstring, const CSAssistUnicodeChar *language, const CSAssistGameAPIUID uid);
void setMaxPacketsPerSecond(const unsigned n);
// ----- remember to copy off any pointer based variables for your own use -----
// ----- when the callback returns, this data will be deleted!! -----
virtual void OnConnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
virtual void OnConnectRejectedCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
virtual void OnDisconnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
virtual void OnNewTicketActivity(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NewActivityFlag, const unsigned HasTickets);
virtual void OnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
virtual void OnUnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
virtual void OnGetIssueHierarchy(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML hierarchyBody, const unsigned modifyDate);
virtual void OnCreateTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket);
virtual void OnAppendTicketComment(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket);
virtual void OnGetTicketByID(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicket *ticketBody);
virtual void OnGetTicketComments(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketComment *comments, const unsigned numberRead);
virtual void OnGetTicketByCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NumberReturned, const unsigned TotalNumber, const CSAssistGameAPITicket *ticketBody);
virtual void OnTicketChange(const CSAssistGameAPITicketID ticketID, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character);
virtual void OnMarkTicketRead(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
virtual void OnCancelTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket);
virtual void OnGetTicketCommentsCount(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket, const unsigned count);
virtual void OnRequestGameLocation(const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID CSRUID);
virtual void OnGetDocumentList(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIDocumentHeader *docList, const unsigned numberRead);
virtual void OnGetDocument(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistUnicodeChar *documentBody);
virtual void OnGetTicketXMLBlock(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML XMLBody);
virtual void OnGetKBArticle(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML articleBody, const CSAssistUnicodeChar *articleTitle);
virtual void OnSearchKB(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPISearchResult *results, const unsigned numberRead);
virtual void OnIssueHierarchyChanged(const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language, const CSAssistGameAPIHierarchyChangeType type);
void Update();
const char *getErrorString(const CSAssistGameAPIResult result);
const char *GetConnectedHost();
int GetConnectedPort();
private:
CSAssistGameAPIcore *core;
};
} // namespace CSAssist
#endif
@@ -0,0 +1,225 @@
#ifndef __CSASSISTGAMEAPICORE_H
#define __CSASSISTGAMEAPICORE_H
//------------------------------------------------------------------------------
//
// CSAssistgameapicore.h
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// Main API internal header file
//
//------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <string>
#ifdef USE_UDP_LIBRARY
#include "UdpLibrary/UdpLibrary.hpp"
#else
#include <TcpLibrary/TcpConnection.h>
#include <TcpLibrary/TcpHandlers.h>
#include <TcpLibrary/TcpManager.h>
#endif
#include "Base/Archive.h"
#include "CSAssistgameapi.h"
#include "CSAssistgameobjects.h"
#include "packdata.h"
#include "Unicode/Unicode.h"
namespace CSAssist
{
static const unsigned MAX_PACKETS_PER_SEC = 500;
static const unsigned NORMAL_TIMEOUT_VAL = 60; // 60 seconds
//static const unsigned NORMAL_TIMEOUT_VAL = 5; // debug = 5 seconds
static const unsigned TRACK_CONNECTLB = 0;
static const unsigned CONNECTLB_TIMEOUT = 5; // 5 seconds
struct timeout {
inline timeout()
{
time = 0;
track = 0;
}
inline timeout(unsigned tr, int ti)
{
time = ti;
track = tr;
}
int time;
unsigned track;
};
enum CONNECT_STATE
{
CONNECT_INIT = 0
,CONNECT_REDIRECT_INIT // 1
,CONNECT_REDIRECT_NEGOTIATING // 2
,CONNECT_REDIRECT_CONNECTED // 3
,CONNECT_REDIRECT_DISCONNECTED // 4
,CONNECT_BACKEND_INIT // 5
,CONNECT_BACKEND_NEGOTIATING // 6
,CONNECT_BACKEND_CONNECTED // 7
,CONNECT_BACKEND_CONNECTED_AND_AUTHED // 8
,CONNECT_BACKEND_DISCONNECTED // 9
};
struct ServerID {
std::string host;
unsigned port;
};
//--------------------------------------
class RegisteredCharacter
//--------------------------------------
{
public:
RegisteredCharacter(const unsigned uid, const Plat_Unicode::String character, const unsigned avaconID);
virtual ~RegisteredCharacter();
Plat_Unicode::String getCharacter() { return character; }
unsigned getUID() { return uid; }
unsigned getAvaconID() { return avaconID; }
private:
CSAssistGameAPIUID uid; // station UID
Plat_Unicode::String character; // character name
unsigned avaconID; // universal chat system UID
};
class Response;
class Request;
class CSAssistReceiver;
class CSAssistGameAPI;
class RegisteredCharacter;
//--------------------------------------
class CSAssistGameAPIcore
//--------------------------------------
{
public:
friend class CSAssist::CSAssistReceiver;
CSAssistGameAPIcore(CSAssistGameAPI *api, const char *host, const unsigned port, const unsigned timeout, const unsigned flags);
CSAssistGameAPIcore(CSAssistGameAPI *api, const char *serverList, const unsigned timeout, const unsigned flags);
virtual ~CSAssistGameAPIcore();
// **** ADD CODE HERE ****
CSAssistGameAPITrack connectCSAssist(const void *userData, const CSAssistUnicodeChar *GameName, const CSAssistUnicodeChar *ServerName);
CSAssistGameAPITrack disconnectCSAssist(const void *userData);
CSAssistGameAPITrack requestNewTicketActivity(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character);
CSAssistGameAPITrack requestRegisterCharacter(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const unsigned avaconID);
CSAssistGameAPITrack requestUnRegisterCharacter(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character);
CSAssistGameAPITrack requestGetIssueHierarchy(const void *userData, const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language);
CSAssistGameAPITrack requestCreateTicket(const void *userData, const CSAssistGameAPITicket *ticketBody, const CSAssistUnicodeChar *XMLBody, const CSAssistGameAPIUID uid);
CSAssistGameAPITrack requestAppendTicketComment(const void *userData, const CSAssistGameAPITicketID ticket, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistUnicodeChar *comment);
CSAssistGameAPITrack requestGetTicketByID(const void *userData, const CSAssistGameAPITicketID ticket, const unsigned FlagAsRead);
CSAssistGameAPITrack requestGetTicketComments(const void *userData, const CSAssistGameAPITicketID ticket, const unsigned Start, const unsigned Count, const CSAssistGameAPIOffset offset);
CSAssistGameAPITrack requestGetTicketByCharacter(const void *userData, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const unsigned Start, const unsigned Count, const unsigned FlagAsRead);
CSAssistGameAPITrack requestMarkTicketRead(const void *userData, const CSAssistGameAPITicketID ticket);
CSAssistGameAPITrack requestCancelTicket(const void *userData, const CSAssistGameAPITicketID ticket, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *comment);
CSAssistGameAPITrack requestGetTicketCommentsCount(const void *userData, const CSAssistGameAPITicketID ticket);
CSAssistGameAPITrack replyGameLocation(const void *userData, const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID csruid, const CSAssistUnicodeChar *locationString);
CSAssistGameAPITrack requestGetDocumentList(const void *userData, const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language);
CSAssistGameAPITrack requestGetDocument(const void *userData, const unsigned id);
CSAssistGameAPITrack requestGetTicketXMLBlock(const void *userData, const CSAssistGameAPITicketID id);
CSAssistGameAPITrack requestGetKBArticle(const void *userData, const CSAssistUnicodeChar *id, const CSAssistUnicodeChar *language, const CSAssistGameAPIUID uid);
CSAssistGameAPITrack requestSearchKB(const void *userData, const CSAssistUnicodeChar *searchstring, const CSAssistUnicodeChar *language, const CSAssistGameAPIUID uid);
void setMaxPacketsPerSecond(const unsigned n);
void Update();
void CSAssistGameCallback(Response *);
void localUnRegisterCharacter(const unsigned uid, const Plat_Unicode::String character);
void localRegisterCharacter(const unsigned uid, const Plat_Unicode::String character, const unsigned avaconID);
void reregisterCharacters();
bool isInternalTrackingNumber(const unsigned track);
void batchRegisterCharacters(const unsigned numToSend);
const char* GetConnectedHost();// { return m_ip.c_str(); }
int GetConnectedPort();// { return m_port; }
private:
void SubmitRequest(Request *req, Response *res);
void SubmitImmediateError(Response *res);
Response *getPending(CSAssistGameAPITrack track);
Response *getResponse(CSAssistGameAPITrack track);
Response *createServerResponse(short msgtype);
void SubmitRequestInt(Request *req, Response *res);
Response *getPendingInt(CSAssistGameAPITrack track);
Response *getResponseInt(CSAssistGameAPITrack track);
CSAssistGameAPITrack connectCSAssistInternal();
void ConnectLB();
void GetLBHost();
void OnConnectLB(unsigned track, unsigned result, std::string serverName, unsigned serverPort, Request *, Response *);
#ifdef USE_UDP_LIBRARY
inline bool actuallyConnected() { return (bool)((m_connection != NULL) && (m_connection->GetStatus() == UdpConnection::cStatusConnected)); }
UdpManager *m_conManager;
UdpConnection *m_connection;
#else
inline bool actuallyConnected() { return (bool)((m_connection != NULL) && (m_connection->GetStatus() == TcpConnection::StatusConnected)); }
TcpManager *m_conManager;
TcpConnection *m_connection;
#endif
short m_port;
short m_oldPort;
short m_connectedPort;
std::string m_ip; // this is supposed to be non-internationalised
std::string m_oldIP; // this is supposed to be non-internationalised
std::string m_connectedIP; // this is supposed to be non-internationalised
std::list<ServerID> m_serverList;
std::list<ServerID>::iterator m_curServer;
CSAssistReceiver *m_receiver;
CSAssistGameAPI *m_api;
std::map<CSAssistGameAPITrack, Response *> m_pending;
std::queue<timeout *> m_timeout;
std::queue<Request *> m_outQueue;
std::queue<Response *> m_error;
CSAssistGameAPITrack m_currTrack;
std::map<CSAssistGameAPITrack, Response *> m_pendingInt;
std::queue<timeout *> m_timeoutInt;
std::queue<Request *> m_outQueueInt;
std::queue<Response *> m_errorInt;
CSAssistGameAPITrack m_currTrackInt;
time_t m_reconnectTimeout;
Plat_Unicode::String m_identityGame;
Plat_Unicode::String m_identityServer;
unsigned m_userTimeout;
unsigned m_flags;
std::multimap<unsigned, RegisteredCharacter> m_registeredCharacters;
std::set<unsigned> m_internalTracks;
int m_numberPacketsSendPerSec;
time_t m_gatingSecond;
int m_packetsLeftThisSecond;
std::multimap<unsigned, RegisteredCharacter> m_registeredCharactersCopy;
bool m_useRedirectServer;
bool m_isConnectedToCSAServer;
bool m_canConnect;
bool m_useFailoverHosts;
bool m_connectFailed;
CONNECT_STATE m_connectState;
unsigned m_connectReqCount;
unsigned m_lastConnectReqTrack;
};
} // namespace CSAssist
#endif
@@ -0,0 +1,168 @@
//------------------------------------------------------------------------------
//
// CSAssistgameobjects.cpp
//
// Class member functions for user objects
//
//------------------------------------------------------------------------------
#include "CSAssistgameobjects.h"
#include <stdio.h>
#include <string.h>
#include <Unicode/UnicodeUtils.h>
namespace CSAssist
{
using namespace Plat_Unicode;
extern CSAssistUnicodeChar *get_c_str(Plat_Unicode::String s);
extern CSAssistUnicodeChar *copy_c_str(Plat_Unicode::String s, CSAssistUnicodeChar *dest);
//-----------------------------------------------------------
unsigned UnicodeLength(const CSAssistUnicodeChar *string)
// Return the character length of a raw uint16 string
//-----------------------------------------------------------
{
CSAssistUnicodeChar *p = const_cast<CSAssistUnicodeChar *>(string);
unsigned count = 0;
while (*(p++) != 0)
count++;
return count;
}
//-----------------------------------------------------------
CSAssistGameAPITicket::CSAssistGameAPITicket() :
ticketID(0), uid(0), createDate(0), modifiedDate(0), status(TICKET_STATUS_NEWTICKET),
bugstatus(BUG_STATUS_NONE), isRead(0)
//-----------------------------------------------------------
{
game[0] = 0;
server[0] = 0;
character[0] = 0;
details[0] = 0;
Plat_Unicode::String lang = narrowToWide("en");
copy_c_str(lang, language);
location[0] = 0;
for (short i=0; i < CSASSIST_NUM_CATEGORIES; i++)
category[i] = 0;
}
//-----------------------------------------------------------
CSAssistGameAPIResult CSAssistGameAPITicket::setUID(CSAssistGameAPIUID u)
//-----------------------------------------------------------
{
if (u == 0)
return CSASSIST_RESULT_BADPARAMS;
uid = u;
return CSASSIST_RESULT_SUCCESS;
}
//-----------------------------------------------------------
CSAssistGameAPIResult CSAssistGameAPITicket::setGame(const CSAssistUnicodeChar *string)
//-----------------------------------------------------------
{
unsigned length = UnicodeLength(string);
if (length > CSASSIST_TICKET_LENGTH_GAME)
return CSASSIST_RESULT_BADPARAMS;
memcpy(game, string, (length+1) * sizeof(CSAssistUnicodeChar));
return CSASSIST_RESULT_SUCCESS;
}
//-----------------------------------------------------------
CSAssistGameAPIResult CSAssistGameAPITicket::setServer(const CSAssistUnicodeChar *string)
//-----------------------------------------------------------
{
unsigned length = UnicodeLength(string);
if (length > CSASSIST_TICKET_LENGTH_SERVER)
return CSASSIST_RESULT_BADPARAMS;
memcpy(server, string, (length+1) * sizeof(CSAssistUnicodeChar));
return CSASSIST_RESULT_SUCCESS;
}
//-----------------------------------------------------------
CSAssistGameAPIResult CSAssistGameAPITicket::setCharacter(const CSAssistUnicodeChar *string)
//-----------------------------------------------------------
{
unsigned length = UnicodeLength(string);
if (length > CSASSIST_TICKET_LENGTH_CHARACTER)
return CSASSIST_RESULT_BADPARAMS;
memcpy(character, string, (length+1) * sizeof(CSAssistUnicodeChar));
return CSASSIST_RESULT_SUCCESS;
}
//-----------------------------------------------------------
CSAssistGameAPIResult CSAssistGameAPITicket::setDetails(const CSAssistUnicodeChar *string)
//-----------------------------------------------------------
{
unsigned length = UnicodeLength(string);
if (length > CSASSIST_TICKET_LENGTH_DETAILS)
return CSASSIST_RESULT_BADPARAMS;
memcpy(details, string, (length+1) * sizeof(CSAssistUnicodeChar));
return CSASSIST_RESULT_SUCCESS;
}
//-----------------------------------------------------------
CSAssistGameAPIResult CSAssistGameAPITicket::setLanguage(const CSAssistUnicodeChar *string)
//-----------------------------------------------------------
{
unsigned length = UnicodeLength(string);
if (length > CSASSIST_TICKET_LENGTH_LANGUAGE)
return CSASSIST_RESULT_BADPARAMS;
memcpy(language, string, (length+1) * sizeof(CSAssistUnicodeChar));
return CSASSIST_RESULT_SUCCESS;
}
//-----------------------------------------------------------
CSAssistGameAPIResult CSAssistGameAPITicket::setLocation(const CSAssistUnicodeChar *string)
//-----------------------------------------------------------
{
unsigned length = UnicodeLength(string);
if (length > CSASSIST_TICKET_LENGTH_LOCATION)
return CSASSIST_RESULT_BADPARAMS;
memcpy(location, string, (length+1) * sizeof(CSAssistUnicodeChar));
return CSASSIST_RESULT_SUCCESS;
}
//-----------------------------------------------------------
CSAssistGameAPIResult CSAssistGameAPITicket::setCategory(unsigned index, unsigned value)
//-----------------------------------------------------------
{
if (index < 0 || index >= (short)CSASSIST_NUM_CATEGORIES)
return CSASSIST_RESULT_BADPARAMS;
category[index] = value;
return CSASSIST_RESULT_SUCCESS;
}
//-----------------------------------------------------------
CSAssistGameAPITicketComment::CSAssistGameAPITicketComment() :
ticketID(0), commentID(0), uid(0), type(CSASSIST_COMMENT_NONE), modifiedDate(0)
//-----------------------------------------------------------
{
comment[0] = 0;
name[0] = 0;
}
//-----------------------------------------------------------
CSAssistGameAPIDocumentHeader::CSAssistGameAPIDocumentHeader() :
id(0), modifiedDate(0)
//-----------------------------------------------------------
{
game[0] = 0;
language[0] = 0;
title[0] = 0;
version[0] = 0;
}
//--------------------------------------------
CSAssistGameAPISearchResult::CSAssistGameAPISearchResult()
: matchPercent(0)
//--------------------------------------------
{
title[0] = 0;
idstring[0] = 0;
}
} // namespace CSAssist
@@ -0,0 +1,115 @@
#ifndef __GAMEOBJECTS_H
#define __GAMEOBJECTS_H
//------------------------------------------------------------------------------
//
// CSAssistgameobjects.h
//
// Header file for objects used by API clients
//
//------------------------------------------------------------------------------
#include "CSAssistgameapi.h"
namespace CSAssist
{
//------------------------------------------------------------------------------
// CSAssistGameAPITicket
//
// This is what a ticket looks like to the client
//------------------------------------------------------------------------------
class CSADLL_EXPORT CSAssistGameAPITicket
{
public:
CSAssistGameAPITicket();
void setBug() { bugstatus = BUG_STATUS_BUG; }
CSAssistGameAPIResult setUID(CSAssistGameAPIUID u);
CSAssistGameAPIResult setGame(const CSAssistUnicodeChar *string);
CSAssistGameAPIResult setServer(const CSAssistUnicodeChar *string);
CSAssistGameAPIResult setCharacter(const CSAssistUnicodeChar *string);
CSAssistGameAPIResult setDetails(const CSAssistUnicodeChar *string);
CSAssistGameAPIResult setLanguage(const CSAssistUnicodeChar *string);
CSAssistGameAPIResult setLocation(const CSAssistUnicodeChar *string);
CSAssistGameAPIResult setCategory(unsigned index, unsigned value);
CSAssistGameAPITicketID ticketID; // unique ID
CSAssistGameAPIUID uid; // station UID
time_t createDate;
time_t modifiedDate;
CSAssistUnicodeChar game[CSASSIST_TICKET_LENGTH_GAME+1]; // game name
CSAssistUnicodeChar server[CSASSIST_TICKET_LENGTH_SERVER+1]; // server name
CSAssistUnicodeChar character[CSASSIST_TICKET_LENGTH_CHARACTER+1]; // character name
CSAssistTicketStatus status; // status of this ticket (CSAssistTicketStatus)
CSAssistBugStatus bugstatus; // whether this is a bug report (CSAssistBugStatus)
unsigned category[CSASSIST_NUM_CATEGORIES]; // 'n' category codes
CSAssistUnicodeChar details[CSASSIST_TICKET_LENGTH_DETAILS+1]; // petition text from player
CSAssistUnicodeChar language[CSASSIST_TICKET_LENGTH_LANGUAGE+1]; // language code, e.g. en, jp, fr
unsigned isRead; // whether ticket has been read by player or not
CSAssistUnicodeChar location[CSASSIST_TICKET_LENGTH_LOCATION+1]; // location string
// it is recommended that location take the form of:
// zone: X=xx.xx Y=yy.yy Z=zz.zz
// where zone is a textual name for a region of the game and X,Y,Z are coords
// e.g.: 'dreadlands: X=-126.89 Y=1022.67 Z=301.65
};
//------------------------------------------------------------------------------
// CSAssistGameAPITicketComment
//
// This is what a ticket comment looks like to the client
//------------------------------------------------------------------------------
class CSADLL_EXPORT CSAssistGameAPITicketComment
{
public:
CSAssistGameAPITicketComment();
CSAssistGameAPITicketID ticketID; // ticket to which this comment belongs
unsigned commentID; // unique ID (can be used to sort comments)
CSAssistGameAPIUID uid; // station UID (will be 0 if a CSR comment)
CSAssistGameAPICommentType type; // whether CSR or player comment
time_t modifiedDate; // date of this comment
CSAssistUnicodeChar comment[CSASSIST_TICKET_LENGTH_COMMENT+1];
CSAssistUnicodeChar name[CSASSIST_TICKET_LENGTH_NAME+1];
};
//------------------------------------------------------------------------------
// CSAssistGameAPIDocumentHeader
//
// This is what a DocumentHeader looks like to the client
//------------------------------------------------------------------------------
class CSADLL_EXPORT CSAssistGameAPIDocumentHeader
{
public:
CSAssistGameAPIDocumentHeader();
unsigned id;
CSAssistUnicodeChar game[CSASSIST_DOCUMENT_LENGTH_NAME+1];
CSAssistUnicodeChar language[CSASSIST_DOCUMENT_LENGTH_LANGUAGE+1];
CSAssistUnicodeChar title[CSASSIST_DOCUMENT_LENGTH_TITLE+1];
CSAssistUnicodeChar version[CSASSIST_DOCUMENT_LENGTH_GAMESUBCODE+1];
time_t modifiedDate;
};
//------------------------------------------------------------------------------
// CSAssistGameAPISearchResult
//
// This is what a Knowledge Base Search Result looks like to the client
//------------------------------------------------------------------------------
class CSADLL_EXPORT CSAssistGameAPISearchResult
{
public:
CSAssistGameAPISearchResult();
CSAssistUnicodeChar title[CSASSIST_KBSEARCH_LENGTH_TITLE+1];
CSAssistUnicodeChar idstring[CSASSIST_KBSEARCH_LENGTH_ID+1];
short matchPercent;
};
} // namespace CSAssist
#endif
@@ -0,0 +1,172 @@
//------------------------------------------------------------------------------
//
// CSAssistreceiver.cpp
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// UDPLibrary wrapper and handler
//
//------------------------------------------------------------------------------
#pragma warning (disable: 4786)
#include "CSAssistgameapicore.h"
#include "CSAssistreceiver.h"
#include "response.h"
namespace CSAssist
{
using namespace Base;
extern CSAssistUnicodeChar *get_c_str(Plat_Unicode::String s);
extern CSAssistUnicodeChar *copy_c_str(Plat_Unicode::String s, CSAssistUnicodeChar *dest);
CSAssistReceiver::CSAssistReceiver(CSAssistGameAPIcore *core)
: m_api(core), m_firstConnection(false), m_reconnectTrack(0)
{
}
CSAssistReceiver::~CSAssistReceiver()
{
}
//--------------------------------------------------
#ifdef USE_UDP_LIBRARY
void CSAssistReceiver::OnConnectComplete(UdpConnection *con)
#else
void CSAssistReceiver::OnConnectRequest(TcpConnection *con)
#endif
//
// Called when API has successfully connected to server...
//--------------------------------------------------
{
//fprintf(stderr, "OnConnectComplete: enter!\n");
if (m_api->m_useRedirectServer)
{
switch(m_api->m_connectState)
{
case CONNECT_REDIRECT_NEGOTIATING:
m_api->m_connectState = CONNECT_REDIRECT_CONNECTED;
//if (m_firstConnection)
m_api->ConnectLB();
break;
case CONNECT_BACKEND_NEGOTIATING:
m_api->m_connectState = CONNECT_BACKEND_CONNECTED;
//m_firstConnection = true;
break;
default:
fprintf(stderr, "OnConnectComplete(): unknown connect state (%u)\n", m_api->m_connectState);
}
}
else
{
m_api->m_connectState = CONNECT_BACKEND_CONNECTED;
//m_firstConnection = true;
}
//fprintf(stderr, "debug: OnConnectComplete(): Now m_connectState=%u\n", m_api->m_connectState);
// resend identity to server
if ((m_firstConnection == true || m_api->m_connectFailed) && m_api->m_connectState == CONNECT_BACKEND_CONNECTED)
{
//fprintf(stderr, "Trying to auto re-connect\n");
m_reconnectTrack = m_api->connectCSAssistInternal();
}
}
#ifdef USE_UDP_LIBRARY
void CSAssistReceiver::OnTerminated(UdpConnection *con)
#else
void CSAssistReceiver::OnTerminated(TcpConnection *con)
#endif
{
//fprintf(stderr,"OnTerminated(): enter\n");
if (m_api->m_useRedirectServer)
{
m_api->m_connectReqCount = 0;
switch(m_api->m_connectState)
{
case CONNECT_REDIRECT_CONNECTED:
case CONNECT_REDIRECT_NEGOTIATING:
m_api->m_connectState = CONNECT_REDIRECT_DISCONNECTED;
m_api->GetLBHost();
break;
case CONNECT_BACKEND_CONNECTED_AND_AUTHED:
m_api->m_api->OnDisconnectCSAssist(0, CSASSIST_RESULT_SERVER_DISCONNECT, NULL);
case CONNECT_BACKEND_CONNECTED:
m_api->GetLBHost();
case CONNECT_BACKEND_NEGOTIATING: m_api->m_connectState = CONNECT_BACKEND_DISCONNECTED; break;
default:
fprintf(stderr,"OnTermintated(): bad connectState (%u)\n", m_api->m_connectState);
}
}
else
{
if (m_api->m_connectState == CONNECT_BACKEND_CONNECTED_AND_AUTHED)
m_api->m_api->OnDisconnectCSAssist(0, CSASSIST_RESULT_SERVER_DISCONNECT, NULL);
m_api->m_connectState = CONNECT_BACKEND_DISCONNECTED;
m_api->GetLBHost();
}
}
#ifdef USE_UDP_LIBRARY
void CSAssistReceiver::OnCrcReject(UdpConnection *con, uchar *data, int dataLen)
#else
void CSAssistReceiver::OnCrcReject(TcpConnection *con, uchar *data, int dataLen)
#endif
{
}
//--------------------------------------------------
#ifdef USE_UDP_LIBRARY
void CSAssistReceiver::OnRoutePacket(UdpConnection *con, const uchar *data, int dataLen)
#else
void CSAssistReceiver::OnRoutePacket(TcpConnection *con, const uchar *data, int dataLen)
#endif
//--------------------------------------------------
{
unsigned track, result;
short type;
Response *res = 0;
ByteStream msg(data, dataLen);
ByteStream::ReadIterator iter = msg.begin();
iter.advance(2); // skip short num_args
get(iter, type);
get(iter, track);
get(iter, result);
if (type > CSASSIST_CALL_START_SERVER_MESSAGES)
{ // ----- server-initiated calls need to create a new Response object -----
res = m_api->createServerResponse(type);
}
else if (type == CSASSIST_CALL_CONNECTLB || (type == CSASSIST_CALL_CONNECT && m_firstConnection))
{
//fprintf(stderr,"OnRoutePacket(): got an internal connect/lb request\n");
res = m_api->getPendingInt(track);
}
else // ----- API-initiated calls already have a Response object -----
{
res = m_api->getPending(track);
}
if(res != NULL)
{
res->init(type, track, result);
res->decode(iter);
m_api->CSAssistGameCallback(res);
}
else
{
//fprintf(stderr,"Dropping timed-out response type(%u) track(%u) result(%u)", type, track, result);
}
}
} // namespace CSAssist
@@ -0,0 +1,68 @@
#ifndef __CSASSISTRECEIVER_H__
#define __CSASSISTRECEIVER_H__
//------------------------------------------------------------------------------
//
// CSAssistreceiver.h
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// UDPLibrary wrapper and handler
//
//------------------------------------------------------------------------------
#ifdef USE_UDP_LIBRARY
#include "UdpLibrary/UdpHandler.hpp"
#else
#include <TcpLibrary/TcpConnection.h>
#include <TcpLibrary/TcpHandlers.h>
#include <TcpLibrary/TcpManager.h>
#endif
#ifndef uchar
typedef unsigned char uchar;
#endif
namespace CSAssist
{
class CSAssistGameAPIcore;
#ifdef USE_UDP_LIBRARY
class CSAssistReceiver : public UdpConnectionHandler
#else
class CSAssistReceiver : public TcpConnectionHandler, public TcpManagerHandler
#endif
{
public:
CSAssistReceiver(CSAssistGameAPIcore *api);
virtual ~CSAssistReceiver();
#ifdef USE_UDP_LIBRARY
virtual void OnRoutePacket(UdpConnection *con, const uchar *data, int dataLen);
virtual void OnConnectComplete(UdpConnection *con);
virtual void OnTerminated(UdpConnection *con);
virtual void OnCrcReject(UdpConnection *con, uchar *data, int dataLen);
#else
virtual void OnRoutePacket(TcpConnection *con, const uchar *data, int dataLen);
virtual void OnConnectRequest(TcpConnection *con);
virtual void OnTerminated(TcpConnection *con);
virtual void OnCrcReject(TcpConnection *con, uchar *data, int dataLen);
#endif
CSAssistGameAPITrack getReconnectTrack() { return m_reconnectTrack; }
friend class CSAssistGameAPIcore;
private:
CSAssistGameAPIcore *m_api;
bool m_firstConnection;
CSAssistGameAPITrack m_reconnectTrack;
};
} // namespace CSAssist
#endif
@@ -0,0 +1,693 @@
//-----------------------------------------------------------------
//
// CSAssist Module
//
// API Test Program
//
// Author: Graeme Ing ([email protected] x3130)
//
// Copyright (c) 2002 Sony Online Interactive inc.
//
// This program simply demonstrates some calls to the
// CSAssist API. See main()
//
//-----------------------------------------------------------------
#include "test.h"
#include "Unicode/UnicodeUtils.h"
using namespace CSAssist;
using namespace Plat_Unicode;
#include <signal.h>
#include <iostream>
#include <time.h>
#include <string.h>
#ifdef WIN32
#include <conio.h>
#endif
using namespace std;
apiTest *api;
int received = 0;
int submitted = 0;
CSAssistGameAPIUID gUID=623259672; // csatest account
CSAssistGameAPITicketID globalTicketID=0;
bool ready = false;
Plat_Unicode::String globalArticleID;
//----------------------------------------------
CSAssistUnicodeChar *get_c_str(Plat_Unicode::String s)
// This replaces c_str() by allocating a new buffer, erasing it, and then
// using the non-null terminated data() to copy the data into the buffer.
//----------------------------------------------
{
unsigned length = s.size() + 1;
CSAssistUnicodeChar *temp = new CSAssistUnicodeChar[length];
memset(temp, 0, length * sizeof(CSAssistUnicodeChar));
memcpy(temp, s.data(), (length - 1) * sizeof(CSAssistUnicodeChar));
return temp;
}
//----------------------------------------------
CSAssistUnicodeChar *copy_c_str(Plat_Unicode::String s, CSAssistUnicodeChar *dest)
//----------------------------------------------
{
unsigned length = s.size() + 1;
memset(dest, 0, length * sizeof(CSAssistUnicodeChar));
memcpy(dest, s.data(), (length - 1) * sizeof(CSAssistUnicodeChar));
return dest;
}
//---------------------------------------------
//
// The routines that follow display basic objects
//
//---------------------------------------------
//---------------------------------------------
void DisplayTicket(const CSAssistGameAPITicket *t)
//---------------------------------------------
{
if (t != 0)
{
char date1[64], date2[64];
strcpy(date1,ctime(&t->createDate));
Plat_Unicode::String game = t->game;
Plat_Unicode::String server = t->server;
Plat_Unicode::String character = t->character;
Plat_Unicode::String language = t->language;
Plat_Unicode::String location = t->location;
Plat_Unicode::String details = t->details;
// std::cout << wideToNarrow(character) << " " << t->modifiedDate << " " << date2;
std::cout << "***Ticket: " << t->ticketID << "\n Created: " << date1;
strcpy(date2,ctime(&t->modifiedDate));
std::cout << " Modified: " << date2 << " Game/Server: " << wideToNarrow(game) << ", " << wideToNarrow(server);
std::cout << "\n Character: " << wideToNarrow(character) << "\n Status: " << t->status << "," << t->bugstatus;
std::cout << "\n UID: " << t->uid << "\n Category: ";
for (short i=0; i < CSASSIST_NUM_CATEGORIES; i++)
std::cout << t->category[i] << ",";
std::cout << "\n Language: " << wideToNarrow(language);
std::cout << "\n Location: " << wideToNarrow(location);
std::cout << "\n IsRead: " << t->isRead << "\n ";
std::cout << wideToNarrow(details) << "\n***\n";
}
else
std::cout << "***Ticket IS NULL! ***\n";
}
//---------------------------------------------
void DisplayComment(const CSAssistGameAPITicketComment *t)
//---------------------------------------------
{
if (t != 0)
{
Plat_Unicode::String name = t->name;
Plat_Unicode::String comment = t->comment;
std::cout << "***Comment: Comment ID: " << t->commentID << " Ticket ID: " << t->ticketID << " UID: " << t->uid;
std::cout << " Name: " << wideToNarrow(name) << " Type: " << t->type << " Modified: " << ctime(&t->modifiedDate);
std::cout << "\n " << wideToNarrow(comment) << "\n";
}
else
std::cout << "***Comment IS NULL! ***\n";
}
//---------------------------------------------
void DisplayDocumentHeader(const CSAssistGameAPIDocumentHeader *doc)
//---------------------------------------------
{
if (doc != 0)
{
char date2[32];
strcpy(date2,ctime(&doc->modifiedDate));
Plat_Unicode::String game = doc->game;
Plat_Unicode::String language = doc->language;
Plat_Unicode::String title = doc->title;
Plat_Unicode::String version = doc->version;
std::cout << "***Document Header: ID: " << doc->id << ", Game: " << wideToNarrow(game);
std::cout << ", Lang: " << wideToNarrow(language);
std::cout << ", Title: " << wideToNarrow(title);
std::cout << ", Version: " << wideToNarrow(version);
std::cout << ", Modified: " << date2 << "\n";
}
else
std::cout << "***Document Header IS NULL! ***\n";
}
//---------------------------------------------
void DisplaySearchResult(const CSAssistGameAPISearchResult *doc)
//---------------------------------------------
{
if (doc != 0)
{
Plat_Unicode::String id = doc->idstring;
globalArticleID = id;
Plat_Unicode::String title = doc->title;
std::cout << "ID: " << wideToNarrow(id) << ", Match: " << doc->matchPercent;
std::cout << ", Title: " << wideToNarrow(title) << "\n";
}
else
std::cout << "***Search Result IS NULL! ***\n";
}
//---------------------------------------------
apiTest::apiTest(const char *hostList, const unsigned timeout = 0, const unsigned flags = 0)
: CSAssistGameAPI(hostList, timeout, flags)
//---------------------------------------------
{
}
apiTest::apiTest(const char *host, const unsigned port, const unsigned timeout, const unsigned flags)
: CSAssistGameAPI(host, port, timeout, flags)
//---------------------------------------------
{
}
//---------------------------------------------
apiTest::~apiTest()
//---------------------------------------------
{
}
//---------------------------------------------
//
// The routines that follow override the API
// callbacks. You only need to override those
// that you are interested in.
// Default API behavior on the callbacks is to
// delete the message and continue.
//
//---------------------------------------------
//---------------------------------------------
void apiTest::OnConnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
std::cout << "Connect: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << "\n";
if (result == CSASSIST_RESULT_SUCCESS)
{
std::cerr <<"Connected to host("<<api->GetConnectedHost()<<") port("<<api->GetConnectedPort()<<")"<<endl;
ready = true;
}
else
{
}
}
//---------------------------------------------
void apiTest::OnConnectRejectedCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
std::cerr << "Connect REJECTED("<<GetConnectedHost() <<","<<GetConnectedPort()<<"): Track: " << track
<< " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << "\n";
}
//---------------------------------------------
void apiTest::OnDisconnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
std::cerr << "DisConnect: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << "\n";
received++;
}
//---------------------------------------------
void apiTest::OnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
std::cout << "Register: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << "\n";
received++;
}
//---------------------------------------------
void apiTest::OnUnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
std::cout << "UnRegister: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << "\n";
received++;
}
//---------------------------------------------
void apiTest::OnNewTicketActivity(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NewActivityFlag, const unsigned HasTickets)
//---------------------------------------------
{
std::cout << "NewActivity: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << ", New(" << NewActivityFlag;
std::cout << "), HasTickets(" << HasTickets << ")\n";
received++;
}
//---------------------------------------------
void apiTest::OnGetIssueHierarchy(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML hierarchyBody, const unsigned modifyDate)
//---------------------------------------------
{
received++;
Plat_Unicode::String body = hierarchyBody;
std::cout << "Hierarchy: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData;
std::cout << ", XML(" << wideToNarrow(body).c_str();
std::cout << "), ModifyDate(" << ctime((const time_t *)(&modifyDate)) << ")";
}
//---------------------------------------------
void apiTest::OnCreateTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------------------------
{
std::cout << "Create Ticket: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << ", TicketID(" << ticket << ")\n";
received++;
globalTicketID = ticket;
}
//---------------------------------------------
void apiTest::OnAppendTicketComment(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------------------------
{
std::cout << "Append Comment: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << ", TicketID(" << ticket << ")\n";
received++;
}
//---------------------------------------------
void apiTest::OnGetTicketByID(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicket *ticketBody)
//---------------------------------------------
{
std::cout << "Get Ticket ID: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << "\n";
if (result == CSASSIST_RESULT_SUCCESS)
DisplayTicket(ticketBody);
received++;
}
//---------------------------------------------
void apiTest::OnGetTicketComments(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketComment *comments, const unsigned numberRead)
//---------------------------------------------
{
std::cout << "Get Ticket Comments: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << ", numberRead(" << numberRead << ")\n";
if (comments == 0)
{
std::cout << "***Returned no data array***\n";
}
else
{
const CSAssistGameAPITicketComment *pt = comments;
for (unsigned i=0; i < numberRead; i++)
{
DisplayComment(pt);
pt++;
}
}
received++;
}
//---------------------------------------------
void apiTest::OnGetTicketByCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NumberReturned, const unsigned TotalNumber, const CSAssistGameAPITicket *tickets)
//---------------------------------------------
{
std::cout << "Get Tickets Char: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << ", numberRead(" << NumberReturned;
std::cout << ") totalNumber(" << TotalNumber << ")\n";
if (tickets == 0)
{
std::cout << "***Returned no data array***\n";
}
else
{
const CSAssistGameAPITicket *pt = tickets;
for (unsigned i=0; i < NumberReturned; i++)
{
DisplayTicket(pt);
pt++;
}
}
received++;
}
//---------------------------------------------
void apiTest::OnTicketChange(const CSAssistGameAPITicketID ticketID, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character)
//---------------------------------------------
{
Plat_Unicode::String charry = character;
std::cout << "Ticket Change: Ticket(" << ticketID << "), uid(" << uid << "), character(" << wideToNarrow(charry) << ")\n";
}
//---------------------------------------------
void apiTest::OnMarkTicketRead(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData)
//---------------------------------------------
{
std::cout << "Mark Read: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << "\n";
received++;
}
//---------------------------------------------
void apiTest::OnCancelTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket)
//---------------------------------------------
{
std::cout << "Cancel Ticket: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << ", TicketID: " << ticket << "\n";
received++;
}
//---------------------------------------------
void apiTest::OnGetTicketCommentsCount(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket, const unsigned count)
//---------------------------------------------
{
std::cout << "Comment Count: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << ", TicketID(" << ticket << "), Count: " << count << "\n";
received++;
}
//---------------------------------------------
void apiTest::OnRequestGameLocation(const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID CSRUID)
//---------------------------------------------
{
Plat_Unicode::String charry = character;
Plat_Unicode::String loc = narrowToWide("-debug character=qeynos hills");
CSAssistUnicodeChar *rawCharry = get_c_str(charry);
CSAssistUnicodeChar *rawLoc = get_c_str(loc);
std::cout << "Request Game Location: Source Track(" << sourceTrack << "), uid(" << uid << "), character(";
std::cout << wideToNarrow(charry) << "), CSR UID(" << CSRUID << ")\n";
api->replyGameLocation(NULL, sourceTrack, uid, rawCharry, CSRUID, rawLoc);
delete [] rawCharry;
delete [] rawLoc;
}
//---------------------------------------------
void apiTest::OnGetDocumentList(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIDocumentHeader *docList, const unsigned numberRead)
//---------------------------------------------
{
std::cout << "Get DocumentList: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << ", numberRead(" << numberRead << ")\n";
if (docList == 0)
{
std::cout << "***Returned no data array***\n";
}
else
{
const CSAssistGameAPIDocumentHeader *pt = docList;
for (unsigned i=0; i < numberRead; i++)
{
DisplayDocumentHeader(pt);
pt++;
}
}
received++;
}
//---------------------------------------------
void apiTest::OnGetDocument(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistUnicodeChar *documentBody)
//---------------------------------------------
{
Plat_Unicode::String body = documentBody;
std::cout << "Document: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << ", Text(";
std::cout << wideToNarrow(body) << ")\n";
received++;
}
//---------------------------------------------
void apiTest::OnGetTicketXMLBlock(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML XMLBody)
//---------------------------------------------
{
Plat_Unicode::String xml = XMLBody;
std::cout << "Ticket XML Block: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData;
std::cout << ", XML(" << wideToNarrow(xml) << ")\n";
received++;
}
//---------------------------------------------
void apiTest::OnSearchKB(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPISearchResult *results, const unsigned numberRead)
//---------------------------------------------
{
std::cout << "Search KB: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData << ", numberRead(" << numberRead << ")\n";
if (results == 0)
{
std::cout << "***Returned no data array***\n";
}
else
{
const CSAssistGameAPISearchResult *pt = results;
for (unsigned i=0; i < numberRead; i++)
{
DisplaySearchResult(pt);
pt++;
}
}
received++;
}
//---------------------------------------------
void apiTest::OnGetKBArticle(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML articleBody)
//---------------------------------------------
{
std::cout << "KB Article: Track: " << track << " - Result: " << getErrorString(result) << " UserData: " << (unsigned)userData;
Plat_Unicode::String body = articleBody;
std::cout << ", Text(" << wideToNarrow(body) << ")\n";
received++;
}
//---------------------------------------------
void apiTest::OnIssueHierarchyChanged(const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language)
//---------------------------------------------
{
Plat_Unicode::String ver = version;
Plat_Unicode::String lang = language;
std::cout << "Hierarchy Changed: " << "Version: " << wideToNarrow(ver) << ", Lang: " << wideToNarrow(lang) << "\n";
}
void sigh(int signal)
{
cerr<<"Caught signal: "<< signal << endl;
}
//---------------------------------------------
int main(int argc, char **argv)
//
// Here is some test code to demonstrate the API
//
// NOTE: The copy_c_str() and get_c_str() calls are simply "hacks"
// to replace the standard c_str() member function for unicode strings (Plat_Unicode::String)
// This is necessary because c_str() is broken under gcc 2.96 and will not compile with
// unicode strings :(
// In replace of these hacks and the associated "delete [] foo" code,
// simply use .c_str()
//
//---------------------------------------------
{
//signal(SIGPIPE, sigh);
printf("CSAssist test client\n");
// int serverport = 3010;
int serverport = 3019;
char *host = "sdplatdev2";
string gameStr("SWG");
for (int i(0); i < argc; i++)
{
if (!strcmp(argv[i],"-host"))
host = argv[i+1];
else if(!strcmp(argv[i], "-port"))
serverport = atoi(argv[i+1]);
else if(!strcmp(argv[i], "-server"))
gameStr = argv[i+1];
}
//api = new apiTest(host, serverport, 160, CSASSIST_APIFLAG_ASSUME_RECONNECT);
//api = new apiTest(host, serverport, 160, CSASSIST_APIFLAG_ASSUME_RECONNECT|CSASSIST_APIFLAG_NO_REDIRECT);
api = new apiTest("sdplatdev2:3016 ", 30, CSASSIST_APIFLAG_ASSUME_RECONNECT);
std::cout << "Client API ceated.\n";
//std::cout <<"Connected to host via("<<api->GetConnectedHost()<<") port("<<api->GetConnectedPort()<<")"<<endl;
//api->setMaxPacketsPerSecond(40);
//---------------------------------------------
// test out some calls:
// for a list of all those available, see
// CSAssistgameapi.h
//---------------------------------------------
Plat_Unicode::String game = narrowToWide(gameStr); //EQOA
Plat_Unicode::String server = narrowToWide("CsatestServer"); // Test
CSAssistUnicodeChar rawGame[16];
CSAssistUnicodeChar rawServer[16];
copy_c_str(game, rawGame);
copy_c_str(server, rawServer);
api->connectCSAssist((void *)6000, rawGame, rawServer);
while (!ready)
api->Update();
//return 0;
Plat_Unicode::String lang = narrowToWide("en");
CSAssistUnicodeChar rawLanguage[16];
copy_c_str(lang, rawLanguage);
/* Plat_Unicode::String hversion = narrowToWide("test"); // test
CSAssistUnicodeChar rawVersion[32];
copy_c_str(hversion, rawVersion);
api->requestGetIssueHierarchy((void *)1, rawVersion, rawLanguage);
submitted++;
*/
/* Plat_Unicode::String search = narrowToWide("jedi");
CSAssistUnicodeChar rawSearch[64];
copy_c_str(search, rawSearch);
api->requestSearchKB((void *)1, rawSearch, rawLanguage);
submitted++;
while (submitted > received)
{
api->Update();
}
Plat_Unicode::String kbid = narrowToWide("soe603");
CSAssistUnicodeChar rawkbid[64];
copy_c_str(kbid, rawkbid);
api->requestGetKBArticle((void *)1, rawkbid, rawLanguage);
submitted++;
while (submitted > received)
{
api->Update();
}
*/
api->setMaxPacketsPerSecond(200);
Plat_Unicode::String testc;
//unsigned i;
unsigned j;
//while (1)
{
CSAssistUnicodeChar rawChar[64];
for (j=0; j < 100; j++)
{
char buff[100] = {0};
char uidc[25] = {0};
sprintf(buff,"TestChar%04d", j+1);
testc = narrowToWide(buff);
copy_c_str(testc, rawChar);
sprintf(uidc, "%04d", j+1);
unsigned uid = atoi(uidc);
api->requestRegisterCharacter((void *)uid, uid, rawChar, 0);
submitted++;
//api->requestNewTicketActivity((void *)6002, uid, rawChar);
//submitted++;
//while (submitted > received)
{
api->Update();
}
}
/* for (j=0; j < 20; j++)
{
for (i=0; i < 100; i++)
{
sprintf(buff,"TestChar%d%d", j+1, i+1);
testc = narrowToWide(buff);
copy_c_str(testc, rawChar);
api->requestUnRegisterCharacter((void *)6001, (i+1)*(j+1), rawChar);
submitted++;
}
//while (submitted > received)
//{
// api->Update();
//}
}
*/
api->Update();
cerr<<"Waiting for register requests..."<<endl;
while (submitted > received)
{
api->Update();
}
cerr<<"done waiting for registers."<<endl;
}
// now wait for events
std::cerr <<"Connected to host("<<api->GetConnectedHost()<<") port("<<api->GetConnectedPort()<<")"<<endl;
while (1)
{
api->Update();
Base::sleep(50);
}
Plat_Unicode::String character = narrowToWide("CSATestChar1");
CSAssistUnicodeChar rawChar[64];
copy_c_str(character, rawChar);
api->requestRegisterCharacter((void *)6001, gUID, rawChar, 0);
submitted++;
while (submitted > received)
{
api->Update();
}
api->requestNewTicketActivity((void *)6002, gUID, rawChar);
submitted++;
while (submitted > received)
{
api->Update();
}
getchar();return 0;
Plat_Unicode::String details = narrowToWide("CsaTest's petition text.");
CSAssistUnicodeChar rawDetails[64];
copy_c_str(details, rawDetails);
Plat_Unicode::String xml = narrowToWide("CsaTest's XML text.");
CSAssistUnicodeChar rawxml[64];
copy_c_str(xml, rawxml);
CSAssistGameAPITicket t;
t.setUID(gUID);
t.setGame(rawGame);
t.setServer(rawServer);
t.setCharacter(rawChar);
t.setDetails(rawDetails);
t.setLanguage(rawLanguage);
t.setCategory(0, 12);
t.setCategory(1, 2);
//t.setBug();
api->requestCreateTicket((void *)1, &t, rawxml, gUID);
submitted++;
while (submitted > received)
{
api->Update();
}
// api->requestNewTicketActivity((void *)6002, 99709401, 0);
// submitted++;
// while (submitted > received)
// {
// api->Update();
// }
/* api->requestGetTicketByID((void *)6001, 156368, 1);
submitted++;
while (submitted > received)
{
api->Update();
}
*/
// api->requestGetTicketXMLBlock((void *)1, globalTicketID);
// submitted++;
// while (submitted > received)
// {
// api->Update();
// }
/* Plat_Unicode::String comment = narrowToWide("Fippys closing comment");
CSAssistUnicodeChar rawComment[64];
copy_c_str(comment, rawComment);
api->requestCancelTicket((void *)1, 267997, 99709401, rawComment);
submitted++;
while (submitted > received)
{
api->Update();
}
*/
#ifdef WIN32
while (submitted > received || !kbhit()) // make sure everything is complete before disconnecting
#else
while (submitted > received) // make sure everything is complete before disconnecting
#endif
{
api->Update();
}
api->disconnectCSAssist((void *)6013);
submitted++;
// ----- loop here until all sent messages have arrived -----
// ----- in your application, just call api->Update() at regular intervals -----
while (submitted > received)
{
api->Update();
}
delete api;
return(0);
}
@@ -0,0 +1,50 @@
#ifndef TEST_H
#define TEST_H
#include "CSAssistgameapi.h"
#include "CSAssistgameobjects.h"
extern "C" {
#include <stdio.h>
};
using namespace CSAssist;
//---------------------------------------------
class apiTest : public CSAssistGameAPI
//---------------------------------------------
{
public:
apiTest(const char *, const unsigned, const unsigned);
apiTest(const char *, const unsigned, const unsigned, const unsigned);
virtual ~apiTest();
void OnConnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnConnectRejectedCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnDisconnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnNewTicketActivity(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NewActivityFlag, const unsigned HasTickets);
void OnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnUnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnGetIssueHierarchy(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML hierarchyBody, const unsigned modifyDate);
void OnCreateTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket);
void OnAppendTicketComment(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket);
void OnGetTicketByID(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicket *ticketBody);
void OnGetTicketComments(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketComment *comments, const unsigned numberRead);
void OnGetTicketByCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NumberReturned, const unsigned TotalNumber, const CSAssistGameAPITicket *ticketBody);
void OnTicketChange(const CSAssistGameAPITicketID ticketID, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character);
void OnMarkTicketRead(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData);
void OnCancelTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket);
void OnGetTicketCommentsCount(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket, const unsigned count);
void OnRequestGameLocation(const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID CSRUID);
void OnGetDocumentList(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIDocumentHeader *docList, const unsigned numberRead);
void OnGetDocument(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistUnicodeChar *documentBody);
void OnGetTicketXMLBlock(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML XMLBody);
void OnSearchKB(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPISearchResult *results, const unsigned numberRead);
void OnGetKBArticle(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML articleBody);
void OnIssueHierarchyChanged(const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language);
private:
};
#endif
@@ -0,0 +1,190 @@
//------------------------------------------------------------------------------
//
// packdata.cpp
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// decode/encode class data for sending over the wire
//
//------------------------------------------------------------------------------
#include "Base/Archive.h"
#include "CSAssistgameapi.h"
#include "CSAssistgameobjects.h"
#include "Unicode/UnicodeUtils.h"
#include "packdata.h"
#include <stdio.h>
namespace CSAssist
{
using namespace Base;
using namespace std;
using namespace CSAssist;
using namespace Plat_Unicode;
//----------------------------------------------
CSAssistUnicodeChar *get_c_str(Plat_Unicode::String s)
// This replaces c_str() by allocating a new buffer, erasing it, and then
// using the non-null terminated data() to copy the data into the buffer.
//----------------------------------------------
{
unsigned length = s.size() + 1;
CSAssistUnicodeChar *temp = new CSAssistUnicodeChar[length];
memset(temp, 0, length * sizeof(CSAssistUnicodeChar));
memcpy(temp, s.data(), (length - 1) * sizeof(CSAssistUnicodeChar));
return temp;
}
//----------------------------------------------
CSAssistUnicodeChar *copy_c_str(Plat_Unicode::String s, CSAssistUnicodeChar *dest)
//----------------------------------------------
{
unsigned length = s.size() + 1;
memset(dest, 0, length * sizeof(CSAssistUnicodeChar));
memcpy(dest, s.data(), (length - 1) * sizeof(CSAssistUnicodeChar));
return dest;
}
namespace Base
{
//----------------------------------------------
void put(Base::ByteStream & target, const CSAssistGameAPITicket & source)
//----------------------------------------------
{
Plat_Unicode::String sgame = source.game;
Plat_Unicode::String sserver = source.server;
Plat_Unicode::String sdetails = source.details;
Plat_Unicode::String slanguage = source.language;
Plat_Unicode::String scharacter = source.character;
Plat_Unicode::String slocation = source.location;
put(target, source.ticketID);
put(target, source.uid);
put(target, (unsigned)source.createDate);
put(target, (unsigned)source.modifiedDate);
put(target, sgame);
put(target, sserver);
put(target, scharacter);
put(target, (unsigned)source.status);
put(target, (unsigned)source.bugstatus);
for (short i=0; i < CSASSIST_NUM_CATEGORIES; i++)
put(target, source.category[i]);
put(target, sdetails);
put(target, slanguage);
put(target, source.isRead);
put(target, slocation);
}
//----------------------------------------------
void get(ByteStream::ReadIterator & source, CSAssistGameAPITicket & target)
//----------------------------------------------
{
Plat_Unicode::String sgame;
Plat_Unicode::String sserver;
Plat_Unicode::String scharacter;
Plat_Unicode::String sdetails;
Plat_Unicode::String slanguage;
Plat_Unicode::String slocation;
unsigned create, modified, gstatus, bstatus;
get(source, target.ticketID);
get(source, target.uid);
get(source, create);
get(source, modified);
get(source, sgame);
get(source, sserver);
get(source, scharacter);
get(source, gstatus);
get(source, bstatus);
for (short i=0; i < CSASSIST_NUM_CATEGORIES; i++)
get(source, target.category[i]);
get(source, sdetails);
get(source, slanguage);
get(source, target.isRead);
get(source, slocation);
copy_c_str(sgame, target.game);
copy_c_str(sserver, target.server);
copy_c_str(scharacter, target.character);
copy_c_str(sdetails, target.details);
copy_c_str(slanguage, target.language);
copy_c_str(slocation, target.location);
target.createDate = (time_t)create;
target.modifiedDate = (time_t)modified;
target.status = (CSAssistTicketStatus)gstatus;
target.bugstatus = (CSAssistBugStatus)bstatus;
}
//----------------------------------------------
void get(ByteStream::ReadIterator & source, CSAssistGameAPITicket * target)
//----------------------------------------------
{
CSAssistGameAPITicket &t = *target;
get(source, t);
}
} // namespace Base
//----------------------------------------------
void decodeTicketComment(ByteStream::ReadIterator & msg,CSAssistGameAPITicketComment *dest)
//----------------------------------------------
{
Plat_Unicode::String comment, name;
unsigned modified, type;
get(msg, dest->ticketID);
get(msg, dest->commentID);
get(msg, dest->uid);
get(msg, modified);
get(msg, type);
get(msg, comment);
get(msg, name);
copy_c_str(comment, dest->comment);
copy_c_str(name, dest->name);
dest->modifiedDate = (time_t)modified;
dest->type = (CSAssistGameAPICommentType)type;
}
//----------------------------------------------
void decodeDocumentHeader(ByteStream::ReadIterator & msg,CSAssistGameAPIDocumentHeader *dest)
//----------------------------------------------
{
Plat_Unicode::String game, language, title, version;
unsigned modified;
get(msg, dest->id);
get(msg, game);
get(msg, language);
get(msg, title);
get(msg, version);
get(msg, modified);
copy_c_str(game, dest->game);
copy_c_str(language, dest->language);
copy_c_str(title, dest->title);
copy_c_str(version, dest->version);
dest->modifiedDate = (time_t)modified;
}
//----------------------------------------------
void decodeSearchResult(ByteStream::ReadIterator & msg,CSAssistGameAPISearchResult *dest)
//----------------------------------------------
{
Plat_Unicode::String atitle, id;
get(msg, id);
get(msg, dest->matchPercent);
get(msg, atitle);
copy_c_str(id, dest->idstring);
copy_c_str(atitle, dest->title);
}
} // namespace CSAssist
@@ -0,0 +1,37 @@
#ifndef PACKDATA_H
#define PACKDATA_H
//------------------------------------------------------------------------------
//
// packdata.h
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// encoding/decoding API-user objects for transmission over the wire
//
//------------------------------------------------------------------------------
#include <Base/Archive.h>
#include "CSAssistgameapi.h"
namespace CSAssist
{
extern void decodeTicketComment(Base::ByteStream::ReadIterator & msg,CSAssistGameAPITicketComment *dest);
extern void decodeDocumentHeader(Base::ByteStream::ReadIterator & msg,CSAssistGameAPIDocumentHeader *dest);
extern void decodeSearchResult(Base::ByteStream::ReadIterator & msg,CSAssistGameAPISearchResult *dest);
namespace Base
{
//using namespace CSAssist;
void put(Base::ByteStream & target, const CSAssistGameAPITicket & source);
void get(ByteStream::ReadIterator & source, CSAssistGameAPITicket & target);
void get(ByteStream::ReadIterator & source, CSAssistGameAPITicket * target);
}
}
#endif
@@ -0,0 +1,207 @@
RELEASE NOTES - CSASSIST GAME API
------------- -----------------
06-22-04 - v2.0.1
* Changed API_VERSION to 201 from 2.
* Added UserID parameter to GetKBArticle and SearchArticle.
* Added HierarchyChangeType to OnIssueHierarchyChange notification.
03-23-04 - V2.00
* Completely Reworked connection mechanism. Added host failover functionality.
* Added CSASSIST_RESULT_SERVER_DISCONNECT result code to indicate connection loss to server.
* Fixed broken character re-registration upon auto-reconnect to backend.
* Added articleTitle to GetKBArticle() request.
* The old API constructor should be replaced with the new one in client code.
12-05-03 - RC2
* Added the throttling from the main line.
* Added the CSASSIST_APIFLAG_NO_REDIRECT option to connect directly to CSAssist avoiding the RedirectServer.
* Patched a leak and crash bug due to the connectCSAssistRequest().
11-24-2003 - RC1
* New API release based on the TCP scalable backend branch.
* Changed functionality of connectCSAssist: Now the API will try to contact an IP Load Balancing
server (RedirecServer) to get the IP of a valid CSAssist server to connect to. This is
all done transparently inside the connectCSAssist() request. The api constructor should now use
the host and port of the RedirectServer, as all connection requests will expect this one hop
handshake. Re-connects (after a disconnect) will also first connect to the RedirectServer and connect to an appropriate CSAssist backend.
* All client/server connections use the Platform utils TCPLibrary.
* requestNewTicketActivity() will now ignore all "closed" tickets - this became an issue due to
the new server architecture using db calls to fetch tickets, not loading them into memory.
*** This release does not contain changes made for the throttling. Need to integrate/merge those changes from the main line udp-only code base.
10-17-2003
* In 10-15 version, during a reconnect, all the cached "register character" requests were placed in the
output buffer en masse, which meant that any new requests coming through the API had to wait until
all the registers were sent, which might take a minute or more. This could result in those new
requests hitting timeouts.
-----------------
05-28-2003
* m_currTrack(0) now initialised as m_currTrack(1). This allows clients to distinguish
between the connection reply (now on track 1), and any server-initiated broadcasts (track=0)
(Internals, no need to worry about this as a user)
* requestNewTicketActivity() and requestGetTicketByCharacter() will now ignore all tickets that are "bug" tickets.
You no longer need to filter out bug-tickets at the application end. You will never be sent a bug-ticket unless
you request it by ID.
04-04-2003
* Versioning code: To ensure that old API's do not connect to new servers, or incompatible API's and servers
do not talk to each other, a transparent versioning layer has been added. The client will now receive one of
two callbacks: OnConnectCSAssist( ) will be received when connection is successful.
OnConnectRejectedCSAssist( ) will be received if the connection was NOT successful. In the later case, the
result code may give some indication of why the connect was rejected, e.g. code 21 = CSASSIST_RESULT_BAD_VERSION.
A result code is still passed back to OnConnectCSAssist( ) for backwards compatibility, although it will always
be CSASSIST_RESULT_SUCCESS (0).
* Primus Knowledge Base searches will now only return results for YOUR game and not all games.
3-17-2003
* Unicode no longer exposed through header files. This should allow EQOA to link with the library without problems.
3-10-2003
* Can not create a ticket without setting the game, server, character and details fields,
using the appropriate setXXX() calls.
3-7-2003
* 3-7 Release. Minor efficiency improvements since 1-31 release.
1-31-2003
* Fixed namespace and include file issue where a Unicode header file was accidently extended through the API
to the client
* Distribution is now monolithic, i.e. all Platform libraries (Base, UdpLibrary, Unicode) are now moved within
the CSAssist namespace to prevent clashes with other versions of these libraries.
1-9-2003
* Fully internationalised. Note that this has caused almost every string parameter to every API call
to change from a char * to a unicode char pointer.
* EstablishConnection NULL bug fixed
* Ticket object modified to add in Bug Reporting fields for Q/A. Bug reports are treated like tickets.
As well as ticket status there is now a bug status field. Set this if the ticket is a bug report.
Two more subcategories have been requested, making a total of 4 now instead of 2. The previous
category and subcategory have been consolidated into a new array of categories, currently 4.
Finally, a location string has been added. Fill this in with the zone/area of the player and his
X,Y,Z coordinates.
For further details of Bug Reporting, see the API documentation and CSAssistgameapi.h and
CSAssistgameobjects.h
* The monolithic constructor for creating a basic ticket has been replaced with a series of setXX()
member functions. See CSAssistgameobjects.h for details. This was done for reasons of clarity
(no huge list of parameters), future expandability and so that individual fields can be validated.
* All dates returned now have full date and time stamps, they were previously just dates (DD-MON-YY).
11-27-2002
* alternative constructor for CSAssistGameAPITicket for a convenient way for the game application
to create a ticket object for use in requestCreateTicket(). Constructor takes only that
info required to create a ticket.
* Application will no longer receive OnConnect() callbacks whenever the API makes an
automatic reconnect to the CSAssist server. The application will only receive callbacks
in response to its own, application-initiated, connect requests.
* In the event of a loss of connection to the CSAssist server, upon reconnection, the API
will automatically submit register requests for all characters previously registered.
This obviates the need for the application/game to issue those register requests.
* The following calls are now functional:
requestGetKBArticle
requestSearchKB
OnIssueHierarchyChanged
* new call: getErrorString(result) is a local blocking call that returns a matching error
string for a result code passed in. This is for debugging/logging only, not for presenting
to the player.
11-13-2002
* API constructor altered to move the default parameters into the header file.
This removes the need for the application to include the default/optional
parameters even if they will not be used
* All parameters in the API constructor made const
* The following calls are now functional:
requestGetDocumentList
requestGetDocument
requestGetTicketXMLBlock
* KNOWN BUG: requestGetTicketXMLBlock has a problem with the DB stored procedure.
It is likely to time out and not return data. You *will* receive an error code,
just note that this call is currently unreliable.
11-08-2002
* As soon as connection is lost with the server, all requests that are queued
at the client API side will be immediately dumped back to the calling
application with a code of CSASSIST_RESULT_TIMEOUT.
This is default behavior, to change this see the description of
CSASSIST_APIFLAG_ASSUME_RECONNECT in CSAssistgameapi.h, and the API docs.
* If a request is made and the API is in a NON-connected state with the server,
the request will be immediately returned with a code of CSASSIST_RESULT_TIMEOUT.
It will NOT be queued as happened previously. Thus the application will
not have to wait for the timeout (60-90 secs) to know that the server
is non-responsive.
* Extra 2 optional parameters to the constructor of the API class:
Timeout, and Flags. See API doc for details.
Your new overloaded constructor will look something like:
apiTest::apiTest(char *host, unsigned port, unsigned timeout = 0, unsigned flags = 0)
: CSAssistGameAPI(host, port, timeout, flags)
* Default timeout reduced from 90 to 60 seconds.
* Parameters to constructor of the API class changed from ints to unsigned
for consistency.
* Additional parameter added to requestGetIssueHierarchy():
"Version String", which is the identifier for the Hierarchy you require.
This is typically a server name but more accurately a server type, e.g.
Dev, Test, Live, PvP, Japan, etc.
11-5-2002
* The following calls are now functional:
requestGetIssueHierarchy
OnRequestGameLocation
replyGameLocation
10-28-2002
* IPAddress parameter removed from connect call
* Character Name added to parameter list for requestAppendTicketComment
10-12-2002
* Note that the directory structure has changed from previous version.
This new structure mirrors all future releases by the Server Engineering team.
* The following calls are now functional:
requestGetTicketCommentsCount
* void *userData added to all calls
10-02-2002
* Deleted requestGetErrorText function as no longer useful
* Expanded CSAssistGameAPITicketComment object (see CSAssistGameobjects.h)
* Parameters changed for requestAppendTicketComment (see CSAssistgameapi.h)
* The following calls are now functional:
requestAppendTicketComment
requestGetTicketComments
requestMarkTicketRead
requestCancelTicket
9-25-2002
* Parameters changed for OnGetTicketByID()
* see CSAssistcsrapi.h for list of new parameters
* The following calls are operational (see notes below):
connectCSAssist
requestNewTicketActivity
requestRegisterCharacter
disconnectCSAssist
requestUnRegisterCharacter
requestCreateTicket
requestGetTicketByCharacter
requstGetTicketByID
OnTicketChange
requestGetErrorText
* The following calls will return dummy data
requestGetIssueHierarchy
requestAppendTicketComment
requestGetTicketComments
* Note that tickets are only RAM-persistent, not database-persistent.
i.e. Tickets will remain alive as long as the test CSAssist server is up
You may want to write a small app to go and generate a batch of test
tickets if you perceive that the Test CSAssist server has been rebooted.
9-20-2002
* Parameters changed for connectCSAssist
* Parameters changed for requestCreateTicket
* see CSAssistgameapi.h for list of new parameters
* linuxtest directory replaced by csassisttest
This has project files to build under WIN32, and
make file to build under linux. (use make -f linux.mak)
@@ -0,0 +1,498 @@
//------------------------------------------------------------------------------
//
// request.cpp
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// Request functions, prepare data to send to servers
//
//------------------------------------------------------------------------------
#include "request.h"
#include "packdata.h"
#include <stdio.h>
namespace CSAssist
{
using namespace Base;
using namespace std;
using namespace Plat_Unicode;
const static unsigned CSASSIST_VERSION_MAGIC = (4 + (256 * 3) + (65536 * 2) + (65536 * 256 * 1));
const static unsigned API_VERSION = 201;
//------------------------------------------------
Request::Request(short type, unsigned track) :
mType(type), mTrack(track), timeout(0)
//----------------------------------------------
{
}
//----------------------------------------------
void Request::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 2;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
}
//----------------------------------------------
//
// Add new Request objects for each API call here
// **** ADD CODE HERE ****
//
//----------------------------------------------
//----------------------------------------------
RConnectCSAssist::RConnectCSAssist(unsigned track, Plat_Unicode::String GameName, const Plat_Unicode::String ServerName)
: Request(CSASSIST_CALL_CONNECT, track),
mGameName(GameName),
mServerName(ServerName)
//----------------------------------------------
{
}
//----------------------------------------------
void RConnectCSAssist::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 4;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, (unsigned)CSASSIST_VERSION_MAGIC);
put(msg, (unsigned)API_VERSION);
put(msg, mGameName);
put(msg, mServerName);
}
//----------------------------------------------
RDisconnectCSAssist::RDisconnectCSAssist(unsigned track)
: Request(CSASSIST_CALL_DISCONNECT, track)
//----------------------------------------------
{
}
//----------------------------------------------
RNewTicketActivity::RNewTicketActivity(unsigned track, const unsigned uid, const Plat_Unicode::String character)
: Request(CSASSIST_CALL_NEWTICKETACTIVITY, track),
mUID(uid),
mCharacter(character)
//----------------------------------------------
{
}
//----------------------------------------------
void RNewTicketActivity::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 4;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mUID);
put(msg, mCharacter);
}
//----------------------------------------------
RRegisterCharacter::RRegisterCharacter(unsigned track, const unsigned uid, const Plat_Unicode::String character, const unsigned avaconID)
: Request(CSASSIST_CALL_REGISTERCHARACTER, track),
mUID(uid),
mCharacter(character),
mAvaconID(avaconID)
//----------------------------------------------
{
}
//----------------------------------------------
void RRegisterCharacter::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 5;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mUID);
put(msg, mCharacter);
put(msg, mAvaconID);
}
//----------------------------------------------
RUnRegisterCharacter::RUnRegisterCharacter(unsigned track, const unsigned uid, const Plat_Unicode::String character)
: Request(CSASSIST_CALL_UNREGISTERCHARACTER, track),
mUID(uid),
mCharacter(character)
//----------------------------------------------
{
}
//----------------------------------------------
void RUnRegisterCharacter::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 4;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mUID);
put(msg, mCharacter);
}
//----------------------------------------------
RGetIssueHierarchy::RGetIssueHierarchy(unsigned track, const Plat_Unicode::String version, const Plat_Unicode::String language)
: Request(CSASSIST_CALL_GETISSUEHIERARCHY, track),
mVersion(version),
mLanguage(language)
//----------------------------------------------
{
}
//----------------------------------------------
void RGetIssueHierarchy::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 4;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mVersion);
put(msg, mLanguage);
}
//----------------------------------------------
RCreateTicket::RCreateTicket(unsigned track, const CSAssistGameAPITicket *ticketBody, const Plat_Unicode::String XMLBody, const unsigned uid)
: Request(CSASSIST_CALL_CREATETICKET, track),
mXMLBody(XMLBody),
mUID(uid)
//----------------------------------------------
{
mTicketStruct = *ticketBody;
}
//----------------------------------------------
void RCreateTicket::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 5;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mTicketStruct);
put(msg, mXMLBody);
put(msg, mUID);
}
//----------------------------------------------
RAppendComment::RAppendComment(unsigned track, const unsigned ticket, const unsigned uid, const Plat_Unicode::String character, const Plat_Unicode::String comment)
: Request(CSASSIST_CALL_APPENDCOMMENT, track),
mTicketID(ticket),
mUID(uid),
mComment(comment),
mCharacter(character)
//----------------------------------------------
{
}
//----------------------------------------------
void RAppendComment::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 6;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mTicketID);
put(msg, mUID);
put(msg, mComment);
put(msg, mCharacter);
}
//----------------------------------------------
RGetTicketByID::RGetTicketByID(unsigned track, const unsigned ticket, const unsigned MarkAsRead)
: Request(CSASSIST_CALL_GETTICKETBYID, track),
mTicketID(ticket),
mMarkAsRead(MarkAsRead)
//----------------------------------------------
{
}
//----------------------------------------------
void RGetTicketByID::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 4;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mTicketID);
put(msg, mMarkAsRead);
}
//----------------------------------------------
RGetTicketComments::RGetTicketComments(unsigned track, const unsigned ticket, const unsigned start, const unsigned count, const unsigned offset)
: Request(CSASSIST_CALL_GETTICKETCOMMENTS, track),
mTicketID(ticket),
mStart(start),
mCount(count),
mOffset(offset)
//----------------------------------------------
{
}
//----------------------------------------------
void RGetTicketComments::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 6;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mTicketID);
put(msg, mStart);
put(msg, mCount);
put(msg, mOffset);
}
//----------------------------------------------
RGetTicketByCharacter::RGetTicketByCharacter(unsigned track, const unsigned uid, const Plat_Unicode::String character, const unsigned Start, const unsigned Count, const unsigned MarkAsRead)
: Request(CSASSIST_CALL_GETTICKET, track),
mUID(uid),
mCharacter(character),
mStart(Start),
mCount(Count),
mMarkAsRead(MarkAsRead)
//----------------------------------------------
{
}
//----------------------------------------------
void RGetTicketByCharacter::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 7;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mUID);
put(msg, mCharacter);
put(msg, mStart);
put(msg, mCount);
put(msg, mMarkAsRead);
}
//----------------------------------------------
RMarkTicketRead::RMarkTicketRead(unsigned track, const unsigned ticket)
: Request(CSASSIST_CALL_MARKREAD, track),
mTicketID(ticket)
//----------------------------------------------
{
}
//----------------------------------------------
void RMarkTicketRead::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 3;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mTicketID);
}
//----------------------------------------------
RCancelTicket::RCancelTicket(unsigned track, const unsigned ticket, const unsigned uid, const Plat_Unicode::String comment)
: Request(CSASSIST_CALL_CANCELTICKET, track),
mTicketID(ticket),
mUID(uid),
mComment(comment)
//----------------------------------------------
{
}
//----------------------------------------------
void RCancelTicket::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 5;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mTicketID);
put(msg, mUID);
put(msg, mComment);
}
//----------------------------------------------
RCommentCount::RCommentCount(unsigned track, const unsigned ticket)
: Request(CSASSIST_CALL_COMMENTCOUNT, track),
mTicketID(ticket)
//----------------------------------------------
{
}
//----------------------------------------------
void RCommentCount::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 3;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mTicketID);
}
//----------------------------------------------
RReplyGameLocation::RReplyGameLocation(unsigned track, const unsigned sourceTrack, const unsigned uid, const Plat_Unicode::String character, const unsigned csruid, const Plat_Unicode::String location)
: Request(CSASSIST_CALL_REPLYLOCATION, track),
mSourceTrack(sourceTrack),
mUID(uid),
mCharacter(character),
mCSRUID(csruid),
mLocationString(location)
//----------------------------------------------
{
}
//----------------------------------------------
void RReplyGameLocation::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 7;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mSourceTrack);
put(msg, mUID);
put(msg, mCharacter);
put(msg, mCSRUID);
put(msg, mLocationString);
}
//----------------------------------------------
RGetDocumentList::RGetDocumentList(unsigned track, Plat_Unicode::String version, Plat_Unicode::String language)
: Request(CSASSIST_CALL_GETDOCUMENTLIST, track), mVersion(version), mLanguage(language)
//----------------------------------------------
{
}
//----------------------------------------------
void RGetDocumentList::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 4;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mVersion);
put(msg, mLanguage);
}
//----------------------------------------------
RGetDocument::RGetDocument(unsigned track, const unsigned id)
: Request(CSASSIST_CALL_GETDOCUMENT, track), mID(id)
//----------------------------------------------
{
}
//----------------------------------------------
void RGetDocument::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 3;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mID);
}
//----------------------------------------------
RGetTicketXMLBlock::RGetTicketXMLBlock(unsigned track, const unsigned id)
: Request(CSASSIST_CALL_GETTICKETXMLBLOCK, track),
mID(id)
//----------------------------------------------
{
}
//----------------------------------------------
void RGetTicketXMLBlock::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 3;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mID);
}
//----------------------------------------------
RGetKBArticle::RGetKBArticle(unsigned track, const Plat_Unicode::String id, const Plat_Unicode::String language, const unsigned uid)
: Request(CSASSIST_CALL_GETKBARTICLE, track),
mID(id),
mLanguage(language),
mUID(uid)
//----------------------------------------------
{
}
//----------------------------------------------
void RGetKBArticle::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 5;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mID);
put(msg, mLanguage);
put(msg, mUID);
}
//----------------------------------------------
RSearchKB::RSearchKB(unsigned track, const Plat_Unicode::String searchstring, const Plat_Unicode::String language, const unsigned uid)
: Request(CSASSIST_CALL_SEARCHKB, track),
mSearchString(searchstring),
mLanguage(language),
mUID(uid)
//----------------------------------------------
{
}
//----------------------------------------------
void RSearchKB::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 5;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mSearchString);
put(msg, mLanguage);
put(msg, mUID);
}
//----------------------------------------------
RConnectLB::RConnectLB(unsigned track, const std::string connectString)
: Request(CSASSIST_CALL_CONNECTLB, track),
mConnectString(connectString)
//----------------------------------------------
{
setTimeout(time(0) + 5);
}
//----------------------------------------------
void RConnectLB::pack(ByteStream &msg)
//----------------------------------------------
{
short num_args = 3;
put(msg, num_args);
put(msg, mType);
put(msg, mTrack);
put(msg, mConnectString);
}
} // namespace CSAssist
@@ -0,0 +1,355 @@
#ifndef REQUEST_H
#define REQUEST_H
//------------------------------------------------------------------------------
//
// request.h
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// Class definitions for all user-initiated requests
//
//------------------------------------------------------------------------------
#include "Base/Archive.h"
#include "Unicode/UnicodeUtils.h"
#include "CSAssistgameapi.h"
#include "CSAssistgameobjects.h"
namespace CSAssist
{
// ----- Add all new messages to this list! -----
// **** ADD CODE HERE ****
enum SubCMessage
{
CSASSIST_CALL_CONNECT, // 0
CSASSIST_CALL_DISCONNECT, // 1
CSASSIST_CALL_NEWTICKETACTIVITY, // 2
CSASSIST_CALL_REGISTERCHARACTER, // 3
CSASSIST_CALL_UNREGISTERCHARACTER, // 4
CSASSIST_CALL_ERRORTEXT, // 5
CSASSIST_CALL_GETISSUEHIERARCHY, // 6
CSASSIST_CALL_CREATETICKET, // 7
CSASSIST_CALL_APPENDCOMMENT, // 8
CSASSIST_CALL_GETTICKETBYID, // 9
CSASSIST_CALL_GETTICKETCOMMENTS, // 10
CSASSIST_CALL_GETTICKET, // 11
CSASSIST_CALL_MARKREAD, // 12
CSASSIST_CALL_CANCELTICKET, // 13
CSASSIST_CALL_COMMENTCOUNT, // 14
CSASSIST_CALL_REPLYLOCATION, // 15
CSASSIST_CALL_GETDOCUMENTLIST, // 16
CSASSIST_CALL_GETDOCUMENT, // 17
CSASSIST_CALL_GETTICKETXMLBLOCK, // 18
CSASSIST_CALL_GETKBARTICLE, // 19
CSASSIST_CALL_SEARCHKB, // 20
// insert API message types above this line
CSASSIST_CALL_REQUEST_MAX, // 21 - always needs to be last of API messages
CSASSIST_CALL_CONNECTLB = 2001, // only used internally to connect to connection-load balancing server
CSASSIST_CALL_START_SERVER_MESSAGES=10000,
// insert server-initiated message types below this line
CSASSIST_SERVER_TICKETCHANGE, // 10001
CSASSIST_SERVER_BROADCASTTICKET, // 10002
CSASSIST_SERVER_BROADCASTCOMMENT, // 10003
CSASSIST_SERVER_REQUESTLOCATION, // 10004
CSASSIST_SERVER_REPORTLOCATION, // 10005
CSASSIST_SERVER_HIERARCHYCHANGE // 10006
};
//----------------------------------------------
class Request
//----------------------------------------------
{
public:
Request(short type, unsigned track);
virtual ~Request() { }
unsigned getType() { return (unsigned)mType; }
unsigned getTrack() { return mTrack; }
void setTimeout(unsigned t) { timeout = t; }
unsigned getTimeout() { return timeout; }
virtual void pack(Base::ByteStream &msg);
protected:
short mType;
unsigned mTrack;
private:
unsigned timeout;
};
//----------------------------------------------
//
// Add new Request objects for each API call here
//
// **** ADD CODE HERE ****
//----------------------------------------------
//----------------------------------------------
class RConnectCSAssist : public Request
//----------------------------------------------
{
public:
RConnectCSAssist(unsigned track, const Plat_Unicode::String GameName, const Plat_Unicode::String ServerName);
virtual void pack(Base::ByteStream &msg);
private:
Plat_Unicode::String mGameName;
Plat_Unicode::String mServerName;
};
//----------------------------------------------
class RDisconnectCSAssist : public Request
//----------------------------------------------
{
public:
RDisconnectCSAssist(unsigned track);
private:
};
//----------------------------------------------
class RNewTicketActivity : public Request
//----------------------------------------------
{
public:
RNewTicketActivity(unsigned track, const unsigned uid, const Plat_Unicode::String character);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mUID;
Plat_Unicode::String mCharacter;
};
//----------------------------------------------
class RRegisterCharacter : public Request
//----------------------------------------------
{
public:
RRegisterCharacter(unsigned track, const unsigned uid, const Plat_Unicode::String character, const unsigned avaconID);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mUID;
Plat_Unicode::String mCharacter;
unsigned mAvaconID;
};
//----------------------------------------------
class RUnRegisterCharacter : public Request
//----------------------------------------------
{
public:
RUnRegisterCharacter(unsigned track, const unsigned uid, const Plat_Unicode::String character);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mUID;
Plat_Unicode::String mCharacter;
};
//----------------------------------------------
class RGetIssueHierarchy : public Request
//----------------------------------------------
{
public:
RGetIssueHierarchy(unsigned track, const Plat_Unicode::String version, const Plat_Unicode::String language);
virtual void pack(Base::ByteStream &msg);
private:
Plat_Unicode::String mVersion;
Plat_Unicode::String mLanguage;
};
//----------------------------------------------
class RCreateTicket : public Request
//----------------------------------------------
{
public:
RCreateTicket(unsigned track, const CSAssistGameAPITicket *ticketBody, const Plat_Unicode::String XMLBody, const unsigned uid);
virtual void pack(Base::ByteStream &msg);
private:
CSAssistGameAPITicket mTicketStruct;
Plat_Unicode::String mXMLBody;
unsigned mUID;
};
//----------------------------------------------
class RAppendComment : public Request
//----------------------------------------------
{
public:
RAppendComment(unsigned track, const unsigned ticket, const unsigned uid, const Plat_Unicode::String character, const Plat_Unicode::String comment);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mTicketID;
unsigned mUID;
Plat_Unicode::String mComment;
Plat_Unicode::String mCharacter;
};
//----------------------------------------------
class RGetTicketByID : public Request
//----------------------------------------------
{
public:
RGetTicketByID(unsigned track, const unsigned ticket, const unsigned MarkAsRead);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mTicketID;
unsigned mMarkAsRead;
};
//----------------------------------------------
class RGetTicketComments : public Request
//----------------------------------------------
{
public:
RGetTicketComments(unsigned track, const unsigned ticket, const unsigned start, const unsigned count, const unsigned offset);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mTicketID;
unsigned mStart;
unsigned mCount;
unsigned mOffset;
};
//----------------------------------------------
class RGetTicketByCharacter : public Request
//----------------------------------------------
{
public:
RGetTicketByCharacter(unsigned track, const unsigned uid, const Plat_Unicode::String character, const unsigned Start, const unsigned Count, const unsigned MarkAsRead);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mUID;
Plat_Unicode::String mCharacter;
unsigned mStart;
unsigned mCount;
unsigned mMarkAsRead;
};
//----------------------------------------------
class RMarkTicketRead : public Request
//----------------------------------------------
{
public:
RMarkTicketRead(unsigned track, const unsigned ticket);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mTicketID;
};
//----------------------------------------------
class RCancelTicket : public Request
//----------------------------------------------
{
public:
RCancelTicket(unsigned track, const unsigned ticket, const unsigned uid, const Plat_Unicode::String comment);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mTicketID;
unsigned mUID;
Plat_Unicode::String mComment;
};
//----------------------------------------------
class RCommentCount : public Request
//----------------------------------------------
{
public:
RCommentCount(unsigned track, const unsigned ticket);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mTicketID;
};
//----------------------------------------------
class RReplyGameLocation : public Request
//----------------------------------------------
{
public:
RReplyGameLocation(unsigned track, const unsigned sourceTrack, const unsigned uid, const Plat_Unicode::String character, const unsigned csruid, const Plat_Unicode::String locationString);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mSourceTrack;
unsigned mUID;
Plat_Unicode::String mCharacter;
unsigned mCSRUID;
Plat_Unicode::String mLocationString;
};
//----------------------------------------------
class RGetDocumentList : public Request
//----------------------------------------------
{
public:
RGetDocumentList(unsigned track, Plat_Unicode::String version, Plat_Unicode::String language);
virtual void pack(Base::ByteStream &msg);
private:
Plat_Unicode::String mVersion;
Plat_Unicode::String mLanguage;
};
//----------------------------------------------
class RGetDocument : public Request
//----------------------------------------------
{
public:
RGetDocument(unsigned track, const unsigned id);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mID;
};
//----------------------------------------------
class RGetTicketXMLBlock : public Request
//----------------------------------------------
{
public:
RGetTicketXMLBlock(unsigned track, const unsigned id);
virtual void pack(Base::ByteStream &msg);
private:
unsigned mID;
};
//----------------------------------------------
class RGetKBArticle : public Request
//----------------------------------------------
{
public:
RGetKBArticle(unsigned track, const Plat_Unicode::String id, const Plat_Unicode::String language, const unsigned uid);
virtual void pack(Base::ByteStream &msg);
private:
Plat_Unicode::String mID;
Plat_Unicode::String mLanguage;
unsigned mUID;
};
//----------------------------------------------
class RSearchKB : public Request
//----------------------------------------------
{
public:
RSearchKB(unsigned track, const Plat_Unicode::String searchstring, const Plat_Unicode::String language, const unsigned uid);
virtual void pack(Base::ByteStream &msg);
private:
Plat_Unicode::String mSearchString;
Plat_Unicode::String mLanguage;
unsigned mUID;
};
//----------------------------------------------
class RConnectLB : public Request
//----------------------------------------------
{
public:
RConnectLB(unsigned track, const std::string connectString);
virtual void pack(Base::ByteStream &msg);
private:
std::string mConnectString;
};
} // namespace CSAssist
#endif
@@ -0,0 +1,582 @@
//------------------------------------------------------------------------------
//
// CSAssistgameapi.cpp
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// Response functions, process data from the servers
//
//------------------------------------------------------------------------------
#pragma warning (disable: 4786)
#include "response.h"
namespace CSAssist
{
using namespace Base;
using namespace std;
extern CSAssistUnicodeChar *get_c_str(Plat_Unicode::String s);
extern CSAssistUnicodeChar *copy_c_str(Plat_Unicode::String s, CSAssistUnicodeChar *dest);
//----------------------------------------------
Response::Response(unsigned type, unsigned track, const void *userData)
: mType(type),
mTrack(track),
mResult(CSASSIST_RESULT_TIMEOUT)
//----------------------------------------------
{
muserData = (void *)userData;
//fprintf(stderr,"Response(%p) type(%d),track(%d)\n", this, mType,mTrack);
}
Response::~Response()
{
//fprintf(stderr,"~Response(%p) type(%d),track(%d)\n", this,mType,mTrack);
}
//----------------------------------------------
void Response::decode(ByteStream::ReadIterator &msg)
//----------------------------------------------
{
}
//----------------------------------------------
//
// Add new Response objects for each API call here
//
// **** ADD CODE HERE ****
//----------------------------------------------
//----------------------------------------------
ResConnectCSAssist::ResConnectCSAssist(unsigned track, const void *userData)
: Response(CSASSIST_CALL_CONNECT, track, userData)
//----------------------------------------------
{
}
//----------------------------------------------
ResDisconnectCSAssist::ResDisconnectCSAssist(unsigned track, const void *userData)
: Response(CSASSIST_CALL_DISCONNECT, track, userData)
//----------------------------------------------
{
}
//----------------------------------------------
ResNewTicketActivity::ResNewTicketActivity(unsigned track, const void *userData)
: Response(CSASSIST_CALL_NEWTICKETACTIVITY, track, userData), mNewActivityFlag(0), mHasTickets(0)
//----------------------------------------------
{
}
ResNewTicketActivity::~ResNewTicketActivity()
{
}
//----------------------------------------------
void ResNewTicketActivity::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg, mNewActivityFlag);
get(msg, mHasTickets);
}
//----------------------------------------------
ResRegisterCharacter::ResRegisterCharacter(unsigned track, const void *userData)
: Response(CSASSIST_CALL_REGISTERCHARACTER, track, userData)
//----------------------------------------------
{
}
//----------------------------------------------
ResUnRegisterCharacter::ResUnRegisterCharacter(unsigned track, const void *userData)
: Response(CSASSIST_CALL_UNREGISTERCHARACTER, track, userData)
//----------------------------------------------
{
}
//----------------------------------------------
ResGetIssueHierarchy::ResGetIssueHierarchy(unsigned track, const void *userData)
: Response(CSASSIST_CALL_GETISSUEHIERARCHY, track, userData), mModifyDate(0), rawStringPtr(0)
//----------------------------------------------
{
}
//----------------------------------------------
ResGetIssueHierarchy::~ResGetIssueHierarchy()
//----------------------------------------------
{
if (rawStringPtr)
delete [] rawStringPtr;
}
//----------------------------------------------
void ResGetIssueHierarchy::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg, mHierarchyBody);
get(msg, mModifyDate);
rawStringPtr = get_c_str(mHierarchyBody);
}
//----------------------------------------------
ResCreateTicket::ResCreateTicket(unsigned track, const void *userData)
: Response(CSASSIST_CALL_CREATETICKET, track, userData), mTicketID(0)
//----------------------------------------------
{
}
ResCreateTicket::~ResCreateTicket()
{
}
//----------------------------------------------
void ResCreateTicket::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg, mTicketID);
}
//----------------------------------------------
ResAppendComment::ResAppendComment(unsigned track, const void *userData)
: Response(CSASSIST_CALL_APPENDCOMMENT, track, userData), mTicketID(0)
//----------------------------------------------
{
}
ResAppendComment::~ResAppendComment()
{
}
//----------------------------------------------
void ResAppendComment::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg, mTicketID);
}
//----------------------------------------------
ResGetTicketByID::ResGetTicketByID(unsigned track, const void *userData)
: Response(CSASSIST_CALL_GETTICKETBYID, track, userData), mTicketBody(CSAssist::CSAssistGameAPITicket())
//----------------------------------------------
{
}
ResGetTicketByID::~ResGetTicketByID()
{
}
//----------------------------------------------
void ResGetTicketByID::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg, mTicketBody);
}
//----------------------------------------------
ResGetTicketComments::ResGetTicketComments(unsigned track, const void *userData)
: Response(CSASSIST_CALL_GETTICKETCOMMENTS, track, userData), mNumberRead(0), mCommentArray(0)
//----------------------------------------------
{
}
//----------------------------------------------
ResGetTicketComments::~ResGetTicketComments()
//----------------------------------------------
{
if (mCommentArray != 0)
delete [] mCommentArray; // be sure to free up any resources!
}
//----------------------------------------------
void ResGetTicketComments::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg,mNumberRead);
mCommentArray = 0;
if (mNumberRead > 0)
{
mCommentArray = new CSAssistGameAPITicketComment[mNumberRead];
if (mCommentArray == 0) // memory allocation error, return error code
{
mNumberRead = 0;
setResult(CSASSIST_RESULT_OUTOFMEMORY);
return;
}
CSAssistGameAPITicketComment *pcomments = mCommentArray;
for (unsigned i=0; i < mNumberRead; i++)
{
decodeTicketComment(msg, pcomments);
pcomments++;
}
}
}
//----------------------------------------------
ResGetTicketByCharacter::ResGetTicketByCharacter(unsigned track, const void *userData)
: Response(CSASSIST_CALL_GETTICKET, track, userData), mNumberReturned(0), mTotalNumber(0), mTicketArray(0)
//----------------------------------------------
{
}
//----------------------------------------------
ResGetTicketByCharacter::~ResGetTicketByCharacter()
//----------------------------------------------
{
if (mTicketArray != 0)
delete [] mTicketArray; // be sure to free up any resources!
}
//----------------------------------------------
void ResGetTicketByCharacter::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg, mNumberReturned);
get(msg, mTotalNumber);
mTicketArray = 0;
if (mNumberReturned > 0)
{
mTicketArray = new CSAssistGameAPITicket[mNumberReturned];
if (mTicketArray == 0) // memory allocation error, return error code
{
mNumberReturned = 0;
mTotalNumber = 0;
setResult(CSASSIST_RESULT_OUTOFMEMORY);
return;
}
CSAssistGameAPITicket *ptickets = mTicketArray;
for (unsigned i=0; i < mNumberReturned; i++)
{
get(msg, ptickets);
ptickets++;
}
}
}
//----------------------------------------------
ResTicketChange::ResTicketChange(unsigned track)
: Response(CSASSIST_SERVER_TICKETCHANGE, track, 0), mTicketID(0), mUID(0), rawCharacter(0)
//----------------------------------------------
{
}
//----------------------------------------------
ResTicketChange::~ResTicketChange()
//----------------------------------------------
{
if (rawCharacter)
delete [] rawCharacter;
}
//----------------------------------------------
void ResTicketChange::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg, mTicketID);
get(msg, mUID);
get(msg, mCharacter);
rawCharacter = get_c_str(mCharacter);
}
//----------------------------------------------
ResMarkTicketRead::ResMarkTicketRead(unsigned track, const void *userData)
: Response(CSASSIST_CALL_MARKREAD, track, userData)
//----------------------------------------------
{
}
//----------------------------------------------
ResCancelTicket::ResCancelTicket(unsigned track, const void *userData)
: Response(CSASSIST_CALL_CANCELTICKET, track, userData), mTicketID(0)
//----------------------------------------------
{
}
ResCancelTicket::~ResCancelTicket()
{
}
//----------------------------------------------
void ResCancelTicket::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg, mTicketID);
}
//----------------------------------------------
ResCommentCount::ResCommentCount(unsigned track, const void *userData)
: Response(CSASSIST_CALL_COMMENTCOUNT, track, userData), mTicketID(0), mCount(0)
//----------------------------------------------
{
}
ResCommentCount::~ResCommentCount()
{
}
//----------------------------------------------
void ResCommentCount::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg, mTicketID);
get(msg, mCount);
}
//----------------------------------------------
ResRequestGameLocation::ResRequestGameLocation(unsigned track)
: Response(CSASSIST_SERVER_REQUESTLOCATION, track, 0), mSourceTrack(0), mUID(0), mCSRUID(0),
rawCharacter(0)
//----------------------------------------------
{
}
//----------------------------------------------
ResRequestGameLocation::~ResRequestGameLocation()
//----------------------------------------------
{
if (rawCharacter)
delete [] rawCharacter;
}
//----------------------------------------------
void ResRequestGameLocation::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg,mSourceTrack);
get(msg,mUID);
get(msg,mCharacter);
get(msg,mCSRUID);
rawCharacter = get_c_str(mCharacter);
}
//----------------------------------------------
ResReplyGameLocation::ResReplyGameLocation(unsigned track, const void *userData)
: Response(CSASSIST_CALL_REPLYLOCATION, track, userData)
//----------------------------------------------
{
}
//----------------------------------------------
ResGetDocumentList::ResGetDocumentList(unsigned track, const void *userData)
: Response(CSASSIST_CALL_GETDOCUMENTLIST, track, userData), mNumberRead(0), mDocumentArray(0)
//----------------------------------------------
{
}
//----------------------------------------------
ResGetDocumentList::~ResGetDocumentList()
//----------------------------------------------
{
if (mDocumentArray != 0)
delete [] mDocumentArray; // be sure to free up any resources!
}
//----------------------------------------------
void ResGetDocumentList::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg,mNumberRead);
mDocumentArray = 0;
if (mNumberRead > 0)
{
mDocumentArray = new CSAssistGameAPIDocumentHeader[mNumberRead];
if (mDocumentArray == 0) // memory allocation error, return error code
{
mNumberRead = 0;
setResult(CSASSIST_RESULT_OUTOFMEMORY);
return;
}
CSAssistGameAPIDocumentHeader *pdocs = mDocumentArray;
for (unsigned i=0; i < mNumberRead; i++)
{
decodeDocumentHeader(msg, pdocs);
pdocs++;
}
}
}
//----------------------------------------------
ResGetDocument::ResGetDocument(unsigned track, const void *userData)
: Response(CSASSIST_CALL_GETDOCUMENT, track, userData), rawDocument(0)
//----------------------------------------------
{
}
//----------------------------------------------
ResGetDocument::~ResGetDocument()
//----------------------------------------------
{
if (rawDocument)
delete [] rawDocument;
}
//----------------------------------------------
void ResGetDocument::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg,mDocumentBody);
rawDocument = get_c_str(mDocumentBody);
}
//----------------------------------------------
ResGetTicketXMLBlock::ResGetTicketXMLBlock(unsigned track, const void *userData)
: Response(CSASSIST_CALL_GETTICKETXMLBLOCK, track, userData), rawXML(0)
//----------------------------------------------
{
}
//----------------------------------------------
ResGetTicketXMLBlock::~ResGetTicketXMLBlock()
//----------------------------------------------
{
if (rawXML)
delete [] rawXML;
}
//----------------------------------------------
void ResGetTicketXMLBlock::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg,mXMLBody);
rawXML = get_c_str(mXMLBody);
}
//----------------------------------------------
ResGetKBArticle::ResGetKBArticle(unsigned track, const void *userData)
: Response(CSASSIST_CALL_GETKBARTICLE, track, userData), rawArticle(0), rawTitle(0)
//----------------------------------------------
{
}
//----------------------------------------------
ResGetKBArticle::~ResGetKBArticle()
//----------------------------------------------
{
if (rawArticle)
delete [] rawArticle;
if (rawTitle)
delete [] rawTitle;
}
//----------------------------------------------
void ResGetKBArticle::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg,mArticleBody);
rawArticle = get_c_str(mArticleBody);
// don't try to read title from older servers
if (msg.getSize() <= 0)
return;
get(msg,mArticleTitle);
rawTitle = get_c_str(mArticleTitle);
}
//----------------------------------------------
ResSearchKB::ResSearchKB(unsigned track, const void *userData)
: Response(CSASSIST_CALL_SEARCHKB, track, userData), mNumberRead(0), mArticleArray(0)
//----------------------------------------------
{
}
//----------------------------------------------
ResSearchKB::~ResSearchKB()
//----------------------------------------------
{
if (mArticleArray != 0)
delete [] mArticleArray; // be sure to free up any resources!
}
//----------------------------------------------
void ResSearchKB::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg, mNumberRead);
mArticleArray = 0;
if (mNumberRead > 0)
{
mArticleArray = new CSAssistGameAPISearchResult[mNumberRead];
if (mArticleArray == 0) // memory allocation error, return error code
{
mNumberRead = 0;
setResult(CSASSIST_RESULT_OUTOFMEMORY);
return;
}
CSAssistGameAPISearchResult *pdocs = mArticleArray;
for (unsigned i=0; i < mNumberRead; i++)
{
decodeSearchResult(msg, pdocs);
pdocs++;
}
}
}
//----------------------------------------------
ResHierarchyChange::ResHierarchyChange(unsigned track)
: Response(CSASSIST_SERVER_HIERARCHYCHANGE, track, 0),
rawGame(0), rawVersion(0), rawLanguage(0), mChangeType(CSASSIST_HIERARCHY_NONE)
//----------------------------------------------
{
}
ResHierarchyChange::~ResHierarchyChange()
{
if (rawGame)
delete [] rawGame;
if (rawVersion)
delete [] rawVersion;
if (rawLanguage)
delete [] rawLanguage;
}
//----------------------------------------------
void ResHierarchyChange::decode(Base::ByteStream::ReadIterator &msg)
//----------------------------------------------
{
get(msg,mGame);
get(msg,mVersion);
get(msg,mLanguage);
rawGame = get_c_str(mGame);
rawVersion = get_c_str(mVersion);
rawLanguage = get_c_str(mLanguage);
get(msg, mChangeType);
}
ResConnectLB::ResConnectLB(unsigned track, Request *req, Response *res)
: Response(CSASSIST_CALL_CONNECTLB, track, 0),
mServerPort(0),
mConnectRequest(req),
mConnectResponse(res)
{
//fprintf(stderr,"Const:Req=%p,Res=%p\n", mConnectRequest,mConnectResponse);
}
ResConnectLB::~ResConnectLB()
{
if (mResult == CSASSIST_RESULT_TIMEOUT)
{
//fprintf(stderr,"Dest: Req=%p,Res=%p\n", mConnectRequest,mConnectResponse);
delete mConnectRequest;
delete mConnectResponse;
}
}
void ResConnectLB::decode(Base::ByteStream::ReadIterator &msg)
{
get(msg, mServerName);
get(msg, mServerPort);
}
} // namespace CSAssist
@@ -0,0 +1,405 @@
#ifndef RESPONSE_H
#define RESPONSE_H
//------------------------------------------------------------------------------
//
// response.h
//
// Author: Graeme Ing ([email protected])
// Module: CSAssist API
//
// copyright 2002 (c) Sony Online Entertainment Inc.
//
// Class definitions for all response objects from servers
//
//------------------------------------------------------------------------------
#include "Base/Archive.h"
#include "CSAssistgameapicore.h"
#include "request.h"
namespace CSAssist
{
//------------------------------------------------
class Response
//------------------------------------------------
{
public:
Response(unsigned type, unsigned track, const void *muserData);
virtual ~Response();
unsigned getType() { return (unsigned)mType; }
virtual CSAssistGameAPITrack getTrack() { return (CSAssistGameAPITrack)mTrack; }
virtual CSAssistGameAPIResult getResult() { return (CSAssistGameAPIResult)mResult; }
inline void *getUserData() { return muserData; }
inline void init(short type, unsigned track, unsigned result)
{ mType = type; mTrack = track; mResult = result; }
inline void setResult(unsigned result) { mResult = result; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
protected:
short mType;
unsigned mTrack;
unsigned mResult;
void *muserData;
};
//----------------------------------------------
//
// Add new Response objects for each API call here
//
// **** ADD CODE HERE ****
//----------------------------------------------
//------------------------------------------------
class ResConnectCSAssist : public Response
//------------------------------------------------
{
public:
ResConnectCSAssist(unsigned track, const void *userData);
private:
};
//------------------------------------------------
class ResDisconnectCSAssist : public Response
//------------------------------------------------
{
public:
ResDisconnectCSAssist(unsigned track, const void *userData);
private:
};
//------------------------------------------------
class ResNewTicketActivity : public Response
//------------------------------------------------
{
public:
ResNewTicketActivity(unsigned track, const void *userData);
~ResNewTicketActivity();
inline unsigned getNewActivityFlag() { return mNewActivityFlag; }
inline unsigned getHasTickets() { return mHasTickets; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mNewActivityFlag;
unsigned mHasTickets;
};
//------------------------------------------------
class ResRegisterCharacter : public Response
//------------------------------------------------
{
public:
ResRegisterCharacter(unsigned track, const void *userData);
private:
};
//------------------------------------------------
class ResUnRegisterCharacter : public Response
//------------------------------------------------
{
public:
ResUnRegisterCharacter(unsigned track, const void *userData);
private:
};
//------------------------------------------------
class ResGetIssueHierarchy : public Response
//------------------------------------------------
{
public:
ResGetIssueHierarchy(unsigned track, const void *userData);
virtual ~ResGetIssueHierarchy();
inline CSAssistUnicodeChar *getHierarchyBody() { return rawStringPtr; }
inline unsigned getModifyDate() { return mModifyDate; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
Plat_Unicode::String mHierarchyBody;
unsigned mModifyDate;
CSAssistUnicodeChar *rawStringPtr;
};
//------------------------------------------------
class ResCreateTicket : public Response
//------------------------------------------------
{
public:
ResCreateTicket(unsigned track, const void *userData);
~ResCreateTicket();
inline unsigned getTicketID() { return mTicketID; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mTicketID;
};
//------------------------------------------------
class ResAppendComment : public Response
//------------------------------------------------
{
public:
ResAppendComment(unsigned track, const void *userData);
~ResAppendComment();
inline unsigned getTicketID() { return mTicketID; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mTicketID;
};
//------------------------------------------------
class ResGetTicketByID : public Response
//------------------------------------------------
{
public:
ResGetTicketByID(unsigned track, const void *userData);
~ResGetTicketByID();
inline CSAssistGameAPITicket &getTicketBody() { return (CSAssistGameAPITicket &)mTicketBody; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
CSAssistGameAPITicket mTicketBody;
};
//------------------------------------------------
class ResGetTicketComments : public Response
//------------------------------------------------
{
public:
ResGetTicketComments(unsigned track, const void *userData);
~ResGetTicketComments();
inline unsigned getNumberRead() { return mNumberRead; }
inline CSAssistGameAPITicketComment *getCommentArray() { return mCommentArray; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mNumberRead;
CSAssistGameAPITicketComment *mCommentArray;
};
//------------------------------------------------
class ResGetTicketByCharacter : public Response
//------------------------------------------------
{
public:
ResGetTicketByCharacter(unsigned track, const void *userData);
~ResGetTicketByCharacter();
inline unsigned getNumberReturned() { return mNumberReturned; }
inline unsigned getTotalNumber() { return mTotalNumber; }
inline CSAssistGameAPITicket *getTicketArray() { return mTicketArray; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mNumberReturned;
unsigned mTotalNumber;
CSAssistGameAPITicket *mTicketArray;
};
//------------------------------------------------
class ResTicketChange : public Response
//------------------------------------------------
{
public:
ResTicketChange(unsigned track);
~ResTicketChange();
inline unsigned getTicketID() { return mTicketID; }
inline unsigned getUID() { return mUID; }
inline CSAssistUnicodeChar *getCharacter() { return rawCharacter; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mTicketID;
unsigned mUID;
Plat_Unicode::String mCharacter;
CSAssistUnicodeChar *rawCharacter;
};
//------------------------------------------------
class ResMarkTicketRead : public Response
//------------------------------------------------
{
public:
ResMarkTicketRead(unsigned track, const void *userData);
private:
};
//------------------------------------------------
class ResCancelTicket : public Response
//------------------------------------------------
{
public:
ResCancelTicket(unsigned track, const void *userData);
~ResCancelTicket();
inline unsigned getTicketID() { return mTicketID; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mTicketID;
};
//------------------------------------------------
class ResCommentCount : public Response
//------------------------------------------------
{
public:
ResCommentCount(unsigned track, const void *userData);
~ResCommentCount();
inline unsigned getTicketID() { return mTicketID; }
inline unsigned getCount() { return mCount; };
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mTicketID;
unsigned mCount;
};
//------------------------------------------------
class ResRequestGameLocation : public Response
//------------------------------------------------
{
public:
ResRequestGameLocation(unsigned track);
~ResRequestGameLocation();
inline unsigned getSourceTrack() { return mSourceTrack; }
inline unsigned getUID() { return mUID; }
inline CSAssistUnicodeChar *getCharacter() { return rawCharacter; }
inline unsigned getCSRUID() { return mCSRUID; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mSourceTrack;
unsigned mUID;
Plat_Unicode::String mCharacter;
unsigned mCSRUID;
CSAssistUnicodeChar *rawCharacter;
};
//------------------------------------------------
class ResReplyGameLocation : public Response
//------------------------------------------------
{
public:
ResReplyGameLocation(unsigned track, const void *userData);
private:
};
//------------------------------------------------
class ResGetDocumentList : public Response
//------------------------------------------------
{
public:
ResGetDocumentList(unsigned track, const void *userData);
virtual ~ResGetDocumentList();
inline unsigned getNumberRead() { return mNumberRead; }
inline CSAssistGameAPIDocumentHeader *getDocumentList() { return mDocumentArray; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mNumberRead;
CSAssistGameAPIDocumentHeader *mDocumentArray;
};
//------------------------------------------------
class ResGetDocument : public Response
//------------------------------------------------
{
public:
ResGetDocument(unsigned track, const void *userData);
virtual ~ResGetDocument();
inline CSAssistUnicodeChar *getDocumentBody() { return rawDocument; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
Plat_Unicode::String mDocumentBody;
CSAssistUnicodeChar *rawDocument;
};
//------------------------------------------------
class ResGetTicketXMLBlock : public Response
//------------------------------------------------
{
public:
ResGetTicketXMLBlock(unsigned track, const void *userData);
~ResGetTicketXMLBlock();
inline CSAssistUnicodeChar *getXMLBody() { return rawXML; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
Plat_Unicode::String mXMLBody;
CSAssistUnicodeChar *rawXML;
};
//------------------------------------------------
class ResGetKBArticle : public Response
//------------------------------------------------
{
public:
ResGetKBArticle(unsigned track, const void *userData);
~ResGetKBArticle();
inline CSAssistUnicodeChar *getArticleBody() { return rawArticle; }
inline CSAssistUnicodeChar *getArticleTitle() { return rawTitle; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
Plat_Unicode::String mArticleBody;
CSAssistUnicodeChar *rawArticle;
Plat_Unicode::String mArticleTitle;
CSAssistUnicodeChar *rawTitle;
};
//------------------------------------------------
class ResSearchKB : public Response
//------------------------------------------------
{
public:
ResSearchKB(unsigned track, const void *userData);
~ResSearchKB();
inline unsigned getNumberRead() { return mNumberRead; }
inline CSAssistGameAPISearchResult *getArticleList() { return mArticleArray; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
unsigned mNumberRead;
CSAssistGameAPISearchResult *mArticleArray;
};
//------------------------------------------------
class ResHierarchyChange : public Response
//------------------------------------------------
{
public:
ResHierarchyChange(unsigned track);
~ResHierarchyChange();
inline CSAssistUnicodeChar *getGame() { return rawGame; }
inline CSAssistUnicodeChar *getVersion() { return rawVersion; }
inline CSAssistUnicodeChar *getLanguage() { return rawLanguage; }
inline CSAssistGameAPIHierarchyChangeType getChangeType() { return (CSAssistGameAPIHierarchyChangeType)mChangeType; }
virtual void decode(Base::ByteStream::ReadIterator &msg);
private:
Plat_Unicode::String mGame;
Plat_Unicode::String mVersion;
Plat_Unicode::String mLanguage;
CSAssistUnicodeChar *rawGame;
CSAssistUnicodeChar *rawVersion;
CSAssistUnicodeChar *rawLanguage;
unsigned mChangeType;
};
//------------------------------------------------
class ResConnectLB : public Response
//------------------------------------------------
{
public:
ResConnectLB(unsigned track, Request *req, Response *res);
~ResConnectLB();
virtual void decode(Base::ByteStream::ReadIterator &msg);
inline std::string getServerName() { return mServerName; }
inline unsigned getServerPort() { return mServerPort; }
Request *getRequest() { return mConnectRequest; }
Response *getResponse() { return mConnectResponse; }
private:
std::string mServerName;
unsigned short mServerPort;
Request *mConnectRequest;
Response *mConnectResponse;
};
} // namespace CSAssist
#endif
@@ -0,0 +1,286 @@
////////////////////////////////////////////////////////////////////////////////
// The author of this code is Justin Randall
//
// I have made modifications to the ByteStream
// and AutoByteStream classes in order to make them suitable
// for use in messaging systems which require objects that
// are copyable and assignable. It is also desirable for
// the ByteStream object to use a flexible allocator system
// that may support multi-threaded programming models.
#include "Archive.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
////////////////////////////////////////////////////////////////////////////////
#if defined(USE_ARCHIVE_MUTEX)
CMutex ByteStreamMutex;
#endif
// Default to Data object reuse
bool ByteStream::ms_reuseData = true;
#if defined (PASCAL_STRING)
#pragma message ("--- Packing pascal style strings ---")
void get(Base::ByteStream::ReadIterator& source, std::string& target)
{
unsigned int size = 0;
Base::get (source, size);
const unsigned char *buf = source.getBuffer();
target.assign((const char *)buf, (const char *)(buf + size));
const unsigned int readSize = size * sizeof(char);
source.advance(readSize);
}
void put(ByteStream& target, const std::string& source)
{
const unsigned int size = source.size();
put(target, size);
target.put(source.data(), size * sizeof (char));
}
#else
#pragma message ("--- Packing c style strings ---")
void get(ByteStream::ReadIterator & source, std::string & target)
{
target = reinterpret_cast<const char *>(source.getBuffer());
source.advance(target.length() + 1);
}
void put(ByteStream & target, const std::string & source)
{
target.put(source.c_str(), source.size()+1);
}
#endif
ByteStream::ReadIterator::ReadIterator() :
readPtr(0),
stream(0)
{
}
ByteStream::ReadIterator::ReadIterator(const ReadIterator & source) :
readPtr(source.readPtr),
stream(source.stream)
{
}
ByteStream::ReadIterator::ReadIterator(const ByteStream & source) :
readPtr(0),
stream(&source)
{
}
ByteStream::ReadIterator::~ReadIterator()
{
stream = 0;
}
ByteStream::ByteStream() :
allocatedSize(0),
beginReadIterator(),
data(NULL),
size(0),
lastPutSize(0)
{
data = Data::getNewData();
beginReadIterator = ReadIterator(*this);
}
ByteStream::ByteStream(const unsigned char * const newBuffer, const unsigned int bufferSize) :
allocatedSize(bufferSize),
data(0),
size(bufferSize),
lastPutSize(0)
{
data = Data::getNewData();
if(data->size < size)
{
delete[] data->buffer;
data->buffer = new unsigned char[size];
data->size = size;
}
memcpy(data->buffer, newBuffer, size);
beginReadIterator = ReadIterator(*this);
}
ByteStream::ByteStream(const ByteStream & source):
allocatedSize(source.getSize()), // only allocate what is really there, be opportinistic when grow()'ing
data(source.data),
size(source.getSize()),
lastPutSize(source.lastPutSize)
{
source.data->ref();
beginReadIterator = ReadIterator(*this);
}
ByteStream::ByteStream(ReadIterator & source) :
allocatedSize(0),
size(0),
lastPutSize(0)
{
data = Data::getNewData();
put(source.getBuffer(), source.getSize());
source.advance(source.getSize());
beginReadIterator = ReadIterator(*this);
}
ByteStream::~ByteStream()
{
data->deref();
allocatedSize = 0;
data = 0; //lint !e672 (data deref insures the data is deleted if no one references it)
size = 0;
}
ByteStream & ByteStream::operator=(const ByteStream & rhs)
{
if(this != &rhs)
{
data->deref(); // deref local data
rhs.data->ref();
allocatedSize = rhs.allocatedSize;
size = rhs.size;
data = rhs.data; //lint !e672 (data is ref counted)
}
return *this;
}
void ByteStream::get(void * target, ReadIterator & readIterator, const unsigned long int targetSize) const
{
assert(readIterator.getReadPosition() + targetSize <= allocatedSize);
memcpy(target, &data->buffer[readIterator.getReadPosition()], targetSize);
}
void ByteStream::put(const void * const source, const unsigned int sourceSize)
{
if(data->getRef() > 1)
{
const unsigned char * const tmp = data->buffer;
data->deref();
data = Data::getNewData();
if(data->size < sourceSize)
{
delete[] data->buffer;
data->buffer = new unsigned char[size];
data->size = size;
}
memcpy(data->buffer, tmp, size);
allocatedSize = size;
}
growToAtLeast(size + sourceSize);
memcpy(&data->buffer[size], source, sourceSize);
size += sourceSize;
if (sourceSize > 0)
lastPutSize = sourceSize;
}
bool ByteStream::overwriteEnd(const void * const source, const unsigned int sourceSize)
{
if(data->getRef() <= 1 &&
lastPutSize == sourceSize &&
sourceSize <= data->size)
{
memcpy(&data->buffer[size-sourceSize], source, sourceSize);
return true;
}
else
{
return false;
}
}
void ByteStream::reAllocate(const unsigned int newSize)
{
allocatedSize = newSize;
if(data->size < allocatedSize)
{
unsigned char * tmp = new unsigned char[newSize];
if(data->buffer != NULL)
memcpy(tmp, data->buffer, size);
delete[] data->buffer;
data->buffer = tmp;
data->size = newSize;
}
}
////////////////////////////////////////////////////////////////////////////////
AutoByteStream::AutoByteStream() :
members()
{
}
AutoByteStream::~AutoByteStream()
{
}
void AutoByteStream::addVariable(AutoVariableBase & newVariable)
{
members.push_back(&newVariable);
}
const unsigned int AutoByteStream::getItemCount() const
{
return members.size();
}
void AutoByteStream::pack(ByteStream & target) const
{
std::vector<AutoVariableBase *>::const_iterator i;
unsigned short packedSize=static_cast<unsigned short>(members.size());
put(target,packedSize);
for(i = members.begin(); i != members.end(); ++i)
{
(*i)->pack(target);
}
}
void AutoByteStream::unpack(ByteStream::ReadIterator & source)
{
std::vector<AutoVariableBase *>::iterator i;
unsigned short packedSize;
get(source,packedSize);
for(i = members.begin(); i != members.end(); ++i)
{
(*i)->unpack(source);
}
}
////////////////////////////////////////////////////////////////////////////////
AutoVariableBase::AutoVariableBase()
{
}
AutoVariableBase::~AutoVariableBase()
{
}
////////////////////////////////////////////////////////////////////////////////
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,756 @@
////////////////////////////////////////////////////////////////////////////////
// The author of this code is Justin Randall
//
// I have made modifications to the ByteStream
// and AutoByteStream classes in order to make them suitable
// for use in messaging systems which require objects that
// are copyable and assignable. It is also desirable for
// the ByteStream object to use a flexible allocator system
// that may support multi-threaded programming models.
#ifndef BASE_ARCHIVE_H
#define BASE_ARCHIVE_H
#include <assert.h>
#include <string>
#include <vector>
#include "Platform.h"
#include "Mutex.h"
#if defined _MT || defined _REENTRANT
# define USE_ARCHIVE_MUTEX
#endif
#ifdef WIN32
# include "win32/Archive.h"
#elif linux
# include "linux/Archive.h"
#elif sparc
# include "solaris/Archive.h"
#else
#error /Base/Archive.h: Undefine platform type
#endif
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
const unsigned MAX_ARRAY_SIZE = 1024;
////////////////////////////////////////////////////////////////////////////////
#if defined(USE_ARCHIVE_MUTEX)
extern CMutex ByteStreamMutex;
#endif
class ByteStream;
class ReadIterator
{
public:
ReadIterator();
ReadIterator(const ReadIterator & source);
explicit ReadIterator(const ByteStream & source);
~ReadIterator();
ReadIterator & operator = (const ReadIterator & source);
void advance (const unsigned int distance);
void get (void * target, const unsigned long int readSize);
const unsigned int getSize () const;
const unsigned char * const getBuffer () const;
const unsigned int getReadPosition () const;
private:
unsigned int readPtr;
const ByteStream * stream;
};
class ByteStream
{
public:
typedef Base::ReadIterator ReadIterator;
private:
class Data
{
friend class ByteStream;
friend class Base::ReadIterator;
public:
~Data();
static Data * getNewData();
const int getRef () const;
void deref ();
void ref ();
protected:
unsigned char * buffer;
unsigned long size;
private:
struct DataFreeList
{
~DataFreeList()
{
std::vector<ByteStream::Data *>::iterator i;
for(i = freeList.begin(); i != freeList.end(); ++i)
{
delete (*i);
}
};
std::vector<Data *> freeList;
};
Data();
//explicit Data(unsigned char * buffer);
static std::vector<Data *> & getDataFreeList();
static void releaseOldData(Data * oldData);
private:
int refCount;
};
friend class Base::ReadIterator;
public:
ByteStream();
ByteStream(const unsigned char * const buffer, const unsigned int bufferSize);
ByteStream(const ByteStream & source);
virtual ~ByteStream();
public:
ByteStream(ReadIterator & source);
ByteStream & operator = (const ByteStream & source);
ByteStream & operator = (ReadIterator & source);
const ReadIterator & begin() const;
void clear();
const unsigned char * const getBuffer() const;
const unsigned int getSize() const;
void put(const void * const source, const unsigned int sourceSize);
bool overwriteEnd(const void * const source, const unsigned int sourceSize);
static bool ms_reuseData;
private:
void get(void * target, ReadIterator & readIterator, const unsigned long int readSize) const;
void growToAtLeast(const unsigned int targetSize);
void reAllocate(const unsigned int newSize);
private:
unsigned int allocatedSize;
ReadIterator beginReadIterator;
Data * data;
unsigned int size;
unsigned int lastPutSize;
};
inline ByteStream::Data::Data() :
buffer(0),
size(0),
refCount(1)
{
}
inline ByteStream::Data::~Data()
{
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Lock();
#endif
refCount = 0;
delete[] buffer;
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Unlock();
#endif
}
inline void ByteStream::Data::deref()
{
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Lock();
#endif
refCount--;
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Unlock();
#endif
if(refCount < 1)
releaseOldData(this);
}
inline std::vector<ByteStream::Data *> & ByteStream::Data::getDataFreeList()
{
static DataFreeList freeList;
return freeList.freeList;
}
inline ByteStream::Data * ByteStream::Data::getNewData()
{
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Lock();
#endif
Data * result = 0;
if(getDataFreeList().empty())
{
result = new Data;
}
else
{
result = getDataFreeList().back();
getDataFreeList().pop_back();
}
result->refCount = 1;
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Unlock();
#endif
return result;
}
inline const int ByteStream::Data::getRef() const
{
return refCount;
}
inline void ByteStream::Data::ref()
{
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Lock();
#endif
refCount++;
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Unlock();
#endif
}
inline void ByteStream::Data::releaseOldData(ByteStream::Data * oldData)
{
if (ByteStream::ms_reuseData)
{
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Lock();
#endif
getDataFreeList().push_back(oldData);
oldData->refCount = 0;
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Unlock();
#endif
}
else
{
delete oldData;
}
}
inline ByteStream::ReadIterator & ByteStream::ReadIterator::operator = (const ByteStream::ReadIterator & rhs)
{
if(&rhs != this)
{
readPtr = rhs.readPtr;
stream = rhs.stream;
}
return *this;
}
inline void ByteStream::ReadIterator::get(void * target, const unsigned long int readSize)
{
assert(stream);
stream->get(target, *this, readSize);
readPtr += readSize;
}
inline const unsigned int ByteStream::ReadIterator::getSize() const
{
assert(stream);
return stream->getSize() - readPtr;
}
inline const ByteStream::ReadIterator & ByteStream::begin() const
{
return beginReadIterator;
}
inline void ByteStream::ReadIterator::advance(const unsigned int distance)
{
readPtr += distance;
}
inline const unsigned int ByteStream::ReadIterator::getReadPosition() const
{
return readPtr;
}
inline const unsigned char * const ByteStream::ReadIterator::getBuffer() const
{
if(stream)
return &stream->data->buffer[readPtr];
return 0;
}
inline void ByteStream::clear()
{
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Lock();
#endif
size = 0;
#if defined(USE_ARCHIVE_MUTEX)
ByteStreamMutex.Unlock();
#endif
}
inline const unsigned char * const ByteStream::getBuffer() const
{
return data->buffer;
}
inline const unsigned int ByteStream::getSize() const
{
return size;
}
inline void ByteStream::growToAtLeast(const unsigned int targetSize)
{
if(allocatedSize < targetSize)
{
reAllocate(allocatedSize + allocatedSize + targetSize);
}
}
////////////////////////////////////////////////////////////////////////////////
inline void get(ByteStream::ReadIterator & source, ByteStream & target)
{
target.put(source.getBuffer(), source.getSize());
source.advance(source.getSize());
}
inline void get(ByteStream::ReadIterator & source, double & target)
{
source.get(&target, 8);
target = byteSwap(target);
}
inline void get(ByteStream::ReadIterator & source, float & target)
{
source.get(&target, 4);
target = byteSwap(target);
}
inline void get(ByteStream::ReadIterator & source, uint64 & target)
{
source.get(&target, 8);
target = byteSwap(target);
}
inline void get(ByteStream::ReadIterator & source, int64 & target)
{
source.get(&target, 8);
target = byteSwap(target);
}
inline void get(ByteStream::ReadIterator & source, uint32 & target)
{
source.get(&target, 4);
target = byteSwap(target);
}
inline void get(ByteStream::ReadIterator & source, int32 & target)
{
source.get(&target, 4);
target = byteSwap(target);
}
inline void get(ByteStream::ReadIterator & source, uint16 & target)
{
source.get(&target, 2);
target = byteSwap(target);
}
inline void get(ByteStream::ReadIterator & source, int16 & target)
{
source.get(&target, 2);
target = byteSwap(target);
}
inline void get(ByteStream::ReadIterator & source, uint8 & target)
{
source.get(&target, 1);
}
inline void get(ByteStream::ReadIterator & source, int8 & target)
{
source.get(&target, 1);
}
inline void get(ByteStream::ReadIterator & source, unsigned char * const target, const unsigned int targetSize)
{
source.get(target, targetSize);
}
inline void get(ByteStream::ReadIterator & source, bool & target)
{
source.get(&target, 1);
}
////////////////////////////////////////////////////////////////////////////////
inline void put(ByteStream & target, ByteStream::ReadIterator & source)
{
target.put(source.getBuffer(), source.getSize());
source.advance(source.getSize());
}
inline void put(ByteStream & target, const double value)
{
double temp = byteSwap(value);
target.put(&temp, 8);
}
inline void put(ByteStream & target, const float value)
{
float temp = byteSwap(value);
target.put(&temp, 4);
}
inline void put(ByteStream & target, const uint64 value)
{
uint64 temp = byteSwap(value);
target.put(&temp, 8);
}
inline void put(ByteStream & target, const int64 value)
{
int64 temp = byteSwap(value);
target.put(&temp, 8);
}
inline void put(ByteStream & target, const uint32 value)
{
uint32 temp = byteSwap(value);
target.put(&temp, 4);
}
inline void put(ByteStream & target, const int32 value)
{
int32 temp = byteSwap(value);
target.put(&temp, 4);
}
inline void put(ByteStream & target, const uint16 value)
{
uint16 temp = byteSwap(value);
target.put(&temp, 2);
}
inline void put(ByteStream & target, const int16 value)
{
int16 temp = byteSwap(value);
target.put(&temp, 2);
}
inline void put(ByteStream & target, const uint8 value)
{
target.put(&value, 1);
}
inline void put(ByteStream & target, const int8 value)
{
target.put(&value, 1);
}
inline void put(ByteStream & target, const bool & source)
{
target.put(&source, 1);
}
inline void put(ByteStream & target, const unsigned char * const source, const unsigned int sourceSize)
{
target.put(source, sourceSize);
}
inline void put(ByteStream & target, const ByteStream & source)
{
target.put(source.begin().getBuffer(), source.begin().getSize());
}
void get(ByteStream::ReadIterator & source, std::string & target);
void put(ByteStream & target, const std::string & source);
////////////////////////////////////////////////////////////////////////////////
class AutoVariableBase
{
public:
AutoVariableBase();
virtual ~AutoVariableBase();
virtual void pack(ByteStream & target) const = 0;
virtual void unpack(ByteStream::ReadIterator & source) = 0;
};
////////////////////////////////////////////////////////////////////////////////
class AutoByteStream
{
public:
AutoByteStream();
virtual ~AutoByteStream();
void addVariable(AutoVariableBase & newVariable);
virtual const unsigned int getItemCount() const;
virtual void pack(ByteStream & target) const;
virtual void unpack(ByteStream::ReadIterator & source);
protected:
std::vector<AutoVariableBase *> members;
private:
AutoByteStream(const AutoByteStream & source);
};
////////////////////////////////////////////////////////////////////////////////
template<class ValueType>
class AutoVariable : public AutoVariableBase
{
public:
AutoVariable();
explicit AutoVariable(const ValueType & source);
virtual ~AutoVariable();
const ValueType & get() const;
virtual void pack(ByteStream & target) const;
void set(const ValueType & rhs);
virtual void unpack(ByteStream::ReadIterator & source);
private:
ValueType value;
};
template<class ValueType>
AutoVariable<ValueType>::AutoVariable() :
AutoVariableBase(),
value()
{
}
template<class ValueType>
AutoVariable<ValueType>::AutoVariable(const ValueType & source) :
AutoVariableBase(),
value(source)
{
}
template<class ValueType>
AutoVariable<ValueType>::~AutoVariable()
{
}
template<class ValueType>
const ValueType & AutoVariable<ValueType>::get() const
{
return value;
}
template<class ValueType>
void AutoVariable<ValueType>::pack(ByteStream & target) const
{
Base::put(target, value);
}
template<class ValueType>
void AutoVariable<ValueType>::set(const ValueType & rhs)
{
value = rhs;
}
template<class ValueType>
void AutoVariable<ValueType>::unpack(ByteStream::ReadIterator & source)
{
Base::get(source, value);
}
////////////////////////////////////////////////////////////////////////////////
template<class ValueType>
class AutoArray : public AutoVariableBase
{
public:
AutoArray();
AutoArray(const AutoArray & source);
~AutoArray();
const std::vector<ValueType> & get() const;
void set(const std::vector<ValueType> & source);
virtual void pack(ByteStream & target) const;
virtual void unpack(ByteStream::ReadIterator & source);
private:
std::vector<ValueType> array;
};
template<class ValueType>
inline AutoArray<ValueType>::AutoArray()
{
}
template<class ValueType>
inline AutoArray<ValueType>::AutoArray(const AutoArray & source) :
array(source.array)
{
}
template<class ValueType>
inline AutoArray<ValueType>::~AutoArray()
{
}
template<class ValueType>
inline const std::vector<ValueType> & AutoArray<ValueType>::get() const
{
return array;
}
template<class ValueType>
inline void AutoArray<ValueType>::set(const std::vector<ValueType> & source)
{
array = source;
}
template<class ValueType>
inline void AutoArray<ValueType>::pack(ByteStream & target) const
{
unsigned int arraySize = array.size();
Base::put(target, arraySize);
typename std::vector<ValueType>::const_iterator i;
for(i = array.begin(); i != array.end(); ++i)
{
ValueType v = (*i);
Base::put(target, v);
}
}
template<class ValueType>
inline void AutoArray<ValueType>::unpack(ByteStream::ReadIterator & source)
{
unsigned int arraySize;
Base::get(source, arraySize);
ValueType v;
if (arraySize > MAX_ARRAY_SIZE)
arraySize = 0;
for(unsigned int i = 0; i < arraySize; ++i)
{
Base::get(source, v);
array.push_back(v);
}
}
inline bool overwriteEnd(ByteStream & target, const double value)
{
double temp = byteSwap(value);
return target.overwriteEnd(&temp, 8);
}
inline bool overwriteEnd(ByteStream & target, const float value)
{
float temp = byteSwap(value);
return target.overwriteEnd(&temp, 4);
}
inline bool overwriteEnd(ByteStream & target, const uint64 value)
{
uint64 temp = byteSwap(value);
return target.overwriteEnd(&temp, 8);
}
inline bool overwriteEnd(ByteStream & target, const int64 value)
{
int64 temp = byteSwap(value);
return target.overwriteEnd(&temp, 8);
}
inline bool overwriteEnd(ByteStream & target, const uint32 value)
{
uint32 temp = byteSwap(value);
return target.overwriteEnd(&temp, 4);
}
inline bool overwriteEnd(ByteStream & target, const int32 value)
{
int32 temp = byteSwap(value);
return target.overwriteEnd(&temp, 4);
}
inline bool overwriteEnd(ByteStream & target, const uint16 value)
{
uint16 temp = byteSwap(value);
return target.overwriteEnd(&temp, 2);
}
inline bool overwriteEnd(ByteStream & target, const int16 value)
{
int16 temp = byteSwap(value);
return target.overwriteEnd(&temp, 2);
}
inline bool overwriteEnd(ByteStream & target, const uint8 value)
{
return target.overwriteEnd(&value, 1);
}
inline bool overwriteEnd(ByteStream & target, const int8 value)
{
return target.overwriteEnd(&value, 1);
}
inline bool overwriteEnd(ByteStream & target, const bool & source)
{
return target.overwriteEnd(&source, 1);
}
inline bool overwriteEnd(ByteStream & target, const unsigned char * const source, const unsigned int sourceSize)
{
return target.overwriteEnd(source, sourceSize);
}
////////////////////////////////////////////////////////////////////////////////
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif
@@ -0,0 +1,349 @@
#include "AutoLog.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
#ifdef WIN32
#include <direct.h> // for NT directory commands
#define SLASHCHAR "\\"
#define WRONGSLASH '/'
#else
#define SLASHCHAR "/"
#define WRONGSLASH '\\'
#endif
// set default values for global masks
CAutoLog::eLogLevel CAutoLog::nLogMask = eLOG_NORMAL; // what is logged in log files
CAutoLog::eLogLevel CAutoLog::nPrintMask = eLOG_ERROR; // what is printed on the screen
CAutoLog::eLogLevel CAutoLog::nFlushMask = eLOG_ERROR; // when is file flushed on every entry?
// class info
//-------------------------------------
bool CAutoLog::Open(const char * filename)
//-------------------------------------
{
if( NULL == filename)
return false;
if (pFilename)
return false;
pFilename = strdup(filename);
// Sanitize slashes
char *ptr;
while ((ptr = strchr(pFilename,WRONGSLASH)) != NULL)
*ptr = SLASHCHAR[0];
char strPath[1024];
strcpy(strPath,pFilename);
ptr = strrchr(strPath, SLASHCHAR[0]);
if (ptr != NULL)
{
*ptr = 0;
#ifdef WIN32
char curdir[128];
// remember current directory
if( getcwd(curdir,sizeof(curdir)) == NULL )
{
fprintf(stderr,"CAutoLog::Archive failed to get current directory!\n");
free(pFilename);
pFilename = NULL;
return false; // error, can't proceed
}
if (_chdir(strPath))
{
// failed to find the directory, so we must create it
if (mkdir(strPath))
{
fprintf(stderr,"CAutoLog::Archive failed to make directory: %s\n", strPath);
free(pFilename);
pFilename = NULL;
return false; // error, can't proceed
}
}
else
{
// found the directory, but we don't want to be there, so go back
_chdir(curdir);
}
#else
struct stat SS;
// see if directory exists
if (stat(strPath,&SS))
{
// create directory
if (mkdir(strPath,0777))
{
fprintf(stderr,"CAutoLog::Archive failed to make directory: %s\n", strPath);
free(pFilename);
pFilename = NULL;
return false; // error, can't proceed
}
}
#endif
}
pFile = fopen(pFilename,"a+");
if( pFile == NULL || pFile == (FILE *)-1)
{
//fprintf(stderr,"CAutoLog::Open failed to open log file: %s\n",pFilename);
Close();
return false;
}
time_t t;
time(&t);
struct tm *ptm = localtime(&t);
nTodaysDayOfYear = ptm->tm_yday;
//printf("Open log file: %s\n",pFilename);
return true;
}
//-------------------------------------
void CAutoLog::Close(void)
//-------------------------------------
{
if( pFile != (FILE *)-1 && pFile != NULL)
{
fclose(pFile);
}
pFile = (FILE *)-1;
if (pFilename)
{
free(pFilename);
}
pFilename = NULL;
}
//-------------------------------------
void CAutoLog::LogError(char * format, ...)
{
char strInput[1024];
// parse format and input arguments
va_list varg;
va_start(varg, format);
vsprintf(strInput, format, varg);
va_end(varg);
Log(eLOG_ERROR, strInput);
}
//-------------------------------------
void CAutoLog::LogAlert(char * format, ...)
{
char strInput[1024];
// parse format and input arguments
va_list varg;
va_start(varg, format);
vsprintf(strInput, format, varg);
va_end(varg);
Log(eLOG_ALERT, strInput);
}
//-------------------------------------
void CAutoLog::Log(char * format, ...)
{
char strInput[1024];
// parse format and input arguments
va_list varg;
va_start(varg, format);
vsprintf(strInput, format, varg);
va_end(varg);
Log(eLOG_NORMAL, strInput);
}
//-------------------------------------
void CAutoLog::LogDebug(char * format, ...)
{
char strInput[1024];
// parse format and input arguments
va_list varg;
va_start(varg, format);
vsprintf(strInput, format, varg);
va_end(varg);
Log(eLOG_DEBUG, strInput);
}
//-------------------------------------
void CAutoLog::Log(eLogLevel severity, char *fmt, ...)
//-------------------------------------
{
if (pFile == (FILE *)-1 || pFile == NULL)
{
//fprintf(stderr,"CAutoLog::Log called with no file open!\n");
return;
}
if (nLogMask == eLOG_NONE || nLogMask < severity)
{
if (nPrintMask == eLOG_NONE || nPrintMask < severity)
{ // no point in parsing, we're doing nothing.
return;
}
}
char strTime[128];
char strInput[1024];
char strOutput[1024+128];
time_t t;
// parse format and input arguments
va_list varg;
va_start(varg, fmt);
vsprintf(strInput, fmt, varg);
va_end(varg);
// make timestamp
time(&t);
strftime(strTime, sizeof(strTime), "[%m/%d/%Y %H:%M:%S]", localtime(&t) );
// construct output string
sprintf(strOutput, "%s %s\n", strTime, strInput);
// check to see if current file needs to be archived
Archive();
// log to file
if (!(nLogMask == eLOG_NONE || nLogMask < severity))
{
fwrite(strOutput,strlen(strOutput),1,pFile);
}
// print as standard output
if (!(nPrintMask == eLOG_NONE || nPrintMask < severity))
{
printf("%s", strOutput);
}
// flush file buffer if error is high severity
if (severity <= nFlushMask)
fflush(pFile);
}
//-------------------------------------
void CAutoLog::Archive(void)
//-------------------------------------
{
if( pFile == (FILE *)-1 || pFile == NULL)
{
//fprintf(stderr,"CAutoLog::Archive called with no file open!\n");
return;
}
// check to see if it's time to archive
time_t t;
time(&t);
struct tm *ptm = localtime(&t);
if (ptm->tm_yday == nTodaysDayOfYear)
{
return; // nope, not time to archive
}
nTodaysDayOfYear = ptm->tm_yday;
char strPath[1024];
char strCurrent[1024];
char strTime[128];
char * pCurrent;
#ifdef WIN32
char curdir[128];
#else
struct stat SS;
#endif
strftime(strTime, sizeof(strTime), "%m%d%Y", localtime(&t) ); // numerical time e.g. 041698
strcpy(strCurrent,pFilename);
pCurrent = strrchr(strCurrent, SLASHCHAR[0]);
if (pCurrent != NULL)
*pCurrent = 0;
else
sprintf(strCurrent,".");
sprintf(strPath,"%s"SLASHCHAR"%s", strCurrent, strTime); // logs/041698
#ifdef WIN32
// remember current directory
if( getcwd(curdir,sizeof(curdir)) == NULL )
{
fprintf(stderr,"CAutoLog::Archive failed to get current directory!\n");
return; // error, can't proceed
}
if (_chdir(strPath))
{
// failed to find the directory, so we must create it
if (mkdir(strPath))
{
fprintf(stderr,"CAutoLog::Archive failed to make directory: %s\n", strPath);
return; // error, can't proceed
}
}
else
{
// found the directory, but we don't want to be there, so go back
_chdir(curdir);
}
#else
// see if directory exists
if (stat(strPath,&SS))
{
// create directory
if (mkdir(strPath,0777))
{
fprintf(stderr,"CAutoLog::Archive failed to make directory: %s\n", strPath);
return; // error, can't proceed
}
}
#endif
pCurrent = strrchr(pFilename, SLASHCHAR[0]);
if (pCurrent == NULL)
pCurrent = pFilename;
else
pCurrent++;
sprintf(strCurrent,"%s"SLASHCHAR"%s",strPath,pCurrent);
fflush(pFile);
fclose(pFile);
rename(pFilename,strCurrent);
pFile = fopen(pFilename,"w+");
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,117 @@
#ifndef _AUTOLOG_H
#define _AUTOLOG_H
#pragma warning (disable : 4786)
#include <stdio.h>
#include <time.h>
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
class CAutoLog
{
public:
enum eLogLevel {
eLOG_NONE = 0, // log entries are discarded
eLOG_ERROR = 1, // log errors only
eLOG_ALERT = 2, // log alerts and errors only
eLOG_NORMAL = 3, // log all normal events, no debug
eLOG_DEBUG = 4 // log everything
};
// Global setting for all AutoLog instances for this application. Can be set on the fly. Default is eLOG_NORMAL.
void SetLogLevel(eLogLevel loglevel);
// Global setting for all AutoLog instances for this application. Can be set on the fly. Default is eLOG_ERROR.
void SetPrintLevel(eLogLevel printlevel);
// Global setting for all AutoLog instances for this application. Can be set on the fly. Default is eLOG_ERROR.
void SetFlushLevel(eLogLevel flushlevel);
// constructor, no file loaded
CAutoLog();
// version of constructor that calls Open(file)
CAutoLog(const char * file);
// destructor, will close file if opened
~CAutoLog();
// Open log file. If a file is already open, function will fail.
// returns true if no error
bool Open(const char * file);
// Close log file if opened.
void Close(void);
// Make an entry in the log. Format and variable arguments are identical to printf.
// severity will be compared to master log level to determine if the log entry will be made
// severity will be compared to master print level to determine if the log entry will be printed to stdout
void Log(eLogLevel severity, char * format, ...);
// Equivalent to the above with the approriate severity argument
void LogError(char * format, ...);
void LogAlert(char * format, ...);
void Log(char * format, ...);
void LogDebug(char * format, ...);
private:
FILE * pFile; // current log file opened
char * pFilename; // current log file opened
int nTodaysDayOfYear; // remember the current day to detect change of day
void Archive(void); // archives current log
static eLogLevel nLogMask; // master severity level
static eLogLevel nPrintMask; // master severity level
static eLogLevel nFlushMask; // master severity level
};
//-------------------------------------
inline void CAutoLog::SetLogLevel(eLogLevel loglevel)
{
nLogMask = loglevel;
}
//-------------------------------------
inline void CAutoLog::SetPrintLevel(eLogLevel printlevel)
{
nPrintMask = printlevel;
}
//-------------------------------------
inline void CAutoLog::SetFlushLevel(eLogLevel flushlevel)
{
nFlushMask = flushlevel;
}
//-------------------------------------
inline CAutoLog::CAutoLog()
{
pFilename = NULL;
pFile = (FILE *)-1;
}
//-------------------------------------
inline CAutoLog::CAutoLog(const char * file)
{
pFilename = NULL;
pFile = (FILE *)-1;
Open(file);
}
//-------------------------------------
inline CAutoLog::~CAutoLog()
{
Close();
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif
@@ -0,0 +1 @@
#include "Base.h"
@@ -0,0 +1,63 @@
////////////////////////////////////////
// Base.h
//
// Purpose:
// 1. Provide a single header file that may be used to include all
// Base library header files.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef _BASEPCH_H
#define _BASEPCH_H
#ifdef WIN32
#include "win32/Platform.h"
#include "win32/Types.h"
#include "win32/Mutex.h"
#include "win32/Event.h"
#include "win32/Thread.h"
#include "Logger.h"
#include "Config.h"
#include "ScopeLock.h"
#include "Statistics.h"
#include "TemplateObjectAllocator.h"
#include "BlockAllocator.h"
#elif linux
#include "linux/Platform.h"
#include "linux/Types.h"
#include "linux/Mutex.h"
#include "linux/Event.h"
#include "linux/Thread.h"
#include "Logger.h"
#include "Config.h"
#include "ScopeLock.h"
#include "Statistics.h"
#include "TemplateObjectAllocator.h"
#include "BlockAllocator.h"
#elif sparc
#include "solaris/Platform.h"
#include "solaris/Types.h"
#include "solaris/Mutex.h"
#include "solaris/Event.h"
#include "solaris/Thread.h"
#include "Logger.h"
#include "Config.h"
#include "ScopeLock.h"
#include "Statistics.h"
#include "TemplateObjectAllocator.h"
#include "BlockAllocator.h"
#else
#error Base.h: Undefine platform type
#endif
#endif // _BASEPCH_H
@@ -0,0 +1,30 @@
#if !defined (BLOCKALLOCATOR_H_)
#define BLOCKALLOCATOR_H_
#include <stdio.h>
#include <stdlib.h>
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
class BlockAllocator
{
public:
BlockAllocator();
~BlockAllocator();
void *getBlock(unsigned accum);
void returnBlock(unsigned *handle);
private:
unsigned *m_blocks[31];
};
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif
@@ -0,0 +1,179 @@
#include "Config.h"
//#include <stdlib.h>
//#include <stdio.h>
//#include <string.h>
#include <ctype.h>
#include "Platform.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
//-----------------------------------
/// Read the config file into memory
/// Returns true for success
bool CConfig::LoadFile(char * file)
//-----------------------------------
{
char ch;
FILE * fp;
UnloadFile();
// open file
fp = fopen(file, "r");
if (fp == NULL || fp == (FILE *)-1)
{
//fprintf(stderr,"Failed to open config file %s!",file);
return false;
}
// get length of file
fseek(fp,0,SEEK_END);
long length = ftell(fp);
rewind(fp);
// allocate buffer
pConfig = new char[length + 1];
if (pConfig == NULL)
{
fclose(fp);
fprintf(stderr,"Failed to alloc config buffer length %d",(int32)length);
return false;
}
memset(pConfig,0,length);
// read data, stripping comments
int i = 0;
while (i < length)
{
ch = fgetc(fp);
if (feof(fp))
break;
if (ch == '#')
{
while (ch != 10 && !feof (fp))
{
ch = fgetc(fp);
}
}
pConfig[i++] = ch;
}
pConfig[i] = 0; // mark end of file buffer
fclose(fp);
return true;
}
//-----------------------------------
/// remove the config file from memory
void CConfig::UnloadFile(void)
//-----------------------------------
{
if (pConfig)
delete[] pConfig;
pConfig = NULL;
}
//-----------------------------------
/// finds a key of the config in memory
// key argument is case-insensitive, but must be upper case in config file
// Returns true for success (passing NULL is a special case returned as success)
bool CConfig::FindKey(char *key)
//-----------------------------------
{
if (pConfig == NULL)
return false;
// special case...continue with existing key
if (key == NULL)
return true;
// form the search key
strcpy(strBuffer, "[");
strcat(strBuffer, key);
strcat(strBuffer,"]");
_strupr(strBuffer); // keywords must be upper case
// find the key heading
pCursor = strstr(pConfig,strBuffer);
if (pCursor==NULL)
return false;
// find the closing bracket of key heading
pCursor = strchr(pCursor,']');
if (pCursor==NULL)
return false;
pCursor++;
return true;
}
//-----------------------------------
/// extract a number from the config string
// pass the key to find the first number in the list, else NULL to find the next number in the list
// returns 0 if no number is found, else returns the number
long CConfig::GetLong(char *key)
//-----------------------------------
{
if (!FindKey(key))
return 0;
// look for start of number or end of key
while (*pCursor && !isdigit(*pCursor) && *pCursor != '[' && *pCursor != '-')
pCursor++;
int c = 0;
while (*pCursor && (isdigit(*pCursor) || *pCursor == '-') && c < (int)sizeof(strBuffer))
strBuffer[c++] = *(pCursor++);
strBuffer[c] = '\0';
return atol(strBuffer);
}
//-----------------------------------
/// extract string (in double-quotes) from the list.
// pass the key to find the first string in the list, else NULL to find the next string in the list
// returns NULL if no string found, else returns a temporary copy of the string (without quotes)
char * CConfig::GetString(char *key)
//-----------------------------------
{
if (!FindKey(key))
return NULL;
// look for start of string or end of key
while (*pCursor && *pCursor != '"' && *pCursor != '[')
pCursor++;
if (*(pCursor++) != '"')
return NULL;
// until closing quote
int c = 0;
while (*pCursor && c < (int)sizeof(strBuffer))
{
strBuffer[c++] = *pCursor; // extract string
if (*pCursor++ == '"')
{
strBuffer[--c] = '\0';
return strBuffer;
}
}
return NULL;
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,111 @@
/*
; Example syntax of a config file.
# This is a comment to end of line.
; This is a comment too....both comments are to end of line
[KEYWORD] ; all keywords must be upper case to be recognized
; single number, with code example
# long number = config.GetLong("PORT");
[PORT] 5999 ; common single-value case
; list of strings, with code example
# config.FindKey("NUMBERS");
# while (number = config.GetLong(NULL))
# YourHandleNumber(number);
[NUMBERS] 100
200, 300 ; formatting is very flexible as long as numbers are delimited by non-numbers
400 500
600 ; This is badly formatted for example purposes only
; single string, with code example
# strcpy(mystring, config.GetString("STRING"));
[STRING] "This is a string"
; list of strings, with code example
# config.FindKey("HOSTS");
# while (string = config.GetString(NULL))
# YourHandleString(string);
[HOSTS]
"206.19.151.173:5999"
"206.19.151.173:5998"
"206.19.151.173:2000"
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include <stdio.h>
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
class CConfig
{
public:
// constructor, no file loaded
CConfig();
// version of constructor that calls LoadFile(file)
CConfig(char * file);
// destructor, will delete all buffers
~CConfig();
// copy text config file into memory. Required to use extraction methods.
// if called with a different filename, existing file will be discarded.
bool LoadFile(char * file);
// delete memory buffer of file
void UnloadFile();
// set cursor in file based on key name. Alternate way to select first key when extracting lists.
// returns TRUE if key is found.
bool FindKey(char *key);
// extract string from config. If key is NULL, extract next string in list, else extract first string.
// if key was not found, returns NULL
char * GetString(char *key = NULL);
// extract number from config. If key is NULL, extract next number in list, else extract first number.
// if key was not found, returns 0
long GetLong(char *key = NULL); // extract number from config.
// indicate if config file has been loaded
inline bool FileLoaded() { return pConfig == NULL ? false : true; }
private:
char * pConfig; // pointer to file memory
char * pCursor; // current cursor into file memory
char strBuffer[8196]; // buffer for GetString return pointer -- reused
};
inline CConfig::CConfig()
{
pConfig = NULL;
pCursor = NULL;
}
inline CConfig::CConfig(char * file)
{
pConfig = NULL;
pCursor = NULL;
LoadFile(file);
}
inline CConfig::~CConfig()
{
UnloadFile();
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif
@@ -0,0 +1,22 @@
#ifndef BASE_EVENT_H
#define BASE_EVENT_H
#ifdef WIN32
#include "win32/Event.h"
#elif linux
#include "linux/Event.h"
#elif sparc
#include "solaris/Event.h"
#else
#error /Base/Event.h: Undefine platform type
#endif
#endif // BASE_EVENT_H
@@ -0,0 +1,688 @@
#include "Logger.h"
#include "Mutex.h"
#include <sys/stat.h>
using namespace std;
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
const long kDateLenAllowance = 256;
#ifndef _BASE_LOGGER_MAX_BUF_SIZE_
#define _BASE_LOGGER_MAX_BUF_SIZE_ 2048
#endif
#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__)
# ifdef _MT
# define LOGGER_LOCK rLock.Lock();
# define LOGGER_UNLOCK rLock.Unlock();
# else // ifndef _MT
# define LOGGER_LOCK
# define LOGGER_UNLOCK
# endif // _MT
#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__)
# ifdef _REENTRANT
# define LOGGER_LOCK rLock.Lock();
# define LOGGER_UNLOCK rLock.Unlock();
# else // ifndef _REENTRANT
# define LOGGER_LOCK
# define LOGGER_UNLOCK
# endif // _REENTRANT
#endif // WIN32
Logger::Logger(const char *prefix,
int level,
unsigned size,
bool rollDate)
: m_defaultLevel(level),
m_defaultSize(size),
m_dirPrefix(prefix),
m_rollDate(rollDate)
{
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)
{
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)
{
sprintf(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
{
sprintf(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
}
#ifndef WIN32
// Open connection to syslog
if (0 != (m_logType & eUseSysLog))
openlog(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::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)
{
LOGGER_LOCK
if(info->ts.tm_mday != m_lastDateTime.tm_mday)
{
memcpy(&m_lastDateTime, &info->ts, sizeof(tm));
rollDate(t);
}
LOGGER_UNLOCK
}
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)
{
LOGGER_LOCK
if(info->ts.tm_mday != m_lastDateTime.tm_mday)
{
memcpy(&m_lastDateTime, &info->ts, sizeof(tm));
rollDate(t);
}
LOGGER_UNLOCK
}
if(iter != m_logTable.end())
{
if (m_logRolloverSize> 0)
checkLogRoll(info, ::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, ...)
{
char buf[_BASE_LOGGER_MAX_BUF_SIZE_];
va_list varg;
va_start(varg, message);
vsnprintf(buf, _BASE_LOGGER_MAX_BUF_SIZE_, message, varg);
buf[_BASE_LOGGER_MAX_BUF_SIZE_ - 1] = 0;
va_end(varg);
// ensure that the buf does not contain any '%' characters.
// prevent crash problem
char *rv;
while((rv = strchr(buf, '%')) != NULL)
{
*rv = ' '; // replace with space
}
logWithSys(logenum, LOG_NOTICE, level, buf);
}
void Logger::logWithSys(unsigned logenum, unsigned priority, int level, const char *message, ...)
{
char buf[_BASE_LOGGER_MAX_BUF_SIZE_];
va_list varg;
va_start(varg, message);
vsnprintf(buf, _BASE_LOGGER_MAX_BUF_SIZE_, message, varg);
buf[_BASE_LOGGER_MAX_BUF_SIZE_ - 1] = 0;
va_end(varg);
#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)
{
LOGGER_LOCK
if(info->ts.tm_mday != m_lastDateTime.tm_mday)
{
memcpy(&m_lastDateTime, &info->ts, sizeof(tm));
rollDate(t);
}
LOGGER_UNLOCK
}
if(iter != m_logTable.end())
{
if (m_logRolloverSize> 0)
checkLogRoll(info, ::strlen(buf) + 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, buf);
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, buf);
fputc('\n', info->file);
fflush(info->file);
}
}
}
}
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);
sprintf(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);
sprintf(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)
{
LOGGER_LOCK
rollLog(logInfo);
LOGGER_UNLOCK
}
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,136 @@
#ifndef __LOGGER_H__
#define __LOGGER_H__
// make the compiler shut up
#pragma warning (disable : 4786)
#include "Platform.h"
#include <string>
#include <map>
#include "Mutex.h"
#ifndef WIN32
#include <syslog.h>
#endif
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
#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
};
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 flushAll();
void flush(unsigned logenum);
unsigned long getLogRolloverSize() { return m_logRolloverSize; }
void setLogRolloverSize(unsigned long maxLogSize) { m_logRolloverSize = maxLogSize; }
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 (_REENTRANT) || defined (_MT)
Base::CMutex rLock;
#endif
bool m_rollDate;
ELogType m_logType;
unsigned long m_logRolloverSize;
};
extern const char file_sep;
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif
@@ -0,0 +1,325 @@
// MD5.cpp: implementation of the MD5 class.
//
//////////////////////////////////////////////////////////////////////
#include "MD5.h"
#include "Types.h"
using namespace std;
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
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);
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,75 @@
// MD5.h: interface for the MD5 class.
//
//////////////////////////////////////////////////////////////////////
#ifndef MD5_H
#define MD5_H
#include <string>
#include <vector>
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
class MD5
{
struct State
{
State();
std::vector<int> state;
std::vector<int> count;
std::vector<char> buffer;
};
public:
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;
};
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // MD5_H
@@ -0,0 +1,23 @@
#ifndef BASE_MUTEX_H
#define BASE_MUTEX_H
#ifdef WIN32
#include "win32/Mutex.h"
#elif linux
#include "linux/Mutex.h"
#elif sparc
#include "solaris/Mutex.h"
#else
#error /Base/Mutex.h: Undefine platform type
#endif
#endif // BASE_MUTEX_H
@@ -0,0 +1,105 @@
#ifndef BASE_PLATFORM_H
#define BASE_PLATFORM_H
#include <assert.h>
#ifdef WIN32
#include "win32/Platform.h"
#elif linux
#include "linux/Platform.h"
#elif sparc
#include "solaris/Platform.h"
#else
#error /Base/Platform.h: Undefine platform type
#endif
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
template <class T> inline T rotlFixed(T x, unsigned int y)
{
assert(y < sizeof(T)*8);
return (T)((x<<y) | (x>>(sizeof(T)*8-y)));
}
template <class T> inline T rotrFixed(T x, unsigned int y)
{
assert(y < sizeof(T)*8);
return (x>>y) | (x<<(sizeof(T)*8-y));
}
template <class T> inline T rotlMod(T x, unsigned int y)
{
y %= sizeof(T)*8;
return (x<<y) | (x>>(sizeof(T)*8-y));
}
template <class T> inline T rotrMod(T x, unsigned int y)
{
y %= sizeof(T)*8;
return (x>>y) | (x<<(sizeof(T)*8-y));
}
inline uint16 byteReverse16(void * data)
{
uint16 value = *static_cast<uint16 *>(data);
return *static_cast<uint16 *>(data) = rotlFixed(value, 8U);
// return rotlFixed(value, 8U);
}
inline uint32 byteReverse32(void * data)
{
uint32 value = *static_cast<uint32 *>(data);
return *static_cast<uint32 *>(data) = (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff);
// return (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff);
}
inline uint64 byteReverse64(void * data)
{
uint64 value = *static_cast<uint64 *>(data);
return *static_cast<uint64 *>(data) = (
uint64((rotrFixed(uint32(value), 8U) & 0xff00ff00) | (rotlFixed(uint32(value), 8U) & 0x00ff00ff)) << 32) |
(rotrFixed(uint32(value>>32), 8U) & 0xff00ff00) | (rotlFixed(uint32(value>>32), 8U) & 0x00ff00ff);
// return (uint64(byteReverse(uint32(value))) << 32) | byteReverse(uint32(value>>32));
}
inline uint32 strlen(const unsigned short * string)
{
if (string == 0)
return 0;
uint32 length=0;
while (*(string+length++) != 0);
return length-1;
}
inline double getTimerLatency(Base::uint64 startTime, Base::uint64 finishTime=0)
{
Base::int64 requestAge;
Base::int64 freq = Base::getTimerFrequency();
Base::uint64 finish = (finishTime ? finishTime : Base::getTimer());
if (finish < startTime)
requestAge = (0 - 1) - startTime - finish;
else
requestAge = finish - startTime;
return (double)requestAge/freq;
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // BASE_PLATFORM_H
@@ -0,0 +1,34 @@
#include "ScopeLock.h"
#ifdef INCLUDE_SCOPELOCK
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
CScopeLock::CScopeLock(CMutex& mutex) :
mMutex(&mutex)
{
mMutex->Lock();
}
CScopeLock::CScopeLock(CScopeLock& lock) :
mMutex(lock.mMutex)
{
mMutex->Lock();
}
CScopeLock::~CScopeLock()
{
mMutex->Unlock();
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // INCLUDE_SCOPELOCK
@@ -0,0 +1,40 @@
// ScopeLock.h: interface for the CScopeLock class.
//
//////////////////////////////////////////////////////////////////////
#ifndef SCOPELOCK_H
#define SCOPELOCK_H
#if defined _MT || defined _REENTRANT
# define INCLUDE_SCOPELOCK
#endif
#ifdef INCLUDE_SCOPELOCK
#include "Mutex.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
class CScopeLock
{
public:
CScopeLock(CMutex& mutex);
CScopeLock(CScopeLock& lock);
virtual ~CScopeLock();
private:
CMutex *mMutex;
};
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // INCLUDE_SCOPELOCK
#endif // SCOPELOCK_H
@@ -0,0 +1,45 @@
#include "Statistics.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
CStatisticTimer::CStatisticTimer(bool running) :
mTotal(0),
mStart(getTimer()),
mRunning(running)
{
}
double CStatisticTimer::GetTime()
{
uint64 total = mTotal;
if (mRunning)
total += getTimer()-mStart;
return (double)((int64)(total/getTimerFrequency()));
}
uint64 CStatisticTimer::GetFraction(uint32 fraction)
{
uint64 total = mTotal;
if (mRunning)
total += getTimer()-mStart;
if (fraction == 0)
return total;
else
return total/(getTimerFrequency()/fraction);
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,140 @@
#ifndef STATISTICS_H
#define STATISTICS_H
#include <time.h>
#include "Platform.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
template <class TYPE, uint32 COUNT>
class CStatistic
{
public:
CStatistic(uint32 freq=0) :
mSampleFrequency(freq),
mLastSampleTime(0),
mSample(0),
mSampleTotal(0),
mAggregateTotal(0),
mAggregateMaximum(0),
mAggregateMinimum(0),
mAverageTotal(0),
mAverageIndex(0),
mAverageCount(0)
{
}
bool Sample(TYPE value)
{
bool commit = false;
if (!mLastSampleTime)
mLastSampleTime = time(NULL);
if (!mSampleFrequency || mLastSampleTime + mSampleFrequency < (unsigned)time(NULL))
{
mSampleTotal++;
mAggregateTotal += value;
if (value > mAggregateMaximum)
mAggregateMaximum = value;
if (value < mAggregateMinimum)
mAggregateMinimum = value;
if (mAverageIndex == COUNT)
mAverageIndex = 0;
if (mAverageCount > COUNT)
mAverageTotal -= mAverageData[mAverageIndex];
mAverageData[mAverageIndex++] = value;
mAverageTotal += value;
if (mAverageCount < COUNT)
mAverageCount++;
commit = true;
mSample = 0;
}
mSample += value;
return commit;
}
TYPE GetSample(uint32 age = 0)
{
if (age > mAverageCount)
return 0;
uint32 index = mAverageIndex;
if (age > index)
index = COUNT - (age - index);
else
index -= age;
return mAverageData[index];
}
double GetAverage()
{
return (double)mAverageTotal/mAverageCount;
}
double GetAggregateAverage()
{
return (double)mAggregateTotal/mSampleTotal;
}
TYPE GetMaximum()
{
return mAggregateMaximum;
}
TYPE GetMinimum()
{
return mAggregateMinimum;
}
private:
uint32 mSampleFrequency;
time_t mLastSampleTime;
TYPE mSample;
uint32 mSampleTotal;
TYPE mAggregateTotal;
TYPE mAggregateMaximum;
TYPE mAggregateMinimum;
TYPE mAverageData[COUNT];
TYPE mAverageTotal;
uint32 mAverageIndex;
uint32 mAverageCount;
};
class CStatisticTimer
{
public:
CStatisticTimer(bool running = true);
void Start() { if (mRunning) return; mStart = getTimer(); mRunning = true; }
void Stop() { if (!mRunning) return; mTotal += getTimer()-mStart; mRunning = false; }
void Reset() { mTotal = 0; mStart = getTimer(); }
double GetTime();
uint64 GetFraction(uint32 fraction=1000);
private:
uint64 mTotal;
uint64 mStart;
bool mRunning;
};
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // STATISTICS_H
@@ -0,0 +1,238 @@
#ifndef BLOCK_ALLOCATOR_H
#define BLOCK_ALLOCATOR_H
#if defined _MT || defined _REENTRANT
# define USE_ALLOCATOR_MUTEX
#endif
#include <new>
#include "Mutex.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
template<int BLOCK_SIZE>
class CBlockAllocator
{
private:
class Node
{
public:
Node * mNext;
unsigned mBuffer[(BLOCK_SIZE-1)/sizeof(unsigned)+1];
};
public:
CBlockAllocator() :
mMemoryBlockCount(0),
mNodesAllocated(0),
mNodesUsed(0),
mUnusedList(0)
{
for (int block=0; block<MAX_BLOCK_COUNT; block++)
mMemoryBlock[block] = 0;
Allocate();
}
~CBlockAllocator()
{
for (int block=0; block<MAX_BLOCK_COUNT; block++)
delete[] mMemoryBlock[block];
}
void * Allocate()
{
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Lock();
#endif
void * data;
Node * node = mUnusedList;
mUnusedList = node->mNext;
node->mNext = (Node *)1;
data = node->mBuffer;
mNodesUsed++;
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Unlock();
#endif
return data;
}
void Deallocate(void * data)
{
if (!data)
return;
char * memoryPtr = reinterpret_cast<char *>(data) - sizeof(Node *);
Node * node = reinterpret_cast<Node *>(memoryPtr);
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Lock();
#endif
node->mNext = mUnusedList;
mUnusedList = node;
mNodesUsed--;
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Unlock();
#endif
}
template<class T> T * Construct(const T & object)
{
T * objectPtr;
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Lock();
#endif
if (sizeof(T) > BLOCK_SIZE || (!mUnusedList && !Allocate()))
{
char * memoryPtr = reinterpret_cast<char *>(new unsigned[(sizeof(Node *)+sizeof(T)-1)/sizeof(unsigned)+1]);
objectPtr = reinterpret_cast<T *>(memoryPtr+sizeof(Node *));
*reinterpret_cast<unsigned *>(memoryPtr) = 0;
}
else
{
Node * node = mUnusedList;
mUnusedList = node->mNext;
node->mNext = (Node *)1;
objectPtr = reinterpret_cast<T *>(node->mBuffer);
mNodesUsed++;
}
new (objectPtr) T(object);
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Unlock();
#endif
return objectPtr;
}
template<class T> void Destroy(T * object)
{
if (!object)
return;
char * memoryPtr = reinterpret_cast<char *>(object) - sizeof(Node *);
Node * node = reinterpret_cast<Node *>(memoryPtr);
object->~T();
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Lock();
#endif
if (node->mNext == 0)
delete []memoryPtr;
else
{
node->mNext = mUnusedList;
mUnusedList = node;
mNodesUsed--;
}
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Unlock();
#endif
}
template<class T> T * FastConstruct(const T & object)
{
T * objectPtr;
if (sizeof(T) > BLOCK_SIZE || (!mUnusedList && !Allocate()))
{
char * memoryPtr = reinterpret_cast<char *>(new unsigned[(sizeof(Node *)+sizeof(T)-1)/sizeof(unsigned)+1]);
objectPtr = reinterpret_cast<T *>(memoryPtr+sizeof(Node *));
*reinterpret_cast<unsigned *>(memoryPtr) = 0;
}
else
{
Node * node = mUnusedList;
mUnusedList = node->mNext;
node->mNext = (Node *)1;
objectPtr = reinterpret_cast<T *>(node->mBuffer);
mNodesUsed++;
}
new (objectPtr) T(object);
return objectPtr;
}
template<class T> void FastDestroy(T * object)
{
if (!object)
return;
char * memoryPtr = reinterpret_cast<char *>(object) - sizeof(Node *);
Node * node = reinterpret_cast<Node *>(memoryPtr);
object->~T();
if (node->mNext == 0)
delete []memoryPtr;
else
{
node->mNext = mUnusedList;
mUnusedList = node;
mNodesUsed--;
}
}
bool Allocate()
{
if (mMemoryBlockCount == MAX_BLOCK_COUNT)
return false;
unsigned count = (mNodesAllocated ? mNodesAllocated : 32);
Node* newMemoryBlock = new Node[count];
for (unsigned i=0; i<count-1; i++)
newMemoryBlock[i].mNext = &newMemoryBlock[i+1];
newMemoryBlock[count-1].mNext = mUnusedList;
mUnusedList = newMemoryBlock;
mMemoryBlock[mMemoryBlockCount++] = newMemoryBlock;
mNodesAllocated += count;
return true;
};
private:
enum { MAX_BLOCK_COUNT = 32 };
void * mMemoryBlock[MAX_BLOCK_COUNT];
unsigned mMemoryBlockCount;
unsigned mNodesAllocated;
unsigned mNodesUsed;
Node * mUnusedList;
#ifdef USE_ALLOCATOR_MUTEX
Base::CMutex mMutex;
#endif
};
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // BLOCK_ALLOCATOR_H
@@ -0,0 +1,200 @@
// TemplateCBlockAlloc.h: interface for the CBlockAlloc class.
//
//////////////////////////////////////////////////////////////////////
#ifndef _TEMPLATE_COBJECTALLOCATOR_H
#define _TEMPLATE_COBJECTALLOCATOR_H
#if defined _MT || defined _REENTRANT
# define USE_ALLOCATOR_MUTEX
#endif
#include <new>
#include "Types.h"
#include "Mutex.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
const uint32 MAX_BLOCK_COUNT = 32;
template <class TYPE>
class CObjectAllocator
{
public:
CObjectAllocator(uint32 size=32)
{
if (size < 32)
size = 32;
for (uint32 index=0; index<MAX_BLOCK_COUNT; index++)
mMemoryBlock[index] = 0;
mMemoryBlockCount = 0;
mObjectsAllocated = 0;
mObjectCount = 0;
mUnusedList = 0;
mBytesAllocated = 0;
Allocate(size);
}
~CObjectAllocator()
{
for (uint32 index=0; index<MAX_BLOCK_COUNT; index++)
delete[] mMemoryBlock[index];
}
TYPE *Construct()
{
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Lock();
#endif
if (!mUnusedList)
Allocate(mObjectCount);
Node *node = mUnusedList;
mUnusedList = mUnusedList->next;
new (node) TYPE;
mObjectCount++;
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Unlock();
#endif
return (TYPE *)node;
}
TYPE *Construct(const TYPE& object)
{
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Lock();
#endif
if (!mUnusedList)
Allocate(mObjectCount);
Node *node = mUnusedList;
mUnusedList = mUnusedList->next;
new (node) TYPE(object);
mObjectCount++;
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Unlock();
#endif
return (TYPE *)node;
}
void Destroy(TYPE *object)
{
if (object == NULL)
return;
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Lock();
#endif
object->~TYPE();
Node *node = reinterpret_cast<Node *>(object);
node->next = mUnusedList;
mUnusedList = node;
mObjectCount--;
#ifdef USE_ALLOCATOR_MUTEX
mMutex.Unlock();
#endif
}
TYPE *FastConstruct()
{
if (!mUnusedList)
Allocate(mObjectCount);
Node *node = mUnusedList;
mUnusedList = mUnusedList->next;
new (node) TYPE;
mObjectCount++;
return (TYPE *)node;
}
TYPE *FastConstruct(const TYPE& object)
{
if (!mUnusedList)
Allocate(mObjectCount);
Node *node = mUnusedList;
mUnusedList = mUnusedList->next;
new (node) TYPE(object);
mObjectCount++;
return (TYPE *)node;
}
void FastDestroy(TYPE *object)
{
if (object == NULL)
return;
object->~TYPE();
Node *node = reinterpret_cast<Node *>(object);
node->next = mUnusedList;
mUnusedList = node;
mObjectCount--;
}
private:
struct Node
{
char buffer[sizeof(TYPE)];
Node* next;
};
bool Allocate(uint32 size)
{
if (mMemoryBlockCount == MAX_BLOCK_COUNT)
return false;
Node* newMemoryBlock = new Node[size];
mBytesAllocated += size * sizeof(Node);
for (uint32 i=0; i<size-1; i++)
newMemoryBlock[i].next = &newMemoryBlock[i+1];
newMemoryBlock[size-1].next = mUnusedList;
mUnusedList = newMemoryBlock;
mMemoryBlock[mMemoryBlockCount++] = newMemoryBlock;
mObjectsAllocated += size;
return true;
};
Node* mMemoryBlock[MAX_BLOCK_COUNT];
uint32 mMemoryBlockCount;
uint32 mObjectsAllocated;
uint32 mObjectCount;
Node* mUnusedList;
#ifdef USE_ALLOCATOR_MUTEX
CMutex mMutex;
#endif
uint64 mBytesAllocated;
};
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // _TEMPLATE_CBLOCKALLOC_H
@@ -0,0 +1,22 @@
#ifndef BASE_THREAD_H
#define BASE_THREAD_H
#ifdef WIN32
#include "win32/Thread.h"
#elif linux
#include "linux/Thread.h"
#elif sparc
#include "solaris/Thread.h"
#else
#error /Base/Thread.h: Undefine platform type
#endif
#endif // BASE_THREAD_H
@@ -0,0 +1,23 @@
#ifndef BASE_TYPES_H
#define BASE_TYPES_H
#ifdef WIN32
#include "win32/Types.h"
#elif linux
#include "linux/Types.h"
#elif sparc
#include "solaris/Types.h"
#else
#error /Base/Types.h: Undefine platform type
#endif
#endif
@@ -0,0 +1,664 @@
#ifndef BASE__UCS2_H
#define BASE__UCS2_H
#include <algorithm>
#include <string>
#include <vector>
#include "Base/Archive.h"
namespace ucs2
{
class string
{
public:
typedef unsigned short char_type;
typedef unsigned size_type;
public:
string();
string(const string & copy);
string(const char * copy);
string(const char_type * copy);
explicit string(const std::string & copy);
~string();
string & operator=(const char * rhs);
string & operator=(const std::string & rhs);
string & operator=(const char_type * rhs);
string & operator=(const string & rhs);
string & operator+=(const char * rhs);
string & operator+=(const std::string & rhs);
string & operator+=(const char_type * rhs);
string & operator+=(const string & rhs);
const char_type & at(size_type index) const;
char_type & at(size_type index);
const char_type & operator[](size_type index) const;
char_type & operator[](size_type index);
bool operator==(const string & rhs) const;
bool operator!=(const string & rhs) const;
bool operator<(const string & rhs) const;
bool operator<=(const string & rhs) const;
bool operator>(const string & rhs) const;
bool operator>=(const string & rhs) const;
string & assign(const char_type * rhs);
string & assign(const char_type * rhs, size_type count);
string & assign(const string & rhs, size_type position, size_type count);
string & assign(const string & rhs);
string & assign(size_type count, char_type c);
string & assign(const char_type * first, const char_type * last);
string & append(const char_type * rhs);
string & append(const char_type * rhs, size_type count);
string & append(const string & rhs, size_type position, size_type count);
string & append(const string & rhs);
string & append(size_type count, char_type c);
string & append(const char_type * first, const char_type * last);
std::string narrow() const;
const char_type * c_str() const;
const char_type * data() const;
size_type length() const;
size_type size() const;
size_type max_size() const;
void resize(size_type n, char_type c = 0x0032);
size_type capacity() const;
void reserve(size_type n = 0);
bool empty() const;
private:
size_type mLength;
std::vector<char_type> mData;
static char_type mOutOfRangeCharacter;
};
inline char WideToNarrow(string::char_type c) { return (char)c; }
inline string::char_type NarrowToWide(char c) { return (string::char_type)c; }
string::char_type string::mOutOfRangeCharacter(0);
////////////////////////////////////////
// default constructor allocates 8 characters and sets length to zero
inline string::string() :
mLength(0),
mData(8,0)
{
}
////////////////////////////////////////
// target string is a null-terminated C string
inline string::string(const char * copy) :
mLength(0),
mData(8,0)
{
// (1) protect from null pointer
if (!copy)
{
return;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (*copy)
{
reserve(mLength+1);
mData[mLength++] = *copy++;
}
// (3) ensure null termination
mData[mLength]=0;
}
////////////////////////////////////////
// target string is a C string that may or may not include null characters
inline string::string(const std::string & copy) :
mLength(copy.length()),
mData(8,0)
{
// (1) ensure we have the storage for the entire string
reserve(mLength);
// (2) perform transform to copy the narrow string to our
// wide string
std::transform(copy.begin(), copy.end(), mData.begin(), NarrowToWide);
// (3) ensure null termination
mData[mLength] = 0;
}
////////////////////////////////////////
// target string is a wide null-terminated C string
inline string::string(const char_type * copy) :
mLength(0),
mData(8,0)
{
// (1) protect from null pointer
if (!copy)
{
return;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (*copy)
{
reserve(mLength+1);
mData[mLength++] = *copy++;
}
// (3) ensure null termination
mData[mLength]=0;
}
////////////////////////////////////////
// copy constructor
inline string::string(const string & copy) :
mLength(copy.mLength),
mData(8,0)
{
reserve(mLength);
mData.assign(copy.mData.begin(), copy.mData.begin()+copy.mLength+1);
}
inline string::~string()
{
}
inline string & string::operator=(const char * rhs)
{
mLength = 0;
// (1) protect from null pointer
if (!rhs)
{
mData[0] = 0;
return *this;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (*rhs)
{
reserve(mLength+1);
mData[mLength++] = *rhs++;
}
// (3) ensure null termination
mData[mLength]=0;
return *this;
}
inline string & string::operator=(const std::string & rhs)
{
mLength = rhs.length();
// (1) ensure we have the storage for the entire string
reserve(mLength);
// (2) perform transform to copy the narrow string to our
// wide string
std::transform(rhs.begin(), rhs.end(), mData.begin(), NarrowToWide);
// (3) ensure null termination
mData[mLength] = 0;
return *this;
}
inline string & string::operator=(const char_type * rhs)
{
mLength = 0;
// (1) protect from null pointer
if (!rhs)
{
mData[0] = 0;
return *this;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (*rhs)
{
reserve(mLength+1);
mData[mLength++] = *rhs++;
}
// (3) ensure null termination
mData[mLength]=0;
return *this;
}
inline string & string::operator=(const string & rhs)
{
// (1) protect from assigning to self
if (&rhs != this)
{
mLength = rhs.mLength;
reserve(mLength);
mData.assign(rhs.mData.begin(), rhs.mData.begin()+rhs.mLength+1);
}
return *this;
}
inline string & string::operator+=(const char * rhs)
{
// (1) protect from null pointer
if (!rhs)
{
return *this;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (*rhs)
{
reserve(mLength+1);
mData[mLength++] = *rhs++;
}
// (3) ensure null termination
mData[mLength]=0;
return *this;
}
inline string & string::operator+=(const std::string & rhs)
{
// (1) ensure we have the storage for the entire string
reserve(mLength+rhs.length());
// (2) perform transform to copy the narrow string to our
// wide string
std::transform(rhs.begin(), rhs.end(), mData.begin()+mLength, NarrowToWide);
// (3) ensure null termination
mLength += rhs.length();
mData[mLength] = 0;
return *this;
}
inline string & string::operator+=(const char_type * rhs)
{
// (1) protect from null pointer
if (!rhs)
{
return *this;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (*rhs)
{
reserve(mLength+1);
mData[mLength++] = *rhs++;
}
// (3) ensure null termination
mData[mLength]=0;
return *this;
}
inline string & string::operator+=(const string & rhs)
{
reserve(mLength+rhs.mLength);
std::copy(rhs.mData.begin(), rhs.mData.begin()+rhs.mLength+1, mData.begin()+mLength);
mLength += rhs.mLength;
return *this;
}
inline const string::char_type & string::at(string::size_type index) const
{
return (index > mLength) ? mOutOfRangeCharacter : mData[index];
}
inline string::char_type & string::at(string::size_type index)
{
return (index > mLength) ? mOutOfRangeCharacter : mData[index];
}
inline const string::char_type & string::operator[](string::size_type index) const
{
return (index > mLength) ? mOutOfRangeCharacter : mData[index];
}
inline string::char_type & string::operator[](string::size_type index)
{
return (index > mLength) ? mOutOfRangeCharacter : mData[index];
}
inline bool string::operator==(const string & rhs) const
{
if (mLength != rhs.mLength)
{
return false;
}
else
{
return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) == 0);
}
}
inline bool string::operator!=(const string & rhs) const
{
if (mLength != rhs.mLength)
{
return true;
}
else
{
return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) != 0);
}
}
inline bool string::operator<(const string & rhs) const
{
if (mLength <= rhs.mLength)
{
return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) < 0);
}
else
{
return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*rhs.mLength) < 0);
}
}
inline bool string::operator<=(const string & rhs) const
{
if (mLength <= rhs.mLength)
{
return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) <= 0);
}
else
{
return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*rhs.mLength) <= 0);
}
}
inline bool string::operator>(const string & rhs) const
{
if (mLength <= rhs.mLength)
{
return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) > 0);
}
else
{
return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*rhs.mLength) > 0);
}
}
inline bool string::operator>=(const string & rhs) const
{
if (mLength <= rhs.mLength)
{
return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*mLength) >= 0);
}
else
{
return (memcmp(&mData[0], &rhs.mData[0], sizeof(size_type)*rhs.mLength) >= 0);
}
}
inline string & string::assign(const char_type * rhs)
{
mLength = 0;
// (1) protect from null pointer
if (!rhs)
{
mData[0] = 0;
return *this;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (*rhs)
{
reserve(mLength+1);
mData[mLength++] = *rhs++;
}
// (3) ensure null termination
mData[mLength]=0;
return *this;
}
inline string & string::assign(const char_type * rhs, size_type count)
{
mLength = 0;
// (1) protect from null pointer
if (!rhs)
{
mData[0] = 0;
return *this;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (count--)
{
reserve(mLength+1);
mData[mLength++] = *rhs++;
}
// (3) ensure null termination
mData[mLength]=0;
return *this;
}
inline string & string::assign(const string & rhs, size_type position, size_type count)
{
// (1) protect from assigning to self
if (&rhs != this)
{
mLength = count;
reserve(mLength);
mData.assign(rhs.mData.begin()+position, rhs.mData.begin()+position+count+1);
}
return *this;
}
inline string & string::assign(const string & rhs)
{
// (1) protect from assigning to self
if (&rhs != this)
{
mLength = rhs.mLength;
reserve(mLength);
mData.assign(rhs.mData.begin(), rhs.mData.begin()+rhs.mLength+1);
}
return *this;
}
inline string & string::assign(size_type count, char_type c)
{
mLength = count;
reserve(mLength);
std::fill(mData.begin(), mData.end(), c);
mData[mLength]=0;
return *this;
}
inline string & string::assign(const char_type * first, const char_type * last)
{
mLength = 0;
// (1) protect from null pointer
if (!first || !last)
{
mData[0] = 0;
return *this;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (first != last)
{
reserve(mLength+1);
mData[mLength++] = *first++;
}
// (3) ensure null termination
mData[mLength]=0;
return *this;
}
inline string & string::append(const char_type * rhs)
{
// (1) protect from null pointer
if (!rhs)
{
return *this;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (*rhs)
{
reserve(mLength+1);
mData[mLength++] = *rhs++;
}
// (3) ensure null termination
mData[mLength]=0;
return *this;
}
inline string & string::append(const char_type * rhs, size_type count)
{
// (1) protect from null pointer
if (!rhs)
{
return *this;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (count--)
{
reserve(mLength+1);
mData[mLength++] = *rhs++;
}
// (3) ensure null termination
mData[mLength]=0;
return *this;
}
inline string & string::append(const string & rhs, size_type position, size_type count)
{
// (1) protect from invalid position value
if (rhs.mLength <= position)
{
return *this;
}
// (2) make sure we copy count charatcers, or to the end of the string
if (rhs.mLength < position+count)
{
count = rhs.mLength-position;
}
// (3) perform copy
reserve(mLength+count);
std::copy(rhs.mData.begin()+position, rhs.mData.begin()+position+count+1, mData.begin()+mLength);
mLength += count;
return *this;
}
inline string & string::append(const string & rhs)
{
// (1) perform copy
reserve(mLength+rhs.mLength);
std::copy(rhs.mData.begin(), rhs.mData.begin()+rhs.mLength+1, mData.begin()+mLength);
mLength += rhs.mLength;
return *this;
}
inline string & string::append(size_type count, char_type c)
{
reserve(mLength+count);
std::fill(mData.begin()+mLength, mData.begin()+mLength+count, c);
mLength += count;
mData[mLength]=0;
return *this;
}
inline string & string::append(const char_type * first, const char_type * last)
{
// (1) protect from null pointer
if (!first || !last)
{
return *this;
}
// (2) linear copy the string, must reserve before each character
// because the string length is unknown
while (first != last)
{
reserve(mLength+1);
mData[mLength++] = *first++;
}
// (3) ensure null termination
mData[mLength]=0;
return *this;
}
inline std::string string::narrow() const
{
std::string narrow;
narrow.resize(mLength);
std::transform(mData.begin(), mData.begin()+mLength+1, narrow.begin(), WideToNarrow);
return narrow;
}
inline const string::char_type * string::c_str() const
{
return &mData[0];
}
inline const string::char_type * string::data() const
{
return &mData[0];
}
inline string::size_type string::length() const
{
return mLength;
}
inline string::size_type string::size() const
{
return mLength;
}
inline void string::resize(string::size_type n, string::char_type c)
{
reserve(n);
while (mLength<n)
{
mData[mLength++] = c;
}
}
inline string::size_type string::capacity() const
{
return mData.size()-1;
}
inline void string::reserve(string::size_type n)
{
while (n > capacity())
mData.resize((capacity()+1)*2,0x0000);
}
inline bool string::empty() const
{
return mLength == 0;
}
}
namespace Base
{
inline void get(ByteStream::ReadIterator & source, ucs2::string & target)
{
unsigned int size = 0;
get(source, size);
const unsigned char * const buf = source.getBuffer();
const ucs2::string::char_type * const ubuf = reinterpret_cast<const ucs2::string::char_type *>(buf);
target.assign(ubuf, ubuf + size);
const unsigned int readSize = size * sizeof(ucs2::string::char_type);
source.advance(readSize);
}
inline void put(ByteStream & target, const ucs2::string & source)
{
const unsigned int size = source.size();
put(target, size);
put(target, (const unsigned char *)source.data(), size*sizeof(ucs2::string::char_type));
}
}
#endif
@@ -0,0 +1,44 @@
#ifndef BASE_LINUX_ARCHIVE_H
#define BASE_LINUX_ARCHIVE_H
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
#ifdef PACK_BIG_ENDIAN
inline double byteSwap(double value) { byteReverse(&value); return value; }
inline float byteSwap(float value) { byteReverse(&value); return value; }
inline uint64 byteSwap(uint64 value) { byteReverse(&value); return value; }
inline int64 byteSwap(int64 value) { byteReverse(&value); return value; }
inline uint32 byteSwap(uint32 value) { byteReverse(&value); return value; }
inline int32 byteSwap(int32 value) { byteReverse(&value); return value; }
inline uint16 byteSwap(uint16 value) { byteReverse(&value); return value; }
inline int16 byteSwap(int16 value) { byteReverse(&value); return value; }
#else
inline double byteSwap(double value) { return value; }
inline float byteSwap(float value) { return value; }
inline uint64 byteSwap(uint64 value) { return value; }
inline int64 byteSwap(int64 value) { return value; }
inline uint32 byteSwap(uint32 value) { return value; }
inline int32 byteSwap(int32 value) { return value; }
inline uint16 byteSwap(uint16 value) { return value; }
inline int16 byteSwap(int16 value) { return value; }
#endif
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif
@@ -0,0 +1,110 @@
#include "../BlockAllocator.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
BlockAllocator::BlockAllocator()
{
for(unsigned i = 0; i < 31; i++)
{
m_blocks[i] = NULL;
}
}
BlockAllocator::~BlockAllocator()
{
// free all allocated memory blocks
for(unsigned i = 0; i < 31; i++)
{
while(m_blocks[i] != NULL)
{
unsigned *tmp = m_blocks[i];
m_blocks[i] = (unsigned *)*m_blocks[i];
free(tmp);
}
}
}
// Allocate a block that is the next power of two greater than the # of bytes passed.
// 33 bytes yields a 64 byte block of memory and so forth.
void *BlockAllocator::getBlock(unsigned bytes)
{
unsigned accum = 16, bits = 16;
unsigned *handle = NULL;
// Perform a binary search looking for the highest bit.
while(bits != 0)
{
// If bytes is less than the bit we're testing for, subtract half
// from the bit value and repeat
if(bytes < (unsigned)(1 << accum))
{
bits /= 2;
accum -= bits;
}
// If bytes is greater than the bit we're testing for, add half
// from the but value and repeat
else if(bytes > (unsigned)(1 << accum))
{
bits /= 2;
accum += bits;
}
// Got lucky and hit the value dead on
else
{
break;
}
}
// At this point accum contains the most significant bit index, increment
accum++;
if(accum < 2)
{
accum = 2;
}
// Note that when memory is actually allocated, 8 extra bytes will be allocated.at the front
// The first integer is the address of the next block of memory when the block is in the allocator
// The second integer is the bit length of the block
// Memory is allocated on 4 byte boundaries to sidestep byte alignment problems
// Check if the allocator already has a block of that size
if(m_blocks[accum] == 0)
{
// remove the pre allocated block from the linked list
handle = (unsigned *)calloc(((1 << accum) / 4) + 2, sizeof(unsigned));
handle[1] = accum;
handle[0] = 0;
}
else
{
// Allocate a new block
handle = m_blocks[accum];
m_blocks[accum] = (unsigned *)handle[0];
handle[0] = 0;
}
// return a pointer that skips over the header used for the allocator's purposes
return(handle + 2);
}
void BlockAllocator::returnBlock(unsigned *handle)
{
// C++ allows for safe deletion of a NULL pointer
if(handle)
{
// Update the allocator linked list, insert this entry at the head
*(handle - 2) = (unsigned)m_blocks[*(handle - 1)];
// Add this entry to the proper linked list node
m_blocks[*(handle - 1)] = (handle - 2);
}
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,103 @@
////////////////////////////////////////
// Event.cpp
//
// Purpose:
// 1. Implementation of the CEvent class.
//
// Revisions:
// 07/10/2001 Created
//
#if defined(_REENTRANT)
#include "Event.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
CEvent::CEvent() :
mMutex(),
mCond(),
mThreadCount(0)
{
pthread_mutex_init(&mMutex, NULL);
pthread_cond_init(&mCond, NULL);
}
CEvent::~CEvent()
{
pthread_cond_destroy(&mCond);
pthread_mutex_destroy(&mMutex);
}
bool CEvent::Signal()
{
pthread_mutex_lock(&mMutex);
if (mThreadCount == 0)
mThreadCount = SIGNALED;
pthread_cond_signal(&mCond);
pthread_mutex_unlock(&mMutex);
return true;
}
int32 CEvent::Wait(uint32 timeout)
{
int result;
pthread_mutex_lock(&mMutex);
if (mThreadCount == SIGNALED)
{
mThreadCount = 0;
pthread_mutex_unlock(&mMutex);
return eWAIT_SIGNAL;
}
if (!timeout)
{
mThreadCount++;
result = pthread_cond_wait(&mCond, &mMutex);
mThreadCount--;
pthread_mutex_unlock(&mMutex);
}
else
{
struct timeval now;
struct timespec abs_timeout;
gettimeofday(&now, NULL);
abs_timeout.tv_sec = now.tv_sec + timeout/1000;
abs_timeout.tv_nsec = now.tv_usec * 1000 + (timeout%1000)*1000000;
abs_timeout.tv_sec += abs_timeout.tv_nsec / 1000000000;
abs_timeout.tv_nsec %= 1000000000;
mThreadCount++;
result = pthread_cond_timedwait(&mCond, &mMutex, &abs_timeout);
mThreadCount--;
pthread_mutex_unlock(&mMutex);
}
if (result == 0 || result == EINTR)
return eWAIT_SIGNAL;
else if (result == ETIMEDOUT)
return eWAIT_TIMEOUT;
else
return eWAIT_ERROR;
}
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_REENTRANT)
@@ -0,0 +1,74 @@
////////////////////////////////////////
// Event.h
//
// Purpose:
// 1. Declair the CEvent class that encapsulates the functionality of a
// single-locking semaphore.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_LINUX_EVENT_H
#define BASE_LINUX_EVENT_H
#if !defined(_REENTRANT)
# pragma message( "Excluding Base::CEvent - requires multi-threaded compile. (_REENTRANT)" )
#else
#include <pthread.h>
#include "Platform.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
////////////////////////////////////////
// Class:
// CEvent
//
// Purpose:
// Encapsulates the functionality of a singal-locking semaphore.
// This class is valuable for thread syncronization when a thead's
// execution needs to be dependent upon another thread.
//
// Public Methods:
// Signal() : Signals a thread that has called Wait() so that it can
// continue execution. This function returns true if the waiting
// thread was signalled successfully, otherwise false is returned.
// Wait() : Halts the calling thread's execution indefinately until
// a Singal() call is made by an external thread. If the thread is
// successfully signalled, the function returns eWAIT_SIGNAL. If
// timeout period expires without a signal, eWAIT_TIMEOUT is returned.
// If the function fails, eWAIT_ERROR is returned.
//
class CEvent
{
public:
CEvent();
virtual ~CEvent();
bool Signal();
int32 Wait(uint32 timeout = 0);
public:
enum { eWAIT_ERROR, eWAIT_SIGNAL, eWAIT_TIMEOUT };
enum { SIGNALED = -1 };
private:
pthread_mutex_t mMutex;
pthread_cond_t mCond;
int mThreadCount;
};
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_MT)
#endif // BASE_LINUX_EVENT_H
@@ -0,0 +1,40 @@
////////////////////////////////////////
// Mutex.cpp
//
// Purpose:
// 1. Implementation of the CMutex class.
//
// Revisions:
// 07/10/2001 Created
//
#if defined(_REENTRANT)
#include "Mutex.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
CMutex::CMutex()
{
mInitialized = (pthread_mutex_init(&mMutex, 0) == 0);
}
CMutex::~CMutex()
{
if (mInitialized)
pthread_mutex_destroy(&mMutex);
}
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_REENTRANT)
@@ -0,0 +1,79 @@
////////////////////////////////////////
// Mutex.h
//
// Purpose:
// 1. Declair the CMutex class that encapsulates the functionality of a
// mutually-exclusive device.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_LINUX_MUTEX_H
#define BASE_LINUX_MUTEX_H
#if !defined(_REENTRANT)
# pragma message( "Excluding Base::CMutex - requires multi-threaded compile. (_REENTRANT)" )
#else
#include "Platform.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
////////////////////////////////////////
// Class:
// CMutex
//
// Purpose:
// Encapsulates the functionality of a mutually-exclusive device.
// This class is valuable for protecting against race conditions
// within threaded applications. The CMutex class can be used to
// only allow a single thread to run within a specified code
// segment at a time.
//
// Public Methods:
// Lock() : Locks the mutex. If the mutex is already locked, the
// operating system will block the calling thread until another
// thread has unlocked the mutex.
// Unlock() : Unlocks the mutex.
//
class CMutex
{
public:
CMutex();
~CMutex();
void Lock();
void Unlock();
private:
pthread_mutex_t mMutex;
bool mInitialized;
};
inline void CMutex::Lock(void)
{
if (mInitialized)
pthread_mutex_lock(&mMutex);
}
inline void CMutex::Unlock(void)
{
if (mInitialized)
pthread_mutex_unlock(&mMutex);
}
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_MT)
#endif // BASE_LINUX_MUTEX_H
@@ -0,0 +1,55 @@
////////////////////////////////////////
// Platform.cpp
//
// Purpose:
// 1. Implementation of the global functionality declaired in Platform.h.
//
// Revisions:
// 07/10/2001 Created
//
#include <ctype.h>
#include "Platform.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
// Implementation of microsoft strlwr extension
// This non-ANSI function is not supported under UNIX
void _strlwr(char * s)
{
while (*s)
{
*s = tolower(*s);
s++;
}
}
// Implementation of microsoft strlwr extension
// This non-ANSI function is not supported under UNIX
void _strupr(char * s)
{
while (*s)
{
*s = toupper(*s);
s++;
}
}
CTimer::CTimer() :
mTimer(0)
{
}
}
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,112 @@
////////////////////////////////////////
// Platform.h
//
// Purpose:
// 1. Include relevent system headers that are platform specific.
// 2. Declair global platform specific functionality.
// 3. Include primative type definitions
//
// Global Functions:
// getTimer() : Return the current high resolution clock count.
// getTimerFrequency() : Return the frequency of the high resolution clock.
// sleep() : Voluntarily relinquish timeslice of the calling thread for a
// specified number of milliseconds.
// strlwr() : Alters the contents of a string, making it all lower-case.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_LINUX_PLATFORM_H
#define BASE_LINUX_PLATFORM_H
#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>
#include "Types.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
uint64 getTimer(void);
uint64 getTimerFrequency(void);
void sleep(uint32 ms);
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 uint64 getTimerFrequency(void)
{
uint64 f = 1000000;
return f;
}
inline void sleep(uint32 ms)
{
usleep(static_cast<unsigned long>(ms * 1000));
}
void _strlwr(char * s);
void _strupr(char * s);
class CTimer
{
public:
CTimer();
void Set(uint32 seconds);
void Signal();
bool Expired();
private:
uint32 mTimer;
};
inline void CTimer::Set(uint32 interval)
{
mTimer = (uint32)time(0) + interval;
}
inline void CTimer::Signal()
{
mTimer = 0;
}
inline bool CTimer::Expired()
{
return (mTimer <= (uint32)time(0));
}
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // BASE_LINUX_PLATFORM_H
@@ -0,0 +1,274 @@
////////////////////////////////////////
// Thread.cpp
//
// Purpose:
// 1. Implementation of the CThread class.
//
// Revisions:
// 07/10/2001 Created
//
#if defined(_REENTRANT)
#include <pthread.h>
#include <time.h>
#include "Thread.h"
using namespace std;
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
void *threadProc(void *threadPtr)
{
CThread &thread = *((CThread*)threadPtr);
thread.mThreadActive = true;
thread.ThreadProc();
thread.mThreadActive = false;
return 0;
}
CThread::CThread()
{
mThreadID = 0;
mThreadActive = false;
mThreadContinue = false;
}
CThread::~CThread()
{
StopThread();
}
void CThread::StartThread()
{
mThreadContinue = true;
pthread_create(&mThreadID,0,threadProc,this);
while (!IsThreadActive())
Base::sleep(1);
}
int32 CThread::StopThread(int timeout)
{
timeout += time(0);
mThreadContinue = false;
while (mThreadActive && time(0)<timeout)
sleep(1);
if (mThreadActive)
{
mThreadActive = false;
return eSTOP_TIMEOUT;
}
return eSTOP_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////
CThreadPool::CMember::CMember(CThreadPool * parent) :
mParent(parent),
mFunction(NULL),
mArgument(NULL),
mSemaphore()
{
StartThread();
}
CThreadPool::CMember::~CMember()
{
}
void CThreadPool::CMember::Destroy()
{
mThreadContinue = false;
mSemaphore.Signal();
}
bool CThreadPool::CMember::Execute(void( *function )( void * ), void * arg)
{
if (mFunction)
return false;
mArgument = arg;
mFunction = function;
mSemaphore.Signal();
return true;
}
void CThreadPool::CMember::ThreadProc()
{
mParent->OnStartup(this);
while (mThreadContinue)
{
mParent->OnIdle(this);
mSemaphore.Wait(mParent->GetTimeOut()*1000);
if (mFunction)
{
mFunction(mArgument);
mArgument = NULL;
mFunction = NULL;
}
else if (mParent->OnDestory(this))
mThreadContinue = false;
}
}
////////////////////////////////////////////////////////////////////////////////
CThreadPool::CThreadPool(uint32 maxThreads, uint32 minThreads, uint32 timeout) :
mMutex(),
mIdleMember(),
mBusyMember(),
mNullMember(),
mThreadCount(0),
mMaxThreads(maxThreads),
mMinThreads(minThreads),
mTimeOut(timeout)
{
if (mMaxThreads == 0) mMaxThreads = 1;
if (mMinThreads == 0) mMinThreads = 1;
if (mMinThreads > mMaxThreads) mMinThreads = mMaxThreads;
for (uint32 i=0; i<mMinThreads; i++)
new CMember(this);
}
CThreadPool::~CThreadPool()
{
set<CMember *>::iterator setIterator;
////////////////////////////////////////
// (1) Destory all busy member threads
mMutex.Lock();
setIterator = mBusyMember.begin();
while (setIterator != mBusyMember.end())
(*setIterator++)->Destroy();
mMutex.Unlock();
////////////////////////////////////////
// (2) Destory all idle member threads
while (mThreadCount)
{
mMutex.Lock();
setIterator = mIdleMember.begin();
while (setIterator != mIdleMember.end())
(*setIterator++)->Destroy();
mMutex.Unlock();
sleep(1);
}
////////////////////////////////////////
// (3) Delete the null member threads
mMutex.Lock();
while (!mNullMember.empty())
{
delete mNullMember.front();
mNullMember.pop_front();
}
mMutex.Unlock();
}
bool CThreadPool::Execute(void( *function )( void * ), void * arg)
{
mMutex.Lock();
////////////////////////////////////////
// (1) If no idle members, return false to indicate that no threads
// were available. If the thread count is below the max, create
// a new thread.
if (mIdleMember.empty())
{
if (mThreadCount < mMaxThreads)
new CMember(this);
mMutex.Unlock();
return false;
}
////////////////////////////////////////
// (2) Delete any null member threads.
while (!mNullMember.empty())
{
delete mNullMember.front();
mNullMember.pop_front();
}
////////////////////////////////////////
// (3) Move the first idle thread to the busy set and signal the
// thread to execute the specified function.
CMember * member = *(mIdleMember.begin());
mIdleMember.erase(member);
mBusyMember.insert(member);
member->Execute(function,arg);
mMutex.Unlock();
return true;
}
uint32 CThreadPool::GetTimeOut()
{
return mTimeOut;
}
void CThreadPool::OnStartup(CMember * member)
{
mMutex.Lock();
mThreadCount++;
mIdleMember.insert(member);
mMutex.Unlock();
}
void CThreadPool::OnIdle(CMember * member)
{
mMutex.Lock();
mBusyMember.erase(member);
mIdleMember.insert(member);
mMutex.Unlock();
}
bool CThreadPool::OnDestory(CMember * member)
{
set<CMember *>::iterator setIterator;
mMutex.Lock();
bool result = (setIterator = mIdleMember.find(member)) != mIdleMember.end();
if (result)
{
mNullMember.push_back(member);
mIdleMember.erase(setIterator);
mThreadCount--;
}
mMutex.Unlock();
return result;
}
////////////////////////////////////////////////////////////////////////////////
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_REENTRANT)
@@ -0,0 +1,146 @@
////////////////////////////////////////
// Thread.h
//
// Purpose:
// 1. Declair the CThread class that encapsulates threading functionality.
// This abstract base class in intended to be used to encapsulate
// individual tasks that require threading in derived classes.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_LINUX_THREAD_H
#define BASE_LINUX_THREAD_H
#if !defined(_REENTRANT)
# pragma message( "Excluding Base::CThread - requires multi-threaded compile. (_REENTRANT)" )
#else
#pragma warning( disable : 4786)
#include <list>
#include <set>
#include "Platform.h"
#include "Mutex.h"
#include "Event.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
////////////////////////////////////////
// Class:
// CThread
//
// Purpose:
// Encapsulates threading functionality. Creating classes derived
// from CThread provides an easy way to encapsulate tasks that require
// their own thread.
//
// Public Methods:
// StartThread() : Creates the low-level thread handle and begins executing
// the CThread::ThreadProc() function within the new thread.
// StopThread() : Signals the ThreadProc() function to stop executing using
// the mThreadContinue member variable, and waits for the ThreadProc()
// function to exit. By default, the function will block for a maximum
// of 5 seconds before exiting without the thread halting.
// IsThreadActive() : Returns true if the physical thread is still executing
// within the ThreadProc() function, otherwise it returns false.
// ThreadProc() : Pure-virtual function that will be executed when the StartThread()
// function is called. Derived classes must implement this function. The
// mThreadContinue member variable should be used internal the the ThreadProc()
// function to indicate whether it should continue executing or exit.
// Protected Attributes:
// mThreadContinue : Boolean value indicating to the ThreadProc() function
// whether to continue executing or to exit. If mThreadContinue is true,
// ThreadProc() should continue, otherwise ThreadProc() should exit. It
// left up to the derived class to implement a ThreadProc() function that
// uses the mThreadContinue member.
//
//
class CThread
{
friend void * threadProc(void *);
public:
enum { eSTOP_SUCCESS, eSTOP_TIMEOUT };
public:
CThread();
virtual ~CThread();
void StartThread();
int32 StopThread(int timeout=5);
bool IsThreadActive() { return mThreadActive; }
protected:
virtual void ThreadProc() {}
protected:
bool mThreadContinue;
private:
pthread_t mThreadID;
bool mThreadActive;
};
class CThreadPool
{
private:
class CMember : public CThread
{
public:
CMember(CThreadPool * parent);
virtual ~CMember();
bool Execute(void( *function )( void * ), void * arg);
void Destroy();
protected:
virtual void ThreadProc();
private:
CThreadPool * mParent;
void( * mFunction )( void * );
void * mArgument;
CEvent mSemaphore;
};
friend class CMember;
public:
CThreadPool(uint32 maxThreads, uint32 minThreads=1, uint32 timeout=15*60);
~CThreadPool();
bool Execute(void( *function )( void * ), void * arg);
private:
uint32 GetTimeOut();
void OnStartup(CMember * member);
void OnIdle(CMember * member);
bool OnDestory(CMember * member);
private:
CMutex mMutex;
std::set<CMember *> mIdleMember;
std::set<CMember *> mBusyMember;
std::list<CMember *> mNullMember;
uint32 mThreadCount;
uint32 mMaxThreads;
uint32 mMinThreads;
uint32 mTimeOut;
};
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_REENTRANT)
#endif // BASE_LINUX_THREAD_H
@@ -0,0 +1,42 @@
////////////////////////////////////////
// Types.h
//
// Purpose:
// 1. Define integer types that are unambiguous with respect to size
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_LINUX_TYPES_H
#define BASE_LINUX_TYPES_H
#include <sys/bitypes.h>
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
#define INT32_MAX 0x7FFFFFFF
#define INT32_MIN 0x80000000
#define UINT32_MAX 0xFFFFFFFF
typedef signed char int8;
typedef unsigned char uint8;
typedef signed short int16;
typedef unsigned short uint16;
typedef int32_t int32;
typedef u_int32_t uint32;
typedef int64_t int64;
typedef u_int64_t uint64;
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // BASE_LINUX_TYPES_H
@@ -0,0 +1,585 @@
#ifndef SOE__SERIALIZE_H
#define SOE__SERIALIZE_H
#include <assert.h>
#include <string>
#include <vector>
#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
////////////////////////////////////////////////////////////////////////////////
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace soe
{
using namespace Base;//for types
////////////////////////////////////////////////////////////////////////////////
// 388 ns (50 bytes)
inline unsigned Write(unsigned char * stream, unsigned size, const unsigned char * data, unsigned dataLen)
{
if (size < dataLen)
return 0;
memcpy(stream, data, dataLen);
return dataLen;
}
// 353 ns
inline unsigned Write(unsigned char * stream, unsigned size, bool data)
{
if (size < sizeof(uint8))
return 0;
stream[BYTE1] = data;
return sizeof(uint8);
}
// 362 ns
inline unsigned Write(unsigned char * stream, unsigned size, int8 data)
{
if (size < sizeof(int8))
return 0;
stream[BYTE1] = data;
return sizeof(int8);
}
// 362 ns
inline unsigned Write(unsigned char * stream, unsigned size, uint8 data)
{
if (size < sizeof(uint8))
return 0;
stream[BYTE1] = data;
return sizeof(uint8);
}
// 355 ns
inline unsigned Write(unsigned char * stream, unsigned size, int16 data)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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, bool isPascal=true)
{
if (isPascal)
{
unsigned fieldLen = 0;
unsigned bytes = 0;
fieldLen = Write(stream, size, static_cast<unsigned>(data.length()));
if (!fieldLen)
return 0;
bytes += fieldLen;
if (data.length())
{
fieldLen = Write(stream+bytes, size-bytes, reinterpret_cast<const unsigned char *>(data.data()), data.length());
if (!fieldLen)
return 0;
bytes += fieldLen;
}
return bytes;
}
else
{
unsigned bytes = Write(stream, size, reinterpret_cast<const unsigned char *>(data.c_str()), data.size()+1);
if (!bytes)
return 0;
return bytes;
}
}
template<class T>
inline unsigned Write(unsigned char * stream, unsigned size, const std::vector<T> & data)
{
unsigned bytes = 0;
unsigned elementBytes = 0;
bytes += Write(stream, size, static_cast<unsigned>(data.size()));
if (!bytes)
return 0;
for (typename std::vector<T>::const_iterator iter = data.begin(); iter != data.end(); iter++)
{
elementBytes = Write(stream+bytes, size-bytes, *iter);
if (!elementBytes)
return 0;
bytes += elementBytes;
}
return bytes;
}
inline unsigned Read(const unsigned char * stream, unsigned size, unsigned char * data, unsigned dataLen)
{
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*/)
{
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*/)
{
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*/)
{
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*/)
{
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*/)
{
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*/)
{
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*/)
{
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*/)
{
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*/)
{
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*/)
{
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*/)
{
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, bool isPascal=true)
{
if (isPascal)
{
unsigned bytes = 0;
unsigned length = 0;
bytes += Read(stream, size, length);
if (!bytes || size < bytes+length || length > maxLen)
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;
}
else
{
//find null terminator, if don't find it before maxLen, then err
const unsigned char *strEnd = NULL;
unsigned strLen = 0;
for (;strLen<maxLen && strLen < size;strLen++)
{
if (stream[strLen] == 0)
{
//found it
strEnd = (stream+strLen);
break;
}
}
if (strEnd == NULL)
return 0;
data.assign((const char *)stream, (const char *)strEnd);
return strLen+1;
}
}
template<class T>
inline unsigned Read(const unsigned char * stream, unsigned size, std::vector<T> & data, unsigned maxVecLen, unsigned maxFieldLen = 1)
{
T element;
unsigned bytes = 0;
unsigned elementBytes = 0;
unsigned length = 0;
data.clear();
bytes += Read(stream, size, length);
if (!bytes || length > maxVecLen)
return 0;
for (unsigned i=0; i<length; i++)
{
elementBytes = Read(stream+bytes, size-bytes, element, maxFieldLen);
if (!elementBytes)
return 0;
data.push_back(element);
bytes += elementBytes;
}
return bytes;
}
////////////////////////////////////////////////////////////////////////////////
class AutoVariableBase
{
public:
AutoVariableBase() {}
virtual ~AutoVariableBase() {}
virtual unsigned Write(unsigned char * stream, unsigned size) const = 0;
virtual unsigned Read(const unsigned char * stream, unsigned size, unsigned maxLen=1) = 0;
};
template<class ValueType>
class AutoVariable : public AutoVariableBase
{
public:
AutoVariable() : AutoVariableBase(), 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; }
void Set(const ValueType & rhs) { mValue = rhs; }
virtual unsigned Write(unsigned char * stream, unsigned size) const { return soe::Write(stream, size, mValue); }
virtual unsigned Read(const unsigned char * stream, unsigned size, unsigned maxLen) { return soe::Read(stream, size, mValue, maxLen); }
private:
ValueType mValue;
};
////////////////////////////////////////////////////////////////////////////////
}
#ifdef EXTERNAL_DISTRO
};
#endif
#endif
@@ -0,0 +1,36 @@
#ifndef BASE_SOLARIS_ARCHIVE_H
#define BASE_SOLARIS_ARCHIVE_H
namespace Base
{
#ifdef PACK_BIG_ENDIAN
inline double byteSwap(double value) { return value; }
inline float byteSwap(float value) { return value; }
inline uint64 byteSwap(uint64 value) { return value; }
inline int64 byteSwap(int64 value) { return value; }
inline uint32 byteSwap(uint32 value) { return value; }
inline int32 byteSwap(int32 value) { return value; }
inline uint16 byteSwap(uint16 value) { return value; }
inline int16 byteSwap(int16 value) { return value; }
#else
inline double byteSwap(double value) { byteReverse64(&value); return value; }
inline float byteSwap(float value) { byteReverse32(&value); return value; }
inline uint64 byteSwap(uint64 value) { byteReverse64(&value); return value; }
inline int64 byteSwap(int64 value) { byteReverse64(&value); return value; }
inline uint32 byteSwap(uint32 value) { byteReverse32(&value); return value; }
inline int32 byteSwap(int32 value) { byteReverse32(&value); return value; }
inline uint16 byteSwap(uint16 value) { byteReverse16(&value); return value; }
inline int16 byteSwap(int16 value) { byteReverse16(&value); return value; }
#endif
}
#endif
@@ -0,0 +1,102 @@
#include "../BlockAllocator.h"
namespace Base
{
BlockAllocator::BlockAllocator()
{
for(unsigned i = 0; i < 31; i++)
{
m_blocks[i] = NULL;
}
}
BlockAllocator::~BlockAllocator()
{
// free all allocated memory blocks
for(unsigned i = 0; i < 31; i++)
{
while(m_blocks[i] != NULL)
{
unsigned *tmp = m_blocks[i];
m_blocks[i] = (unsigned *)*m_blocks[i];
free(tmp);
}
}
}
// Allocate a block that is the next power of two greater than the # of bytes passed.
// 33 bytes yields a 64 byte block of memory and so forth.
void *BlockAllocator::getBlock(unsigned bytes)
{
unsigned accum = 16, bits = 16;
unsigned *handle = NULL;
// Perform a binary search looking for the highest bit.
while(bits != 0)
{
// If bytes is less than the bit we're testing for, subtract half
// from the bit value and repeat
if(bytes < (unsigned)(1 << accum))
{
bits /= 2;
accum -= bits;
}
// If bytes is greater than the bit we're testing for, add half
// from the but value and repeat
else if(bytes > (unsigned)(1 << accum))
{
bits /= 2;
accum += bits;
}
// Got lucky and hit the value dead on
else
{
break;
}
}
// At this point accum contains the most significant bit index, increment
accum++;
if(accum < 2)
{
accum = 2;
}
// Note that when memory is actually allocated, 8 extra bytes will be allocated.at the front
// The first integer is the address of the next block of memory when the block is in the allocator
// The second integer is the bit length of the block
// Memory is allocated on 4 byte boundaries to sidestep byte alignment problems
// Check if the allocator already has a block of that size
if(m_blocks[accum] == 0)
{
// remove the pre allocated block from the linked list
handle = (unsigned *)calloc(((1 << accum) / 4) + 2, sizeof(unsigned));
handle[1] = accum;
handle[0] = 0;
}
else
{
// Allocate a new block
handle = m_blocks[accum];
m_blocks[accum] = (unsigned *)handle[0];
handle[0] = 0;
}
// return a pointer that skips over the header used for the allocator's purposes
return(handle + 2);
}
void BlockAllocator::returnBlock(unsigned *handle)
{
// C++ allows for safe deletion of a NULL pointer
if(handle)
{
// Update the allocator linked list, insert this entry at the head
*(handle - 2) = (unsigned)m_blocks[*(handle - 1)];
// Add this entry to the proper linked list node
m_blocks[*(handle - 1)] = (handle - 2);
}
}
};
@@ -0,0 +1,93 @@
////////////////////////////////////////
// Event.cpp
//
// Purpose:
// 1. Implementation of the CEvent class.
//
// Revisions:
// 07/10/2001 Created
//
#if defined(_REENTRANT)
#include "Event.h"
namespace Base
{
CEvent::CEvent()
{
mWaiting = 0;
mSignaled = false;
mInitialized = false;
if (pthread_cond_init( &mCond, NULL ) != 0)
{
return;
}
if (pthread_mutex_init( &mMutex, NULL ) != 0)
{
pthread_cond_destroy( &mCond );
return;
}
mInitialized = true;
}
CEvent::~CEvent()
{
if (mInitialized)
{
pthread_cond_destroy(&mCond);
pthread_mutex_destroy(&mMutex);
}
}
int32 CEvent::Wait(uint32 timeout)
{
if (!mInitialized)
return CEvent::eWAIT_ERROR;
int result;
pthread_mutex_lock(&mMutex);
if (mSignaled)
{
mSignaled = false;
}
else if (!timeout)
{
mWaiting++;
result = pthread_cond_wait(&mCond, &mMutex);
mWaiting--;
}
else
{
struct timespec wake_time;
clock_gettime( CLOCK_REALTIME, &wake_time );
wake_time.tv_sec += timeout/1000;
wake_time.tv_nsec += (timeout%1000)*1000000;
// normalize new time
wake_time.tv_sec += wake_time.tv_nsec / 1000000000;
wake_time.tv_nsec %= 1000000000;
mWaiting++;
result = pthread_cond_timedwait( &mCond, &mMutex, &wake_time );
mWaiting--;
}
pthread_mutex_unlock(&mMutex);
if (result == 0)
return CEvent::eWAIT_SIGNAL;
else if (result == ETIMEDOUT)
return CEvent::eWAIT_TIMEOUT;
else
return CEvent::eWAIT_ERROR;
}
}
#endif // #if defined(_REENTRANT)
@@ -0,0 +1,83 @@
////////////////////////////////////////
// Event.h
//
// Purpose:
// 1. Declair the CEvent class that encapsulates the functionality of a
// single-locking semaphore.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_SOLARIS_EVENT_H
#define BASE_SOLARIS_EVENT_H
#if !defined(_REENTRANT)
# pragma message( "Excluding Base::CEvent - requires multi-threaded compile. (_REENTRANT)" )
#else
#include "Platform.h"
namespace Base
{
////////////////////////////////////////
// Class:
// CEvent
//
// Purpose:
// Encapsulates the functionality of a singal-locking semaphore.
// This class is valuable for thread syncronization when a thead's
// execution needs to be dependent upon another thread.
//
// Public Methods:
// Signal() : Signals a thread that has called Wait() so that it can
// continue execution. This function returns true if the waiting
// thread was signalled successfully, otherwise false is returned.
// Wait() : Halts the calling thread's execution indefinately until
// a Singal() call is made by an external thread. If the thread is
// successfully signalled, the function returns eWAIT_SIGNAL. If
// timeout period expires without a signal, eWAIT_TIMEOUT is returned.
// If the function fails, eWAIT_ERROR is returned.
//
class CEvent
{
public:
CEvent();
virtual ~CEvent();
bool Signal();
int32 Wait(uint32 timeout = 0);
public:
enum { eWAIT_ERROR, eWAIT_SIGNAL, eWAIT_TIMEOUT };
private:
pthread_mutex_t mMutex;
pthread_cond_t mCond;
bool mInitialized;
bool mSignaled;
int32 mWaiting;
};
inline bool CEvent::Signal()
{
if (!mInitialized)
return false;
pthread_mutex_lock(&mMutex);
if(mWaiting > 0)
{
pthread_cond_signal(&mCond);
}
else
{
mWaiting = true;
}
pthread_mutex_unlock(&mMutex);
return true;
}
}
#endif // #if defined(_MT)
#endif // BASE_SOLARIS_EVENT_H
@@ -0,0 +1,387 @@
#include "../Logger.h"
#include "Mutex.h"
#include <sys/stat.h>
using namespace std;
namespace Base
{
const char file_sep = '/';
Logger::Logger(const char *prefix, int level, unsigned size, bool rollDate)
: m_defaultLevel(level), m_defaultSize(size), m_dirPrefix(prefix), m_rollDate(rollDate)
{
char buf[1024];
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;
time_t t = time(NULL);
#ifdef REENTRANT
localtime_r(&t, &now);
#else
now = *(localtime(&t));
#endif
memcpy(&m_lastDateTime, &now, sizeof(tm));
if(m_rollDate)
{
sprintf(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
{
sprintf(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;
}
Logger::~Logger()
{
map<unsigned, LogInfo *>::iterator iter;
for(iter = m_logTable.begin(); iter != m_logTable.end(); iter++)
{
log((*iter).first, LOG_FILEONLY, "---=== Log Stopped ===---");
fflush((*iter).second->file);
fclose((*iter).second->file);
delete((*iter).second);
}
m_logTable.clear();
}
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()
{
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)
{
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+");
}
log(logenum, LOG_FILEONLY, "---=== Log Started ===---");
}
void Logger::addLog(const char *id, unsigned logenum)
{
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+");
}
log(logenum, LOG_FILEONLY, "---===Log Started ===---");
}
void Logger::updateLog(unsigned logenum, int level, unsigned size)
{
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)
{
map<unsigned, LogInfo *>::iterator iter = m_logTable.find(logenum);
if(iter != m_logTable.end())
{
log((*iter).first, LOG_ALWAYS, "---=== Log Stopped ===---");
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;
}
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 defined(_REENTRANT)
rLock.Lock();
#endif
if(info->ts.tm_mday != m_lastDateTime.tm_mday)
{
memcpy(&m_lastDateTime, &info->ts, sizeof(tm));
rollDate(t);
}
#if defined(_REENTRANT)
rLock.Unlock();
#endif
}
if(iter != m_logTable.end())
{
if(info->max > 0)
{
int tmp = fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s\n", (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 += tmp;
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\n", (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);
fflush(info->file);
}
}
}
void Logger::log(unsigned logenum, int level, const char *message, ...)
{
char buf[2048];
va_list varg;
va_start(varg, message);
vsnprintf(buf, 2047, message, varg);
buf[2047] = 0;
va_end(varg);
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(info->last != t)
{
#ifdef REENTRANT
localtime_r(&t, &info->ts);
#else
info->ts = *(localtime(&t));
#endif
info->last = t;
}
if(info->ts.tm_mday != m_lastDateTime.tm_mday)
{
#if defined(_REENTRANT)
rLock.Lock();
#endif
if(info->ts.tm_mday != m_lastDateTime.tm_mday)
{
memcpy(&m_lastDateTime, &info->ts, sizeof(tm));
rollDate(t);
}
#if defined(_REENTRANT)
rLock.Unlock();
#endif
}
if(iter != m_logTable.end())
{
if(info->max > 0)
{
int tmp = fprintf(info->file, "[%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d] %s\n", (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 += tmp;
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\n", (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);
fflush(info->file);
}
}
}
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;
#ifdef REENTRANT
localtime_r(&t, &now);
#else
now = *(localtime(&t));
#endif
sprintf(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+");
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;
// 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();
}
}
mkdir(j, mode);
close(handle);
(*i) = file_sep;
}
else if(*(i + 1) == 0)
{
mkdir(j, mode);
}
i++;
}
}
};
@@ -0,0 +1,32 @@
////////////////////////////////////////
// Mutex.cpp
//
// Purpose:
// 1. Implementation of the CMutex class.
//
// Revisions:
// 07/10/2001 Created
//
#if defined(_REENTRANT)
#include "Mutex.h"
namespace Base
{
CMutex::CMutex()
{
mInitialized = (pthread_mutex_init(&mMutex, 0) == 0);
}
CMutex::~CMutex()
{
if (mInitialized)
pthread_mutex_destroy(&mMutex);
}
}
#endif // #if defined(_REENTRANT)
@@ -0,0 +1,71 @@
////////////////////////////////////////
// Mutex.h
//
// Purpose:
// 1. Declair the CMutex class that encapsulates the functionality of a
// mutually-exclusive device.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_SOLARIS_MUTEX_H
#define BASE_SOLARIS_MUTEX_H
#if !defined(_REENTRANT)
# pragma message( "Excluding Base::CMutex - requires multi-threaded compile. (_REENTRANT)" )
#else
#include "Platform.h"
namespace Base
{
////////////////////////////////////////
// Class:
// CMutex
//
// Purpose:
// Encapsulates the functionality of a mutually-exclusive device.
// This class is valuable for protecting against race conditions
// within threaded applications. The CMutex class can be used to
// only allow a single thread to run within a specified code
// segment at a time.
//
// Public Methods:
// Lock() : Locks the mutex. If the mutex is already locked, the
// operating system will block the calling thread until another
// thread has unlocked the mutex.
// Unlock() : Unlocks the mutex.
//
class CMutex
{
public:
CMutex();
~CMutex();
void Lock();
void Unlock();
private:
pthread_mutex_t mMutex;
bool mInitialized;
};
inline void CMutex::Lock(void)
{
if (mInitialized)
pthread_mutex_lock(&mMutex);
}
inline void CMutex::Unlock(void)
{
if (mInitialized)
pthread_mutex_unlock(&mMutex);
}
}
#endif // #if defined(_MT)
#endif // BASE_SOLARIS_MUTEX_H
@@ -0,0 +1,46 @@
////////////////////////////////////////
// Platform.cpp
//
// Purpose:
// 1. Implementation of the global functionality declaired in Platform.h.
//
// Revisions:
// 07/10/2001 Created
//
#include <ctype.h>
#include "Platform.h"
namespace Base
{
// Implementation of microsoft strlwr extension
// This non-ANSI function is not supported under UNIX
void _strlwr(char * s)
{
while (*s)
{
*s = tolower(*s);
s++;
}
}
// Implementation of microsoft strupr extension
// This non-ANSI function is not supported under UNIX
void _strupr(char * s)
{
while (*s)
{
*s = toupper(*s);
s++;
}
}
CTimer::CTimer() :
mTimer(0)
{
}
}
@@ -0,0 +1,106 @@
////////////////////////////////////////
// Platform.h
//
// Purpose:
// 1. Include relevent system headers that are platform specific.
// 2. Declair global platform specific functionality.
// 3. Include primative type definitions
//
// Global Functions:
// getTimer() : Return the current high resolution clock count.
// getTimerFrequency() : Return the frequency of the high resolution clock.
// sleep() : Voluntarily relinquish timeslice of the calling thread for a
// specified number of milliseconds.
// strlwr() : Alters the contents of a string, making it all lower-case.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_SOLARIS_PLATFORM_H
#define BASE_SOLARIS_PLATFORM_H
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "Types.h"
namespace Base
{
uint64 getTimer(void);
uint64 getTimerFrequency(void);
void Sleep(uint32 ms);
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 uint64 getTimerFrequency(void)
{
uint64 f = 1000000;
return f;
}
inline void sleep(uint32 ms)
{
//usleep(static_cast<unsigned long>(ms * 1000));
struct timeval sleep_tv;
sleep_tv.tv_sec = ms / 1000;
sleep_tv.tv_usec = (ms % 1000) * 1000;
select(1, NULL, NULL, NULL, &sleep_tv);
}
void _strlwr(char * s);
void _strupr(char * s);
class CTimer
{
public:
CTimer();
void Set(uint32 seconds);
void Signal();
bool Expired();
private:
uint32 mTimer;
};
inline void CTimer::Set(uint32 interval)
{
mTimer = (uint32)time(0) + interval;
}
inline void CTimer::Signal()
{
mTimer = 0;
}
inline bool CTimer::Expired()
{
return (mTimer <= (uint32)time(0));
}
}
#endif BASE_SOLARIS_PLATFORM_H
@@ -0,0 +1,258 @@
////////////////////////////////////////
// Thread.cpp
//
// Purpose:
// 1. Implementation of the CThread class.
//
// Revisions:
// 07/10/2001 Created
//
#if defined(_REENTRANT)
#include <pthread.h>
#include <time.h>
#include "Thread.h"
using namespace std;
namespace Base
{
void *threadProc(void *threadPtr)
{
CThread &thread = *((CThread*)threadPtr);
thread.mThreadActive = true;
thread.ThreadProc();
thread.mThreadActive = false;
return 0;
}
CThread::CThread()
{
mThreadID = 0;
mThreadActive = false;
mThreadContinue = false;
}
CThread::~CThread()
{
StopThread();
}
void CThread::StartThread()
{
mThreadContinue = true;
pthread_create(&mThreadID,0,threadProc,this);
while (!IsThreadActive())
Base::sleep(1);
}
int32 CThread::StopThread(int timeout)
{
timeout += time(0);
mThreadContinue = false;
while (mThreadActive && time(0)<timeout)
sleep(1);
if (mThreadActive)
{
mThreadActive = false;
return eSTOP_TIMEOUT;
}
return eSTOP_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////
CThreadPool::CMember::CMember(CThreadPool * parent) :
mParent(parent),
mFunction(NULL),
mArgument(NULL),
mSemaphore()
{
StartThread();
}
CThreadPool::CMember::~CMember()
{
}
void CThreadPool::CMember::Destroy()
{
mThreadContinue = false;
mSemaphore.Signal();
}
bool CThreadPool::CMember::Execute(void( *function )( void * ), void * arg)
{
if (mFunction)
return false;
mArgument = arg;
mFunction = function;
mSemaphore.Signal();
return true;
}
void CThreadPool::CMember::ThreadProc()
{
while (mThreadContinue)
{
mParent->OnIdle(this);
mSemaphore.Wait(mParent->GetTimeOut()*1000);
mParent->OnBusy(this);
if (mFunction)
{
mFunction(mArgument);
mArgument = NULL;
mFunction = NULL;
}
else
mThreadContinue = false;
}
mParent->OnDestory(this);
}
////////////////////////////////////////////////////////////////////////////////
CThreadPool::CThreadPool(uint32 maxThreads, uint32 minThreads, uint32 timeout) :
mMutex(),
mIdleMember(),
mBusyMember(),
mNullMember(),
mThreadCount(0),
mMaxThreads(maxThreads),
mMinThreads(minThreads),
mTimeOut(timeout)
{
if (mMaxThreads == 0) mMaxThreads = 1;
if (mMinThreads == 0) mMinThreads = 1;
if (mMinThreads > mMaxThreads) mMinThreads = mMaxThreads;
if (mTimeOut < 60)
mTimeOut = 60;
for (uint32 i=0; i<mMinThreads; i++)
new CMember(this);
}
CThreadPool::~CThreadPool()
{
set<CMember *>::iterator setIterator;
mMutex.Lock();
setIterator = mBusyMember.begin();
while (setIterator != mBusyMember.end())
(*setIterator++)->Destroy();
mMutex.Unlock();
while (mThreadCount)
{
mMutex.Lock();
setIterator = mIdleMember.begin();
while (setIterator != mIdleMember.end())
(*setIterator++)->Destroy();
mMutex.Unlock();
sleep(1);
}
mMutex.Lock();
while (!mNullMember.empty())
{
delete mNullMember.front();
mNullMember.pop_front();
}
mMutex.Unlock();
}
bool CThreadPool::Execute(void( *function )( void * ), void * arg)
{
mMutex.Lock();
if (mIdleMember.empty())
{
if (mThreadCount < mMaxThreads)
new CMember(this);
mMutex.Unlock();
return false;
}
while (!mNullMember.empty())
{
delete mNullMember.front();
mNullMember.pop_front();
}
CMember * member = *(mIdleMember.begin());
mIdleMember.erase(member);
member->Execute(function,arg);
mMutex.Unlock();
return true;
}
uint32 CThreadPool::GetTimeOut()
{
return mTimeOut;
}
void CThreadPool::OnIdle(CMember * member)
{
mMutex.Lock();
set<CMember *>::iterator setIterator = mBusyMember.find(member);
if (setIterator != mBusyMember.end())
mBusyMember.erase(member);
else
mThreadCount++;
mIdleMember.insert(member);
mMutex.Unlock();
}
void CThreadPool::OnBusy(CMember * member)
{
mMutex.Lock();
mBusyMember.insert(member);
mMutex.Unlock();
}
void CThreadPool::OnDestory(CMember * member)
{
set<CMember *>::iterator setIterator;
mMutex.Lock();
setIterator = mBusyMember.find(member);
if (setIterator != mBusyMember.end())
{
mNullMember.push_back(member);
mBusyMember.erase(member);
mThreadCount--;
}
mMutex.Unlock();
}
////////////////////////////////////////////////////////////////////////////////
}
#endif // #if defined(_REENTRANT)
@@ -0,0 +1,139 @@
////////////////////////////////////////
// Thread.h
//
// Purpose:
// 1. Declair the CThread class that encapsulates threading functionality.
// This abstract base class in intended to be used to encapsulate
// individual tasks that require threading in derived classes.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_SOLARIS_THREAD_H
#define BASE_SOLARIS_THREAD_H
#if !defined(_REENTRANT)
# pragma message( "Excluding Base::CThread - requires multi-threaded compile. (_REENTRANT)" )
#else
#pragma warning( disable : 4786)
#include <list>
#include <set>
#include "Platform.h"
#include "Mutex.h"
#include "Event.h"
namespace Base
{
////////////////////////////////////////
// Class:
// CThread
//
// Purpose:
// Encapsulates threading functionality. Creating classes derived
// from CThread provides an easy way to encapsulate tasks that require
// their own thread.
//
// Public Methods:
// StartThread() : Creates the low-level thread handle and begins executing
// the CThread::ThreadProc() function within the new thread.
// StopThread() : Signals the ThreadProc() function to stop executing using
// the mThreadContinue member variable, and waits for the ThreadProc()
// function to exit. By default, the function will block for a maximum
// of 5 seconds before exiting without the thread halting.
// IsThreadActive() : Returns true if the physical thread is still executing
// within the ThreadProc() function, otherwise it returns false.
// ThreadProc() : Pure-virtual function that will be executed when the StartThread()
// function is called. Derived classes must implement this function. The
// mThreadContinue member variable should be used internal the the ThreadProc()
// function to indicate whether it should continue executing or exit.
// Protected Attributes:
// mThreadContinue : Boolean value indicating to the ThreadProc() function
// whether to continue executing or to exit. If mThreadContinue is true,
// ThreadProc() should continue, otherwise ThreadProc() should exit. It
// left up to the derived class to implement a ThreadProc() function that
// uses the mThreadContinue member.
//
//
class CThread
{
friend void * threadProc(void *);
public:
enum { eSTOP_SUCCESS, eSTOP_TIMEOUT };
public:
CThread();
virtual ~CThread();
void StartThread();
int32 StopThread(int timeout=5);
bool IsThreadActive() { return mThreadActive; }
protected:
virtual void ThreadProc() = 0;
protected:
bool mThreadContinue;
private:
bool mThreadActive;
pthread_t mThreadID;
};
class CThreadPool
{
private:
class CMember : public CThread
{
public:
CMember(CThreadPool * parent);
virtual ~CMember();
bool Execute(void( *function )( void * ), void * arg);
void Destroy();
protected:
virtual void ThreadProc();
private:
CThreadPool * mParent;
void( * mFunction )( void * );
void * mArgument;
CEvent mSemaphore;
};
friend class CMember;
public:
CThreadPool(uint32 maxThreads, uint32 minThreads=1, uint32 timeout=15*60);
~CThreadPool();
bool Execute(void( *function )( void * ), void * arg);
private:
uint32 GetTimeOut();
void OnIdle(CMember * member);
void OnBusy(CMember * member);
void OnDestory(CMember * member);
private:
CMutex mMutex;
std::set<CMember *> mIdleMember;
std::set<CMember *> mBusyMember;
std::list<CMember *> mNullMember;
uint32 mThreadCount;
uint32 mMaxThreads;
uint32 mMinThreads;
uint32 mTimeOut;
};
}
#endif // #if defined(_MT)
#endif // BASE_SOLARIS_THREAD_H
@@ -0,0 +1,28 @@
////////////////////////////////////////
// Types.h
//
// Purpose:
// 1. Define integer types that are unambiguous with respect to size
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_SOLARIS_TYPES_H
#define BASE_SOLARIS_TYPES_H
namespace Base
{
typedef signed char int8;
typedef unsigned char uint8;
typedef signed short int16;
typedef unsigned short uint16;
typedef signed int int32;
typedef unsigned int uint32;
typedef signed long long int64;
typedef unsigned long long uint64;
}
#endif // BASE_SOLARIS_TYPES_H
@@ -0,0 +1,42 @@
#ifndef BASE_WIN32_ARCHIVE_H
#define BASE_WIN32_ARCHIVE_H
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
#ifdef PACK_BIG_ENDIAN
inline double byteSwap(double value) { byteReverse64(&value); return value; }
inline float byteSwap(float value) { byteReverse32(&value); return value; }
inline uint64 byteSwap(uint64 value) { byteReverse64(&value); return value; }
inline int64 byteSwap(int64 value) { byteReverse64(&value); return value; }
inline uint32 byteSwap(uint32 value) { byteReverse32(&value); return value; }
inline int32 byteSwap(int32 value) { byteReverse32(&value); return value; }
inline uint16 byteSwap(uint16 value) { byteReverse16(&value); return value; }
inline int16 byteSwap(int16 value) { byteReverse16(&value); return value; }
#else
inline double byteSwap(double value) { return value; }
inline float byteSwap(float value) { return value; }
inline uint64 byteSwap(uint64 value) { return value; }
inline int64 byteSwap(int64 value) { return value; }
inline uint32 byteSwap(uint32 value) { return value; }
inline int32 byteSwap(int32 value) { return value; }
inline uint16 byteSwap(uint16 value) { return value; }
inline int16 byteSwap(int16 value) { return value; }
#endif
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif
@@ -0,0 +1,112 @@
#include "../BlockAllocator.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
BlockAllocator::BlockAllocator()
{
for(unsigned i = 0; i < 31; i++)
{
m_blocks[i] = NULL;
}
}
BlockAllocator::~BlockAllocator()
{
// free all allocated memory blocks
for(unsigned i = 0; i < 31; i++)
{
while(m_blocks[i] != NULL)
{
unsigned *tmp = m_blocks[i];
m_blocks[i] = (unsigned *)*m_blocks[i];
free(tmp);
}
}
}
// Allocate a block that is the next power of two greater than the # of bytes passed.
// 33 bytes yields a 64 byte block of memory and so forth.
void *BlockAllocator::getBlock(unsigned bytes)
{
unsigned accum = 16, bits = 16;
unsigned *handle = NULL;
// Perform a binary search looking for the highest bit.
while(bits != 0)
{
// If bytes is less than the bit we're testing for, subtract half
// from the bit value and repeat
if(bytes < (unsigned)(1 << accum))
{
bits /= 2;
accum -= bits;
}
// If bytes is greater than the bit we're testing for, add half
// from the but value and repeat
else if(bytes > (unsigned)(1 << accum))
{
bits /= 2;
accum += bits;
}
// Got lucky and hit the value dead on
else
{
break;
}
}
// At this point accum contains the most significant bit index, increment
accum++;
if(accum < 2)
{
accum = 2;
}
// Note that when memory is actually allocated, 8 extra bytes will be allocated.at the front
// The first integer is the address of the next block of memory when the block is in the allocator
// The second integer is the bit length of the block
// Memory is allocated on 4 byte boundaries to sidestep byte alignment problems
// Check if the allocator already has a block of that size
if(m_blocks[accum] == 0)
{
// remove the pre allocated block from the linked list
handle = (unsigned *)calloc(((1 << accum) / 4) + 2, sizeof(unsigned));
handle[1] = accum;
handle[0] = 0;
}
else
{
// Allocate a new block
handle = m_blocks[accum];
m_blocks[accum] = (unsigned *)handle[0];
handle[0] = 0;
}
// return a pointer that skips over the header used for the allocator's purposes
return(handle + 2);
}
void BlockAllocator::returnBlock(unsigned *handle)
{
// C++ allows for safe deletion of a NULL pointer
if(handle)
{
// Update the allocator linked list, insert this entry at the head
*(handle - 2) = (unsigned)m_blocks[*(handle - 1)];
// Add this entry to the proper linked list node
m_blocks[*(handle - 1)] = (handle - 2);
}
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,44 @@
////////////////////////////////////////
// Event.cpp
//
// Purpose:
// 1. Implementation of the CEvent class.
//
// Revisions:
// 07/10/2001 Created
//
#if !defined(_MT)
# pragma message( "Excluding Base::CEvent - requires multi-threaded compile. (_MT)" )
#else
#include "Event.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
CEvent::CEvent()
{
mEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
}
CEvent::~CEvent()
{
if (mEvent)
CloseHandle(mEvent);
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_MT)
@@ -0,0 +1,92 @@
////////////////////////////////////////
// Event.h
//
// Purpose:
// 1. Declair the CEvent class that encapsulates the functionality of a
// single-locking semaphore.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_WIN32_EVENT_H
#define BASE_WIN32_EVENT_H
#if defined(_MT)
#include "Platform.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
////////////////////////////////////////
// Class:
// CEvent
//
// Purpose:
// Encapsulates the functionality of a singal-locking semaphore.
// This class is valuable for thread syncronization when a thead's
// execution needs to be dependent upon another thread.
//
// Public Methods:
// Signal() : Signals a thread that has called Wait() so that it can
// continue execution. This function returns true if the waiting
// thread was signalled successfully, otherwise false is returned.
// Wait() : Halts the calling thread's execution indefinately until
// a Singal() call is made by an external thread. If the thread is
// successfully signalled, the function returns eWAIT_SIGNAL. If
// timeout period expires without a signal, eWAIT_TIMEOUT is returned.
// If the function fails, eWAIT_ERROR is returned.
//
class CEvent
{
public:
CEvent();
virtual ~CEvent();
bool Signal();
int32 Wait(uint32 timeout = 0);
public:
enum { eWAIT_ERROR, eWAIT_SIGNAL, eWAIT_TIMEOUT };
private:
HANDLE mEvent;
};
inline bool CEvent::Signal()
{
if (mEvent)
return SetEvent(mEvent)!=0;
return false;
}
inline int32 CEvent::Wait(uint32 timeout)
{
if (!mEvent)
return CEvent::eWAIT_ERROR;
DWORD result = WaitForSingleObjectEx(mEvent, timeout ? timeout : INFINITE, FALSE);
if (result == WAIT_OBJECT_0)
return CEvent::eWAIT_SIGNAL;
else if (result == WAIT_TIMEOUT)
return CEvent::eWAIT_TIMEOUT;
else
return CEvent::eWAIT_ERROR;
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_MT)
#endif // BASE_WIN32_EVENT_H
@@ -0,0 +1,19 @@
// File.cpp: implementation of the CFile class.
//
//////////////////////////////////////////////////////////////////////
#include "File.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFile::CFile(const char *)
{
}
CFile::~CFile()
{
}
@@ -0,0 +1,22 @@
// File.h: interface for the CFile class.
//
//////////////////////////////////////////////////////////////////////
#ifndef BASE_FILE_H
#define BASE_FILE_H
#include <stdio.h>
class CFile
{
public:
CFile(const char *);
virtual ~CFile();
bool IsOpen();
private:
FILE* mFileHandle;
};
#endif // BASE_FILE_H
@@ -0,0 +1,40 @@
////////////////////////////////////////
// Mutex.cpp
//
// Purpose:
// 1. Implementation of the CMutex class.
//
// Revisions:
// 07/10/2001 Created
//
#if !defined(_MT)
# pragma message( "Excluding Base::CMutex - requires multi-threaded compile. (_MT)" )
#else
#include "Mutex.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
CMutex::CMutex()
{
InitializeCriticalSection(&mCriticalSection);
}
CMutex::~CMutex()
{
DeleteCriticalSection(&mCriticalSection);
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_MT)
@@ -0,0 +1,73 @@
////////////////////////////////////////
// Mutex.h
//
// Purpose:
// 1. Declair the CMutex class that encapsulates the functionality of a
// mutually-exclusive device.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_WIN32_MUTEX_H
#define BASE_WIN32_MUTEX_H
#if defined (_MT)
#include "Platform.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
////////////////////////////////////////
// Class:
// CMutex
//
// Purpose:
// Encapsulates the functionality of a mutually-exclusive device.
// This class is valuable for protecting against race conditions
// within threaded applications. The CMutex class can be used to
// only allow a single thread to run within a specified code
// segment at a time.
//
// Public Methods:
// Lock() : Locks the mutex. If the mutex is already locked, the
// operating system will block the calling thread until another
// thread has unlocked the mutex.
// Unlock() : Unlocks the mutex.
//
class CMutex
{
public:
CMutex();
~CMutex();
void Lock();
void Unlock();
private:
CRITICAL_SECTION mCriticalSection;
};
inline void CMutex::Lock()
{
EnterCriticalSection(&mCriticalSection);
}
inline void CMutex::Unlock()
{
LeaveCriticalSection(&mCriticalSection);
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_MT)
#endif // BASE_WIN32_MUTEX_H
@@ -0,0 +1,31 @@
////////////////////////////////////////
// Platform.cpp
//
// Purpose:
// 1. Implementation of the global functionality declaired in Platform.h.
//
// Revisions:
// 07/10/2001 Created
//
#include "Platform.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
CTimer::CTimer() :
mTimer(0)
{
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
@@ -0,0 +1,98 @@
////////////////////////////////////////
// Platform.h
//
// Purpose:
// 1. Include relevent system headers that are platform specific.
// 2. Declair global platform specific functionality.
// 3. Include primative type definitions
//
// Global Functions:
// getTimer() : Return the current high resolution clock count.
// getTimerFrequency() : Return the frequency of the high resolution clock.
// sleep() : Voluntarily relinquish timeslice of the calling thread for a
// specified number of milliseconds.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_WIN32_PLATFORM_H
#define BASE_WIN32_PLATFORM_H
#include <memory.h>
#include <winsock2.h>
#include <time.h>
#include <io.h>
#include <fcntl.h>
#include <direct.h>
#include <stdio.h>
#include <errno.h>
#include "Types.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
uint64 getTimer(void);
uint64 getTimerFrequency(void);
inline uint64 getTimer(void)
{
uint64 result;
if (!QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&result)))
result = 0;
return result;
}
inline uint64 getTimerFrequency(void)
{
uint64 result;
if (!QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&result)))
result = 0;
return result;
}
inline void sleep(uint32 ms)
{
Sleep(ms);
}
class CTimer
{
public:
CTimer();
void Set(uint32 seconds);
void Signal();
bool Expired();
private:
uint32 mTimer;
};
inline void CTimer::Set(uint32 interval)
{
mTimer = (uint32)time(0) + interval;
}
inline void CTimer::Signal()
{
mTimer = 0;
}
inline bool CTimer::Expired()
{
return (mTimer <= (uint32)time(0));
}
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif BASE_WIN32_PLATFORM_H
@@ -0,0 +1,279 @@
////////////////////////////////////////
// Thread.cpp
//
// Purpose:
// 1. Implementation of the CThread class.
//
// Revisions:
// 07/10/2001 Created
//
#pragma warning ( disable: 4786 )
#if !defined(_MT)
# pragma message( "Excluding Base::CThread - requires multi-threaded compile. (_MT)" )
#else
#include <process.h>
#include <time.h>
#include "Thread.h"
using namespace std;
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
void threadProc(void *threadPtr)
{
CThread &thread = *((CThread*)threadPtr);
thread.mThreadActive = true;
thread.ThreadProc();
thread.mThreadActive = false;
}
CThread::CThread()
{
mThreadID = 0;
mThreadActive = false;
mThreadContinue = false;
}
CThread::~CThread()
{
StopThread();
}
void CThread::StartThread()
{
mThreadContinue = true;
mThreadID = _beginthread(threadProc,0,this);
while (!IsThreadActive())
Base::sleep(1);
}
int32 CThread::StopThread(int32 timeout)
{
timeout += time(0);
mThreadContinue = false;
while (mThreadActive && time(0)<timeout)
sleep(1);
if (mThreadActive)
{
mThreadActive = false;
return eSTOP_TIMEOUT;
}
return eSTOP_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////
CThreadPool::CMember::CMember(CThreadPool * parent) :
mParent(parent),
mFunction(NULL),
mArgument(NULL),
mSemaphore()
{
StartThread();
}
CThreadPool::CMember::~CMember()
{
}
void CThreadPool::CMember::Destroy()
{
mThreadContinue = false;
mSemaphore.Signal();
}
bool CThreadPool::CMember::Execute(void( __cdecl *function )( void * ), void * arg)
{
if (mFunction)
return false;
mArgument = arg;
mFunction = function;
mSemaphore.Signal();
return true;
}
void CThreadPool::CMember::ThreadProc()
{
mParent->OnStartup(this);
while (mThreadContinue)
{
mParent->OnIdle(this);
mSemaphore.Wait(mParent->GetTimeOut()*1000);
if (mFunction)
{
mFunction(mArgument);
mArgument = NULL;
mFunction = NULL;
}
else if (mParent->OnDestory(this))
mThreadContinue = false;
}
}
////////////////////////////////////////////////////////////////////////////////
CThreadPool::CThreadPool(uint32 maxThreads, uint32 minThreads, uint32 timeout) :
mMutex(),
mIdleMember(),
mBusyMember(),
mNullMember(),
mThreadCount(0),
mMaxThreads(maxThreads),
mMinThreads(minThreads),
mTimeOut(timeout)
{
if (mMaxThreads == 0) mMaxThreads = 1;
if (mMinThreads == 0) mMinThreads = 1;
if (mMinThreads > mMaxThreads) mMinThreads = mMaxThreads;
for (uint32 i=0; i<mMinThreads; i++)
new CMember(this);
}
CThreadPool::~CThreadPool()
{
set<CMember *>::iterator setIterator;
////////////////////////////////////////
// (1) Destory all busy member threads
mMutex.Lock();
setIterator = mBusyMember.begin();
while (setIterator != mBusyMember.end())
(*setIterator++)->Destroy();
mMutex.Unlock();
////////////////////////////////////////
// (2) Destory all idle member threads
while (mThreadCount)
{
mMutex.Lock();
setIterator = mIdleMember.begin();
while (setIterator != mIdleMember.end())
(*setIterator++)->Destroy();
mMutex.Unlock();
sleep(1);
}
////////////////////////////////////////
// (3) Delete the null member threads
mMutex.Lock();
while (!mNullMember.empty())
{
delete mNullMember.front();
mNullMember.pop_front();
}
mMutex.Unlock();
}
bool CThreadPool::Execute(void( __cdecl *function )( void * ), void * arg)
{
mMutex.Lock();
////////////////////////////////////////
// (1) If no idle members, return false to indicate that no threads
// were available. If the thread count is below the max, create
// a new thread.
if (mIdleMember.empty())
{
if (mThreadCount < mMaxThreads)
new CMember(this);
mMutex.Unlock();
return false;
}
////////////////////////////////////////
// (2) Delete any null member threads.
while (!mNullMember.empty())
{
delete mNullMember.front();
mNullMember.pop_front();
}
////////////////////////////////////////
// (3) Move the first idle thread to the busy set and signal the
// thread to execute the specified function.
CMember * member = *(mIdleMember.begin());
mIdleMember.erase(member);
mBusyMember.insert(member);
member->Execute(function,arg);
mMutex.Unlock();
return true;
}
uint32 CThreadPool::GetTimeOut()
{
return mTimeOut;
}
void CThreadPool::OnStartup(CMember * member)
{
mMutex.Lock();
mThreadCount++;
mIdleMember.insert(member);
mMutex.Unlock();
}
void CThreadPool::OnIdle(CMember * member)
{
mMutex.Lock();
mBusyMember.erase(member);
mIdleMember.insert(member);
mMutex.Unlock();
}
bool CThreadPool::OnDestory(CMember * member)
{
set<CMember *>::iterator setIterator;
mMutex.Lock();
bool result = (setIterator = mIdleMember.find(member)) != mIdleMember.end();
if (result)
{
mNullMember.push_back(member);
mIdleMember.erase(setIterator);
mThreadCount--;
}
mMutex.Unlock();
return result;
}
////////////////////////////////////////////////////////////////////////////////
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_MT)
@@ -0,0 +1,144 @@
////////////////////////////////////////
// Thread.h
//
// Purpose:
// 1. Declair the CThread class that encapsulates threading functionality.
// This abstract base class in intended to be used to encapsulate
// individual tasks that require threading in derived classes.
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_WIN32_THREAD_H
#define BASE_WIN32_THREAD_H
#if defined(_MT)
#pragma warning( disable : 4786)
#include <list>
#include <set>
#include "Platform.h"
#include "Mutex.h"
#include "Event.h"
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
////////////////////////////////////////
// Class:
// CThread
//
// Purpose:
// Encapsulates threading functionality. Creating classes derived
// from CThread provides an easy way to encapsulate tasks that require
// their own thread.
//
// Public Methods:
// StartThread() : Creates the low-level thread handle and begins executing
// the CThread::ThreadProc() function within the new thread.
// StopThread() : Signals the ThreadProc() function to stop executing using
// the mThreadContinue member variable, and waits for the ThreadProc()
// function to exit. By default, the function will block for a maximum
// of 5 seconds before exiting without the thread halting.
// IsThreadActive() : Returns true if the physical thread is still executing
// within the ThreadProc() function, otherwise it returns false.
// ThreadProc() : Pure-virtual function that will be executed when the StartThread()
// function is called. Derived classes must implement this function. The
// mThreadContinue member variable should be used internal the the ThreadProc()
// function to indicate whether it should continue executing or exit.
// Protected Attributes:
// mThreadContinue : Boolean value indicating to the ThreadProc() function
// whether to continue executing or to exit. If mThreadContinue is true,
// ThreadProc() should continue, otherwise ThreadProc() should exit. It
// left up to the derived class to implement a ThreadProc() function that
// uses the mThreadContinue member.
//
//
class CThread
{
friend void threadProc(void *);
public:
enum { eSTOP_SUCCESS, eSTOP_TIMEOUT };
public:
CThread();
virtual ~CThread();
void StartThread();
int32 StopThread(int32 timeout=5);
bool IsThreadActive() { return mThreadActive; }
protected:
virtual void ThreadProc() = 0;
protected:
bool mThreadContinue;
private:
uint32 mThreadID;
bool mThreadActive;
};
class CThreadPool
{
private:
class CMember : public CThread
{
public:
CMember(CThreadPool * parent);
virtual ~CMember();
bool Execute(void( __cdecl *function )( void * ), void * arg);
void Destroy();
protected:
virtual void ThreadProc();
private:
CThreadPool * mParent;
void( __cdecl * mFunction )( void * );
void * mArgument;
CEvent mSemaphore;
};
friend class CMember;
public:
CThreadPool(uint32 maxThreads, uint32 minThreads=1, uint32 timeout=15*60);
~CThreadPool();
bool Execute(void( __cdecl *function )( void * ), void * arg);
private:
uint32 GetTimeOut();
void OnStartup(CMember * member);
void OnIdle(CMember * member);
bool OnDestory(CMember * member);
private:
CMutex mMutex;
std::set<CMember *> mIdleMember;
std::set<CMember *> mBusyMember;
std::list<CMember *> mNullMember;
uint32 mThreadCount;
uint32 mMaxThreads;
uint32 mMinThreads;
uint32 mTimeOut;
};
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // #if defined(_MT)
#endif // BASE_WIN32_THREAD_H
@@ -0,0 +1,42 @@
////////////////////////////////////////
// Types.h
//
// Purpose:
// 1. Define integer types that are unambiguous with respect to size
//
// Revisions:
// 07/10/2001 Created
//
#ifndef BASE_WIN32_TYPES_H
#define BASE_WIN32_TYPES_H
#ifdef EXTERNAL_DISTRO
namespace NAMESPACE
{
#endif
namespace Base
{
#define INT32_MAX 0x7FFFFFFF
#define INT32_MIN 0x80000000
#define UINT32_MAX 0xFFFFFFFF
typedef signed char int8;
typedef unsigned char uint8;
typedef short int16;
typedef unsigned short uint16;
typedef int int32;
typedef unsigned uint32;
typedef __int64 int64;
typedef unsigned __int64 uint64;
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif // BASE_WIN32_TYPES_H
@@ -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 <winsock.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,784 @@
#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, 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)
{
//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, 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;
/**< 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)
{
if (errno != EINPROGRESS && errno != EALREADY)
{
Disconnect(false);
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(false);
returnVal = -1;
}
else if (returnVal ==1/* && m_connectTimeout != 0*/)
{
//need to give, onConnect callback
if (m_manager->m_handler)
m_manager->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)
Disconnect(false);
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
switch(WSAGetLastError())
{
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,157 @@
#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.
*/
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; }
protected:
friend class TcpManager;
TcpConnection(TcpManager *tcpManager, TcpBlockAllocator *sendAlloc, TcpManager::TcpParams &params, const IPAddress &destIP, 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, 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;
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_wasConRemovedFromMgr;
};
#ifdef EXTERNAL_DISTRO
};
#endif
#endif //TCPCONNECTION_H

Some files were not shown because too many files have changed in this diff Show More