From c1dc1453c5e47b46a43a81e006ab34005b20526d Mon Sep 17 00:00:00 2001 From: Frank Schmirler Date: Sat, 3 Mar 2012 23:04:11 +0100 Subject: [PATCH] Added timeout to Commit() --- HISTORY | 1 + tools/socket.c | 34 +++++++++++++++++++++++++++++----- tools/socket.h | 12 +++++++----- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/HISTORY b/HISTORY index 81d476b..54d215c 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,7 @@ VDR Plugin 'streamdev' Revision History --------------------------------------- +- 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 (suggested by Methodus) diff --git a/tools/socket.c b/tools/socket.c index 5dde45a..2fc2c42 100644 --- a/tools/socket.c +++ b/tools/socket.c @@ -1,4 +1,5 @@ #include "tools/socket.h" +#include "tools/select.h" #include #include @@ -27,7 +28,7 @@ cTBSocket::~cTBSocket() { if (IsOpen()) Close(); } -bool cTBSocket::Connect(const std::string &Host, unsigned int Port) { +bool cTBSocket::Connect(const std::string &Host, unsigned int Port, unsigned int TimeoutMs) { socklen_t len; int socket; @@ -45,13 +46,36 @@ bool cTBSocket::Connect(const std::string &Host, unsigned int Port) { return false; } + if (TimeoutMs > 0 && ::fcntl(socket, F_SETFL, O_NONBLOCK) == -1) { + ::close(socket); + return false; + } + m_RemoteAddr.sin_family = AF_INET; m_RemoteAddr.sin_port = htons(Port); m_RemoteAddr.sin_addr.s_addr = inet_addr(Host.c_str()); - if (::connect(socket, (struct sockaddr*)&m_RemoteAddr, - sizeof(m_RemoteAddr)) == -1) { - ::close(socket); - return false; + if (::connect(socket, (struct sockaddr*)&m_RemoteAddr, sizeof(m_RemoteAddr)) == -1) { + if (TimeoutMs > 0 && errno == EINPROGRESS) { + int so_error; + socklen_t len = sizeof(so_error); + cTBSelect select; + select.Add(socket); + if (select.Select(TimeoutMs) == -1 || + ::getsockopt(socket, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) { + ::close(socket); + return false; + } + if (so_error) { + errno = so_error; + ::close(socket); + return false; + } + + } + else { + ::close(socket); + return false; + } } if (m_Type == SOCK_STREAM) { diff --git a/tools/socket.h b/tools/socket.h index 3dc7a33..effdef8 100644 --- a/tools/socket.h +++ b/tools/socket.h @@ -32,11 +32,13 @@ public: Reimplemented for TCP/IPv4 sockets. */ virtual ssize_t SysWrite(const void *Buffer, size_t Length) const; - /* Connect() tries to connect an available local socket to the port given - by Port of the target host given by Host in numbers-and-dots notation - (i.e. "212.43.45.21"). Returns true if the connection attempt was - successful and false otherwise, setting errno appropriately. */ - virtual bool Connect(const std::string &Host, uint Port); + /* Connect() tries to connect an available local socket within TimeoutMs + milliseconds to the port given by Port of the target host given by + Host in numbers-and-dots notation (i.e. "212.43.45.21"). A TimeoutMs + of 0 will disable non-blocking IO for the connect call. Returns true + if the connection attempt was successful and false otherwise, setting + errno appropriately. */ + virtual bool Connect(const std::string &Host, uint Port, uint TimeoutMs = 0); /* Shutdown() shuts down one or both ends of a socket. If called with How set to SHUT_RD, further reads on this socket will be denied. If called