MythTV  master
libs/libmythprotoserver/sockethandler/filetransfer.cpp
Go to the documentation of this file.
1 #include <QFileInfo>
2 #include <QMutexLocker>
3 #include <utility>
4 
5 #include "filetransfer.h"
6 #include "ringbuffer.h"
7 #include "programinfo.h"
8 #include "mythsocket.h"
9 #include "mythlogging.h"
10 
12  MythSocketManager *parent,
13  bool usereadahead, int timeout_ms) :
14  SocketHandler(remote, parent, ""),
15  m_rbuffer(RingBuffer::Create(filename, false, usereadahead, timeout_ms))
16 {
19 }
20 
22  MythSocketManager *parent, bool write) :
23  SocketHandler(remote, parent, ""),
24  m_rbuffer(RingBuffer::Create(filename, write)),
25  m_writemode(write)
26 {
29 
30  if (write)
31  {
32  remote->SetReadyReadCallbackEnabled(false);
34  }
35 }
36 
38 {
39  Stop();
40 
41  if (m_rbuffer)
42  {
43  delete m_rbuffer;
44  m_rbuffer = nullptr;
45  }
46 
47  if (m_pginfo)
48  {
50  delete m_pginfo;
51  }
52 }
53 
55 {
56  return m_rbuffer && m_rbuffer->IsOpen();
57 }
58 
59 bool FileTransfer::ReOpen(QString newFilename)
60 {
61  if (!m_writemode)
62  return false;
63 
64  if (m_rbuffer)
65  return m_rbuffer->ReOpen(std::move(newFilename));
66 
67  return false;
68 }
69 
71 {
72  if (m_readthreadlive)
73  {
74  m_readthreadlive = false;
75  LOG(VB_FILE, LOG_INFO, "calling StopReads()");
77  QMutexLocker locker(&m_lock);
78  m_readsLocked = true;
79  }
80 
81  if (m_writemode)
83 
84  if (m_pginfo)
86 }
87 
89 {
90  LOG(VB_FILE, LOG_INFO, "calling StopReads()");
92  QMutexLocker locker(&m_lock);
93  m_readsLocked = true;
94 
95  if (m_pginfo)
97 }
98 
100 {
101  LOG(VB_FILE, LOG_INFO, "calling StartReads()");
103  {
104  QMutexLocker locker(&m_lock);
105  m_readsLocked = false;
106  }
107  m_readsUnlockedCond.wakeAll();
108 
109  if (m_pginfo)
111 }
112 
114 {
115  if (!m_readthreadlive || !m_rbuffer)
116  return -1;
117 
118  int tot = 0;
119  int ret = 0;
120 
121  QMutexLocker locker(&m_lock);
122  while (m_readsLocked)
123  m_readsUnlockedCond.wait(&m_lock, 100 /*ms*/);
124 
125  m_requestBuffer.resize(max((size_t)max(size,0) + 128, m_requestBuffer.size()));
126  char *buf = &m_requestBuffer[0];
127  while (tot < size && !m_rbuffer->GetStopReads() && m_readthreadlive)
128  {
129  int request = size - tot;
130 
131  ret = m_rbuffer->Read(buf, request);
132 
133  if (m_rbuffer->GetStopReads() || ret <= 0)
134  break;
135 
136  if (GetSocket()->Write(buf, (uint)ret) != ret)
137  {
138  tot = -1;
139  break;
140  }
141 
142  tot += ret;
143  if (ret < request)
144  break; // we hit eof
145  }
146 
147  if (m_pginfo)
149 
150  return (ret < 0) ? -1 : tot;
151 }
152 
154 {
155  if (!m_writemode || !m_rbuffer)
156  return -1;
157 
158  int tot = 0;
159  int ret = 0;
160 
161  QMutexLocker locker(&m_lock);
162 
163  m_requestBuffer.resize(max((size_t)max(size,0) + 128, m_requestBuffer.size()));
164  char *buf = &m_requestBuffer[0];
165  int attempts = 0;
166 
167  while (tot < size)
168  {
169  int request = size - tot;
170  int received = GetSocket()->Read(buf, (uint)request, 200 /*ms */);
171 
172  if (received != request)
173  {
174  LOG(VB_FILE, LOG_DEBUG,
175  QString("WriteBlock(): Read failed. Requested %1 got %2")
176  .arg(request).arg(received));
177  if (received < 0)
178  {
179  // An error occurred, abort immediately
180  break;
181  }
182  if (received == 0)
183  {
184  attempts++;
185  if (attempts > 3)
186  {
187  LOG(VB_FILE, LOG_ERR,
188  "WriteBlock(): Read tried too many times, aborting "
189  "(client or network too slow?)");
190  break;
191  }
192  continue;
193  }
194  }
195  attempts = 0;
196  ret = m_rbuffer->Write(buf, received);
197  if (ret <= 0)
198  {
199  LOG(VB_FILE, LOG_DEBUG,
200  QString("WriteBlock(): Write failed. Requested %1 got %2")
201  .arg(received).arg(ret));
202  break;
203  }
204 
205  tot += received;
206  }
207 
208  if (m_pginfo)
210 
211  return (ret < 0) ? -1 : tot;
212 }
213 
214 long long FileTransfer::Seek(long long curpos, long long pos, int whence)
215 {
216  if (m_pginfo)
218 
219  if (!m_rbuffer)
220  return -1;
221  if (!m_readthreadlive)
222  return -1;
223 
224  m_ateof = false;
225 
226  Pause();
227 
228  if (whence == SEEK_CUR)
229  {
230  long long desired = curpos + pos;
231  long long realpos = m_rbuffer->GetReadPosition();
232 
233  pos = desired - realpos;
234  }
235 
236  long long ret = m_rbuffer->Seek(pos, whence);
237 
238  Unpause();
239 
240  if (m_pginfo)
242 
243  return ret;
244 }
245 
247 {
248  if (m_pginfo)
250 
251  return m_rbuffer->GetRealFileSize();
252 }
253 
255 {
256  if (!m_rbuffer)
257  return QString();
258 
259  return m_rbuffer->GetFilename();
260 }
261 
263 {
264  if (m_pginfo)
266 
267  m_rbuffer->SetOldFile(fast);
268 }
269 
270 /* vim: set expandtab tabstop=4 shiftwidth=4: */
def write(text, progress=True)
Definition: mythburn.py:279
void WriterFlush(void)
Calls ThreadedFileWriter::Flush(void)
bool WriterSetBlocking(bool lock=true)
Calls ThreadedFileWriter::SetBlocking(bool)
void StartReads(void)
????
Definition: ringbuffer.cpp:722
void SetReadyReadCallbackEnabled(bool enabled)
Definition: mythsocket.h:49
QString GetFilename(void) const
Returns name of file used by this RingBuffer.
int Read(char *, int size, int max_wait_ms)
Definition: mythsocket.cpp:537
void UpdateInUseMark(bool force=false)
void MarkAsInUse(bool inuse, const QString &usedFor="")
Tracks a recording's in use status, to prevent deletion and to allow the storage scheduler to perform...
bool GetStopReads(void) const
Returns value of stopreads.
Holds information on recordings and videos.
Definition: programinfo.h:66
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
int Write(const char *, int size)
Definition: mythsocket.cpp:524
void SetOldFile(bool is_old)
Tell RingBuffer if this is an old file or not.
virtual bool IsOpen(void) const =0
Returns true if open for either reading or writing.
FileTransfer(QString &filename, MythSocket *remote, MythSocketManager *parent, bool usereadahead, int timeout_ms)
unsigned int uint
Definition: compat.h:140
virtual long long GetReadPosition(void) const =0
Returns how far into the file we have read.
MythSocket * GetSocket(void)
Definition: sockethandler.h:29
void StopReads(void)
????
Definition: ringbuffer.cpp:711
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
long long Seek(long long curpos, long long pos, int whence)
long long GetRealFileSize(void) const
Returns the size of the file we are reading/writing, or -1 if the query fails.
Definition: ringbuffer.cpp:497
const char * kFileTransferInUseID
int Read(void *buf, int count)
This is the public method for reading from a file, it calls the appropriate read method if the file i...
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
int Write(const void *buf, uint count)
Writes buffer to ThreadedFileWriter::Write(const void*,uint)
Implements a file/stream reader/writer.
long long Seek(long long pos, int whence, bool has_lock=false)
Seeks to a particular position in the file.
Definition: ringbuffer.cpp:510
virtual bool ReOpen(QString="")