Merge branch 'Network' of https://github.com/dean11/Danbias into GameLogic
This commit is contained in:
commit
0adb831f7a
|
@ -3,8 +3,8 @@
|
|||
/////////////////////////////////////////////////////////////////////
|
||||
#include "CustomNetProtocol.h"
|
||||
#include <map>
|
||||
|
||||
using namespace Network;
|
||||
#include "Translator.h"
|
||||
using namespace Oyster::Network;
|
||||
|
||||
|
||||
struct CustomNetProtocol::PrivateData
|
||||
|
@ -55,4 +55,4 @@ NetAttributeContainer& CustomNetProtocol::operator[](int ID)
|
|||
}
|
||||
|
||||
return this->privateData->attributes[ID];
|
||||
}
|
||||
}
|
|
@ -12,82 +12,89 @@
|
|||
#define NET_PROTOCOL_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
namespace Network
|
||||
namespace Oyster
|
||||
{
|
||||
extern "C"
|
||||
namespace Network
|
||||
{
|
||||
enum NetAttributeType
|
||||
extern "C"
|
||||
{
|
||||
NetAttributeType_Bool,
|
||||
NetAttributeType_Char,
|
||||
NetAttributeType_UnsignedChar,
|
||||
NetAttributeType_Short,
|
||||
NetAttributeType_UnsignedShort,
|
||||
NetAttributeType_Int,
|
||||
NetAttributeType_UnsignedInt,
|
||||
NetAttributeType_Int64,
|
||||
NetAttributeType_UnsignedInt64,
|
||||
NetAttributeType_Float,
|
||||
NetAttributeType_Double,
|
||||
NetAttributeType_CharArray,
|
||||
NetAttributeType_UNKNOWN,
|
||||
};
|
||||
union NetAttributeValue
|
||||
{
|
||||
bool netBool;
|
||||
char netChar;
|
||||
unsigned char netUChar;
|
||||
short netShort;
|
||||
unsigned short netUShort;
|
||||
int netInt;
|
||||
unsigned int netUInt;
|
||||
__int64 netInt64;
|
||||
unsigned __int64 netUInt64;
|
||||
float netFloat;
|
||||
double netDouble;
|
||||
char* netCharPtr;
|
||||
//Please don't create a type with a number higher than 127 for now.
|
||||
//This may increase to 255 later on.
|
||||
enum NetAttributeType
|
||||
{
|
||||
NetAttributeType_Bool,
|
||||
NetAttributeType_Char,
|
||||
NetAttributeType_UnsignedChar,
|
||||
NetAttributeType_Short,
|
||||
NetAttributeType_UnsignedShort,
|
||||
NetAttributeType_Int,
|
||||
NetAttributeType_UnsignedInt,
|
||||
NetAttributeType_Int64,
|
||||
NetAttributeType_UnsignedInt64,
|
||||
NetAttributeType_Float,
|
||||
NetAttributeType_Double,
|
||||
NetAttributeType_CharArray,
|
||||
NetAttributeType_UNKNOWN,
|
||||
};
|
||||
union NetAttributeValue
|
||||
{
|
||||
bool netBool;
|
||||
char netChar;
|
||||
unsigned char netUChar;
|
||||
short netShort;
|
||||
unsigned short netUShort;
|
||||
int netInt;
|
||||
unsigned int netUInt;
|
||||
__int64 netInt64;
|
||||
unsigned __int64 netUInt64;
|
||||
float netFloat;
|
||||
double netDouble;
|
||||
char* netCharPtr;
|
||||
|
||||
NetAttributeValue(){ memset(this, 0, sizeof(NetAttributeValue)); }
|
||||
NetAttributeValue(bool v) : netBool (v) {}
|
||||
NetAttributeValue(char v) : netChar (v) {}
|
||||
NetAttributeValue(unsigned char v) : netUChar (v) {}
|
||||
NetAttributeValue(short v) : netShort (v) {}
|
||||
NetAttributeValue(unsigned short v) : netUShort (v) {}
|
||||
NetAttributeValue(int v) : netInt (v) {}
|
||||
NetAttributeValue(unsigned int v) : netUInt (v) {}
|
||||
NetAttributeValue(__int64 v) : netInt64 (v) {}
|
||||
NetAttributeValue(unsigned __int64 v) : netUInt64 (v) {}
|
||||
NetAttributeValue(float v) : netFloat (v) {}
|
||||
NetAttributeValue(double v) : netDouble (v) {}
|
||||
NetAttributeValue(char* v) : netCharPtr(v) {}
|
||||
};
|
||||
struct NetAttributeContainer
|
||||
{
|
||||
NetAttributeType type;
|
||||
NetAttributeValue value;
|
||||
NetAttributeContainer() { type = NetAttributeType_UNKNOWN; }
|
||||
};
|
||||
class CustomNetProtocol;
|
||||
struct CustomProtocolObject
|
||||
{
|
||||
virtual CustomNetProtocol* GetProtocol() = 0;
|
||||
};
|
||||
NetAttributeValue(){ memset(this, 0, sizeof(NetAttributeValue)); }
|
||||
NetAttributeValue(bool v) : netBool (v) {}
|
||||
NetAttributeValue(char v) : netChar (v) {}
|
||||
NetAttributeValue(unsigned char v) : netUChar (v) {}
|
||||
NetAttributeValue(short v) : netShort (v) {}
|
||||
NetAttributeValue(unsigned short v) : netUShort (v) {}
|
||||
NetAttributeValue(int v) : netInt (v) {}
|
||||
NetAttributeValue(unsigned int v) : netUInt (v) {}
|
||||
NetAttributeValue(__int64 v) : netInt64 (v) {}
|
||||
NetAttributeValue(unsigned __int64 v) : netUInt64 (v) {}
|
||||
NetAttributeValue(float v) : netFloat (v) {}
|
||||
NetAttributeValue(double v) : netDouble (v) {}
|
||||
NetAttributeValue(char* v) : netCharPtr(v) {}
|
||||
};
|
||||
struct NetAttributeContainer
|
||||
{
|
||||
NetAttributeType type;
|
||||
NetAttributeValue value;
|
||||
NetAttributeContainer() { type = NetAttributeType_UNKNOWN; }
|
||||
};
|
||||
class CustomNetProtocol;
|
||||
struct CustomProtocolObject
|
||||
{
|
||||
virtual CustomNetProtocol* GetProtocol() = 0;
|
||||
};
|
||||
|
||||
class NET_PROTOCOL_EXPORT CustomNetProtocol
|
||||
{
|
||||
public:
|
||||
CustomNetProtocol();
|
||||
~CustomNetProtocol();
|
||||
class NET_PROTOCOL_EXPORT CustomNetProtocol
|
||||
{
|
||||
public:
|
||||
CustomNetProtocol();
|
||||
~CustomNetProtocol();
|
||||
|
||||
NetAttributeContainer& operator[](int ID);
|
||||
NetAttributeContainer& operator[](int ID);
|
||||
|
||||
private:
|
||||
struct PrivateData;
|
||||
PrivateData* privateData;
|
||||
};
|
||||
private:
|
||||
struct PrivateData;
|
||||
PrivateData* privateData;
|
||||
|
||||
}//End extern "C"
|
||||
} //End namespace Network
|
||||
friend class Translator;
|
||||
};
|
||||
|
||||
}//End extern "C"
|
||||
} //End namespace Network
|
||||
}
|
||||
#endif // !NETWORK_CUSTOM_NETWORK_PROTOCOL_H
|
||||
|
||||
|
||||
|
|
|
@ -163,11 +163,14 @@
|
|||
<ClCompile Include="CustomNetProtocol.cpp" />
|
||||
<ClCompile Include="NetworkServer.cpp" />
|
||||
<ClCompile Include="NetworkClient.cpp" />
|
||||
<ClCompile Include="Translator.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CustomNetProtocol.h" />
|
||||
<ClInclude Include="NetworkCallbackHelper.h" />
|
||||
<ClInclude Include="NetworkServer.h" />
|
||||
<ClInclude Include="NetworkClient.h" />
|
||||
<ClInclude Include="Translator.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NetworkDependencies\NetworkDependencies.vcxproj">
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef NETWORK_API_NETWORK_CALLBACK_HELPER_H
|
||||
#define NETWORK_API_NETWORK_CALLBACK_HELPER_H
|
||||
|
||||
/////////////////////////////////////
|
||||
// Created by Dennis Andersen 2013 //
|
||||
/////////////////////////////////////
|
||||
|
||||
namespace Oyster
|
||||
{
|
||||
namespace Network
|
||||
{
|
||||
enum NetworkProtocolCallbackType
|
||||
{
|
||||
NetworkProtocolCallbackType_Function,
|
||||
NetworkProtocolCallbackType_Object,
|
||||
NetworkProtocolCallbackType_Unknown = -1,
|
||||
};
|
||||
enum NetworkClientCallbackType
|
||||
{
|
||||
NetworkClientCallbackType_Function,
|
||||
NetworkClientCallbackType_Object,
|
||||
NetworkClientCallbackType_Unknown = -1,
|
||||
};
|
||||
|
||||
class NetworkClient;
|
||||
class CustomNetProtocol;
|
||||
typedef void (*ClientConnectCallbackMethod)(NetworkClient&);
|
||||
typedef void(*ProtocolRecieverFunction)(CustomNetProtocol& protocol);
|
||||
struct ClientConnectedObject
|
||||
{
|
||||
virtual void ClientConnectCallback(NetworkClient &client) = 0;
|
||||
};
|
||||
struct ProtocolRecieverObject
|
||||
{
|
||||
virtual void ProtocolRecievedCallback(CustomNetProtocol& protocol) = 0;
|
||||
};
|
||||
|
||||
union RecieverObject
|
||||
{
|
||||
ClientConnectCallbackMethod clientConnectFnc;
|
||||
ProtocolRecieverFunction protocolRecieverFnc;
|
||||
ClientConnectedObject *clientConnectObject;
|
||||
ProtocolRecieverObject *protocolRecievedObject;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,41 +1,247 @@
|
|||
#ifndef INCLUDE_WINSOCK_LIB
|
||||
#define INCLUDE_WINSOCK_LIB
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#endif
|
||||
|
||||
#include "NetworkClient.h"
|
||||
|
||||
#include "Translator.h"
|
||||
#include "CustomNetProtocol.h"
|
||||
|
||||
#include "../NetworkDependencies/Connection.h"
|
||||
#include "../NetworkDependencies/PostBox.h"
|
||||
#include "../NetworkDependencies/WinsockFunctions.h"
|
||||
|
||||
#include "../../Misc/Utilities.h"
|
||||
#include "../../Misc/Thread/IThreadObject.h"
|
||||
#include "../../Misc/Thread/OysterThread.h"
|
||||
|
||||
using namespace Oyster::Network;
|
||||
using namespace Oyster::Thread;
|
||||
using namespace Utility::DynamicMemory;
|
||||
|
||||
/*************************************
|
||||
PrivateData
|
||||
*************************************/
|
||||
|
||||
struct PrivateData
|
||||
struct NetworkClient::PrivateData : public IThreadObject
|
||||
{
|
||||
PrivateData();
|
||||
PrivateData(unsigned int socket);
|
||||
~PrivateData();
|
||||
|
||||
void Start();
|
||||
|
||||
void Send(CustomNetProtocol& protocol); //Is called from the outside to add messages to send.
|
||||
|
||||
//Called on from the thread
|
||||
int Send();
|
||||
int Recv();
|
||||
|
||||
bool DoWork();
|
||||
|
||||
Connection* connection;
|
||||
|
||||
IPostBox<CustomNetProtocol> *sendPostBox;
|
||||
|
||||
RecieverObject recvObj;
|
||||
NetworkProtocolCallbackType callbackType;
|
||||
|
||||
Oyster::Thread::OysterThread thread;
|
||||
std::mutex recvObjMutex;
|
||||
std::mutex postBoxMutex;
|
||||
|
||||
Translator translator;
|
||||
};
|
||||
|
||||
NetworkClient::PrivateData::PrivateData()
|
||||
{
|
||||
InitWinSock();
|
||||
|
||||
callbackType = NetworkProtocolCallbackType_Unknown;
|
||||
|
||||
connection = new Connection();
|
||||
sendPostBox = new PostBox<CustomNetProtocol>;
|
||||
this->thread.Create(this, false);
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
NetworkClient::PrivateData::PrivateData(unsigned int socket)
|
||||
{
|
||||
InitWinSock();
|
||||
|
||||
callbackType = NetworkProtocolCallbackType_Unknown;
|
||||
|
||||
connection = new Connection(socket);
|
||||
sendPostBox = new PostBox<CustomNetProtocol>;
|
||||
this->thread.Create(this, false);
|
||||
|
||||
connection->SetBlockingMode(false);
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
NetworkClient::PrivateData::~PrivateData()
|
||||
{
|
||||
thread.Stop();
|
||||
|
||||
if(connection)
|
||||
{
|
||||
delete connection;
|
||||
connection = NULL;
|
||||
}
|
||||
|
||||
if(sendPostBox)
|
||||
{
|
||||
delete sendPostBox;
|
||||
sendPostBox = NULL;
|
||||
}
|
||||
|
||||
callbackType = NetworkProtocolCallbackType_Unknown;
|
||||
|
||||
ShutdownWinSock();
|
||||
}
|
||||
|
||||
bool NetworkClient::PrivateData::DoWork()
|
||||
{
|
||||
Send();
|
||||
Recv();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkClient::PrivateData::Send(CustomNetProtocol& protocol)
|
||||
{
|
||||
postBoxMutex.lock();
|
||||
sendPostBox->PostMessage(protocol);
|
||||
postBoxMutex.unlock();
|
||||
}
|
||||
|
||||
int NetworkClient::PrivateData::Send()
|
||||
{
|
||||
int errorCode = 0;
|
||||
|
||||
postBoxMutex.lock();
|
||||
if(sendPostBox->IsFull())
|
||||
{
|
||||
SmartPointer<OysterByte> temp = new OysterByte;
|
||||
this->translator.Pack(temp, sendPostBox->FetchMessage());
|
||||
errorCode = this->connection->Send(temp);
|
||||
}
|
||||
postBoxMutex.unlock();
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
int NetworkClient::PrivateData::Recv()
|
||||
{
|
||||
int errorCode = -1;
|
||||
|
||||
SmartPointer<OysterByte> temp = new OysterByte;
|
||||
errorCode = this->connection->Recieve(temp);
|
||||
|
||||
if(errorCode == 0)
|
||||
{
|
||||
CustomNetProtocol protocol;
|
||||
bool ok = translator.Unpack(protocol, temp);
|
||||
|
||||
//Check if the protocol was unpacked correctly
|
||||
if(ok)
|
||||
{
|
||||
recvObjMutex.lock();
|
||||
if(callbackType == NetworkProtocolCallbackType_Function)
|
||||
{
|
||||
recvObj.protocolRecieverFnc(protocol);
|
||||
}
|
||||
else if(callbackType == NetworkProtocolCallbackType_Object)
|
||||
{
|
||||
recvObj.protocolRecievedObject->ProtocolRecievedCallback(protocol);
|
||||
}
|
||||
recvObjMutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
void NetworkClient::PrivateData::Start()
|
||||
{
|
||||
this->thread.Start();
|
||||
}
|
||||
|
||||
/*************************************
|
||||
NetworkClient
|
||||
*************************************/
|
||||
|
||||
NetworkClient::NetworkClient()
|
||||
{
|
||||
privateData = new PrivateData();
|
||||
}
|
||||
|
||||
NetworkClient::NetworkClient(unsigned int socket)
|
||||
{
|
||||
privateData = new PrivateData(socket);
|
||||
}
|
||||
|
||||
NetworkClient::NetworkClient(RecieverObject recvObj, NetworkProtocolCallbackType type)
|
||||
{
|
||||
privateData = new PrivateData();
|
||||
this->privateData->recvObj = recvObj;
|
||||
}
|
||||
|
||||
NetworkClient::NetworkClient(RecieverObject recvObj, NetworkProtocolCallbackType type, unsigned int socket)
|
||||
{
|
||||
privateData = new PrivateData(socket);
|
||||
this->privateData->recvObj = recvObj;
|
||||
this->privateData->callbackType = type;
|
||||
}
|
||||
|
||||
NetworkClient::~NetworkClient()
|
||||
{
|
||||
if(privateData)
|
||||
{
|
||||
delete privateData;
|
||||
privateData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkClient::Connect(unsigned short port, const char serverIP[])
|
||||
{
|
||||
int result = this->privateData->connection->Connect(port, serverIP);
|
||||
|
||||
//Connect has succeeded
|
||||
if(result == 0)
|
||||
{
|
||||
privateData->Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
privateData->connection->SetBlockingMode(false);
|
||||
|
||||
//Connect has failed
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkClient::Disconnect()
|
||||
{
|
||||
|
||||
privateData->connection->Disconnect();
|
||||
}
|
||||
|
||||
bool NetworkClient::IsConnected()
|
||||
{
|
||||
return false;
|
||||
return privateData->connection->IsConnected();
|
||||
}
|
||||
|
||||
void NetworkClient::Send()
|
||||
void NetworkClient::Send(CustomNetProtocol& protocol)
|
||||
{
|
||||
this->privateData->Send(protocol);
|
||||
}
|
||||
|
||||
void NetworkClient::SetRecieverObject(RecieverObject recvObj, NetworkProtocolCallbackType type)
|
||||
{
|
||||
privateData->recvObjMutex.lock();
|
||||
privateData->recvObj = recvObj;
|
||||
privateData->callbackType = type;
|
||||
privateData->recvObjMutex.unlock();
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
#define NET_PROTOCOL_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
class RecieverObject;
|
||||
#include "NetworkCallbackHelper.h"
|
||||
|
||||
namespace Oyster
|
||||
{
|
||||
|
@ -23,12 +23,19 @@ namespace Oyster
|
|||
{
|
||||
public:
|
||||
NetworkClient();
|
||||
NetworkClient(unsigned int socket);
|
||||
NetworkClient(RecieverObject recvObj, NetworkProtocolCallbackType type);
|
||||
NetworkClient(RecieverObject recvObj, NetworkProtocolCallbackType type, unsigned int socket);
|
||||
virtual ~NetworkClient();
|
||||
|
||||
virtual void Disconnect();
|
||||
virtual bool IsConnected();
|
||||
bool Connect(unsigned short port, const char serverIP[]);
|
||||
void Disconnect();
|
||||
|
||||
virtual void Send();
|
||||
bool IsConnected();
|
||||
|
||||
void Send(CustomNetProtocol& protocol);
|
||||
|
||||
void SetRecieverObject(RecieverObject recvObj, NetworkProtocolCallbackType type);
|
||||
|
||||
private:
|
||||
struct PrivateData;
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
#ifndef INCLUDE_WINSOCK_LIB
|
||||
#define INCLUDE_WINSOCK_LIB
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#endif
|
||||
|
||||
#include "NetworkServer.h"
|
||||
#include "NetworkClient.h"
|
||||
|
||||
#include "../NetworkDependencies/Listener.h"
|
||||
#include "../NetworkDependencies/PostBox.h"
|
||||
#include "../NetworkDependencies/WinsockFunctions.h"
|
||||
|
||||
#include "../../Misc/Utilities.h"
|
||||
#include "../../Misc/Thread/OysterThread.h"
|
||||
|
@ -23,12 +28,12 @@ struct NetworkServer::PrivateData : public IThreadObject
|
|||
|
||||
bool Init(INIT_DESC& initDesc);
|
||||
bool Start();
|
||||
bool Stop();
|
||||
bool Shutdown();
|
||||
void Stop();
|
||||
void Shutdown();
|
||||
|
||||
void CheckForNewClient();
|
||||
|
||||
virtual bool DoWork();
|
||||
bool DoWork();
|
||||
|
||||
//
|
||||
IListener* listener;
|
||||
|
@ -63,13 +68,22 @@ bool NetworkServer::PrivateData::Init(INIT_DESC& initDesc)
|
|||
return false;
|
||||
}
|
||||
|
||||
if(!InitWinSock())
|
||||
return false;
|
||||
|
||||
this->initDesc = initDesc;
|
||||
|
||||
//Initiate listener
|
||||
listener = new Listener(postBox);
|
||||
((Listener*)listener)->Init(this->initDesc.port, false);
|
||||
if(!((Listener*)listener)->Init(this->initDesc.port, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
thread.Create(this, false);
|
||||
if(thread.Create(this, false) == OYSTER_THREAD_ERROR_FAILED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -77,15 +91,22 @@ bool NetworkServer::PrivateData::Init(INIT_DESC& initDesc)
|
|||
bool NetworkServer::PrivateData::Start()
|
||||
{
|
||||
//Start listener
|
||||
((Listener*)listener)->Start();
|
||||
if(!((Listener*)listener)->Start())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
started = true;
|
||||
|
||||
thread.Start();
|
||||
if(thread.Start() == OYSTER_THREAD_ERROR_FAILED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetworkServer::PrivateData::Stop()
|
||||
void NetworkServer::PrivateData::Stop()
|
||||
{
|
||||
if(listener)
|
||||
{
|
||||
|
@ -95,11 +116,9 @@ bool NetworkServer::PrivateData::Stop()
|
|||
started = false;
|
||||
|
||||
thread.Stop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetworkServer::PrivateData::Shutdown()
|
||||
void NetworkServer::PrivateData::Shutdown()
|
||||
{
|
||||
//Stop server main thread
|
||||
thread.Stop();
|
||||
|
@ -118,7 +137,7 @@ bool NetworkServer::PrivateData::Shutdown()
|
|||
|
||||
started = false;
|
||||
|
||||
return true;
|
||||
ShutdownWinSock();
|
||||
}
|
||||
|
||||
//Checks for new clients and sends them to the proc function.
|
||||
|
@ -126,8 +145,7 @@ void NetworkServer::PrivateData::CheckForNewClient()
|
|||
{
|
||||
if(postBox->IsFull())
|
||||
{
|
||||
int clientSocketNum;
|
||||
postBox->FetchMessage(clientSocketNum);
|
||||
int clientSocketNum = postBox->FetchMessage();
|
||||
|
||||
//Safety check that is probably not needed.
|
||||
if(clientSocketNum == -1)
|
||||
|
@ -136,10 +154,15 @@ void NetworkServer::PrivateData::CheckForNewClient()
|
|||
}
|
||||
|
||||
//Create client and Proc function if the pointer is not NULL
|
||||
if(initDesc.proc)
|
||||
if(initDesc.callbackType == NetworkClientCallbackType_Function)
|
||||
{
|
||||
Oyster::Network::NetworkClient* client = new Oyster::Network::NetworkClient();
|
||||
initDesc.proc((NetworkClient*)client);
|
||||
Oyster::Network::NetworkClient client(clientSocketNum);
|
||||
initDesc.recvObj.clientConnectFnc(client);
|
||||
}
|
||||
else if(initDesc.callbackType == NetworkClientCallbackType_Object)
|
||||
{
|
||||
Oyster::Network::NetworkClient client(clientSocketNum);
|
||||
initDesc.recvObj.clientConnectObject->ClientConnectCallback(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,30 +193,32 @@ NetworkServer::~NetworkServer()
|
|||
|
||||
bool NetworkServer::Init(INIT_DESC& initDesc)
|
||||
{
|
||||
privateData->Init(initDesc);
|
||||
if(!privateData->Init(initDesc))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetworkServer::Start()
|
||||
{
|
||||
privateData->Start();
|
||||
if(!privateData->Start())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetworkServer::Stop()
|
||||
void NetworkServer::Stop()
|
||||
{
|
||||
privateData->Stop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetworkServer::Shutdown()
|
||||
void NetworkServer::Shutdown()
|
||||
{
|
||||
privateData->Shutdown();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetworkServer::IsStarted() const
|
||||
|
|
|
@ -11,44 +11,41 @@
|
|||
#define NET_PROTOCOL_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
//#include "NetworkClient.h"
|
||||
#include "NetworkClient.h"
|
||||
#include "NetworkCallbackHelper.h"
|
||||
|
||||
namespace Oyster
|
||||
{
|
||||
namespace Network
|
||||
{
|
||||
namespace Server
|
||||
extern "C"
|
||||
{
|
||||
extern "C"
|
||||
class NET_PROTOCOL_EXPORT NetworkServer
|
||||
{
|
||||
class NET_PROTOCOL_EXPORT NetworkServer
|
||||
public:
|
||||
struct INIT_DESC
|
||||
{
|
||||
public:
|
||||
class NetworkClient;
|
||||
struct INIT_DESC
|
||||
{
|
||||
unsigned short port; //Port the server should be accepting clients on.
|
||||
void (*proc)(NetworkClient*);
|
||||
};
|
||||
|
||||
NetworkServer();
|
||||
virtual ~NetworkServer();
|
||||
|
||||
virtual bool Init(INIT_DESC& initDesc);
|
||||
virtual bool Start();
|
||||
virtual bool Stop();
|
||||
virtual bool Shutdown();
|
||||
|
||||
virtual bool IsStarted() const;
|
||||
|
||||
private:
|
||||
struct PrivateData;
|
||||
PrivateData* privateData;
|
||||
|
||||
unsigned short port; //Port the server should be accepting clients on.
|
||||
|
||||
NetworkClientCallbackType callbackType; //The recieverObject type. Function or object.
|
||||
RecieverObject recvObj; //The functions that is called when a new client has connected.
|
||||
};
|
||||
}
|
||||
|
||||
NetworkServer();
|
||||
virtual ~NetworkServer();
|
||||
|
||||
bool Init(INIT_DESC& initDesc);
|
||||
bool Start();
|
||||
void Stop();
|
||||
void Shutdown();
|
||||
|
||||
bool IsStarted() const;
|
||||
|
||||
private:
|
||||
struct PrivateData;
|
||||
PrivateData* privateData;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
#include "Translator.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "CustomNetProtocol.h"
|
||||
|
||||
#include "../NetworkDependencies/Messages/MessageHeader.h"
|
||||
#include "../NetworkDependencies/OysterByte.h"
|
||||
|
||||
using namespace Oyster::Network;
|
||||
using namespace ::Messages;
|
||||
using namespace Utility::DynamicMemory;
|
||||
using namespace std;
|
||||
|
||||
struct MyCastingStruct
|
||||
{
|
||||
std::map<int, NetAttributeContainer> attributes;
|
||||
|
||||
/*MyCastingStruct()
|
||||
{ }
|
||||
~MyCastingStruct()
|
||||
{
|
||||
for (auto i = attributes.begin(); i != attributes.end(); i++)
|
||||
{
|
||||
RemoveAttribute(i->first);
|
||||
}
|
||||
}
|
||||
void RemoveAttribute(int ID)
|
||||
{
|
||||
auto i = attributes.find(ID);
|
||||
if(i == attributes.end()) return;
|
||||
|
||||
switch (i->second.type)
|
||||
{
|
||||
case NetAttributeType_CharArray:
|
||||
delete [] i->second.value.netCharPtr;
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
};
|
||||
|
||||
// TODO: Check if the package has been packed correctly.
|
||||
struct Translator::PrivateData
|
||||
{
|
||||
PrivateData()
|
||||
{
|
||||
numberOfUnknownTypes = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
//Packages a header with a size(int) and a string of characters(char)
|
||||
void PackHeader(SmartPointer<OysterByte> &bytes, CustomNetProtocol& protocol)
|
||||
{
|
||||
auto it = ((MyCastingStruct*)protocol.privateData)->attributes.begin();
|
||||
auto end = ((MyCastingStruct*)protocol.privateData)->attributes.end();
|
||||
|
||||
size = 4 + 2; //size(int) + number of chars(short)
|
||||
message.SetSize(size);
|
||||
|
||||
//Find all the data types
|
||||
for(; it != end; it++)
|
||||
{
|
||||
headerString.push_back(it->second.type);
|
||||
}
|
||||
|
||||
message.PackShort(size, *bytes);
|
||||
|
||||
for(int i = 0; i < (int)headerString.size(); i++)
|
||||
{
|
||||
message.PackChar(headerString.at(i), *bytes);
|
||||
size++;
|
||||
}
|
||||
|
||||
message.SetSize(bytes);
|
||||
}
|
||||
|
||||
void PackMessage(SmartPointer<OysterByte> &bytes, CustomNetProtocol& protocol)
|
||||
{
|
||||
auto it = ((MyCastingStruct*)protocol.privateData)->attributes.begin();
|
||||
auto end = ((MyCastingStruct*)protocol.privateData)->attributes.end();
|
||||
|
||||
for(int i = 0; i < (int)headerString.size(); i++)
|
||||
{
|
||||
switch((int)headerString.at(i))
|
||||
{
|
||||
case NetAttributeType_Bool:
|
||||
message.PackBool(it->second.value.netBool, *bytes);
|
||||
break;
|
||||
case NetAttributeType_Char:
|
||||
message.PackChar(it->second.value.netChar, *bytes);
|
||||
break;
|
||||
case NetAttributeType_UnsignedChar:
|
||||
message.PackUnsignedChar(it->second.value.netUChar, *bytes);
|
||||
break;
|
||||
case NetAttributeType_Short:
|
||||
message.PackShort(it->second.value.netShort, *bytes);
|
||||
break;
|
||||
case NetAttributeType_UnsignedShort:
|
||||
message.PackUnsignedShort(it->second.value.netUShort, *bytes);
|
||||
break;
|
||||
case NetAttributeType_Int:
|
||||
message.PackInt(it->second.value.netInt, *bytes);
|
||||
break;
|
||||
case NetAttributeType_UnsignedInt:
|
||||
message.PackUnsignedInt(it->second.value.netUInt, *bytes);
|
||||
break;
|
||||
case NetAttributeType_Int64:
|
||||
message.PackInt64(it->second.value.netInt64, *bytes);
|
||||
break;
|
||||
case NetAttributeType_UnsignedInt64:
|
||||
message.PackUnsignedInt64(it->second.value.netUInt64, *bytes);
|
||||
break;
|
||||
case NetAttributeType_Float:
|
||||
message.PackFloat(it->second.value.netFloat, *bytes);
|
||||
break;
|
||||
case NetAttributeType_Double:
|
||||
message.PackDouble(it->second.value.netDouble, *bytes);
|
||||
break;
|
||||
case NetAttributeType_CharArray:
|
||||
message.PackStr(it->second.value.netCharPtr, *bytes);
|
||||
break;
|
||||
default:
|
||||
numberOfUnknownTypes++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
message.SetSize(bytes);
|
||||
}
|
||||
|
||||
bool UnpackHeader(CustomNetProtocol& protocol, SmartPointer<OysterByte> &bytes)
|
||||
{
|
||||
message.SetSize(0);
|
||||
int packageSize = message.UnpackInt(*bytes);
|
||||
if(packageSize != bytes->GetSize())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
short numberOfTypes = message.UnpackShort(*bytes);
|
||||
|
||||
for(int i = 0; i < numberOfTypes; i++)
|
||||
{
|
||||
char temp = message.UnpackChar(*bytes);
|
||||
headerString.push_back(temp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnpackMessage(CustomNetProtocol& protocol, SmartPointer<OysterByte> &bytes)
|
||||
{
|
||||
for(int i = 0; i < (int)headerString.size(); i++)
|
||||
{
|
||||
protocol[i].type = (NetAttributeType)headerString.at(i);
|
||||
switch(protocol[i].type)
|
||||
{
|
||||
case NetAttributeType_Bool:
|
||||
protocol[i].value.netBool = message.UnpackBool(*bytes);
|
||||
break;
|
||||
case NetAttributeType_Char:
|
||||
protocol[i].value.netChar = message.UnpackChar(*bytes);
|
||||
break;
|
||||
case NetAttributeType_UnsignedChar:
|
||||
protocol[i].value.netUChar = message.UnpackUnsignedChar(*bytes);
|
||||
break;
|
||||
case NetAttributeType_Short:
|
||||
protocol[i].value.netShort = message.UnpackShort(*bytes);
|
||||
break;
|
||||
case NetAttributeType_UnsignedShort:
|
||||
protocol[i].value.netUShort = message.UnpackUnsignedShort(*bytes);
|
||||
break;
|
||||
case NetAttributeType_Int:
|
||||
protocol[i].value.netInt = message.UnpackInt(*bytes);
|
||||
break;
|
||||
case NetAttributeType_UnsignedInt:
|
||||
protocol[i].value.netUInt = message.UnpackUnsignedInt(*bytes);
|
||||
break;
|
||||
case NetAttributeType_Int64:
|
||||
protocol[i].value.netInt64 = message.UnpackInt64(*bytes);
|
||||
break;
|
||||
case NetAttributeType_UnsignedInt64:
|
||||
protocol[i].value.netUInt64 = message.UnpackUnsignedInt64(*bytes);
|
||||
break;
|
||||
case NetAttributeType_Float:
|
||||
protocol[i].value.netFloat = message.UnpackFloat(*bytes);
|
||||
break;
|
||||
case NetAttributeType_Double:
|
||||
protocol[i].value.netDouble = message.UnpackDouble(*bytes);
|
||||
break;
|
||||
case NetAttributeType_CharArray:
|
||||
//protocol[i].value.netCharPtr = message.UnpackStr(*bytes).c_str();
|
||||
break;
|
||||
default:
|
||||
numberOfUnknownTypes++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MessageHeader message;
|
||||
string headerString;
|
||||
unsigned int size;
|
||||
|
||||
int numberOfUnknownTypes;
|
||||
};
|
||||
|
||||
Translator::Translator()
|
||||
{
|
||||
privateData = new PrivateData();
|
||||
}
|
||||
|
||||
Translator::~Translator()
|
||||
{
|
||||
if(privateData)
|
||||
{
|
||||
delete privateData;
|
||||
privateData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::Pack(SmartPointer<OysterByte> &bytes, CustomNetProtocol& protocol)
|
||||
{
|
||||
privateData->headerString.clear();
|
||||
|
||||
privateData->PackHeader(bytes, protocol);
|
||||
privateData->PackMessage(bytes, protocol);
|
||||
}
|
||||
|
||||
bool Translator::Unpack(CustomNetProtocol& protocol, SmartPointer<OysterByte> &bytes)
|
||||
{
|
||||
if(!privateData->UnpackHeader(protocol, bytes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
privateData->UnpackMessage(protocol, bytes);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef NETWORK_DEPENDENCIES_TRANSLATOR_H
|
||||
#define NETWORK_DEPENDENCIES_TRANSLATOR_H
|
||||
|
||||
//////////////////////////////////
|
||||
// Created by Sam Svensson 2013 //
|
||||
// ----------------------------//
|
||||
// Packs our dynamic protocols //
|
||||
//////////////////////////////////
|
||||
|
||||
/*
|
||||
It packs a header in front of the actual message.
|
||||
Header looks like this:
|
||||
- Size of the entire package
|
||||
- String containing all the types of data that is packed in the package.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Possible optimizing:
|
||||
If there are several of the same type of data in a row,
|
||||
we can instead of saving a character for each type we can instead save a number and the character.
|
||||
|
||||
Example:
|
||||
If we are packing 100 floats.
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF..."
|
||||
Instead of that we can do this:
|
||||
"100F"
|
||||
*/
|
||||
|
||||
#ifdef CUSTOM_NET_PROTOCOL_EXPORT
|
||||
#define NET_PROTOCOL_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define NET_PROTOCOL_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#include "../../Misc/Utilities.h"
|
||||
|
||||
namespace Oyster
|
||||
{
|
||||
namespace Network
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
class OysterByte;
|
||||
class CustomNetProtocol;
|
||||
class NET_PROTOCOL_EXPORT Translator
|
||||
{
|
||||
public:
|
||||
Translator ();
|
||||
~Translator();
|
||||
|
||||
void Pack(Utility::DynamicMemory::SmartPointer<OysterByte> &bytes, CustomNetProtocol& protocol);
|
||||
|
||||
//Returns false if it discovers any faulty stuff with the package.
|
||||
bool Unpack(CustomNetProtocol& protocol, Utility::DynamicMemory::SmartPointer<OysterByte> &bytes);
|
||||
|
||||
private:
|
||||
struct PrivateData;
|
||||
PrivateData* privateData;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -94,9 +94,14 @@ int Connection::InitiateClient()
|
|||
|
||||
int Connection::Disconnect()
|
||||
{
|
||||
closesocket(this->socket);
|
||||
int result = closesocket(this->socket);
|
||||
|
||||
return WSAGetLastError();
|
||||
if(result == SOCKET_ERROR)
|
||||
{
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Connection::Send(Utility::DynamicMemory::SmartPointer<OysterByte> &bytes)
|
||||
|
@ -117,9 +122,10 @@ int Connection::Recieve(Utility::DynamicMemory::SmartPointer<OysterByte> &bytes)
|
|||
int nBytes;
|
||||
|
||||
bytes->Resize(1000);
|
||||
nBytes = recv(this->socket, *bytes , 500, 0);
|
||||
nBytes = recv(this->socket, *bytes, 1000, 0);
|
||||
if(nBytes == SOCKET_ERROR)
|
||||
{
|
||||
bytes->SetSize(0);
|
||||
return WSAGetLastError();
|
||||
}
|
||||
else
|
||||
|
@ -127,11 +133,10 @@ int Connection::Recieve(Utility::DynamicMemory::SmartPointer<OysterByte> &bytes)
|
|||
bytes->SetSize(nBytes);
|
||||
}
|
||||
|
||||
std::cout << "Size of the recieved data: " << nBytes << " bytes" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Listen will only return the correct socket or -1 for failure.
|
||||
int Connection::Listen()
|
||||
{
|
||||
int clientSocket;
|
||||
|
@ -143,18 +148,14 @@ int Connection::Listen()
|
|||
return clientSocket;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
//Private functions
|
||||
///////////////////////////////////////
|
||||
int Connection::InitiateSocket()
|
||||
bool Connection::IsSending()
|
||||
{
|
||||
this->socket = (int)::socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(this->socket == SOCKET_ERROR)
|
||||
{
|
||||
return WSAGetLastError();
|
||||
}
|
||||
return stillSending;
|
||||
}
|
||||
|
||||
return 0;
|
||||
bool Connection::IsConnected()
|
||||
{
|
||||
return !closed;
|
||||
}
|
||||
|
||||
int Connection::SetBlockingMode(bool blocking)
|
||||
|
@ -176,5 +177,19 @@ int Connection::SetBlockingMode(bool blocking)
|
|||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
//Private functions
|
||||
///////////////////////////////////////
|
||||
int Connection::InitiateSocket()
|
||||
{
|
||||
this->socket = (int)::socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(this->socket == SOCKET_ERROR)
|
||||
{
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -24,13 +24,16 @@ namespace Oyster
|
|||
virtual int InitiateClient();
|
||||
|
||||
virtual int Send( Utility::DynamicMemory::SmartPointer<OysterByte> &bytes );
|
||||
virtual int Recieve( Utility::DynamicMemory::SmartPointer<OysterByte> &bytes );
|
||||
virtual int Recieve( Utility::DynamicMemory::SmartPointer<OysterByte> &bytes );
|
||||
|
||||
virtual int Disconnect();
|
||||
virtual int Connect( unsigned short port , const char serverName[] );
|
||||
|
||||
virtual int Listen();
|
||||
|
||||
bool IsSending();
|
||||
bool IsConnected();
|
||||
|
||||
//Setting the socket to blocking/non-blocking mode.
|
||||
int SetBlockingMode( bool blocking );
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Oyster
|
|||
public:
|
||||
virtual ~IPostBox() {}
|
||||
virtual void PostMessage(T& message) = 0;
|
||||
virtual bool FetchMessage(T& message) = 0;
|
||||
virtual T FetchMessage() = 0;
|
||||
virtual bool IsFull() = 0;
|
||||
|
||||
};
|
||||
|
|
|
@ -11,14 +11,14 @@ namespace Oyster
|
|||
{
|
||||
namespace Network
|
||||
{
|
||||
class CustomNetProtocol;
|
||||
class OysterByte;
|
||||
class ITranslate
|
||||
{
|
||||
|
||||
public:
|
||||
//packs and unpacks packages for sending or recieving over the connection
|
||||
virtual void Pack (Protocols::ProtocolHeader &header, Utility::DynamicMemory::SmartPointer<OysterByte> &bytes) = 0;
|
||||
virtual void Unpack (Protocols::ProtocolSet* set, Utility::DynamicMemory::SmartPointer<OysterByte> &bytes ) = 0;
|
||||
virtual void Pack (Utility::DynamicMemory::SmartPointer<OysterByte> &bytes, Oyster::Network::CustomNetProtocol* protocol);
|
||||
virtual void Unpack (Oyster::Network::CustomNetProtocol* protocol, Utility::DynamicMemory::SmartPointer<OysterByte> &bytes);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
using namespace Oyster::Network::Server;
|
||||
using namespace Utility::DynamicMemory;
|
||||
using namespace Oyster::Thread;
|
||||
|
||||
Listener::Listener()
|
||||
{
|
||||
|
@ -28,7 +29,10 @@ bool Listener::Init(unsigned int port)
|
|||
connection = new Connection();
|
||||
connection->InitiateServer(port);
|
||||
|
||||
thread.Create(this, true);
|
||||
if(thread.Create(this, true) == OYSTER_THREAD_ERROR_FAILED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -36,16 +40,27 @@ bool Listener::Init(unsigned int port)
|
|||
bool Listener::Init(unsigned int port, bool start)
|
||||
{
|
||||
connection = new Connection();
|
||||
connection->InitiateServer(port);
|
||||
if(connection->InitiateServer(port) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
thread.Create(this, start);
|
||||
if(thread.Create(this, start) == OYSTER_THREAD_ERROR_FAILED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Listener::Start()
|
||||
bool Listener::Start()
|
||||
{
|
||||
thread.Start();
|
||||
if(thread.Start() == OYSTER_THREAD_ERROR_FAILED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Listener::Stop()
|
||||
|
@ -61,9 +76,7 @@ void Listener::Shutdown()
|
|||
void Listener::SetPostBox(Oyster::Network::IPostBox<int>* postBox)
|
||||
{
|
||||
stdMutex.lock();
|
||||
//mutex.LockMutex();
|
||||
this->postBox = postBox;
|
||||
//mutex.UnlockMutex();
|
||||
stdMutex.unlock();
|
||||
}
|
||||
|
||||
|
@ -75,9 +88,7 @@ int Listener::Accept()
|
|||
if(clientSocket != -1)
|
||||
{
|
||||
stdMutex.lock();
|
||||
//mutex.LockMutex();
|
||||
postBox->PostMessage(clientSocket);
|
||||
//mutex.UnlockMutex();
|
||||
stdMutex.unlock();
|
||||
}
|
||||
|
||||
|
@ -86,7 +97,12 @@ int Listener::Accept()
|
|||
|
||||
bool Listener::DoWork()
|
||||
{
|
||||
Accept();
|
||||
int result = Accept();
|
||||
|
||||
if(result == -1)
|
||||
{
|
||||
//Do something?
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace Oyster
|
|||
|
||||
bool Init(unsigned int port);
|
||||
bool Init(unsigned int port, bool start);
|
||||
void Start();
|
||||
bool Start();
|
||||
void Stop();
|
||||
|
||||
void Shutdown();
|
||||
|
|
|
@ -250,4 +250,9 @@ std::string MessageHeader::UnpackStr(OysterByte& bytes)
|
|||
void MessageHeader::SetSize(OysterByte& bytes)
|
||||
{
|
||||
Packing::Pack(bytes, size);
|
||||
}
|
||||
|
||||
void MessageHeader::SetSize(unsigned int size)
|
||||
{
|
||||
this->size = size;
|
||||
}
|
|
@ -24,7 +24,6 @@ namespace Oyster
|
|||
virtual void Pack(Protocols::ProtocolHeader& header, OysterByte& bytes );
|
||||
virtual void Unpack(OysterByte& bytes, Protocols::ProtocolHeader& header);
|
||||
|
||||
protected:
|
||||
//Pack variables to messages
|
||||
void PackBool(bool i, OysterByte& bytes);
|
||||
|
||||
|
@ -47,10 +46,6 @@ namespace Oyster
|
|||
void PackStr(char str[], OysterByte& bytes);
|
||||
void PackStr(std::string str, OysterByte& bytes);
|
||||
|
||||
//Maybe
|
||||
//TODO: Add Pack functions for Vec2, 3, 4 and maybe Matrix. Etc.
|
||||
|
||||
|
||||
//Unpack variables from message
|
||||
bool UnpackBool(OysterByte& bytes);
|
||||
|
||||
|
@ -72,13 +67,11 @@ namespace Oyster
|
|||
|
||||
std::string UnpackStr(OysterByte& bytes);
|
||||
|
||||
//Maybe
|
||||
//TODO: Add Unpack functions for Vec2, 3, 4 and maybe Matrix. Etc.
|
||||
|
||||
|
||||
//Sets the this->size to the first position in msg
|
||||
void SetSize(OysterByte& bytes);
|
||||
|
||||
void SetSize(unsigned int size);
|
||||
|
||||
private:
|
||||
unsigned int size;
|
||||
|
||||
|
|
|
@ -159,7 +159,6 @@
|
|||
<ClCompile Include="OysterByte.cpp" />
|
||||
<ClCompile Include="Packing.cpp" />
|
||||
<ClCompile Include="ThreadedClient.cpp" />
|
||||
<ClCompile Include="Translator.cpp" />
|
||||
<ClCompile Include="WinsockFunctions.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -178,7 +177,6 @@
|
|||
<ClInclude Include="PostBox.h" />
|
||||
<ClInclude Include="Protocols.h" />
|
||||
<ClInclude Include="ThreadedClient.h" />
|
||||
<ClInclude Include="Translator.h" />
|
||||
<ClInclude Include="WinsockFunctions.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<ClCompile Include="OysterByte.cpp" />
|
||||
<ClCompile Include="Packing.cpp" />
|
||||
<ClCompile Include="ThreadedClient.cpp" />
|
||||
<ClCompile Include="Translator.cpp" />
|
||||
<ClCompile Include="WinsockFunctions.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -28,7 +27,6 @@
|
|||
<ClInclude Include="PostBox.h" />
|
||||
<ClInclude Include="Protocols.h" />
|
||||
<ClInclude Include="ThreadedClient.h" />
|
||||
<ClInclude Include="Translator.h" />
|
||||
<ClInclude Include="WinsockFunctions.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -23,7 +23,7 @@ namespace Oyster
|
|||
virtual ~PostBox();
|
||||
|
||||
virtual void PostMessage(T& message);
|
||||
virtual bool FetchMessage(T& message);
|
||||
virtual T FetchMessage();
|
||||
virtual bool IsFull();
|
||||
|
||||
private:
|
||||
|
@ -49,14 +49,9 @@ namespace Oyster
|
|||
}
|
||||
|
||||
template <class T>
|
||||
bool PostBox<T>::FetchMessage(T& message)
|
||||
T PostBox<T>::FetchMessage()
|
||||
{
|
||||
if(IsFull())
|
||||
{
|
||||
message = messages.Pop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return messages.Pop();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
|
|
@ -9,7 +9,7 @@ using namespace Utility::DynamicMemory;
|
|||
ThreadedClient::ThreadedClient()
|
||||
{
|
||||
this->connection = new Connection();
|
||||
this->sendPostBox = new PostBox<SmartPointer<OysterByte>>();
|
||||
this->sendPostBox = new PostBox<CustomNetProtocol*>;
|
||||
this->recvPostBox = NULL;
|
||||
|
||||
connection->SetBlockingMode(false);
|
||||
|
@ -18,7 +18,7 @@ ThreadedClient::ThreadedClient()
|
|||
ThreadedClient::ThreadedClient(unsigned int socket)
|
||||
{
|
||||
this->connection = new Connection(socket);
|
||||
this->sendPostBox = new PostBox<SmartPointer<OysterByte>>();
|
||||
this->sendPostBox = new PostBox<CustomNetProtocol*>;
|
||||
this->recvPostBox = NULL;
|
||||
|
||||
connection->SetBlockingMode(false);
|
||||
|
@ -26,10 +26,10 @@ ThreadedClient::ThreadedClient(unsigned int socket)
|
|||
thread.Create(this, true);
|
||||
}
|
||||
|
||||
ThreadedClient::ThreadedClient(IPostBox<Utility::DynamicMemory::SmartPointer<OysterByte>>* postBox, unsigned int socket)
|
||||
ThreadedClient::ThreadedClient(IPostBox<CustomNetProtocol*>* postBox, unsigned int socket)
|
||||
{
|
||||
this->connection = new Connection(socket);
|
||||
this->sendPostBox = new PostBox<SmartPointer<OysterByte>>;
|
||||
this->sendPostBox = new PostBox<CustomNetProtocol*>;
|
||||
this->recvPostBox = postBox;
|
||||
|
||||
connection->SetBlockingMode(false);
|
||||
|
@ -51,9 +51,19 @@ ThreadedClient::~ThreadedClient()
|
|||
}
|
||||
}
|
||||
|
||||
void ThreadedClient::Send(SmartPointer<OysterByte>& byte)
|
||||
void ThreadedClient::Send(CustomNetProtocol* protocol)
|
||||
{
|
||||
this->sendPostBox->PostMessage(byte);
|
||||
this->sendPostBox->PostMessage(protocol);
|
||||
}
|
||||
|
||||
bool ThreadedClient::IsConnected()
|
||||
{
|
||||
return connection->IsConnected();
|
||||
}
|
||||
|
||||
void ThreadedClient::Disconnect()
|
||||
{
|
||||
connection->Disconnect();
|
||||
}
|
||||
|
||||
int ThreadedClient::Send()
|
||||
|
@ -62,9 +72,9 @@ int ThreadedClient::Send()
|
|||
|
||||
if(sendPostBox->IsFull())
|
||||
{
|
||||
SmartPointer<OysterByte> temp = new OysterByte;
|
||||
sendPostBox->FetchMessage(temp);
|
||||
errorCode = this->connection->Send(temp);
|
||||
OysterByte temp;
|
||||
sendPostBox->FetchMessage();
|
||||
//errorCode = this->connection->Send(temp);
|
||||
}
|
||||
|
||||
return errorCode;
|
||||
|
@ -76,11 +86,11 @@ int ThreadedClient::Recv()
|
|||
|
||||
SmartPointer<OysterByte> temp = new OysterByte;
|
||||
errorCode = this->connection->Recieve(temp);
|
||||
|
||||
|
||||
if(errorCode == 0)
|
||||
{
|
||||
stdMutex.lock();
|
||||
recvPostBox->PostMessage(temp);
|
||||
//recvPostBox->PostMessage(temp);
|
||||
stdMutex.unlock();
|
||||
}
|
||||
|
||||
|
@ -135,7 +145,7 @@ int ThreadedClient::Connect(unsigned short port, const char serverName[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
void ThreadedClient::setRecvPostBox(IPostBox<SmartPointer<OysterByte>> *postBox)
|
||||
void ThreadedClient::setRecvPostBox(IPostBox<CustomNetProtocol*> *postBox)
|
||||
{
|
||||
stdMutex.lock();
|
||||
this->recvPostBox = postBox;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "PostBox.h"
|
||||
#include "Connection.h"
|
||||
#include "../../Misc/Thread/OysterThread.h"
|
||||
#include "../../Misc/Thread/OysterMutex.h"
|
||||
#include "../../Misc/Utilities.h"
|
||||
|
||||
#include <mutex>
|
||||
|
@ -18,33 +17,39 @@ namespace Oyster
|
|||
{
|
||||
namespace Network
|
||||
{
|
||||
class CustomNetProtocol;
|
||||
class OysterByte;
|
||||
class ThreadedClient : public Thread::IThreadObject
|
||||
{
|
||||
public:
|
||||
ThreadedClient();
|
||||
ThreadedClient(unsigned int socket);
|
||||
ThreadedClient(IPostBox<Utility::DynamicMemory::SmartPointer<OysterByte>> *postBox, unsigned int socket);
|
||||
ThreadedClient(IPostBox<CustomNetProtocol*> *postBox, unsigned int socket);
|
||||
virtual ~ThreadedClient();
|
||||
|
||||
void Send(Utility::DynamicMemory::SmartPointer<OysterByte>& byte);
|
||||
void Send(CustomNetProtocol* protocol);
|
||||
|
||||
bool IsConnected();
|
||||
|
||||
int Connect(unsigned short port, const char serverName[]);
|
||||
|
||||
void setRecvPostBox(IPostBox<Utility::DynamicMemory::SmartPointer<OysterByte>> *postBox);
|
||||
void Disconnect();
|
||||
|
||||
private:
|
||||
void setRecvPostBox(IPostBox<CustomNetProtocol*> *postBox);
|
||||
|
||||
protected:
|
||||
virtual int Send();
|
||||
virtual int Recv();
|
||||
|
||||
//These functions should not be called by any other than the thread.
|
||||
virtual void ThreadEntry();
|
||||
virtual void ThreadExit();
|
||||
virtual bool DoWork();
|
||||
|
||||
private:
|
||||
protected:
|
||||
Connection* connection;
|
||||
IPostBox<Utility::DynamicMemory::SmartPointer<OysterByte>> *sendPostBox;
|
||||
IPostBox<Utility::DynamicMemory::SmartPointer<OysterByte>> *recvPostBox;
|
||||
IPostBox<CustomNetProtocol*> *sendPostBox;
|
||||
IPostBox<CustomNetProtocol*> *recvPostBox;
|
||||
Oyster::Thread::OysterThread thread;
|
||||
std::mutex stdMutex;
|
||||
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
#include "Translator.h"
|
||||
|
||||
using namespace Oyster::Network;
|
||||
using namespace ::Protocols;
|
||||
using namespace ::Messages;
|
||||
|
||||
void Translator::Pack( ProtocolHeader &header, Utility::DynamicMemory::SmartPointer<OysterByte> &bytes )
|
||||
{
|
||||
MessageHeader *message = NULL;
|
||||
|
||||
switch(header.packageType)
|
||||
{
|
||||
case PackageType_header:
|
||||
message = new MessageHeader();
|
||||
break;
|
||||
|
||||
case PackageType_test:
|
||||
message = new MessageTest();
|
||||
break;
|
||||
|
||||
case PackageType_player_pos:
|
||||
message = new MessagePlayerPos();
|
||||
break;
|
||||
}
|
||||
|
||||
if(message != NULL)
|
||||
{
|
||||
message->Pack(header, *bytes);
|
||||
|
||||
delete message;
|
||||
message = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::Unpack(ProtocolSet* set, Utility::DynamicMemory::SmartPointer<OysterByte> &bytes)
|
||||
{
|
||||
ProtocolHeader *header = new ProtocolHeader();
|
||||
MessageHeader *message = new MessageHeader();
|
||||
|
||||
message->Unpack(*bytes, *header);
|
||||
delete message;
|
||||
message = NULL;
|
||||
|
||||
//Switch to the correct package.
|
||||
set->type = (PackageType)header->packageType;
|
||||
switch(set->type)
|
||||
{
|
||||
case PackageType_header:
|
||||
message = new MessageHeader();
|
||||
set->Protocol.pHeader = new ProtocolHeader;
|
||||
message->Unpack(*bytes, *set->Protocol.pHeader);
|
||||
break;
|
||||
|
||||
case PackageType_test:
|
||||
message = new MessageTest();
|
||||
set->Protocol.pTest = new ProtocolTest;
|
||||
message->Unpack(*bytes, *set->Protocol.pTest);
|
||||
break;
|
||||
|
||||
case PackageType_player_pos:
|
||||
message = new MessagePlayerPos();
|
||||
set->Protocol.pPlayerPos = new ProtocolPlayerPos;
|
||||
message->Unpack(*bytes, *set->Protocol.pPlayerPos);
|
||||
break;
|
||||
}
|
||||
|
||||
if(message)
|
||||
{
|
||||
delete message;
|
||||
}
|
||||
delete header;
|
||||
|
||||
//return set;
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
#ifndef NETWORK_DEPENDENCIES_TRANSLATOR_H
|
||||
#define NETWORK_DEPENDENCIES_TRANSLATOR_H
|
||||
|
||||
//////////////////////////////////
|
||||
// Created by Sam Svensson 2013 //
|
||||
//////////////////////////////////
|
||||
|
||||
#include "Messages/MessagesInclude.h"
|
||||
#include "Protocols.h"
|
||||
#include "ITranslate.h"
|
||||
#include "OysterByte.h"
|
||||
|
||||
namespace Oyster
|
||||
{
|
||||
namespace Network
|
||||
{
|
||||
class Translator : public ITranslate
|
||||
{
|
||||
public:
|
||||
Translator () { };
|
||||
~Translator() { };
|
||||
|
||||
void Pack (Protocols::ProtocolHeader &header, Utility::DynamicMemory::SmartPointer<OysterByte> &bytes );
|
||||
void Unpack (Protocols::ProtocolSet* set, Utility::DynamicMemory::SmartPointer<OysterByte> &bytes );
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,3 +1,8 @@
|
|||
#ifndef INCLUDE_WINSOCK_LIB
|
||||
#define INCLUDE_WINSOCK_LIB
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#endif
|
||||
|
||||
#include "WinsockFunctions.h"
|
||||
#include <WinSock2.h>
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <WinSock2.h>
|
||||
#include <vld.h>
|
||||
#include "../NetworkDependencies/WinsockFunctions.h"
|
||||
#include "..\NetworkDependencies\Translator.h"
|
||||
#include "..\NetworkDependencies\Protocols.h"
|
||||
#include "../NetworkDependencies/OysterByte.h"
|
||||
#include "../../Misc/ThreadSafeQueue.h"
|
||||
|
@ -44,6 +43,12 @@ int main()
|
|||
}
|
||||
|
||||
chat(*client);
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
delete client;
|
||||
|
||||
ShutdownWinSock();
|
||||
|
@ -54,10 +59,10 @@ int main()
|
|||
|
||||
void chat(ThreadedClient &client)
|
||||
{
|
||||
Oyster::Network::Translator *t = new Oyster::Network::Translator();
|
||||
/*Oyster::Network::Translator *t = new Oyster::Network::Translator();
|
||||
IPostBox< SmartPointer<OysterByte >> *postBox = new PostBox< SmartPointer<OysterByte >>;
|
||||
|
||||
client.setRecvPostBox(postBox);
|
||||
//client.setRecvPostBox(postBox);
|
||||
|
||||
SmartPointer<OysterByte> msgRecv = new OysterByte();
|
||||
SmartPointer<OysterByte> msgSend = new OysterByte();
|
||||
|
@ -80,7 +85,7 @@ void chat(ThreadedClient &client)
|
|||
while(1)
|
||||
{
|
||||
//Fetch new messages from the postbox
|
||||
if(postBox->FetchMessage(msgRecv))
|
||||
//if(postBox->FetchMessage(msgRecv))
|
||||
{
|
||||
t->Unpack(set, msgRecv);
|
||||
|
||||
|
@ -93,14 +98,14 @@ void chat(ThreadedClient &client)
|
|||
{
|
||||
cout << "Sending to server." << endl;
|
||||
timer.reset();
|
||||
client.Send(msgSend);
|
||||
//client.Send(msgSend);
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
delete postBox;
|
||||
delete t;
|
||||
delete set;
|
||||
delete set;*/
|
||||
}
|
||||
|
||||
void PrintOutMessage(ProtocolSet* set)
|
||||
|
|
|
@ -102,6 +102,8 @@
|
|||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<DelayLoadDLLs>
|
||||
</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
|
@ -161,7 +163,6 @@
|
|||
<ClCompile Include="TestClass.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="RecieverObject.h" />
|
||||
<ClInclude Include="TestClass.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="RecieverObject.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TestClass.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef OYSTER_NETWORK_SERVER_RECIEVER_OBJECT_H
|
||||
#define OYSTER_NETWORK_SERVER_RECIEVER_OBJECT_H
|
||||
|
||||
/////////////////////////////////////
|
||||
// Created by Pontus Fransson 2013 //
|
||||
/////////////////////////////////////
|
||||
|
||||
#include "../NetworkDependencies/Protocols.h"
|
||||
#include "../NetworkDependencies/OysterByte.h"
|
||||
#include "../../Misc/Utilities.h"
|
||||
|
||||
class RecieverObject
|
||||
{
|
||||
public:
|
||||
virtual void ProcFunc(Utility::DynamicMemory::SmartPointer<Oyster::Network::OysterByte> msg) = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,14 +1,11 @@
|
|||
#include <iostream>
|
||||
#include <WinSock2.h>
|
||||
#include <vector>
|
||||
#include <vld.h>
|
||||
#include "../NetworkDependencies/WinsockFunctions.h"
|
||||
#include "TestClass.h"
|
||||
#include "../NetworkAPI/Translator.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void clientProc(Oyster::Network::NetworkClient* client);
|
||||
|
||||
int main()
|
||||
{
|
||||
if(!InitWinSock())
|
||||
|
@ -16,39 +13,6 @@ int main()
|
|||
cout << "errorMessage: unable to start winsock" << endl;
|
||||
}
|
||||
|
||||
Test test;
|
||||
|
||||
cout << "Server" << endl;
|
||||
|
||||
test.mainLoop();
|
||||
|
||||
while(1)
|
||||
{
|
||||
//Fetch new clients from the postbox
|
||||
/*
|
||||
//Send a message every 1 seconds to all clients.
|
||||
if(timer.getElapsedSeconds() > 1)
|
||||
{
|
||||
cout << "Sending to " << clients.size() << " clients." << endl;
|
||||
timer.reset();
|
||||
for(int i = 0; i < (int)clients.size(); i++)
|
||||
{
|
||||
clients.at(i)->Send(sendBuffer);
|
||||
}
|
||||
}*/
|
||||
|
||||
/*//Fetch messages
|
||||
if(recvPostBox->FetchMessage(recvBuffer))
|
||||
{
|
||||
t.Unpack(set, recvBuffer);
|
||||
|
||||
//PrintOutMessage(set);
|
||||
set->Release();
|
||||
}*/
|
||||
}
|
||||
|
||||
Sleep(1000);
|
||||
|
||||
system("pause");
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
#include "TestClass.h"
|
||||
#include "../../Misc/WinTimer.h"
|
||||
#include <iostream>
|
||||
|
||||
/*
|
||||
using namespace Oyster::Network;
|
||||
using namespace ::Server;
|
||||
using namespace ::Protocols;
|
||||
using namespace Utility;
|
||||
using namespace ::DynamicMemory;
|
||||
|
@ -18,7 +17,6 @@ Test::Test()
|
|||
|
||||
NetworkServer::INIT_DESC initDesc;
|
||||
initDesc.port = 9876;
|
||||
initDesc.proc = NULL;
|
||||
server.Init(initDesc);
|
||||
server.Start();
|
||||
|
||||
|
@ -32,7 +30,7 @@ Test::Test()
|
|||
test.matrix[i] = (float)i;
|
||||
}
|
||||
|
||||
t.Pack(test, sendBuffer);
|
||||
//t.Pack(test, sendBuffer);
|
||||
}
|
||||
|
||||
Test::~Test()
|
||||
|
@ -43,7 +41,7 @@ Test::~Test()
|
|||
server.Stop();
|
||||
}
|
||||
|
||||
void Test::ProcFunc(Utility::DynamicMemory::SmartPointer<Oyster::Network::OysterByte> msg)
|
||||
void Test::ProcFunction(CustomNetProtocol& protocol)
|
||||
{
|
||||
|
||||
return;
|
||||
|
@ -83,4 +81,4 @@ void Test::PrintOutMessage(ProtocolSet* set)
|
|||
cout << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
|
@ -1,16 +1,17 @@
|
|||
#ifndef TEST_CLASS_H
|
||||
#define TEST_CLASS_H
|
||||
|
||||
#include "RecieverObject.h"
|
||||
/*
|
||||
#include "../../Misc/Utilities.h"
|
||||
#include "../NetworkDependencies/OysterByte.h"
|
||||
#include "../NetworkDependencies/PostBox.h"
|
||||
#include "../NetworkAPI/NetworkClient.h"
|
||||
#include "../NetworkAPI/NetworkServer.h"
|
||||
#include "../NetworkDependencies/Translator.h"
|
||||
//#include "../NetworkDependencies/Translator.h"
|
||||
#include "../NetworkAPI/CustomNetProtocol.h"
|
||||
#include "../NetworkDependencies/Protocols.h"
|
||||
#include <vector>
|
||||
|
||||
class Test : public RecieverObject
|
||||
class Test
|
||||
{
|
||||
public:
|
||||
Test();
|
||||
|
@ -18,20 +19,20 @@ public:
|
|||
|
||||
void mainLoop();
|
||||
|
||||
virtual void ProcFunc(Utility::DynamicMemory::SmartPointer<Oyster::Network::OysterByte> msg);
|
||||
virtual void ProcFunction(Oyster::Network::CustomNetProtocol& protocol);
|
||||
void PrintOutMessage(Oyster::Network::Protocols::ProtocolSet* set);
|
||||
|
||||
private:
|
||||
std::vector<Oyster::Network::NetworkClient*> clients;
|
||||
Oyster::Network::IPostBox<Utility::DynamicMemory::SmartPointer<Oyster::Network::OysterByte>> *recvPostBox;
|
||||
|
||||
Oyster::Network::Translator t;
|
||||
//Oyster::Network::Translator t;
|
||||
Oyster::Network::Protocols::ProtocolPlayerPos test;
|
||||
Utility::DynamicMemory::SmartPointer<Oyster::Network::OysterByte> sendBuffer;
|
||||
Utility::DynamicMemory::SmartPointer<Oyster::Network::OysterByte> recvBuffer;
|
||||
|
||||
Oyster::Network::Server::NetworkServer server;
|
||||
Oyster::Network::NetworkServer server;
|
||||
|
||||
};
|
||||
|
||||
*/
|
||||
#endif
|
Loading…
Reference in New Issue