summaryrefslogtreecommitdiff
path: root/client/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'client/socket.c')
-rw-r--r--client/socket.c185
1 files changed, 80 insertions, 105 deletions
diff --git a/client/socket.c b/client/socket.c
index 2d5103b..727ffb6 100644
--- a/client/socket.c
+++ b/client/socket.c
@@ -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;
-
- if (!CheckConnection()) return false;
+ m_Abort = true;
+ if (!IsOpen()) 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);
}