MythTV master
filetransfer.cpp
Go to the documentation of this file.
1// C++ headers
2#include <utility>
3
4// Qt headers
5#include <QCoreApplication>
6#include <QDateTime>
7#include <QFileInfo>
8
9// MythTV
15
16// MythBackend
17#include "filetransfer.h"
18
20 bool usereadahead, std::chrono::milliseconds timeout) :
21 ReferenceCounter(QString("BEFileTransfer:%1").arg(filename)),
22 m_pginfo(new ProgramInfo(filename)),
23 m_rbuffer(MythMediaBuffer::Create(filename, false, usereadahead, timeout, true)),
24 m_sock(remote)
25{
27 if (m_rbuffer && m_rbuffer->IsOpen())
29}
30
32 ReferenceCounter(QString("BEFileTransfer:%1").arg(filename)),
33 m_pginfo(new ProgramInfo(filename)),
34 m_rbuffer(MythMediaBuffer::Create(filename, write)),
35 m_sock(remote), m_writemode(write)
36{
38
39 if (write)
40 remote->SetReadyReadCallbackEnabled(false);
41 if (m_rbuffer)
43}
44
46{
47 Stop();
48
49 if (m_sock) // BEFileTransfer becomes responsible for deleting the socket
50 m_sock->DecrRef();
51
52 if (m_rbuffer)
53 {
54 delete m_rbuffer;
55 m_rbuffer = nullptr;
56 }
57
58 if (m_pginfo)
59 {
61 delete m_pginfo;
62 }
63}
64
66{
67 return m_rbuffer && m_rbuffer->IsOpen();
68}
69
70bool BEFileTransfer::ReOpen(const QString& newFilename)
71{
72 if (!m_writemode)
73 return false;
74
75 if (m_rbuffer)
76 return m_rbuffer->ReOpen(newFilename);
77
78 return false;
79}
80
82{
84 {
85 m_readthreadlive = false;
86 LOG(VB_FILE, LOG_INFO, "calling StopReads()");
87 if (m_rbuffer)
89 QMutexLocker locker(&m_lock);
90 m_readsLocked = true;
91 }
92
93 if (m_writemode)
94 if (m_rbuffer)
96
97 if (m_pginfo)
99}
100
102{
103 LOG(VB_FILE, LOG_INFO, "calling StopReads()");
104 if (m_rbuffer)
106 QMutexLocker locker(&m_lock);
107 m_readsLocked = true;
108
109 if (m_pginfo)
111}
112
114{
115 LOG(VB_FILE, LOG_INFO, "calling StartReads()");
116 if (m_rbuffer)
118 {
119 QMutexLocker locker(&m_lock);
120 m_readsLocked = false;
121 }
122 m_readsUnlockedCond.wakeAll();
123
124 if (m_pginfo)
126}
127
129{
131 return -1;
132
133 int tot = 0;
134 int ret = 0;
135
136 QMutexLocker locker(&m_lock);
137 while (m_readsLocked)
138 m_readsUnlockedCond.wait(&m_lock, 100 /*ms*/);
139
140 m_requestBuffer.resize(std::max((size_t)std::max(size,0) + 128, m_requestBuffer.size()));
141 char *buf = (m_requestBuffer).data();
142 while (tot < size && !m_rbuffer->GetStopReads() && m_readthreadlive)
143 {
144 int request = size - tot;
145
146 ret = m_rbuffer->Read(buf, request);
147
148 if (m_rbuffer->GetStopReads() || ret <= 0)
149 break;
150
151 if (m_sock->Write(buf, (uint)ret) != ret)
152 {
153 tot = -1;
154 break;
155 }
156
157 tot += ret;
158 if (ret < request)
159 break; // we hit eof
160 }
161
162 if (m_pginfo)
164
165 return (ret < 0) ? -1 : tot;
166}
167
169{
170 if (!m_writemode || !m_rbuffer)
171 return -1;
172
173 int tot = 0;
174 int ret = 0;
175
176 QMutexLocker locker(&m_lock);
177
178 m_requestBuffer.resize(std::max((size_t)std::max(size,0) + 128, m_requestBuffer.size()));
179 char *buf = (m_requestBuffer).data();
180 int attempts = 0;
181
182 while (tot < size)
183 {
184 int request = size - tot;
185 int received = m_sock->Read(buf, (uint)request, 200ms);
186
187 if (received != request)
188 {
189 LOG(VB_FILE, LOG_DEBUG,
190 QString("WriteBlock(): Read failed. Requested %1 got %2")
191 .arg(request).arg(received));
192 if (received < 0)
193 {
194 // An error occurred, abort immediately
195 break;
196 }
197 if (received == 0)
198 {
199 attempts++;
200 if (attempts > 3)
201 {
202 LOG(VB_FILE, LOG_ERR,
203 "WriteBlock(): Read tried too many times, aborting "
204 "(client or network too slow?)");
205 break;
206 }
207 continue;
208 }
209 }
210 attempts = 0;
211 ret = m_rbuffer->Write(buf, received);
212 if (ret <= 0)
213 {
214 LOG(VB_FILE, LOG_DEBUG,
215 QString("WriteBlock(): Write failed. Requested %1 got %2")
216 .arg(received).arg(ret));
217 break;
218 }
219
220 tot += received;
221 }
222
223 if (m_pginfo)
225
226 return (ret < 0) ? -1 : tot;
227}
228
229long long BEFileTransfer::Seek(long long curpos, long long pos, int whence)
230{
231 if (m_pginfo)
233
234 if (!m_rbuffer)
235 return -1;
236 if (!m_readthreadlive)
237 return -1;
238
239 m_ateof = false;
240
241 Pause();
242
243 if (whence == SEEK_CUR)
244 {
245 long long desired = curpos + pos;
246 long long realpos = m_rbuffer->GetReadPosition();
247
248 pos = desired - realpos;
249 }
250
251 long long ret = m_rbuffer->Seek(pos, whence);
252
253 Unpause();
254
255 if (m_pginfo)
257
258 return ret;
259}
260
262{
263 if (m_pginfo)
265
266 return m_rbuffer ? m_rbuffer->GetRealFileSize() : 0;
267}
268
270{
271 if (!m_rbuffer)
272 return {};
273
274 return m_rbuffer->GetFilename();
275}
276
278{
279 if (m_pginfo)
281
282 if (m_rbuffer)
283 m_rbuffer->SetOldFile(fast);
284}
285
286/* vim: set expandtab tabstop=4 shiftwidth=4: */
int RequestBlock(int size)
bool isOpen(void)
int WriteBlock(int size)
uint64_t GetFileSize(void)
BEFileTransfer(QString &filename, MythSocket *remote, bool usereadahead, std::chrono::milliseconds timeout)
MythSocket * m_sock
Definition: filetransfer.h:57
void Unpause(void)
volatile bool m_readthreadlive
Definition: filetransfer.h:51
void Stop(void)
MythMediaBuffer * m_rbuffer
Definition: filetransfer.h:56
QWaitCondition m_readsUnlockedCond
Definition: filetransfer.h:53
bool ReOpen(const QString &newFilename="")
std::vector< char > m_requestBuffer
Definition: filetransfer.h:60
ProgramInfo * m_pginfo
Definition: filetransfer.h:55
~BEFileTransfer() override
void SetTimeout(bool fast)
long long Seek(long long curpos, long long pos, int whence)
void Pause(void)
QString GetFileName(void)
long long GetRealFileSize(void) const
void SetOldFile(bool Old)
Tell RingBuffer if this is an old file or not.
void Start(void)
Starts the read-ahead thread.
virtual bool ReOpen(const QString &="")
void WriterFlush(void)
Calls ThreadedFileWriter::Flush(void)
int Read(void *Buffer, int Count)
This is the public method for reading from a file, it calls the appropriate read method if the file i...
virtual bool IsOpen(void) const =0
long long Seek(long long Position, int Whence, bool HasLock=false)
bool GetStopReads(void) const
int Write(const void *Buffer, uint Count)
Writes buffer to ThreadedFileWriter::Write(const void*,uint)
virtual long long GetReadPosition(void) const =0
QString GetFilename(void) const
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
int Read(char *data, int size, std::chrono::milliseconds max_wait)
Definition: mythsocket.cpp:527
void SetReadyReadCallbackEnabled(bool enabled)
Definition: mythsocket.h:48
int Write(const char *data, int size)
Definition: mythsocket.cpp:514
Holds information on recordings and videos.
Definition: programinfo.h:68
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...
General purpose reference counter.
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
unsigned int uint
Definition: freesurround.h:24
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
def write(text, progress=True)
Definition: mythburn.py:307
const QString kFileTransferInUseID
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:95
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:89