commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
325
include/modules/io_net/io_net_server.cpp
Normal file
325
include/modules/io_net/io_net_server.cpp
Normal file
@ -0,0 +1,325 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "io_net/io_net_server.h"
|
||||
#include "metafile/nml.h"
|
||||
#include "async/task_loop.h"
|
||||
#include "platform.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS::IO;
|
||||
|
||||
// #define VERBOSE_LOG
|
||||
|
||||
|
||||
// @FIXME Rewrite communication with the controller thread using AsyncCallQueue.
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
NetServer::Client *NetServer::GetClient(void *peer)
|
||||
{
|
||||
ListForeachPtr(Client *, client, clients)
|
||||
if (client->peer == peer)
|
||||
return client;
|
||||
return NULL;
|
||||
}
|
||||
int NetServer::GetClientFreeHandleIndex(const Client &client) const
|
||||
{
|
||||
int free_id = 0;
|
||||
ListForeachPtr(ClientHandleInfo *, i, client.handles)
|
||||
if (i->id >= free_id)
|
||||
free_id = i->id + 1;
|
||||
return free_id;
|
||||
}
|
||||
Handle *NetServer::GetClientHandle(const Client &client, int id) const
|
||||
{
|
||||
ListForeachPtr(ClientHandleInfo *, i, client.handles)
|
||||
if (i->id == id)
|
||||
return i->handle;
|
||||
return NULL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool NetServer::ProcessCloseCommand(Client &client, GS::StringList &args)
|
||||
// Close,handle_id
|
||||
{
|
||||
if (args.GetCount() != 2)
|
||||
return false;
|
||||
|
||||
int id = args[1].Integer();
|
||||
|
||||
ClientHandleInfo *hi = NULL;
|
||||
ListForeachPtr(ClientHandleInfo *, i, client.handles)
|
||||
if (i->id == id)
|
||||
{
|
||||
hi = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hi == NULL)
|
||||
return false;
|
||||
|
||||
client.handles.Remove(hi);
|
||||
|
||||
#ifdef VERBOSE_LOG
|
||||
__LOG__ << "IO::NetServer: Close handle " << id << " (client total: " << client.handles.GetCount() << ").\n";
|
||||
#endif
|
||||
return SendString(client.peer, "Success");
|
||||
}
|
||||
bool NetServer::ProcessReadCommand(Client &client, GS::StringList &args)
|
||||
// Read,size,handle_id
|
||||
{
|
||||
if (args.GetCount() != 3)
|
||||
return false;
|
||||
|
||||
Handle *h = GetClientHandle(client, args[2].Integer());
|
||||
if (h == NULL)
|
||||
return false;
|
||||
|
||||
// Read data.
|
||||
size_t size = size_t(args[1].Integer());
|
||||
Array <char> data(size);
|
||||
size_t read_size = h->Read((void *)data, size);
|
||||
|
||||
// Format answer data (FIXME two allocations are not required for this).
|
||||
String answer = String::Format("Success,%d,", read_size);
|
||||
|
||||
Array <char> answer_data(answer.Len() + read_size);
|
||||
Memory::Copy(answer_data.c_ptr(), answer.c_str(), answer.Len());
|
||||
Memory::Copy(answer_data.c_ptr() + answer.Len(), data.c_ptr(), read_size);
|
||||
|
||||
return Send(client.peer, (void *)answer_data.c_ptr(), answer_data.GetSize());
|
||||
}
|
||||
bool NetServer::ProcessSeekCommand(Client &client, GS::StringList &args)
|
||||
// Seek,offset_from_start,ref,handle_id
|
||||
{
|
||||
if (args.GetCount() != 4)
|
||||
return false;
|
||||
|
||||
Handle *h = GetClientHandle(client, args[3].Integer());
|
||||
if (h == NULL)
|
||||
return false;
|
||||
|
||||
ptrdiff_t offset = ptrdiff_t(args[1].Integer());
|
||||
|
||||
Base::SeekRef seek_ref;
|
||||
if (args[2] == "Start")
|
||||
seek_ref = Base::SeekStart;
|
||||
else if (args[2] == "Current")
|
||||
seek_ref = Base::SeekCurrent;
|
||||
else if (args[2] == "End")
|
||||
seek_ref = Base::SeekEnd;
|
||||
else
|
||||
return false;
|
||||
|
||||
size_t r = h->Seek(offset, seek_ref);
|
||||
return SendString(client.peer, String::Format("Success,%d", r));
|
||||
}
|
||||
bool NetServer::ProcessTellCommand(Client &client, GS::StringList &args)
|
||||
// Tell,handle_id
|
||||
{
|
||||
if (args.GetCount() != 2)
|
||||
return false;
|
||||
|
||||
Handle *h = GetClientHandle(client, args[1].Integer());
|
||||
if (h == NULL)
|
||||
return false;
|
||||
|
||||
return SendString(client.peer, String::Format("Success,%d", h->Tell()));
|
||||
}
|
||||
bool NetServer::ProcessOpenCommand(Client &client, GS::StringList &args)
|
||||
// Open,path
|
||||
{
|
||||
if (args.GetCount() != 2)
|
||||
__ERR__(__LOG_E__ << "NetServer::ProcessOpenCommand(): incorrect argument count.\n", false)
|
||||
|
||||
int index = GetClientFreeHandleIndex(client);
|
||||
|
||||
AutoPtr <ClientHandleInfo> i(new ClientHandleInfo);
|
||||
i->id = index;
|
||||
i->name = args[1];
|
||||
i->handle = basefs->Open(i->name);
|
||||
if (i->handle.IsNull())
|
||||
return false; // __ERR__(__LOG_E__ << "NetServer::ProcessOpenCommand(): failed to open '" << i->name << "' on base filesystem.\n", false)
|
||||
|
||||
client.handles.Add(i.Detach());
|
||||
|
||||
#ifdef VERBOSE_LOG
|
||||
__LOG__ << "IO::NetServer: Open handle '" << args[1] << "' => " << index << " (client total: " << client.handles.GetCount() << ").\n";
|
||||
#endif
|
||||
return SendString(client.peer, String::Format("Success,%d", index));
|
||||
}
|
||||
bool NetServer::ProcessHashCommand(Client &client, GS::StringList &args)
|
||||
// Hash,path
|
||||
{
|
||||
if (args.GetCount() != 2)
|
||||
return false;
|
||||
|
||||
String hash = basefs->Hash(args[1]);
|
||||
if (hash.IsEmpty())
|
||||
return false;
|
||||
|
||||
return SendString(client.peer, String::Format("Success,%s", hash.c_str()));
|
||||
}
|
||||
bool NetServer::ProcessClientRequest(Client &client, const GS::String &data)
|
||||
{
|
||||
StringList args;
|
||||
data.Split(",", args);
|
||||
|
||||
bool r = false;
|
||||
|
||||
// Command dispatch.
|
||||
if (args[0] == "Open")
|
||||
r = ProcessOpenCommand(client, args);
|
||||
else if (args[0] == "Seek")
|
||||
r = ProcessSeekCommand(client, args);
|
||||
else if (args[0] == "Tell")
|
||||
r = ProcessTellCommand(client, args);
|
||||
else if (args[0] == "Read")
|
||||
r = ProcessReadCommand(client, args);
|
||||
else if (args[0] == "Close")
|
||||
r = ProcessCloseCommand(client, args);
|
||||
else if (args[0] == "Hash")
|
||||
r = ProcessHashCommand(client, args);
|
||||
|
||||
if (!r)
|
||||
SendString(client.peer, "Failed");
|
||||
return r;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void NetServer::GetStatistics(Statistics &stats)
|
||||
{
|
||||
Time t = Platform::Get().GetTime();
|
||||
|
||||
stats.connected = asbool(clients.GetCount());
|
||||
|
||||
Network::Enet::Statistics enet_stats;
|
||||
Network::Enet::GetStatistics(enet_stats);
|
||||
|
||||
if ((t - bandwidth_measure.time).toSec() > 2)
|
||||
{
|
||||
bandwidth = int((enet_stats.sent_data - bandwidth_measure.value) / (t - bandwidth_measure.time).toSec());
|
||||
|
||||
bandwidth_measure.time = t;
|
||||
bandwidth_measure.value = enet_stats.sent_data;
|
||||
}
|
||||
|
||||
stats.sent_data = enet_stats.sent_data;
|
||||
stats.bandwidth = bandwidth;
|
||||
|
||||
stats.packet_loss = 0;
|
||||
if (clients.GetCount() > 0)
|
||||
{
|
||||
ListForeachPtr(Client *, client, clients)
|
||||
stats.packet_loss += GetPeerPacketLossRatio(client->peer);
|
||||
stats.packet_loss /= clients.GetCount();
|
||||
}
|
||||
|
||||
// Handle statistics.
|
||||
int handle_count = 0;
|
||||
ListForeachPtr(Client *, client, clients)
|
||||
handle_count += client->handles.GetCount();
|
||||
|
||||
if (stats.handles.Allocate(handle_count))
|
||||
{
|
||||
handle_count = 0;
|
||||
ListForeachPtr(Client *, client, clients)
|
||||
ListForeachPtr(ClientHandleInfo *, i, client->handles)
|
||||
{
|
||||
Statistics::Handle *h = &stats.handles[handle_count++];
|
||||
h->name = i->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void NetServer::OnPeerConnection(void *peer)
|
||||
{
|
||||
__LOG_H__ << "IO::NetServer: OnPeerConnection\n";
|
||||
|
||||
__ASSERT__(GetClient(peer) == NULL);
|
||||
clients.Add(new Client(peer));
|
||||
|
||||
SetPeerTimeout(peer, TimeoutVeryLong);
|
||||
}
|
||||
void NetServer::OnPacketReceived(void *peer, const void *data, size_t size)
|
||||
{
|
||||
Client *client = GetClient(peer);
|
||||
__ASSERT__(client != NULL);
|
||||
|
||||
if (size > 512)
|
||||
{
|
||||
SendString(peer, "DataLengthError");
|
||||
return; // invalid
|
||||
}
|
||||
|
||||
String command((char *)data, (char *)data + size);
|
||||
|
||||
if (client->handshake_step == -1)
|
||||
ProcessClientRequest(*client, command);
|
||||
|
||||
else
|
||||
{
|
||||
switch (client->handshake_step)
|
||||
{
|
||||
case 0:
|
||||
if (command == "RequestIOAccess")
|
||||
{
|
||||
__LOG_V__ << "Granting client access.\n";
|
||||
client->handshake_step = -1;
|
||||
|
||||
SendString(peer, "Granted");
|
||||
}
|
||||
else
|
||||
Disconnect(peer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void NetServer::OnConnectionClosed(void *peer)
|
||||
{
|
||||
__LOG_H__ << "IO::NetServer: OnConnectionClosed\n";
|
||||
|
||||
Client *client = GetClient(peer);
|
||||
__ASSERT__(client != NULL);
|
||||
clients.Remove(client);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool NetServer::Start(const char *ip, int port)
|
||||
{
|
||||
__LOG_H__ << "IO::NetServer: Starting on " << ip << " port " << port << ".\n";
|
||||
return OpenServer(ip, port);
|
||||
}
|
||||
void NetServer::Stop()
|
||||
{
|
||||
__LOG_H__ << "IO::NetServer: Shutting down.\n";
|
||||
|
||||
// Disconnect all clients.
|
||||
ListForeachPtr(Client *, c, clients)
|
||||
Disconnect(c->peer);
|
||||
|
||||
StartTaskLoop(clients.GetCount() > 0, 2000)
|
||||
{
|
||||
UpdateHost();
|
||||
Platform::Get().Sleep(1);
|
||||
}
|
||||
EndTaskLoop
|
||||
|
||||
Close();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
NetServer::NetServer(Base *fs) : basefs(fs), bandwidth(0)
|
||||
{}
|
||||
NetServer::~NetServer()
|
||||
{ Stop(); }
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user