Timout for network operations now configurable in streamdev-client setup

This commit is contained in:
Frank Schmirler 2012-03-03 23:24:30 +01:00
parent c1dc1453c5
commit 3da6ae734e
14 changed files with 132 additions and 122 deletions

View File

@ -1,6 +1,7 @@
VDR Plugin 'streamdev' Revision History
---------------------------------------
- Timout for network operations now configurable in streamdev-client setup
- Added timeout to Connect()
- Report the server-side HTTP status "503 Service unavailable" instead of
the client-side error "409 Conflict" when a channel is unavailable

3
README
View File

@ -387,6 +387,9 @@ during an active transfer. This makes it possible to switch languages, receive
additional channels (for recording on the client) and use plugins that use
receivers themselves (like osdteletext).
The default timeout of 2 seconds for network operations should be sufficient in
most cases. Increase "Timeout" if you get frequent timeout errors in the log.
With "Filter Streaming" enabled, the client will receive meta information like
EPG data and service information, just as if the client had its own DVB card.
Link channels and even a client-side EPG scan have been reported to work.

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2011-02-16 08:49+0100\n"
"POT-Creation-Date: 2012-03-03 23:12+0100\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: Frank Schmirler <vdrdev@schmirler.de>\n"
"Language-Team: German <vdr@linuxtv.org>\n"
@ -40,6 +40,9 @@ msgstr "IP der Gegenseite"
msgid "Remote Port"
msgstr "Port der Gegenseite"
msgid "Timeout (s)"
msgstr "Timeout (s)"
msgid "Filter Streaming"
msgstr "Filter-Daten streamen"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2011-12-11 10:48+0100\n"
"POT-Creation-Date: 2012-03-03 23:12+0100\n"
"PO-Revision-Date: 2010-06-19 03:58+0100\n"
"Last-Translator: Javier Bradineras <jbradi@hotmail.com>\n"
"Language-Team: Spanish <vdr@linuxtv.org>\n"
@ -40,6 +40,9 @@ msgstr "Indicar IP del Servidor"
msgid "Remote Port"
msgstr "Indicar puerto remoto del Servidor"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "Filtrar transmisión"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2011-12-11 10:48+0100\n"
"POT-Creation-Date: 2012-03-03 23:12+0100\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
@ -40,6 +40,9 @@ msgstr "Etäkoneen IP-osoite"
msgid "Remote Port"
msgstr "Etäkoneen portti"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "Suodatetun tiedon suoratoisto"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2011-12-11 10:48+0100\n"
"POT-Creation-Date: 2012-03-03 23:12+0100\n"
"PO-Revision-Date: 2008-03-30 02:11+0200\n"
"Last-Translator: micky979 <micky979@free.fr>\n"
"Language-Team: French <vdr@linuxtv.org>\n"
@ -40,6 +40,9 @@ msgstr "Adresse IP du serveur"
msgid "Remote Port"
msgstr "Port du serveur"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "Filtre streaming"

View File

@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2011-12-11 10:48+0100\n"
"POT-Creation-Date: 2012-03-03 23:12+0100\n"
"PO-Revision-Date: 2010-06-19 03:58+0100\n"
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
"Language-Team: Italian <vdr@linuxtv.org>\n"
@ -42,6 +42,9 @@ msgstr "Indirizzo IP del Server"
msgid "Remote Port"
msgstr "Porta Server Remoto"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "Filtra trasmissione"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2011-12-11 10:48+0100\n"
"POT-Creation-Date: 2012-03-03 23:12+0100\n"
"PO-Revision-Date: 2009-11-26 21:57+0200\n"
"Last-Translator: Valdemaras Pipiras <varas@ambernet.lt>\n"
"Language-Team: Lithuanian <vdr@linuxtv.org>\n"
@ -40,6 +40,9 @@ msgstr "Nuotolinis IP adresas"
msgid "Remote Port"
msgstr "Nuotolinis portas"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "Filtruoti transliavimą"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: streamdev 0.5.0\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2011-12-11 10:48+0100\n"
"POT-Creation-Date: 2012-03-03 23:12+0100\n"
"PO-Revision-Date: 2008-06-26 15:36+0100\n"
"Last-Translator: Oleg Roitburd <oleg@roitburd.de>\n"
"Language-Team: Russian <vdr@linuxtv.org>\n"
@ -40,6 +40,9 @@ msgstr "
msgid "Remote Port"
msgstr "ÃÔÐÛÕÝÝëÙ ßÞàâ"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "ÄØÛìâà ßÞâÞÚÐ"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: streamdev_SK\n"
"Report-Msgid-Bugs-To: <http://www.vdr-developer.org/mantisbt/>\n"
"POT-Creation-Date: 2011-12-11 10:48+0100\n"
"POT-Creation-Date: 2012-03-03 23:12+0100\n"
"PO-Revision-Date: \n"
"Last-Translator: Milan Hrala <hrala.milan@gmail.com>\n"
"Language-Team: Slovak <hrala.milan@gmail.com>\n"
@ -42,6 +42,9 @@ msgstr "Vzdialen
msgid "Remote Port"
msgstr "Vzdialený port"
msgid "Timeout (s)"
msgstr ""
msgid "Filter Streaming"
msgstr "filtrova» prúdy"

View File

@ -12,6 +12,7 @@ cStreamdevClientSetup StreamdevClientSetup;
cStreamdevClientSetup::cStreamdevClientSetup(void) {
StartClient = false;
RemotePort = 2004;
Timeout = 2;
StreamFilters = false;
HideMenuEntry = false;
MinPriority = -1;
@ -31,6 +32,7 @@ bool cStreamdevClientSetup::SetupParse(const char *Name, const char *Value) {
strcpy(RemoteIp, Value);
}
else if (strcmp(Name, "RemotePort") == 0) RemotePort = atoi(Value);
else if (strcmp(Name, "Timeout") == 0) Timeout = atoi(Value);
else if (strcmp(Name, "StreamFilters") == 0) StreamFilters = atoi(Value);
else if (strcmp(Name, "HideMenuEntry") == 0) HideMenuEntry = atoi(Value);
else if (strcmp(Name, "MinPriority") == 0) MinPriority = atoi(Value);
@ -49,6 +51,7 @@ cStreamdevClientMenuSetupPage::cStreamdevClientMenuSetupPage(void) {
Add(new cMenuEditBoolItem(tr("Start Client"), &m_NewSetup.StartClient));
Add(new cMenuEditIpItem (tr("Remote IP"), m_NewSetup.RemoteIp));
Add(new cMenuEditIntItem (tr("Remote Port"), &m_NewSetup.RemotePort, 0, 65535));
Add(new cMenuEditIntItem (tr("Timeout (s)"), &m_NewSetup.Timeout, 1, 15));
Add(new cMenuEditBoolItem(tr("Filter Streaming"), &m_NewSetup.StreamFilters));
Add(new cMenuEditIntItem (tr("Minimum Priority"), &m_NewSetup.MinPriority, -1, MAXPRIORITY));
Add(new cMenuEditIntItem (tr("Maximum Priority"), &m_NewSetup.MaxPriority, -1, MAXPRIORITY));
@ -75,6 +78,7 @@ void cStreamdevClientMenuSetupPage::Store(void) {
else
SetupStore("RemoteIp", m_NewSetup.RemoteIp);
SetupStore("RemotePort", m_NewSetup.RemotePort);
SetupStore("Timeout", m_NewSetup.Timeout);
SetupStore("StreamFilters", m_NewSetup.StreamFilters);
SetupStore("HideMenuEntry", m_NewSetup.HideMenuEntry);
SetupStore("MinPriority", m_NewSetup.MinPriority);

View File

@ -15,6 +15,7 @@ struct cStreamdevClientSetup {
int StartClient;
char RemoteIp[20];
int RemotePort;
int Timeout;
int StreamFilters;
int HideMenuEntry;
int MinPriority;

View File

@ -11,8 +11,11 @@
#define MINLOGREPEAT 10 //don't log connect failures too often (seconds)
// timeout for writing to command socket
#define WRITE_TIMEOUT_MS 200
#define QUIT_TIMEOUT_MS 500
#include "client/socket.h"
#include "client/setup.h"
#include "common.h"
cClientSocket ClientSocket;
@ -21,6 +24,7 @@ cClientSocket::cClientSocket(void)
{
memset(m_DataSockets, 0, sizeof(cTBSocket*) * si_Count);
m_Prio = false;
m_Abort = false;
m_LastSignalUpdate = 0;
m_LastSignalStrength = -1;
m_LastSignalQuality = -1;
@ -45,43 +49,53 @@ cTBSocket *cClientSocket::DataSocket(eSocketId Id) const {
return m_DataSockets[Id];
}
bool cClientSocket::Command(const std::string &Command, uint Expected, uint TimeoutMs)
bool cClientSocket::Command(const std::string &Command, uint Expected)
{
errno = 0;
uint code = 0;
std::string buffer;
if (Send(Command) && Receive(Command, &code, &buffer)) {
if (code == Expected)
return true;
dsyslog("streamdev-client: Command '%s' rejected by %s:%d: %s",
Command.c_str(), RemoteIp().c_str(), RemotePort(), buffer.c_str());
}
return false;
}
bool cClientSocket::Send(const std::string &Command)
{
std::string pkt = Command + "\015\012";
Dprintf("OUT: |%s|\n", Command.c_str());
cTimeMs starttime;
if (!TimedWrite(pkt.c_str(), pkt.size(), TimeoutMs)) {
esyslog("Streamdev: Lost connection to %s:%d: %s", RemoteIp().c_str(), RemotePort(),
strerror(errno));
errno = 0;
if (!TimedWrite(pkt.c_str(), pkt.size(), WRITE_TIMEOUT_MS)) {
esyslog("ERROR: streamdev-client: Failed sending command '%s' to %s:%d: %s",
Command.c_str(), RemoteIp().c_str(), RemotePort(), strerror(errno));
Close();
return false;
}
uint64_t elapsed = starttime.Elapsed();
if (Expected != 0) { // XXX+ What if elapsed > TimeoutMs?
TimeoutMs -= elapsed;
return Expect(Expected, NULL, TimeoutMs);
}
return true;
}
bool cClientSocket::Expect(uint Expected, std::string *Result, uint TimeoutMs) {
char *endptr;
#define TIMEOUT_MS 1000
bool cClientSocket::Receive(const std::string &Command, uint *Code, std::string *Result, uint TimeoutMs) {
int bufcount;
bool res;
errno = 0;
if ((bufcount = ReadUntil(m_Buffer, sizeof(m_Buffer) - 1, "\012", TimeoutMs)) == -1) {
esyslog("Streamdev: Lost connection to %s:%d: %s", RemoteIp().c_str(), RemotePort(),
strerror(errno));
Close();
return false;
}
do
{
errno = 0;
bufcount = ReadUntil(m_Buffer, sizeof(m_Buffer) - 1, "\012", TimeoutMs < TIMEOUT_MS ? TimeoutMs : TIMEOUT_MS);
if (bufcount == -1) {
if (m_Abort)
return false;
if (errno != ETIMEDOUT || TimeoutMs <= TIMEOUT_MS) {
esyslog("ERROR: streamdev-client: Failed reading reply to '%s' from %s:%d: %s",
Command.c_str(), RemoteIp().c_str(), RemotePort(), strerror(errno));
Close();
return false;
}
TimeoutMs -= TIMEOUT_MS;
}
} while (bufcount == -1);
if (m_Buffer[bufcount - 1] == '\015')
--bufcount;
m_Buffer[bufcount] = '\0';
@ -89,9 +103,9 @@ bool cClientSocket::Expect(uint Expected, std::string *Result, uint TimeoutMs) {
if (Result != NULL)
*Result = m_Buffer;
res = strtoul(m_Buffer, &endptr, 10) == Expected;
return res;
if (Code != NULL)
*Code = strtoul(m_Buffer, NULL, 10);
return true;
}
bool cClientSocket::CheckConnection(void) {
@ -115,10 +129,10 @@ bool cClientSocket::CheckConnection(void) {
Close();
}
if (!Connect(StreamdevClientSetup.RemoteIp, StreamdevClientSetup.RemotePort)){
if (!Connect(StreamdevClientSetup.RemoteIp, StreamdevClientSetup.RemotePort, StreamdevClientSetup.Timeout * 1000)){
static time_t lastTime = 0;
if (time(NULL) - lastTime > MINLOGREPEAT) {
esyslog("ERROR: Streamdev: Couldn't connect to %s:%d: %s",
esyslog("ERROR: streamdev-client: Couldn't connect to %s:%d: %s",
(const char*)StreamdevClientSetup.RemoteIp,
StreamdevClientSetup.RemotePort, strerror(errno));
lastTime = time(NULL);
@ -126,18 +140,20 @@ bool cClientSocket::CheckConnection(void) {
return false;
}
if (!Expect(220)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Didn't receive greeting from %s:%d",
RemoteIp().c_str(), RemotePort());
uint code = 0;
std::string buffer;
if (!Receive("<connect>", &code, &buffer)) {
Close();
return false;
}
if (code != 220) {
esyslog("ERROR: streamdev-client: Didn't receive greeting from %s:%d: %s",
RemoteIp().c_str(), RemotePort(), buffer.c_str());
Close();
return false;
}
if (!Command("CAPS TSPIDS", 220)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't negotiate capabilities on %s:%d",
RemoteIp().c_str(), RemotePort());
Close();
return false;
}
@ -152,7 +168,7 @@ bool cClientSocket::CheckConnection(void) {
m_Prio = true;
}
isyslog("Streamdev: Connected to server %s:%d using capabilities TSPIDS%s%s",
isyslog("streamdev-client: Connected to server %s:%d using capabilities TSPIDS%s%s",
RemoteIp().c_str(), RemotePort(), Filters, Prio);
return true;
}
@ -164,14 +180,16 @@ bool cClientSocket::ProvidesChannel(const cChannel *Channel, int Priority) {
std::string command = (std::string)"PROV " + (const char*)itoa(Priority) + " "
+ (const char*)Channel->GetChannelID().ToString();
if (!Command(command))
if (!Send(command))
return false;
uint code;
std::string buffer;
if (!Expect(220, &buffer)) {
if (buffer.substr(0, 3) != "560" && errno == 0)
esyslog("ERROR: Streamdev: Couldn't check if %s:%d provides channel %s",
RemoteIp().c_str(), RemotePort(), Channel->Name());
if (!Receive(command, &code, &buffer))
return false;
if (code != 220 && code != 560) {
esyslog("streamdev-client: Unexpected reply to '%s' from %s:%d: %s",
command.c_str(), RemoteIp().c_str(), RemotePort(), buffer.c_str());
return false;
}
return true;
@ -186,7 +204,7 @@ bool cClientSocket::CreateDataConnection(eSocketId Id) {
DELETENULL(m_DataSockets[Id]);
if (!listen.Listen(LocalIp(), 0, 1)) {
esyslog("ERROR: Streamdev: Couldn't create data connection: %s",
esyslog("ERROR: streamdev-client: Couldn't create data connection: %s",
strerror(errno));
return false;
}
@ -201,13 +219,8 @@ bool cClientSocket::CreateDataConnection(eSocketId Id) {
CMD_LOCK;
if (!Command(command, 220)) {
Dprintf("error: %m\n");
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't establish data connection to %s:%d",
RemoteIp().c_str(), RemotePort());
if (!Command(command, 220))
return false;
}
/* The server SHOULD do the following:
* - get PORT command
@ -217,7 +230,7 @@ bool cClientSocket::CreateDataConnection(eSocketId Id) {
m_DataSockets[Id] = new cTBSocket;
if (!m_DataSockets[Id]->Accept(listen)) {
esyslog("ERROR: Streamdev: Couldn't establish data connection to %s:%d%s%s",
esyslog("ERROR: streamdev-client: Couldn't establish data connection to %s:%d%s%s",
RemoteIp().c_str(), RemotePort(), errno == 0 ? "" : ": ",
errno == 0 ? "" : strerror(errno));
DELETENULL(m_DataSockets[Id]);
@ -228,18 +241,12 @@ bool cClientSocket::CreateDataConnection(eSocketId Id) {
}
bool cClientSocket::CloseDataConnection(eSocketId Id) {
//if (!CheckConnection()) return false;
CMD_LOCK;
if(Id == siLive || Id == siLiveFilter)
if (m_DataSockets[Id] != NULL) {
std::string command = (std::string)"ABRT " + (const char*)itoa(Id);
if (!Command(command, 220)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't cleanly close data connection");
//return false;
}
Command(command, 220);
DELETENULL(m_DataSockets[Id]);
}
return true;
@ -252,12 +259,8 @@ bool cClientSocket::SetChannelDevice(const cChannel *Channel) {
std::string command = (std::string)"TUNE "
+ (const char*)Channel->GetChannelID().ToString();
if (!Command(command, 220, 10000)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't tune %s:%d to channel %s",
RemoteIp().c_str(), RemotePort(), Channel->Name());
if (!Command(command, 220))
return false;
}
m_LastSignalUpdate = 0;
return true;
@ -269,13 +272,7 @@ bool cClientSocket::SetPriority(int Priority) {
CMD_LOCK;
std::string command = (std::string)"PRIO " + (const char*)itoa(Priority);
if (!Command(command, 220)) {
if (errno == 0)
esyslog("Streamdev: Failed to update priority on %s:%d", RemoteIp().c_str(),
RemotePort());
return false;
}
return true;
return Command(command, 220);
}
bool cClientSocket::GetSignal(int *SignalStrength, int *SignalQuality) {
@ -284,8 +281,10 @@ bool cClientSocket::GetSignal(int *SignalStrength, int *SignalQuality) {
CMD_LOCK;
if (m_LastSignalUpdate != time(NULL)) {
uint code = 0;
std::string buffer;
if (!Command("SGNL") || !Expect(220, &buffer)
std::string command("SGNL");
if (!Send(command) || !Receive(command, &code, &buffer) || code != 220
|| sscanf(buffer.c_str(), "%*d %*d %d:%d", &m_LastSignalStrength, &m_LastSignalQuality) != 2) {
m_LastSignalStrength = -1;
m_LastSignalQuality = -1;
@ -305,13 +304,7 @@ bool cClientSocket::SetPid(int Pid, bool On) {
CMD_LOCK;
std::string command = (std::string)(On ? "ADDP " : "DELP ") + (const char*)itoa(Pid);
if (!Command(command, 220)) {
if (errno == 0)
esyslog("Streamdev: Pid %d not available from %s:%d", Pid, RemoteIp().c_str(),
RemotePort());
return false;
}
return true;
return Command(command, 220);
}
bool cClientSocket::SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On) {
@ -321,13 +314,7 @@ bool cClientSocket::SetFilter(ushort Pid, uchar Tid, uchar Mask, bool On) {
std::string command = (std::string)(On ? "ADDF " : "DELF ") + (const char*)itoa(Pid)
+ " " + (const char*)itoa(Tid) + " " + (const char*)itoa(Mask);
if (!Command(command, 220)) {
if (errno == 0)
esyslog("Streamdev: Filter %hu, %hhu, %hhu not available from %s:%d",
Pid, Tid, Mask, RemoteIp().c_str(), RemotePort());
return false;
}
return true;
return Command(command, 220);
}
bool cClientSocket::CloseDvr(void) {
@ -337,27 +324,20 @@ bool cClientSocket::CloseDvr(void) {
if (m_DataSockets[siLive] != NULL) {
std::string command = (std::string)"ABRT " + (const char*)itoa(siLive);
if (!Command(command, 220)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't cleanly close data connection");
if (!Command(command, 220))
return false;
}
DELETENULL(m_DataSockets[siLive]);
}
return true;
}
bool cClientSocket::Quit(void) {
bool res;
m_Abort = true;
if (!IsOpen()) return false;
if (!CheckConnection()) return false;
if (!(res = Command("QUIT", 221))) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't quit command connection to %s:%d",
RemoteIp().c_str(), RemotePort());
}
CMD_LOCK;
std::string command("QUIT");
bool res = Send(command) && Receive(command, NULL, NULL, QUIT_TIMEOUT_MS);
Close();
return res;
}
@ -367,10 +347,5 @@ bool cClientSocket::SuspendServer(void) {
CMD_LOCK;
if (!Command("SUSP", 220)) {
if (errno == 0)
esyslog("ERROR: Streamdev: Couldn't suspend server");
return false;
}
return true;
return Command("SUSP", 220);
}

View File

@ -8,6 +8,7 @@
#include <tools/socket.h>
#include "common.h"
#include "client/setup.h"
#include <string>
@ -21,22 +22,23 @@ private:
cMutex m_Mutex;
char m_Buffer[BUFSIZ + 1]; // various uses
bool m_Prio; // server supports command PRIO
bool m_Abort; // quit command pending
time_t m_LastSignalUpdate;
int m_LastSignalStrength;
int m_LastSignalQuality;
protected:
/* Send Command, and return true if the command results in Expected.
Returns false on failure, setting errno appropriately if it has been
a system failure. If Expected is zero, returns immediately after
sending the command. */
bool Command(const std::string &Command, uint Expected = 0, uint TimeoutMs = 1500);
Returns false on failure. */
bool Command(const std::string &Command, uint Expected);
/* Fetch results from an ongoing Command called with Expected == 0. Returns
true if the response has the code Expected, returning an internal buffer
in the array pointer pointed to by Result. Returns false on failure,
setting errno appropriately if it has been a system failure. */
bool Expect(uint Expected, std::string *Result = NULL, uint TimeoutMs = 1500);
/* Send the given command. Returns false on failure. */
bool Send(const std::string &Command);
/* Fetch results from an ongoing Command. The status code and the
buffer holding the server's response are stored in Code and Result
if non-NULL. Returns false on failure. */
bool Receive(const std::string &Command, uint *Code = NULL, std::string *Result = NULL, uint TimeoutMs = StreamdevClientSetup.Timeout * 1000);
public:
cClientSocket(void);