From 361d6426604505615ae94944a78a0126712b28cd Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Tue, 20 Feb 2018 13:28:04 +0100 Subject: [PATCH] Initiating the client side of a peer-to-peer SVDRP connection is now done with the new SVDRP command CONN instead of using the UDP port with the server's address --- HISTORY | 6 +- svdrp.c | 295 +++++++++++++++++++++++++++++++++++++------------------- svdrp.h | 3 +- 3 files changed, 200 insertions(+), 104 deletions(-) diff --git a/HISTORY b/HISTORY index fa2baf5d..fec7d18e 100644 --- a/HISTORY +++ b/HISTORY @@ -9162,7 +9162,7 @@ Video Disk Recorder Revision History a subdirectory. - SVDRP peering can now be limited to the default SVDRP host (see MANUAL for details). -2018-02-15: Version 2.3.9 +2018-02-20: Version 2.3.9 - Updated the Italian OSD texts (thanks to Diego Pierotto). - Updated the Finnish OSD texts (thanks to Rolf Ahrenberg). @@ -9279,3 +9279,7 @@ Video Disk Recorder Revision History improved logging and debug output. - Fixed case inconsistency with SVDRPDefaultHost in config.c. - Added a section about the '.sort' file to vdr.5. +- Initiating the client side of a peer-to-peer SVDRP connection is now done with the new + SVDRP command CONN instead of using the UDP port with the server's address. + This change requires that all VDRs that shall take part in a peer-to-peer network need + to be updated to this version. diff --git a/svdrp.c b/svdrp.c index 1b1d778e..b89bdf1d 100644 --- a/svdrp.c +++ b/svdrp.c @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 4.26 2018/02/15 14:21:37 kls Exp $ + * $Id: svdrp.c 4.27 2018/02/20 13:28:04 kls Exp $ */ #include "svdrp.h" @@ -106,7 +106,7 @@ public: void Close(void); int Port(void) const { return port; } int Socket(void) const { return sock; } - static bool SendDgram(const char *Dgram, int Port, const char *Address = NULL); + static bool SendDgram(const char *Dgram, int Port); int Accept(void); cString Discover(void); const cIpAddress *LastIpAddress(void) const { return &lastIpAddress; } @@ -210,13 +210,14 @@ bool cSocket::Connect(const char *Address) LOG_ERROR; return false; } + dbgsvdrp("> %s:%d server connection established\n", Address, port); isyslog("SVDRP %s > %s:%d server connection established", Setup.SVDRPHostName, Address, port); return true; } return false; } -bool cSocket::SendDgram(const char *Dgram, int Port, const char *Address) +bool cSocket::SendDgram(const char *Dgram, int Port) { // Create a socket: int Socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); @@ -224,20 +225,18 @@ bool cSocket::SendDgram(const char *Dgram, int Port, const char *Address) LOG_ERROR; return false; } - if (!Address) { - // Enable broadcast: - int One = 1; - if (setsockopt(Socket, SOL_SOCKET, SO_BROADCAST, &One, sizeof(One)) < 0) { - LOG_ERROR; - close(Socket); - return false; - } + // Enable broadcast: + int One = 1; + if (setsockopt(Socket, SOL_SOCKET, SO_BROADCAST, &One, sizeof(One)) < 0) { + LOG_ERROR; + close(Socket); + return false; } // Configure port and ip: sockaddr_in Addr; memset(&Addr, 0, sizeof(Addr)); Addr.sin_family = AF_INET; - Addr.sin_addr.s_addr = Address ? inet_addr(Address) : htonl(INADDR_BROADCAST); + Addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); Addr.sin_port = htons(Port); // Send datagram: dbgsvdrp("> %s:%d %s\n", inet_ntoa(Addr.sin_addr), Port, Dgram); @@ -310,23 +309,25 @@ cString cSocket::Discover(void) class cSVDRPClient { private: - cIpAddress ipAddress; + cIpAddress serverIpAddress; cSocket socket; cString serverName; int timeout; cTimeMs pingTime; cFile file; int fetchFlags; + bool connected; void Close(void); public: cSVDRPClient(const char *Address, int Port, const char *ServerName, int Timeout); ~cSVDRPClient(); const char *ServerName(void) const { return serverName; } - const char *Connection(void) const { return ipAddress.Connection(); } + const char *Connection(void) const { return serverIpAddress.Connection(); } bool HasAddress(const char *Address, int Port) const; bool Send(const char *Command); bool Process(cStringList *Response = NULL); bool Execute(const char *Command, cStringList *Response = NULL); + bool Connected(void) const { return connected; } void SetFetchFlag(eSvdrpFetchFlags Flag); bool HasFetchFlag(eSvdrpFetchFlags Flag); }; @@ -334,27 +335,28 @@ public: static cPoller SVDRPClientPoller; cSVDRPClient::cSVDRPClient(const char *Address, int Port, const char *ServerName, int Timeout) -:ipAddress(Address, Port) +:serverIpAddress(Address, Port) ,socket(Port, true) { serverName = ServerName; timeout = Timeout * 1000 * 9 / 10; // ping after 90% of timeout pingTime.Set(timeout); - fetchFlags = sffTimers; + fetchFlags = sffNone; + connected = false; if (socket.Connect(Address)) { if (file.Open(socket.Socket())) { SVDRPClientPoller.Add(file, false); - dsyslog("SVDRP %s > %s client created for '%s'", Setup.SVDRPHostName, ipAddress.Connection(), *serverName); + dsyslog("SVDRP %s > %s client created for '%s'", Setup.SVDRPHostName, serverIpAddress.Connection(), *serverName); return; } } - esyslog("SVDRP %s > %s ERROR: failed to create client for '%s'", Setup.SVDRPHostName, ipAddress.Connection(), *serverName); + esyslog("SVDRP %s > %s ERROR: failed to create client for '%s'", Setup.SVDRPHostName, serverIpAddress.Connection(), *serverName); } cSVDRPClient::~cSVDRPClient() { Close(); - dsyslog("SVDRP %s > %s client destroyed for '%s'", Setup.SVDRPHostName, ipAddress.Connection(), *serverName); + dsyslog("SVDRP %s > %s client destroyed for '%s'", Setup.SVDRPHostName, serverIpAddress.Connection(), *serverName); } void cSVDRPClient::Close(void) @@ -371,13 +373,13 @@ void cSVDRPClient::Close(void) bool cSVDRPClient::HasAddress(const char *Address, int Port) const { - return strcmp(ipAddress.Address(), Address) == 0 && ipAddress.Port() == Port; + return strcmp(serverIpAddress.Address(), Address) == 0 && serverIpAddress.Port() == Port; } bool cSVDRPClient::Send(const char *Command) { pingTime.Set(timeout); - dbgsvdrp("> %s: %s\n", *serverName, Command); + dbgsvdrp("> C %s: %s\n", *serverName, Command); if (safe_write(file, Command, strlen(Command) + 1) < 0) { LOG_ERROR; return false; @@ -403,7 +405,7 @@ bool cSVDRPClient::Process(cStringList *Response) input[--numChars] = 0; // make sure the string is terminated: input[numChars] = 0; - dbgsvdrp("< %s: %s\n", *serverName, input); + dbgsvdrp("< C %s: %s\n", *serverName, input); if (Response) Response->Append(strdup(input)); else { @@ -414,12 +416,16 @@ bool cSVDRPClient::Process(cStringList *Response) *t = 0; if (strcmp(n, serverName) != 0) { serverName = n; - dsyslog("SVDRP %s < %s remote server name is '%s'", Setup.SVDRPHostName, ipAddress.Connection(), *serverName); + dsyslog("SVDRP %s < %s remote server name is '%s'", Setup.SVDRPHostName, serverIpAddress.Connection(), *serverName); } + Execute(cString::sprintf("CONN name:%s port:%d vdrversion:%d apiversion:%d timeout:%d", Setup.SVDRPHostName, SVDRPTcpPort, VDRVERSNUM, APIVERSNUM, Setup.SVDRPTimeout)); + SetFetchFlag(sffTimers); + connected = true; } } break; - case 221: dsyslog("SVDRP %s < %s remote server closed connection to '%s'", Setup.SVDRPHostName, ipAddress.Connection(), *serverName); + case 221: dsyslog("SVDRP %s < %s remote server closed connection to '%s'", Setup.SVDRPHostName, serverIpAddress.Connection(), *serverName); + connected = false; Close(); break; } @@ -430,7 +436,7 @@ bool cSVDRPClient::Process(cStringList *Response) } else { if (numChars >= int(sizeof(input))) { - esyslog("SVDRP %s < %s ERROR: out of memory", Setup.SVDRPHostName, ipAddress.Connection()); + esyslog("SVDRP %s < %s ERROR: out of memory", Setup.SVDRPHostName, serverIpAddress.Connection()); Close(); break; } @@ -440,13 +446,13 @@ bool cSVDRPClient::Process(cStringList *Response) Timeout.Set(SVDRPResonseTimeout); } else if (r <= 0) { - isyslog("SVDRP %s < %s lost connection to remote server '%s'", Setup.SVDRPHostName, ipAddress.Connection(), *serverName); + isyslog("SVDRP %s < %s lost connection to remote server '%s'", Setup.SVDRPHostName, serverIpAddress.Connection(), *serverName); Close(); return false; } } else if (Timeout.TimedOut()) { - esyslog("SVDRP %s < %s timeout while waiting for response from '%s'", Setup.SVDRPHostName, ipAddress.Connection(), *serverName); + esyslog("SVDRP %s < %s timeout while waiting for response from '%s'", Setup.SVDRPHostName, serverIpAddress.Connection(), *serverName); return false; } else if (!Response && numChars == 0) @@ -477,6 +483,70 @@ bool cSVDRPClient::HasFetchFlag(eSvdrpFetchFlags Flag) return Result; } +// --- cSVDRPServerParams ---------------------------------------------------- + +class cSVDRPServerParams { +private: + cString name; + int port; + cString vdrversion; + cString apiversion; + int timeout; + cString host; + cString error; +public: + cSVDRPServerParams(const char *Params); + const char *Name(void) const { return name; } + const int Port(void) const { return port; } + const char *VdrVersion(void) const { return vdrversion; } + const char *ApiVersion(void) const { return apiversion; } + const int Timeout(void) const { return timeout; } + const char *Host(void) const { return host; } + bool Ok(void) const { return !*error; } + const char *Error(void) const { return error; } + }; + +cSVDRPServerParams::cSVDRPServerParams(const char *Params) +{ + if (Params && *Params) { + name = strgetval(Params, "name", ':'); + if (*name) { + cString p = strgetval(Params, "port", ':'); + if (*p) { + port = atoi(p); + vdrversion = strgetval(Params, "vdrversion", ':'); + if (*vdrversion) { + apiversion = strgetval(Params, "apiversion", ':'); + if (*apiversion) { + cString t = strgetval(Params, "timeout", ':'); + if (*t) { + timeout = atoi(t); + if (timeout > 10) { // don't let it get too small + host = strgetval(Params, "host", ':'); + // no error if missing - this parameter is optional! + } + else + error = "invalid timeout"; + } + else + error = "missing server timeout"; + } + else + error = "missing server apiversion"; + } + else + error = "missing server vdrversion"; + } + else + error = "missing server port"; + } + else + error = "missing server name"; + } + else + error = "missing server parameters"; +} + // --- cSVDRPClientHandler --------------------------------------------------- class cSVDRPClientHandler : public cThread { @@ -487,16 +557,17 @@ private: cVector clientConnections; void HandleClientConnection(void); void ProcessConnections(void); - cSVDRPClient *GetClientForServer(const char *ServerName); protected: virtual void Action(void); public: cSVDRPClientHandler(int TcpPort, int UdpPort); virtual ~cSVDRPClientHandler(); - void SendDiscover(const char *Address = NULL); + void SendDiscover(void); + void AddClient(cSVDRPServerParams &ServerParams, const char *IpAddress); bool Execute(const char *ServerName, const char *Command, cStringList *Response = NULL); bool GetServerNames(cStringList *ServerNames, eSvdrpFetchFlags FetchFlags = sffNone); bool TriggerFetchingTimers(const char *ServerName); + cSVDRPClient *GetClientForServer(const char *ServerName); }; static cSVDRPClientHandler *SVDRPClientHandler = NULL; @@ -517,6 +588,7 @@ cSVDRPClientHandler::~cSVDRPClientHandler() cSVDRPClient *cSVDRPClientHandler::GetClientForServer(const char *ServerName) { + cMutexLock MutexLock(&mutex); for (int i = 0; i < clientConnections.Size(); i++) { if (strcmp(clientConnections[i]->ServerName(), ServerName) == 0) return clientConnections[i]; @@ -524,11 +596,11 @@ cSVDRPClient *cSVDRPClientHandler::GetClientForServer(const char *ServerName) return NULL; } -void cSVDRPClientHandler::SendDiscover(const char *Address) +void cSVDRPClientHandler::SendDiscover(void) { cMutexLock MutexLock(&mutex); cString Dgram = cString::sprintf("SVDRP:discover name:%s port:%d vdrversion:%d apiversion:%d timeout:%d%s", Setup.SVDRPHostName, tcpPort, VDRVERSNUM, APIVERSNUM, Setup.SVDRPTimeout, (Setup.SVDRPPeering == spmOnly && *Setup.SVDRPDefaultHost) ? *cString::sprintf(" host:%s", Setup.SVDRPDefaultHost) : ""); - udpSocket.SendDgram(Dgram, udpSocket.Port(), Address); + udpSocket.SendDgram(Dgram, udpSocket.Port()); } void cSVDRPClientHandler::ProcessConnections(void) @@ -543,45 +615,30 @@ void cSVDRPClientHandler::ProcessConnections(void) } } +void cSVDRPClientHandler::AddClient(cSVDRPServerParams &ServerParams, const char *IpAddress) +{ + for (int i = 0; i < clientConnections.Size(); i++) { + if (clientConnections[i]->HasAddress(IpAddress, ServerParams.Port())) { + dsyslog("SVDRP %s < %s connection to '%s' already exists", Setup.SVDRPHostName, clientConnections[i]->Connection(), clientConnections[i]->ServerName()); + return; + } + } + if (Setup.SVDRPPeering == spmOnly && strcmp(ServerParams.Name(), Setup.SVDRPDefaultHost) != 0) + return; // we only want to peer with the default host, but this isn't the default host + if (ServerParams.Host() && strcmp(ServerParams.Host(), Setup.SVDRPHostName) != 0) + return; // the remote VDR requests a specific host, but it's not us + clientConnections.Append(new cSVDRPClient(IpAddress, ServerParams.Port(), ServerParams.Name(), ServerParams.Timeout())); +} + void cSVDRPClientHandler::HandleClientConnection(void) { cString NewDiscover = udpSocket.Discover(); if (*NewDiscover) { - cString p = strgetval(NewDiscover, "port", ':'); - if (*p) { - int Port = atoi(p); - for (int i = 0; i < clientConnections.Size(); i++) { - if (clientConnections[i]->HasAddress(udpSocket.LastIpAddress()->Address(), Port)) { - dsyslog("SVDRP %s < %s connection to '%s' confirmed", Setup.SVDRPHostName, clientConnections[i]->Connection(), clientConnections[i]->ServerName()); - return; - } - } - cString ServerName = strgetval(NewDiscover, "name", ':'); - if (*ServerName) { - if (Setup.SVDRPPeering == spmOnly && strcmp(ServerName, Setup.SVDRPDefaultHost) != 0) - return; // we only want to peer with the default host, but this isn't the default host - cString HostName = strgetval(NewDiscover, "host", ':'); - if (*HostName && strcmp(HostName, Setup.SVDRPHostName) != 0) - return; // the remote VDR requests a specific host, but it's not us - cString t = strgetval(NewDiscover, "timeout", ':'); - if (*t) { - int Timeout = atoi(t); - if (Timeout > 10) { // don't let it get too small - const char *Address = udpSocket.LastIpAddress()->Address(); - clientConnections.Append(new cSVDRPClient(Address, Port, ServerName, Timeout)); - SendDiscover(Address); - } - else - esyslog("SVDRP %s < %s ERROR: invalid timeout (%d)", Setup.SVDRPHostName, udpSocket.LastIpAddress()->Connection(), Timeout); - } - else - esyslog("SVDRP %s < %s ERROR: missing timeout", Setup.SVDRPHostName, udpSocket.LastIpAddress()->Connection()); - } - else - esyslog("SVDRP %s < %s ERROR: missing server name", Setup.SVDRPHostName, udpSocket.LastIpAddress()->Connection()); - } + cSVDRPServerParams ServerParams(NewDiscover); + if (ServerParams.Ok()) + AddClient(ServerParams, udpSocket.LastIpAddress()->Address()); else - esyslog("SVDRP %s < %s ERROR: missing port number", Setup.SVDRPHostName, udpSocket.LastIpAddress()->Connection()); + esyslog("SVDRP %s < %s ERROR: %s", Setup.SVDRPHostName, udpSocket.LastIpAddress()->Connection(), ServerParams.Error()); } } @@ -615,8 +672,10 @@ bool cSVDRPClientHandler::GetServerNames(cStringList *ServerNames, eSvdrpFetchFl ServerNames->Clear(); for (int i = 0; i < clientConnections.Size(); i++) { cSVDRPClient *Client = clientConnections[i]; - if (FetchFlag == sffNone || Client->HasFetchFlag(FetchFlag)) - ServerNames->Append(strdup(Client->ServerName())); + if (Client->Connected()) { + if (FetchFlag == sffNone || Client->HasFetchFlag(FetchFlag)) + ServerNames->Append(strdup(Client->ServerName())); + } } return ServerNames->Size() > 0; } @@ -708,6 +767,10 @@ const char *HelpPages[] = { " After a CLRE command, no further EPG processing is done for 10\n" " seconds, so that data sent with subsequent PUTE commands doesn't\n" " interfere with data from the broadcasters.", + "CONN name: port: vdrversion: apiversion: timeout:\n" + " Used by peer-to-peer connections between VDRs to tell the other VDR\n" + " to establish a connection to this VDR. The name is the SVDRP host name\n" + " of this VDR, which may differ from its DNS name.", "DELC \n" " Delete channel.", "DELR \n" @@ -929,7 +992,8 @@ static cString grabImageDir; class cSVDRPServer { private: int socket; - cString connection; + cIpAddress clientIpAddress; + cString clientName; cFile file; cPUTEhandler *PUTEhandler; int numChars; @@ -942,6 +1006,7 @@ private: void PrintHelpTopics(const char **hp); void CmdCHAN(const char *Option); void CmdCLRE(const char *Option); + void CmdCONN(const char *Option); void CmdDELC(const char *Option); void CmdDELR(const char *Option); void CmdDELT(const char *Option); @@ -976,18 +1041,20 @@ private: void CmdVOLU(const char *Option); void Execute(char *Cmd); public: - cSVDRPServer(int Socket, const char *Connection); + cSVDRPServer(int Socket, const cIpAddress *ClientIpAddress); ~cSVDRPServer(); + const char *ClientName(void) const { return clientName; } bool HasConnection(void) { return file.IsOpen(); } bool Process(void); }; static cPoller SVDRPServerPoller; -cSVDRPServer::cSVDRPServer(int Socket, const char *Connection) +cSVDRPServer::cSVDRPServer(int Socket, const cIpAddress *ClientIpAddress) { socket = Socket; - connection = Connection; + clientIpAddress = *ClientIpAddress; + clientName = clientIpAddress.Connection(); // will be set to actual name by a CONN command PUTEhandler = NULL; numChars = 0; length = BUFSIZ; @@ -998,14 +1065,14 @@ cSVDRPServer::cSVDRPServer(int Socket, const char *Connection) Reply(220, "%s SVDRP VideoDiskRecorder %s; %s; %s", Setup.SVDRPHostName, VDRVERSION, *TimeToString(now), cCharSetConv::SystemCharacterTable() ? cCharSetConv::SystemCharacterTable() : "UTF-8"); SVDRPServerPoller.Add(file, false); } - dsyslog("SVDRP %s < %s server created", Setup.SVDRPHostName, *connection); + dsyslog("SVDRP %s > %s server created", Setup.SVDRPHostName, *clientName); } cSVDRPServer::~cSVDRPServer() { Close(true); free(cmdLine); - dsyslog("SVDRP %s < %s server destroyed", Setup.SVDRPHostName, *connection); + dsyslog("SVDRP %s < %s server destroyed", Setup.SVDRPHostName, *clientName); } void cSVDRPServer::Close(bool SendReply, bool Timeout) @@ -1014,7 +1081,7 @@ void cSVDRPServer::Close(bool SendReply, bool Timeout) if (SendReply) { Reply(221, "%s closing connection%s", Setup.SVDRPHostName, Timeout ? " (timeout)" : ""); } - isyslog("SVDRP %s < %s connection closed", Setup.SVDRPHostName, *connection); + isyslog("SVDRP %s < %s connection closed", Setup.SVDRPHostName, *clientName); SVDRPServerPoller.Del(file, false); file.Close(); DELETENULL(PUTEhandler); @@ -1024,7 +1091,7 @@ void cSVDRPServer::Close(bool SendReply, bool Timeout) bool cSVDRPServer::Send(const char *s) { - dbgsvdrp("> %s: %s", *connection, s); // terminating newline is already in the string! + dbgsvdrp("> S %s: %s", *clientName, s); // terminating newline is already in the string! if (safe_write(file, s, strlen(s)) < 0) { LOG_ERROR; Close(); @@ -1056,14 +1123,14 @@ void cSVDRPServer::Reply(int Code, const char *fmt, ...) } else { Reply(451, "Bad format - looks like a programming error!"); - esyslog("SVDRP %s < %s bad format!", Setup.SVDRPHostName, *connection); + esyslog("SVDRP %s < %s bad format!", Setup.SVDRPHostName, *clientName); } va_end(ap); free(buffer); } else { Reply(451, "Zero return code - looks like a programming error!"); - esyslog("SVDRP %s < %s zero return code!", Setup.SVDRPHostName, *connection); + esyslog("SVDRP %s < %s zero return code!", Setup.SVDRPHostName, *clientName); } } } @@ -1219,6 +1286,27 @@ void cSVDRPServer::CmdCLRE(const char *Option) } } +void cSVDRPServer::CmdCONN(const char *Option) +{ + if (*Option) { + if (SVDRPClientHandler) { + cSVDRPServerParams ServerParams(Option); + if (ServerParams.Ok()) { + clientName = ServerParams.Name(); + Reply(250, "OK"); // must finish this transaction before creating the new client + if (!SVDRPClientHandler->GetClientForServer(ServerParams.Name())) + SVDRPClientHandler->AddClient(ServerParams, clientIpAddress.Address()); + } + else + Reply(501, "Error in server parameters: %s", ServerParams.Error()); + } + else + Reply(451, "No SVDRP client handler"); + } + else + Reply(501, "Missing server parameters"); +} + void cSVDRPServer::CmdDELC(const char *Option) { if (*Option) { @@ -1248,7 +1336,7 @@ void cSVDRPServer::CmdDELC(const char *Option) Channels->ReNumber(); Channels->SetModifiedByUser(); Channels->SetModified(); - isyslog("SVDRP %s < %s deleted channel %s", Setup.SVDRPHostName, *connection, Option); + isyslog("SVDRP %s < %s deleted channel %s", Setup.SVDRPHostName, *clientName, Option); if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) Channels->SwitchTo(CurrentChannel->Number()); @@ -1296,7 +1384,7 @@ void cSVDRPServer::CmdDELR(const char *Option) if (Recording->Delete()) { Recordings->DelByName(Recording->FileName()); Recordings->SetModified(); - isyslog("SVDRP %s < %s deleted recording %s", Setup.SVDRPHostName, *connection, Option); + isyslog("SVDRP %s < %s deleted recording %s", Setup.SVDRPHostName, *clientName, Option); Reply(250, "Recording \"%s\" deleted", Option); } else @@ -1326,7 +1414,7 @@ void cSVDRPServer::CmdDELT(const char *Option) } Timers->Del(Timer); Timers->SetModified(); - isyslog("SVDRP %s < %s deleted timer %s", Setup.SVDRPHostName, *connection, *Timer->ToDescr()); + isyslog("SVDRP %s < %s deleted timer %s", Setup.SVDRPHostName, *clientName, *Timer->ToDescr()); Reply(250, "Timer \"%s\" deleted", Option); } else @@ -1472,7 +1560,7 @@ void cSVDRPServer::CmdGRAB(const char *Option) int fd = open(FileName, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC, DEFFILEMODE); if (fd >= 0) { if (safe_write(fd, Image, ImageSize) == ImageSize) { - dsyslog("SVDRP %s < %s grabbed image to %s", Setup.SVDRPHostName, *connection, FileName); + dsyslog("SVDRP %s < %s grabbed image to %s", Setup.SVDRPHostName, *clientName, FileName); Reply(250, "Grabbed image %s", Option); } else { @@ -1826,7 +1914,7 @@ void cSVDRPServer::CmdLSTT(const char *Option) void cSVDRPServer::CmdMESG(const char *Option) { if (*Option) { - isyslog("SVDRP %s < %s message '%s'", Setup.SVDRPHostName, *connection, Option); + isyslog("SVDRP %s < %s message '%s'", Setup.SVDRPHostName, *clientName, Option); Skins.QueueMessage(mtInfo, Option); Reply(250, "Message queued"); } @@ -1851,7 +1939,7 @@ void cSVDRPServer::CmdMODC(const char *Option) Channels->ReNumber(); Channels->SetModifiedByUser(); Channels->SetModified(); - isyslog("SVDRP %s < %s modifed channel %d %s", Setup.SVDRPHostName, *connection, Channel->Number(), *Channel->ToText()); + isyslog("SVDRP %s < %s modifed channel %d %s", Setup.SVDRPHostName, *clientName, Channel->Number(), *Channel->ToText()); Reply(250, "%d %s", Channel->Number(), *Channel->ToText()); } else @@ -1891,7 +1979,7 @@ void cSVDRPServer::CmdMODT(const char *Option) } *Timer = t; Timers->SetModified(); - isyslog("SVDRP %s < %s modified timer %s (%s)", Setup.SVDRPHostName, *connection, *Timer->ToDescr(), Timer->HasFlags(tfActive) ? "active" : "inactive"); + isyslog("SVDRP %s < %s modified timer %s (%s)", Setup.SVDRPHostName, *clientName, *Timer->ToDescr(), Timer->HasFlags(tfActive) ? "active" : "inactive"); Reply(250, "%d %s", Timer->Id(), *Timer->ToText(true)); } else @@ -1935,7 +2023,7 @@ void cSVDRPServer::CmdMOVC(const char *Option) else cDevice::SetCurrentChannel(CurrentChannel->Number()); } - isyslog("SVDRP %s < %s moved channel %d to %d", Setup.SVDRPHostName, *connection, FromNumber, ToNumber); + isyslog("SVDRP %s < %s moved channel %d to %d", Setup.SVDRPHostName, *clientName, FromNumber, ToNumber); Reply(250,"Channel \"%d\" moved to \"%d\"", From, To); } else @@ -2015,7 +2103,7 @@ void cSVDRPServer::CmdNEWC(const char *Option) Channels->ReNumber(); Channels->SetModifiedByUser(); Channels->SetModified(); - isyslog("SVDRP %s < %s new channel %d %s", Setup.SVDRPHostName, *connection, channel->Number(), *channel->ToText()); + isyslog("SVDRP %s < %s new channel %d %s", Setup.SVDRPHostName, *clientName, channel->Number(), *channel->ToText()); Reply(250, "%d %s", channel->Number(), *channel->ToText()); } else @@ -2036,7 +2124,7 @@ void cSVDRPServer::CmdNEWT(const char *Option) LOCK_TIMERS_WRITE; Timer->ClrFlags(tfRecording); Timers->Add(Timer); - isyslog("SVDRP %s < %s added timer %s", Setup.SVDRPHostName, *connection, *Timer->ToDescr()); + isyslog("SVDRP %s < %s added timer %s", Setup.SVDRPHostName, *clientName, *Timer->ToDescr()); Reply(250, "%d %s", Timer->Id(), *Timer->ToText(true)); return; } @@ -2325,11 +2413,11 @@ void cSVDRPServer::CmdUPDT(const char *Option) t->Parse(Option); delete Timer; Timer = t; - isyslog("SVDRP %s < %s updated timer %s", Setup.SVDRPHostName, *connection, *Timer->ToDescr()); + isyslog("SVDRP %s < %s updated timer %s", Setup.SVDRPHostName, *clientName, *Timer->ToDescr()); } else { Timers->Add(Timer); - isyslog("SVDRP %s < %s added timer %s", Setup.SVDRPHostName, *connection, *Timer->ToDescr()); + isyslog("SVDRP %s < %s added timer %s", Setup.SVDRPHostName, *clientName, *Timer->ToDescr()); } Reply(250, "%d %s", Timer->Id(), *Timer->ToText(true)); return; @@ -2395,6 +2483,7 @@ void cSVDRPServer::Execute(char *Cmd) s = skipspace(s); if (CMD("CHAN")) CmdCHAN(s); else if (CMD("CLRE")) CmdCLRE(s); + else if (CMD("CONN")) CmdCONN(s); else if (CMD("DELC")) CmdDELC(s); else if (CMD("DELR")) CmdDELR(s); else if (CMD("DELT")) CmdDELT(s); @@ -2445,7 +2534,7 @@ bool cSVDRPServer::Process(void) // make sure the string is terminated: cmdLine[numChars] = 0; // showtime! - dbgsvdrp("< %s: %s\n", *connection, cmdLine); + dbgsvdrp("< S %s: %s\n", *clientName, cmdLine); Execute(cmdLine); numChars = 0; if (length > BUFSIZ) { @@ -2474,7 +2563,7 @@ bool cSVDRPServer::Process(void) cmdLine = NewBuffer; } else { - esyslog("SVDRP %s < %s ERROR: out of memory", Setup.SVDRPHostName, *connection); + esyslog("SVDRP %s < %s ERROR: out of memory", Setup.SVDRPHostName, *clientName); Close(); break; } @@ -2485,12 +2574,12 @@ bool cSVDRPServer::Process(void) lastActivity = time(NULL); } else if (r <= 0) { - isyslog("SVDRP %s < %s lost connection to client", Setup.SVDRPHostName, *connection); + isyslog("SVDRP %s < %s lost connection to client", Setup.SVDRPHostName, *clientName); Close(); } } if (Setup.SVDRPTimeout && time(NULL) - lastActivity > Setup.SVDRPTimeout) { - isyslog("SVDRP %s < %s timeout on connection", Setup.SVDRPHostName, *connection); + isyslog("SVDRP %s < %s timeout on connection", Setup.SVDRPHostName, *clientName); Close(true, true); } } @@ -2524,6 +2613,7 @@ public: cSVDRPServerHandler(int TcpPort); virtual ~cSVDRPServerHandler(); void WaitUntilReady(void); + cSVDRPServer *GetServerForClient(const char *ClientName); }; static cSVDRPServerHandler *SVDRPServerHandler = NULL; @@ -2565,7 +2655,7 @@ void cSVDRPServerHandler::HandleServerConnection(void) { int NewSocket = tcpSocket.Accept(); if (NewSocket >= 0) - serverConnections.Append(new cSVDRPServer(NewSocket, tcpSocket.LastIpAddress()->Connection())); + serverConnections.Append(new cSVDRPServer(NewSocket, tcpSocket.LastIpAddress())); } void cSVDRPServerHandler::Action(void) @@ -2584,6 +2674,16 @@ void cSVDRPServerHandler::Action(void) } } +cSVDRPServer *cSVDRPServerHandler::GetServerForClient(const char *ClientName) +{ + cMutexLock MutexLock(&mutex); + for (int i = 0; i < serverConnections.Size(); i++) { + if (serverConnections[i]->ClientName() && strcmp(serverConnections[i]->ClientName(), ClientName) == 0) + return serverConnections[i]; + } + return NULL; +} + // --- SVDRP Handler --------------------------------------------------------- static cMutex SVDRPHandlerMutex; @@ -2621,13 +2721,6 @@ void StopSVDRPClientHandler(void) SVDRPClientHandler = NULL; } -void SendSVDRPDiscover(const char *Address) -{ - cMutexLock MutexLock(&SVDRPHandlerMutex); - if (SVDRPClientHandler) - SVDRPClientHandler->SendDiscover(Address); -} - bool GetSVDRPServerNames(cStringList *ServerNames, eSvdrpFetchFlags FetchFlag) { cMutexLock MutexLock(&SVDRPHandlerMutex); diff --git a/svdrp.h b/svdrp.h index e0d3616e..f1ae922a 100644 --- a/svdrp.h +++ b/svdrp.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: svdrp.h 4.7 2017/06/30 09:49:39 kls Exp $ + * $Id: svdrp.h 4.8 2018/02/19 12:36:35 kls Exp $ */ #ifndef __SVDRP_H @@ -29,7 +29,6 @@ void StartSVDRPServerHandler(void); void StartSVDRPClientHandler(void); void StopSVDRPServerHandler(void); void StopSVDRPClientHandler(void); -void SendSVDRPDiscover(const char *Address = NULL); bool GetSVDRPServerNames(cStringList *ServerNames, eSvdrpFetchFlags FetchFlag = sffNone); ///< Gets a list of all available VDRs this VDR is connected to via SVDRP, ///< and stores it in the given ServerNames list. The list is cleared