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 
11 FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
12  MythSocketManager *parent,
13  bool usereadahead, int timeout_ms) :
14  SocketHandler(remote, parent, ""),
15  m_rbuffer(RingBuffer::Create(filename, false, usereadahead, timeout_ms))
16 {
17  m_pginfo = new ProgramInfo(filename);
19 }
20 
21 FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
22  MythSocketManager *parent, bool write) :
23  SocketHandler(remote, parent, ""),
24  m_rbuffer(RingBuffer::Create(filename, write)),
25  m_writemode(write)
26 {
27  m_pginfo = new ProgramInfo(filename);
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;
171 
172  received = GetSocket()->Read(buf, (uint)request, 200 /*ms */);
173 
174  if (received != request)
175  {
176  LOG(VB_FILE, LOG_DEBUG,
177  QString("WriteBlock(): Read failed. Requested %1 got %2")
178  .arg(request).arg(received));
179  if (received < 0)
180  {
181  // An error occurred, abort immediately
182  break;
183  }
184  if (received == 0)
185  {
186  attempts++;
187  if (attempts > 3)
188  {
189  LOG(VB_FILE, LOG_ERR,
190  "WriteBlock(): Read tried too many times, aborting "
191  "(client or network too slow?)");
192  break;
193  }
194  continue;
195  }
196  }
197  attempts = 0;
198  ret = m_rbuffer->Write(buf, received);
199  if (ret <= 0)
200  {
201  LOG(VB_FILE, LOG_DEBUG,
202  QString("WriteBlock(): Write failed. Requested %1 got %2")
203  .arg(received).arg(ret));
204  break;
205  }
206 
207  tot += received;
208  }
209 
210  if (m_pginfo)
212 
213  return (ret < 0) ? -1 : tot;
214 }
215 
216 long long FileTransfer::Seek(long long curpos, long long pos, int whence)
217 {
218  if (m_pginfo)
220 
221  if (!m_rbuffer)
222  return -1;
223  if (!m_readthreadlive)
224  return -1;
225 
226  m_ateof = false;
227 
228  Pause();
229 
230  if (whence == SEEK_CUR)
231  {
232  long long desired = curpos + pos;
233  long long realpos = m_rbuffer->GetReadPosition();
234 
235  pos = desired - realpos;
236  }
237 
238  long long ret = m_rbuffer->Seek(pos, whence);
239 
240  Unpause();
241 
242  if (m_pginfo)
244 
245  return ret;
246 }
247 
249 {
250  if (m_pginfo)
252 
253  return m_rbuffer->GetRealFileSize();
254 }
255 
257 {
258  if (!m_rbuffer)
259  return QString();
260 
261  return m_rbuffer->GetFilename();
262 }
263 
265 {
266  if (m_pginfo)
268 
269  m_rbuffer->SetOldFile(fast);
270 }
271 
272 /* 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
unsigned int uint
Definition: compat.h:140
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)
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="")