vdr-plugin-streamdev/tools/source.c
schmirl c8bf0474f9 Client did not reconnect properly to server when server app restarts.
When Read() on the command channel failed, the buffer size was not
trimmed. Read() was never called again as the buffer appeared to be full. Fixes #322 reported by alexw.
2007-07-20 06:54:03 +00:00

172 lines
3.2 KiB
C

#include "tools/source.h"
#include "tools/select.h"
#include "common.h"
#include <vdr/tools.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
cTBSource::cTBSource(void) {
m_BytesRead = 0;
m_BytesWritten = 0;
m_Filed = -1;
}
bool cTBSource::Open(int Filed, bool IsUnixFd) {
if (IsOpen())
Close();
m_Filed = Filed;
if (IsUnixFd && ::fcntl(m_Filed, F_SETFL, O_NONBLOCK) == -1)
return false;
return true;
}
cTBSource::~cTBSource() {
}
bool cTBSource::Close(void) {
if (!IsOpen()) {
errno = EBADF;
return false;
}
m_Filed = -1;
return true;
}
ssize_t cTBSource::Read(void *Buffer, size_t Length) {
ssize_t res;
while ((res = SysRead(Buffer, Length)) < 0 && errno == EINTR)
errno = 0;
if (res > 0) m_BytesRead += res;
return res;
}
ssize_t cTBSource::Write(const void *Buffer, size_t Length) {
ssize_t res;
while ((res = SysWrite(Buffer, Length)) < 0 && errno == EINTR)
errno = 0;
if (res > 0) m_BytesWritten += res;
return res;
}
bool cTBSource::TimedWrite(const void *Buffer, size_t Length, uint TimeoutMs) {
cTBSelect sel;
int ms, offs;
cTimeMs starttime;
ms = TimeoutMs;
offs = 0;
sel.Clear();
sel.Add(m_Filed, true);
while (Length > 0) {
int b;
if (sel.Select(ms) == -1)
return false;
if (sel.CanWrite(m_Filed)) {
if ((b = Write((char*)Buffer + offs, Length)) == -1)
return false;
offs += b;
Length -= b;
}
ms = TimeoutMs - starttime.Elapsed();
if (ms <= 0) {
errno = ETIMEDOUT;
return false;
}
}
return true;
}
bool cTBSource::SafeWrite(const void *Buffer, size_t Length) {
cTBSelect sel;
int offs;
offs = 0;
sel.Clear();
sel.Add(m_Filed, true);
while (Length > 0) {
int b;
if (sel.Select() == -1)
return false;
if (sel.CanWrite(m_Filed)) {
if ((b = Write((char*)Buffer + offs, Length)) == -1)
return false;
offs += b;
Length -= b;
}
}
return true;
}
ssize_t cTBSource::ReadUntil(void *Buffer, size_t Length, const char *Seq,
uint TimeoutMs) {
int ms;
size_t len;
cTBSelect sel;
if ((len = m_LineBuffer.find(Seq)) != (size_t)-1) {
if (len > Length) {
errno = ENOBUFS;
return -1;
}
memcpy(Buffer, m_LineBuffer.data(), len);
m_LineBuffer.erase(0, len + strlen(Seq));
Dprintf("ReadUntil: Served from Linebuffer: %d, |%.*s|\n", len, len - 1,
(char*)Buffer);
return len;
}
cTimeMs starttime;
ms = TimeoutMs;
sel.Clear();
sel.Add(m_Filed, false);
while (m_LineBuffer.size() < BUFSIZ) {
if (sel.Select(ms) == -1)
return -1;
if (sel.CanRead(m_Filed)) {
int b;
len = m_LineBuffer.size();
m_LineBuffer.resize(BUFSIZ);
if ((b = Read((char*)m_LineBuffer.data() + len, BUFSIZ - len)) == -1) {
m_LineBuffer.resize(len);
return -1;
}
m_LineBuffer.resize(len + b);
if ((len = m_LineBuffer.find(Seq)) != (size_t)-1) {
if (len > Length) {
errno = ENOBUFS;
return -1;
}
memcpy(Buffer, m_LineBuffer.data(), len);
m_LineBuffer.erase(0, len + strlen(Seq));
Dprintf("ReadUntil: Served from Linebuffer: %d, |%.*s|\n", len, len - 1,
(char*)Buffer);
return len;
}
}
ms = TimeoutMs - starttime.Elapsed();
if (ms <= 0) {
errno = ETIMEDOUT;
return -1;
}
}
errno = ENOBUFS;
return -1;
}