MythTV  master
programs/mythbackend/filetransfer.cpp
Go to the documentation of this file.
1 #include <QCoreApplication>
2 #include <QDateTime>
3 #include <QFileInfo>
4 
5 #include "filetransfer.h"
6 #include "ringbuffer.h"
7 #include "mythdate.h"
8 #include "mythsocket.h"
9 #include "programinfo.h"
10 #include "mythlogging.h"
11 
12 FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
13  bool usereadahead, int timeout_ms) :
14  ReferenceCounter(QString("FileTransfer:%1").arg(filename)),
15  readthreadlive(true), readsLocked(false),
16  rbuffer(RingBuffer::Create(filename, false, usereadahead, timeout_ms, true)),
17  sock(remote), ateof(false), lock(QMutex::NonRecursive),
18  writemode(false)
19 {
20  pginfo = new ProgramInfo(filename);
22  if (rbuffer && rbuffer->IsOpen())
23  rbuffer->Start();
24 }
25 
26 FileTransfer::FileTransfer(QString &filename, MythSocket *remote, bool write) :
27  ReferenceCounter(QString("FileTransfer:%1").arg(filename)),
28  readthreadlive(true), readsLocked(false),
29  rbuffer(RingBuffer::Create(filename, write)),
30  sock(remote), ateof(false), lock(QMutex::NonRecursive),
31  writemode(write)
32 {
33  pginfo = new ProgramInfo(filename);
35 
36  if (write)
37  remote->SetReadyReadCallbackEnabled(false);
38  if (rbuffer)
39  rbuffer->Start();
40 }
41 
43 {
44  Stop();
45 
46  if (sock) // FileTransfer becomes responsible for deleting the socket
47  sock->DecrRef();
48 
49  if (rbuffer)
50  {
51  delete rbuffer;
52  rbuffer = nullptr;
53  }
54 
55  if (pginfo)
56  {
58  delete pginfo;
59  }
60 }
61 
62 bool FileTransfer::isOpen(void)
63 {
64  if (rbuffer && rbuffer->IsOpen())
65  return true;
66  return false;
67 }
68 
69 bool FileTransfer::ReOpen(QString newFilename)
70 {
71  if (!writemode)
72  return false;
73 
74  if (rbuffer)
75  return rbuffer->ReOpen(newFilename);
76 
77  return false;
78 }
79 
80 void FileTransfer::Stop(void)
81 {
82  if (readthreadlive)
83  {
84  readthreadlive = false;
85  LOG(VB_FILE, LOG_INFO, "calling StopReads()");
86  if (rbuffer)
87  rbuffer->StopReads();
88  QMutexLocker locker(&lock);
89  readsLocked = true;
90  }
91 
92  if (writemode)
93  if (rbuffer)
95 
96  if (pginfo)
98 }
99 
100 void FileTransfer::Pause(void)
101 {
102  LOG(VB_FILE, LOG_INFO, "calling StopReads()");
103  if (rbuffer)
104  rbuffer->StopReads();
105  QMutexLocker locker(&lock);
106  readsLocked = true;
107 
108  if (pginfo)
110 }
111 
112 void FileTransfer::Unpause(void)
113 {
114  LOG(VB_FILE, LOG_INFO, "calling StartReads()");
115  if (rbuffer)
116  rbuffer->StartReads();
117  {
118  QMutexLocker locker(&lock);
119  readsLocked = false;
120  }
121  readsUnlockedCond.wakeAll();
122 
123  if (pginfo)
125 }
126 
127 int FileTransfer::RequestBlock(int size)
128 {
129  if (!readthreadlive || !rbuffer)
130  return -1;
131 
132  int tot = 0;
133  int ret = 0;
134 
135  QMutexLocker locker(&lock);
136  while (readsLocked)
137  readsUnlockedCond.wait(&lock, 100 /*ms*/);
138 
139  requestBuffer.resize(max((size_t)max(size,0) + 128, requestBuffer.size()));
140  char *buf = &requestBuffer[0];
141  while (tot < size && !rbuffer->GetStopReads() && readthreadlive)
142  {
143  int request = size - tot;
144 
145  ret = rbuffer->Read(buf, request);
146 
147  if (rbuffer->GetStopReads() || ret <= 0)
148  break;
149 
150  if (sock->Write(buf, (uint)ret) != ret)
151  {
152  tot = -1;
153  break;
154  }
155 
156  tot += ret;
157  if (ret < request)
158  break; // we hit eof
159  }
160 
161  if (pginfo)
163 
164  return (ret < 0) ? -1 : tot;
165 }
166 
167 int FileTransfer::WriteBlock(int size)
168 {
169  if (!writemode || !rbuffer)
170  return -1;
171 
172  int tot = 0;
173  int ret = 0;
174 
175  QMutexLocker locker(&lock);
176 
177  requestBuffer.resize(max((size_t)max(size,0) + 128, requestBuffer.size()));
178  char *buf = &requestBuffer[0];
179  int attempts = 0;
180 
181  while (tot < size)
182  {
183  int request = size - tot;
184  int received;
185 
186  received = sock->Read(buf, (uint)request, 200 /*ms */);
187 
188  if (received != request)
189  {
190  LOG(VB_FILE, LOG_DEBUG,
191  QString("WriteBlock(): Read failed. Requested %1 got %2")
192  .arg(request).arg(received));
193  if (received < 0)
194  {
195  // An error occurred, abort immediately
196  break;
197  }
198  if (received == 0)
199  {
200  attempts++;
201  if (attempts > 3)
202  {
203  LOG(VB_FILE, LOG_ERR,
204  "WriteBlock(): Read tried too many times, aborting "
205  "(client or network too slow?)");
206  break;
207  }
208  continue;
209  }
210  }
211  attempts = 0;
212  ret = rbuffer->Write(buf, received);
213  if (ret <= 0)
214  {
215  LOG(VB_FILE, LOG_DEBUG,
216  QString("WriteBlock(): Write failed. Requested %1 got %2")
217  .arg(received).arg(ret));
218  break;
219  }
220 
221  tot += received;
222  }
223 
224  if (pginfo)
226 
227  return (ret < 0) ? -1 : tot;
228 }
229 
230 long long FileTransfer::Seek(long long curpos, long long pos, int whence)
231 {
232  if (pginfo)
234 
235  if (!rbuffer)
236  return -1;
237  if (!readthreadlive)
238  return -1;
239 
240  ateof = false;
241 
242  Pause();
243 
244  if (whence == SEEK_CUR)
245  {
246  long long desired = curpos + pos;
247  long long realpos = rbuffer->GetReadPosition();
248 
249  pos = desired - realpos;
250  }
251 
252  long long ret = rbuffer->Seek(pos, whence);
253 
254  Unpause();
255 
256  if (pginfo)
258 
259  return ret;
260 }
261 
262 uint64_t FileTransfer::GetFileSize(void)
263 {
264  if (pginfo)
266 
267  return rbuffer ? rbuffer->GetRealFileSize() : 0;
268 }
269 
270 QString FileTransfer::GetFileName(void)
271 {
272  if (!rbuffer)
273  return QString();
274 
275  return rbuffer->GetFilename();
276 }
277 
278 void FileTransfer::SetTimeout(bool fast)
279 {
280  if (pginfo)
282 
283  if (rbuffer)
284  rbuffer->SetOldFile(fast);
285 }
286 
287 /* vim: set expandtab tabstop=4 shiftwidth=4: */
def write(text, progress=True)
Definition: mythburn.py:279
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
void WriterFlush(void)
Calls ThreadedFileWriter::Flush(void)
General purpose reference counter.
void MarkAsInUse(bool inuse, QString usedFor="")
Tracks a recording's in use status, to prevent deletion and to allow the storage scheduler to perform...
void StartReads(void)
????
Definition: ringbuffer.cpp:757
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:546
unsigned int uint
Definition: compat.h:140
void UpdateInUseMark(bool force=false)
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:533
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
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.
void Start(void)
Starts the read-ahead thread.
Definition: ringbuffer.cpp:688
void StopReads(void)
????
Definition: ringbuffer.cpp:746
#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:532
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:545
virtual bool ReOpen(QString="")