MythTV  master
libs/libmythprotoserver/sockethandler/filetransfer.cpp
Go to the documentation of this file.
1 #include <QFileInfo>
2 #include <QMutexLocker>
3 
4 #include "filetransfer.h"
5 #include "ringbuffer.h"
6 #include "programinfo.h"
7 #include "mythsocket.h"
8 #include "mythlogging.h"
9 
10 FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
11  MythSocketManager *parent,
12  bool usereadahead, int timeout_ms) :
13  SocketHandler(remote, parent, ""),
14  readthreadlive(true), readsLocked(false),
15  rbuffer(RingBuffer::Create(filename, false, usereadahead, timeout_ms)),
16  ateof(false), lock(QMutex::NonRecursive),
17  writemode(false)
18 {
19  pginfo = new ProgramInfo(filename);
21 }
22 
23 FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
24  MythSocketManager *parent, bool write) :
25  SocketHandler(remote, parent, ""),
26  readthreadlive(true), readsLocked(false),
27  rbuffer(RingBuffer::Create(filename, write)),
28  ateof(false), lock(QMutex::NonRecursive),
29  writemode(write)
30 {
31  pginfo = new ProgramInfo(filename);
33 
34  if (write)
35  {
36  remote->SetReadyReadCallbackEnabled(false);
38  }
39 }
40 
42 {
43  Stop();
44 
45  if (rbuffer)
46  {
47  delete rbuffer;
48  rbuffer = nullptr;
49  }
50 
51  if (pginfo)
52  {
54  delete pginfo;
55  }
56 }
57 
59 {
60  if (rbuffer && rbuffer->IsOpen())
61  return true;
62  return false;
63 }
64 
65 bool FileTransfer::ReOpen(QString newFilename)
66 {
67  if (!writemode)
68  return false;
69 
70  if (rbuffer)
71  return rbuffer->ReOpen(newFilename);
72 
73  return false;
74 }
75 
77 {
78  if (readthreadlive)
79  {
80  readthreadlive = false;
81  LOG(VB_FILE, LOG_INFO, "calling StopReads()");
82  rbuffer->StopReads();
83  QMutexLocker locker(&lock);
84  readsLocked = true;
85  }
86 
87  if (writemode)
89 
90  if (pginfo)
92 }
93 
95 {
96  LOG(VB_FILE, LOG_INFO, "calling StopReads()");
97  rbuffer->StopReads();
98  QMutexLocker locker(&lock);
99  readsLocked = true;
100 
101  if (pginfo)
103 }
104 
106 {
107  LOG(VB_FILE, LOG_INFO, "calling StartReads()");
108  rbuffer->StartReads();
109  {
110  QMutexLocker locker(&lock);
111  readsLocked = false;
112  }
113  readsUnlockedCond.wakeAll();
114 
115  if (pginfo)
117 }
118 
120 {
121  if (!readthreadlive || !rbuffer)
122  return -1;
123 
124  int tot = 0;
125  int ret = 0;
126 
127  QMutexLocker locker(&lock);
128  while (readsLocked)
129  readsUnlockedCond.wait(&lock, 100 /*ms*/);
130 
131  requestBuffer.resize(max((size_t)max(size,0) + 128, requestBuffer.size()));
132  char *buf = &requestBuffer[0];
133  while (tot < size && !rbuffer->GetStopReads() && readthreadlive)
134  {
135  int request = size - tot;
136 
137  ret = rbuffer->Read(buf, request);
138 
139  if (rbuffer->GetStopReads() || ret <= 0)
140  break;
141 
142  if (GetSocket()->Write(buf, (uint)ret) != ret)
143  {
144  tot = -1;
145  break;
146  }
147 
148  tot += ret;
149  if (ret < request)
150  break; // we hit eof
151  }
152 
153  if (pginfo)
155 
156  return (ret < 0) ? -1 : tot;
157 }
158 
160 {
161  if (!writemode || !rbuffer)
162  return -1;
163 
164  int tot = 0;
165  int ret = 0;
166 
167  QMutexLocker locker(&lock);
168 
169  requestBuffer.resize(max((size_t)max(size,0) + 128, requestBuffer.size()));
170  char *buf = &requestBuffer[0];
171  int attempts = 0;
172 
173  while (tot < size)
174  {
175  int request = size - tot;
176  int received;
177 
178  received = GetSocket()->Read(buf, (uint)request, 200 /*ms */);
179 
180  if (received != request)
181  {
182  LOG(VB_FILE, LOG_DEBUG,
183  QString("WriteBlock(): Read failed. Requested %1 got %2")
184  .arg(request).arg(received));
185  if (received < 0)
186  {
187  // An error occurred, abort immediately
188  break;
189  }
190  if (received == 0)
191  {
192  attempts++;
193  if (attempts > 3)
194  {
195  LOG(VB_FILE, LOG_ERR,
196  "WriteBlock(): Read tried too many times, aborting "
197  "(client or network too slow?)");
198  break;
199  }
200  continue;
201  }
202  }
203  attempts = 0;
204  ret = rbuffer->Write(buf, received);
205  if (ret <= 0)
206  {
207  LOG(VB_FILE, LOG_DEBUG,
208  QString("WriteBlock(): Write failed. Requested %1 got %2")
209  .arg(received).arg(ret));
210  break;
211  }
212 
213  tot += received;
214  }
215 
216  if (pginfo)
218 
219  return (ret < 0) ? -1 : tot;
220 }
221 
222 long long FileTransfer::Seek(long long curpos, long long pos, int whence)
223 {
224  if (pginfo)
226 
227  if (!rbuffer)
228  return -1;
229  if (!readthreadlive)
230  return -1;
231 
232  ateof = false;
233 
234  Pause();
235 
236  if (whence == SEEK_CUR)
237  {
238  long long desired = curpos + pos;
239  long long realpos = rbuffer->GetReadPosition();
240 
241  pos = desired - realpos;
242  }
243 
244  long long ret = rbuffer->Seek(pos, whence);
245 
246  Unpause();
247 
248  if (pginfo)
250 
251  return ret;
252 }
253 
255 {
256  if (pginfo)
258 
259  return rbuffer->GetRealFileSize();
260 }
261 
263 {
264  if (!rbuffer)
265  return QString();
266 
267  return rbuffer->GetFilename();
268 }
269 
271 {
272  if (pginfo)
274 
275  rbuffer->SetOldFile(fast);
276 }
277 
278 /* 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)
bool WriterSetBlocking(bool lock=true)
Calls ThreadedFileWriter::SetBlocking(bool)
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
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: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="")