MythTV  master
remotefile.cpp
Go to the documentation of this file.
1 #include <iostream>
2 using namespace std;
3 
4 #include <QFile>
5 #include <QFileInfo>
6 #include <QRegularExpression>
7 #include <QUrl>
8 
9 // POSIX C headers
10 #include <unistd.h>
11 #include <fcntl.h>
12 
13 #include "mythconfig.h"
14 
15 #ifndef O_STREAMING
16 #define O_STREAMING 0
17 #endif
18 
19 #ifndef O_LARGEFILE
20 #define O_LARGEFILE 0
21 #endif
22 
23 #ifndef O_BINARY
24 #define O_BINARY 0
25 #endif
26 
27 #include "mythdb.h"
28 #include "remotefile.h"
29 #include "mythcorecontext.h"
30 #include "mythsocket.h"
31 #include "compat.h"
32 #include "mythtimer.h"
33 #include "mythdate.h"
34 #include "mythmiscutil.h"
35 #include "threadedfilewriter.h"
36 #include "storagegroup.h"
37 
38 #define MAX_FILE_CHECK 500 // in ms
39 
40 static bool RemoteSendReceiveStringList(const QString &host, QStringList &strlist)
41 {
42  bool ok = false;
43 
45  {
46  // since the master backend cannot connect back around to
47  // itself, and the libraries do not have access to the list
48  // of connected slave backends to query an existing connection
49  // start up a new temporary connection directly to the slave
50  // backend to query the file list
51  QString ann = QString("ANN Playback %1 0")
52  .arg(gCoreContext->GetHostName());
53  QString addr = gCoreContext->GetBackendServerIP(host);
54  int port = gCoreContext->GetBackendServerPort(host);
55  bool mismatch = false;
56 
58  addr, port, ann, &mismatch);
59  if (sock)
60  {
61  ok = sock->SendReceiveStringList(strlist);
62  sock->DecrRef();
63  }
64  else
65  strlist.clear();
66  }
67  else
68  ok = gCoreContext->SendReceiveStringList(strlist);
69 
70  return ok;
71 }
72 
73 RemoteFile::RemoteFile(QString url, bool write, bool usereadahead,
74  int timeout_ms,
75  const QStringList *possibleAuxiliaryFiles) :
76  m_path(std::move(url)),
77  m_useReadAhead(usereadahead), m_timeoutMs(timeout_ms),
78  m_writeMode(write)
79 {
80  if (m_writeMode)
81  {
82  m_useReadAhead = false;
83  m_timeoutMs = -1;
84  }
85  else if (possibleAuxiliaryFiles)
86  m_possibleAuxFiles = *possibleAuxiliaryFiles;
87 
88  if (!m_path.isEmpty())
89  Open();
90 
91  LOG(VB_FILE, LOG_DEBUG, QString("RemoteFile(%1)").arg(m_path));
92 }
93 
95 {
96  Close();
97  if (m_controlSock)
98  {
100  m_controlSock = nullptr;
101  }
102  if (m_sock)
103  {
104  m_sock->DecrRef();
105  m_sock = nullptr;
106  }
107 }
108 
109 bool RemoteFile::isLocal(const QString &lpath)
110 {
111  bool is_local = !lpath.isEmpty() &&
112  !lpath.startsWith("myth:") &&
113  (lpath.startsWith("/") || QFile::exists(lpath));
114  return is_local;
115 }
116 
117 bool RemoteFile::isLocal(void) const
118 {
119  return isLocal(m_path);
120 }
121 
123 {
124  QUrl qurl(m_path);
125  QString dir;
126 
127  QString host = qurl.host();
128  int port = qurl.port();
129 
130  dir = qurl.path();
131 
132  if (qurl.hasQuery())
133  dir += "?" + QUrl::fromPercentEncoding(
134  qurl.query(QUrl::FullyEncoded).toLocal8Bit());
135 
136  if (qurl.hasFragment())
137  dir += "#" + qurl.fragment();
138 
139  QString sgroup = qurl.userName();
140 
141  auto *lsock = new MythSocket();
142  QString stype = (control) ? "control socket" : "file data socket";
143 
144  QString loc = QString("RemoteFile::openSocket(%1): ").arg(stype);
145 
146  if (port <= 0)
147  {
148  port = gCoreContext->GetBackendServerPort(host);
149  }
150 
151  if (!lsock->ConnectToHost(host, port))
152  {
153  LOG(VB_GENERAL, LOG_ERR, loc +
154  QString("Could not connect to server %1:%2") .arg(host).arg(port));
155  lsock->DecrRef();
156  return nullptr;
157  }
158 
159  QString hostname = GetMythDB()->GetHostName();
160 
161  QStringList strlist;
162 
163 #ifndef IGNORE_PROTO_VER_MISMATCH
164  if (!gCoreContext->CheckProtoVersion(lsock, 5000))
165  {
166  LOG(VB_GENERAL, LOG_ERR, loc +
167  QString("Failed validation to server %1:%2").arg(host).arg(port));
168  lsock->DecrRef();
169  return nullptr;
170  }
171 #endif
172 
173  if (control)
174  {
175  strlist.append(QString("ANN Playback %1 %2")
176  .arg(hostname).arg(static_cast<int>(false)));
177  if (!lsock->SendReceiveStringList(strlist))
178  {
179  LOG(VB_GENERAL, LOG_ERR, loc +
180  QString("Could not read string list from server %1:%2")
181  .arg(host).arg(port));
182  lsock->DecrRef();
183  return nullptr;
184  }
185  }
186  else
187  {
188  strlist.push_back(QString("ANN FileTransfer %1 %2 %3 %4")
189  .arg(hostname).arg(static_cast<int>(m_writeMode))
190  .arg(static_cast<int>(m_useReadAhead)).arg(m_timeoutMs));
191  strlist << QString("%1").arg(dir);
192  strlist << sgroup;
193 
194  for (const auto& fname : qAsConst(m_possibleAuxFiles))
195  strlist << fname;
196 
197  if (!lsock->SendReceiveStringList(strlist))
198  {
199  LOG(VB_GENERAL, LOG_ERR, loc +
200  QString("Did not get proper response from %1:%2")
201  .arg(host).arg(port));
202  strlist.clear();
203  strlist.push_back("ERROR");
204  strlist.push_back("invalid response");
205  }
206 
207  if (strlist.size() >= 3)
208  {
209  auto it = strlist.begin(); ++it;
210  m_recorderNum = (*it).toInt(); ++it;
211  m_fileSize = (*(it)).toLongLong(); ++it;
212  for (; it != strlist.end(); ++it)
213  m_auxFiles << *it;
214  }
215  else if (!strlist.isEmpty() && strlist.size() < 3 &&
216  strlist[0] != "ERROR")
217  {
218  LOG(VB_GENERAL, LOG_ERR, loc +
219  QString("Did not get proper response from %1:%2")
220  .arg(host).arg(port));
221  strlist.clear();
222  strlist.push_back("ERROR");
223  strlist.push_back("invalid response");
224  }
225  }
226 
227  if (strlist.isEmpty() || strlist[0] == "ERROR")
228  {
229  lsock->DecrRef();
230  lsock = nullptr;
231  if (strlist.isEmpty())
232  {
233  LOG(VB_GENERAL, LOG_ERR, loc + "Failed to open socket, timeout");
234  }
235  else
236  {
237  LOG(VB_GENERAL, LOG_ERR, loc + "Failed to open socket" +
238  ((strlist.size() >= 2) ?
239  QString(", error was %1").arg(strlist[1]) :
240  QString(", remote error")));
241  }
242  }
243 
244  return lsock;
245 }
246 
247 bool RemoteFile::isOpen() const
248 {
249  if (isLocal())
250  {
251  return m_writeMode ? (m_fileWriter != nullptr) : (m_localFile != -1);
252  }
253  return m_sock && m_controlSock;
254 }
255 
257 {
258  if (isOpen())
259  return true;
260 
261  QMutexLocker locker(&m_lock);
262  return OpenInternal();
263 }
264 
270 {
271  if (isLocal())
272  {
273  if (m_writeMode)
274  {
275  // make sure the directories are created if necessary
276  QFileInfo fi(m_path);
277  QDir dir(fi.path());
278  if (!dir.exists())
279  {
280  LOG(VB_FILE, LOG_WARNING, QString("RemoteFile::Open(%1) creating directories")
281  .arg(m_path));
282 
283  if (!dir.mkpath(fi.path()))
284  {
285  LOG(VB_GENERAL, LOG_ERR, QString("RemoteFile::Open(%1) failed to create the directories")
286  .arg(m_path));
287  return false;
288  }
289  }
290 
292  O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE,
293  0644);
294 
295  if (!m_fileWriter->Open())
296  {
297  delete m_fileWriter;
298  m_fileWriter = nullptr;
299  LOG(VB_FILE, LOG_ERR, QString("RemoteFile::Open(%1) write mode error")
300  .arg(m_path));
301  return false;
302  }
303  SetBlocking();
304  return true;
305  }
306 
307  // local mode, read only
308  if (!Exists(m_path))
309  {
310  LOG(VB_FILE, LOG_ERR,
311  QString("RemoteFile::Open(%1) Error: Does not exist").arg(m_path));
312  return false;
313  }
314 
315  m_localFile = ::open(m_path.toLocal8Bit().constData(), O_RDONLY);
316  if (m_localFile == -1)
317  {
318  LOG(VB_FILE, LOG_ERR, QString("RemoteFile::Open(%1) Error: %2")
319  .arg(m_path).arg(strerror(errno)));
320  return false;
321  }
322  return true;
323  }
324  m_controlSock = openSocket(true);
325  if (!m_controlSock)
326  return false;
327 
328  m_sock = openSocket(false);
329  if (!m_sock)
330  {
331  // Close the sockets if we received an error so that isOpen() will
332  // return false if the caller tries to use the RemoteFile.
333  Close(true);
334  return false;
335  }
336  m_canResume = true;
337 
338  return true;
339 }
340 
341 bool RemoteFile::ReOpen(const QString& newFilename)
342 {
343  if (isLocal())
344  {
345  if (isOpen())
346  {
347  Close();
348  }
349  m_path = newFilename;
350  return Open();
351  }
352 
353  QMutexLocker locker(&m_lock);
354 
355  if (!CheckConnection(false))
356  {
357  LOG(VB_NETWORK, LOG_ERR, "RemoteFile::ReOpen(): Couldn't connect");
358  return false;
359  }
360 
361  QStringList strlist( m_query.arg(m_recorderNum) );
362  strlist << "REOPEN";
363  strlist << newFilename;
364 
366 
367  m_lock.unlock();
368 
369  bool retval = false;
370  if (!strlist.isEmpty())
371  retval = (strlist[0].toInt() != 0);
372 
373  return retval;
374 }
375 
376 void RemoteFile::Close(bool haslock)
377 {
378  if (isLocal())
379  {
381  m_localFile = -1;
382  delete m_fileWriter;
383  m_fileWriter = nullptr;
384  return;
385  }
386  if (!m_controlSock)
387  return;
388 
389  QStringList strlist( m_query.arg(m_recorderNum) );
390  strlist << "DONE";
391 
392  if (!haslock)
393  {
394  m_lock.lock();
395  }
397  strlist, 0, MythSocket::kShortTimeout))
398  {
399  LOG(VB_GENERAL, LOG_ERR, "Remote file timeout.");
400  }
401 
402  if (m_sock)
403  {
404  m_sock->DecrRef();
405  m_sock = nullptr;
406  }
407  if (m_controlSock)
408  {
410  m_controlSock = nullptr;
411  }
412 
413  if (!haslock)
414  {
415  m_lock.unlock();
416  }
417 }
418 
419 bool RemoteFile::DeleteFile(const QString &url)
420 {
421  if (isLocal(url))
422  {
423  QFile file(url);
424  return file.remove();
425  }
426 
427  bool result = false;
428  QUrl qurl(url);
429  QString filename = qurl.path();
430  QString sgroup = qurl.userName();
431 
432  if (!qurl.fragment().isEmpty() || url.endsWith("#"))
433  filename = filename + "#" + qurl.fragment();
434 
435  if (filename.startsWith("/"))
436  filename = filename.right(filename.length()-1);
437 
438  if (filename.isEmpty() || sgroup.isEmpty())
439  return false;
440 
441  QStringList strlist("DELETE_FILE");
442  strlist << filename;
443  strlist << sgroup;
444 
446 
447  if (!strlist.isEmpty() && strlist[0] == "1")
448  result = true;
449 
450  return result;
451 }
452 
453 bool RemoteFile::Exists(const QString &url)
454 {
455  if (url.isEmpty())
456  return false;
457 
458  struct stat fileinfo {};
459  return Exists(url, &fileinfo);
460 }
461 
462 bool RemoteFile::Exists(const QString &url, struct stat *fileinfo)
463 {
464  if (url.isEmpty())
465  return false;
466 
467  QUrl qurl(url);
468  QString filename = qurl.path();
469  QString sgroup = qurl.userName();
470  QString host = qurl.host();
471 
472  if (isLocal(url) || gCoreContext->IsThisBackend(host))
473  {
474  LOG(VB_FILE, LOG_INFO,
475  QString("RemoteFile::Exists(): looking for local file: %1").arg(url));
476 
477  bool fileExists = false;
478  QString fullFilePath = "";
479 
480  if (url.startsWith("myth:"))
481  {
482  StorageGroup sGroup(sgroup, gCoreContext->GetHostName());
483  fullFilePath = sGroup.FindFile(filename);
484  if (!fullFilePath.isEmpty())
485  fileExists = true;
486  }
487  else
488  {
489  QFileInfo info(url);
490  fileExists = info.exists() /*&& info.isFile()*/;
491  fullFilePath = url;
492  }
493 
494  if (fileExists)
495  {
496  if (stat(fullFilePath.toLocal8Bit().constData(), fileinfo) == -1)
497  {
498  LOG(VB_FILE, LOG_ERR,
499  QString("RemoteFile::Exists(): failed to stat file: %1").arg(fullFilePath) + ENO);
500  }
501  }
502 
503  return fileExists;
504  }
505 
506  LOG(VB_FILE, LOG_INFO,
507  QString("RemoteFile::Exists(): looking for remote file: %1").arg(url));
508 
509  if (!qurl.fragment().isEmpty() || url.endsWith("#"))
510  filename = filename + "#" + qurl.fragment();
511 
512  if (filename.startsWith("/"))
513  filename = filename.right(filename.length()-1);
514 
515  if (filename.isEmpty())
516  return false;
517 
518  QStringList strlist("QUERY_FILE_EXISTS");
519  strlist << filename;
520  if (!sgroup.isEmpty())
521  strlist << sgroup;
522 
523  bool result = false;
524  if (RemoteSendReceiveStringList(host, strlist) && strlist[0] == "1")
525  {
526  if ((strlist.size() >= 15) && fileinfo)
527  {
528  fileinfo->st_dev = strlist[2].toLongLong();
529  fileinfo->st_ino = strlist[3].toLongLong();
530  fileinfo->st_mode = strlist[4].toLongLong();
531  fileinfo->st_nlink = strlist[5].toLongLong();
532  fileinfo->st_uid = strlist[6].toLongLong();
533  fileinfo->st_gid = strlist[7].toLongLong();
534  fileinfo->st_rdev = strlist[8].toLongLong();
535  fileinfo->st_size = strlist[9].toLongLong();
536 #ifndef _WIN32
537  fileinfo->st_blksize = strlist[10].toLongLong();
538  fileinfo->st_blocks = strlist[11].toLongLong();
539 #endif
540  fileinfo->st_atime = strlist[12].toLongLong();
541  fileinfo->st_mtime = strlist[13].toLongLong();
542  fileinfo->st_ctime = strlist[14].toLongLong();
543  result = true;
544  }
545  else if (!fileinfo)
546  {
547  result = true;
548  }
549  }
550 
551  return result;
552 }
553 
554 QString RemoteFile::GetFileHash(const QString &url)
555 {
556  if (isLocal(url))
557  {
558  return FileHash(url);
559  }
560  QString result;
561  QUrl qurl(url);
562  QString filename = qurl.path();
563  QString hostname = qurl.host();
564  QString sgroup = qurl.userName();
565 
566  if (!qurl.fragment().isEmpty() || url.endsWith("#"))
567  filename = filename + "#" + qurl.fragment();
568 
569  if (filename.startsWith("/"))
570  filename = filename.right(filename.length()-1);
571 
572  if (filename.isEmpty() || sgroup.isEmpty())
573  return QString();
574 
575  QStringList strlist("QUERY_FILE_HASH");
576  strlist << filename;
577  strlist << sgroup;
578  strlist << hostname;
579 
581  {
582  result = strlist[0];
583  }
584 
585  return result;
586 }
587 
588 bool RemoteFile::CopyFile (const QString& src, const QString& dst,
589  bool overwrite, bool verify)
590 {
591  LOG(VB_FILE, LOG_INFO,
592  QString("RemoteFile::CopyFile: Copying file from '%1' to '%2'").arg(src).arg(dst));
593 
594  // sanity check
595  if (src == dst)
596  {
597  LOG(VB_GENERAL, LOG_ERR, "RemoteFile::CopyFile: Cannot copy a file to itself");
598  return false;
599  }
600 
601  RemoteFile srcFile(src, false);
602  if (!srcFile.isOpen())
603  {
604  LOG(VB_GENERAL, LOG_ERR,
605  QString("RemoteFile::CopyFile: Failed to open file (%1) for reading.").arg(src));
606  return false;
607  }
608 
609  const int readSize = 2 * 1024 * 1024;
610  char *buf = new char[readSize];
611  if (!buf)
612  {
613  LOG(VB_GENERAL, LOG_ERR, "RemoteFile::CopyFile: ERROR, unable to allocate copy buffer");
614  return false;
615  }
616 
617  if (overwrite)
618  {
619  DeleteFile(dst);
620  }
621  else if (Exists(dst))
622  {
623  LOG(VB_GENERAL, LOG_ERR, "RemoteFile::CopyFile: File already exists");
624  delete[] buf;
625  return false;
626  }
627 
628  RemoteFile dstFile(dst, true);
629  if (!dstFile.isOpen())
630  {
631  LOG(VB_GENERAL, LOG_ERR,
632  QString("RemoteFile::CopyFile: Failed to open file (%1) for writing.").arg(dst));
633  srcFile.Close();
634  delete[] buf;
635  return false;
636  }
637 
638  dstFile.SetBlocking(true);
639 
640  bool success = true;
641  int srcLen = 0;
642 
643  while ((srcLen = srcFile.Read(buf, readSize)) > 0)
644  {
645  int dstLen = dstFile.Write(buf, srcLen);
646 
647  if (dstLen == -1 || srcLen != dstLen)
648  {
649  LOG(VB_GENERAL, LOG_ERR,
650  "RemoteFile::CopyFile: Error while trying to write to destination file.");
651  success = false;
652  }
653  }
654 
655  srcFile.Close();
656  dstFile.Close();
657  delete[] buf;
658 
659  if (success && verify)
660  {
661  // Check written file is correct size
662  struct stat fileinfo {};
663  long long dstSize = Exists(dst, &fileinfo) ? fileinfo.st_size : -1;
664  long long srcSize = srcFile.GetFileSize();
665  if (dstSize != srcSize)
666  {
667  LOG(VB_GENERAL, LOG_ERR,
668  QString("RemoteFile::CopyFile: Copied file is wrong size (%1 rather than %2)")
669  .arg(dstSize).arg(srcSize));
670  success = false;
671  DeleteFile(dst);
672  }
673  }
674 
675  return success;
676 }
677 
678 bool RemoteFile::MoveFile (const QString& src, const QString& dst, bool overwrite)
679 {
680  LOG(VB_FILE, LOG_INFO,
681  QString("RemoteFile::MoveFile: Moving file from '%1' to '%2'").arg(src).arg(dst));
682 
683  // sanity check
684  if (src == dst)
685  {
686  LOG(VB_GENERAL, LOG_ERR, "RemoteFile::MoveFile: Cannot move a file to itself");
687  return false;
688  }
689 
690  if (isLocal(src) != isLocal(dst))
691  {
692  // Moving between local & remote requires a copy & delete
693  bool ok = CopyFile(src, dst, overwrite, true);
694  if (ok)
695  {
696  if (!DeleteFile(src))
697  LOG(VB_FILE, LOG_ERR,
698  "RemoteFile::MoveFile: Failed to delete file after successful copy");
699  }
700  return ok;
701  }
702 
703  if (overwrite)
704  {
705  DeleteFile(dst);
706  }
707  else if (Exists(dst))
708  {
709  LOG(VB_GENERAL, LOG_ERR, "RemoteFile::MoveFile: File already exists");
710  return false;
711  }
712 
713  if (isLocal(src))
714  {
715  // Moving local -> local
716  QFileInfo fi(dst);
717  if (QDir().mkpath(fi.path()) && QFile::rename(src, dst))
718  return true;
719 
720  LOG(VB_FILE, LOG_ERR, "RemoteFile::MoveFile: Rename failed");
721  return false;
722  }
723 
724  // Moving remote -> remote
725  QUrl srcUrl(src);
726  QUrl dstUrl(dst);
727 
728  if (srcUrl.userName() != dstUrl.userName())
729  {
730  LOG(VB_FILE, LOG_ERR, "RemoteFile::MoveFile: Cannot change a file's Storage Group");
731  return false;
732  }
733 
734  QStringList strlist("MOVE_FILE");
735  strlist << srcUrl.userName() << srcUrl.path() << dstUrl.path();
736 
738 
739  if (!strlist.isEmpty() && strlist[0] == "1")
740  return true;
741 
742  LOG(VB_FILE, LOG_ERR, QString("RemoteFile::MoveFile: MOVE_FILE failed with: %1")
743  .arg(strlist.join(",")));
744  return false;
745 }
746 
748 {
749  if (isLocal())
750  return;
751  QMutexLocker locker(&m_lock);
752  if (!m_sock)
753  {
754  LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Reset(): Called with no socket");
755  return;
756  }
757  m_sock->Reset();
758 }
759 
760 long long RemoteFile::Seek(long long pos, int whence, long long curpos)
761 {
762  QMutexLocker locker(&m_lock);
763 
764  return SeekInternal(pos, whence, curpos);
765 }
766 
767 long long RemoteFile::SeekInternal(long long pos, int whence, long long curpos)
768 {
769  if (isLocal())
770  {
771  if (!isOpen())
772  {
773  LOG(VB_FILE, LOG_ERR, "RemoteFile::Seek(): Called with no file opened");
774  return -1;
775  }
776  if (m_writeMode)
777  return m_fileWriter->Seek(pos, whence);
778 
779  long long offset = 0LL;
780  if (whence == SEEK_SET)
781  {
782  QFileInfo info(m_path);
783  offset = min(pos, info.size());
784  }
785  else if (whence == SEEK_END)
786  {
787  QFileInfo info(m_path);
788  offset = info.size() + pos;
789  }
790  else if (whence == SEEK_CUR)
791  {
792  offset = ((curpos > 0) ? curpos : ::lseek64(m_localFile, 0, SEEK_CUR)) + pos;
793  }
794  else
795  return -1;
796 
797  off64_t localpos = ::lseek64(m_localFile, pos, whence);
798  if (localpos != pos)
799  {
800  LOG(VB_FILE, LOG_ERR,
801  QString("RemoteFile::Seek(): Couldn't seek to offset %1")
802  .arg(offset));
803  return -1;
804  }
805  return localpos;
806  }
807 
808  if (!CheckConnection(false))
809  {
810  LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Seek(): Couldn't connect");
811  return -1;
812  }
813 
814  QStringList strlist( m_query.arg(m_recorderNum) );
815  strlist << "SEEK";
816  strlist << QString::number(pos);
817  strlist << QString::number(whence);
818  if (curpos > 0)
819  strlist << QString::number(curpos);
820  else
821  strlist << QString::number(m_readPosition);
822 
823  bool ok = m_controlSock->SendReceiveStringList(strlist);
824 
825  if (ok && !strlist.isEmpty())
826  {
827  m_lastPosition = m_readPosition = strlist[0].toLongLong();
828  m_sock->Reset();
829  return strlist[0].toLongLong();
830  }
831  m_lastPosition = 0LL;
832  return -1;
833 }
834 
835 int RemoteFile::Write(const void *data, int size)
836 {
837  int recv = 0;
838  int sent = 0;
839  unsigned zerocnt = 0;
840  bool error = false;
841  bool response = false;
842 
843  if (!m_writeMode)
844  {
845  LOG(VB_NETWORK, LOG_ERR,
846  "RemoteFile::Write(): Called when not in write mode");
847  return -1;
848  }
849  if (isLocal())
850  {
851  if (!isOpen())
852  {
853  LOG(VB_FILE, LOG_ERR,
854  "RemoteFile::Write(): File not opened");
855  return -1;
856  }
857  return m_fileWriter->Write(data, size);
858  }
859 
860  QMutexLocker locker(&m_lock);
861 
862  if (!CheckConnection())
863  {
864  LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Write(): Couldn't connect");
865  return -1;
866  }
867 
868  QStringList strlist( m_query.arg(m_recorderNum) );
869  strlist << "WRITE_BLOCK";
870  strlist << QString::number(size);
871  bool ok = m_controlSock->WriteStringList(strlist);
872  if (!ok)
873  {
874  LOG(VB_NETWORK, LOG_ERR,
875  "RemoteFile::Write(): Block notification failed");
876  return -1;
877  }
878 
879  recv = size;
880  while (sent < recv && !error && zerocnt++ < 50)
881  {
882  int ret = m_sock->Write((char*)data + sent, recv - sent);
883  if (ret > 0)
884  {
885  sent += ret;
886  }
887  else
888  {
889  LOG(VB_GENERAL, LOG_ERR, "RemoteFile::Write(): socket error");
890  error = true;
891  break;
892  }
893 
896  !strlist.isEmpty())
897  {
898  recv = strlist[0].toInt(); // -1 on backend error
899  response = true;
900  }
901  }
902 
903  if (!error && !response)
904  {
906  !strlist.isEmpty())
907  {
908  recv = strlist[0].toInt(); // -1 on backend error
909  }
910  else
911  {
912  LOG(VB_GENERAL, LOG_ERR,
913  "RemoteFile::Write(): No response from control socket.");
914  recv = -1;
915  }
916  }
917 
918  LOG(VB_NETWORK, LOG_DEBUG,
919  QString("RemoteFile::Write(): reqd=%1, sent=%2, rept=%3, error=%4")
920  .arg(size).arg(sent).arg(recv).arg(error));
921 
922  if (recv < 0)
923  return recv;
924 
925  if (error || recv != sent)
926  {
927  sent = -1;
928  }
929  else
930  {
931  m_lastPosition += sent;
932  }
933 
934  return sent;
935 }
936 
937 int RemoteFile::Read(void *data, int size)
938 {
939  int recv = 0;
940  int sent = 0;
941  bool error = false;
942  bool response = false;
943 
944  QMutexLocker locker(&m_lock);
945 
946  if (isLocal())
947  {
948  if (m_writeMode)
949  {
950  LOG(VB_FILE, LOG_ERR, "RemoteFile:Read() called in writing mode");
951  return -1;
952  }
953  if (isOpen())
954  {
955  return ::read(m_localFile, data, size);
956  }
957  LOG(VB_FILE, LOG_ERR, "RemoteFile:Read() called when local file not opened");
958  return -1;
959  }
960 
961  if (!CheckConnection())
962  {
963  LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Read(): Couldn't connect");
964  return -1;
965  }
966 
967  if (m_sock->IsDataAvailable())
968  {
969  LOG(VB_NETWORK, LOG_ERR,
970  "RemoteFile::Read(): Read socket not empty to start!");
971  m_sock->Reset();
972  }
973 
974  while (m_controlSock->IsDataAvailable())
975  {
976  LOG(VB_NETWORK, LOG_WARNING,
977  "RemoteFile::Read(): Control socket not empty to start!");
978  m_controlSock->Reset();
979  }
980 
981  QStringList strlist( m_query.arg(m_recorderNum) );
982  strlist << "REQUEST_BLOCK";
983  strlist << QString::number(size);
984  bool ok = m_controlSock->WriteStringList(strlist);
985  if (!ok)
986  {
987  LOG(VB_NETWORK, LOG_ERR, "RemoteFile::Read(): Block request failed");
988  return -1;
989  }
990 
991  sent = size;
992 
993  int waitms = 30;
994  MythTimer mtimer;
995  mtimer.start();
996 
997  while (recv < sent && !error && mtimer.elapsed() < 10000)
998  {
999  int ret = m_sock->Read(((char *)data) + recv, sent - recv, waitms);
1000 
1001  if (ret > 0)
1002  recv += ret;
1003  else if (ret < 0)
1004  error = true;
1005 
1006  waitms += (waitms < 200) ? 20 : 0;
1007 
1008  if (m_controlSock->IsDataAvailable() &&
1010  !strlist.isEmpty())
1011  {
1012  sent = strlist[0].toInt(); // -1 on backend error
1013  response = true;
1014  if (ret < sent)
1015  {
1016  // We have received less than what the server sent, retry immediately
1017  ret = m_sock->Read(((char *)data) + recv, sent - recv, waitms);
1018  if (ret > 0)
1019  recv += ret;
1020  else if (ret < 0)
1021  error = true;
1022  }
1023  }
1024  }
1025 
1026  if (!error && !response)
1027  {
1028  // Wait up to 1.5s for the backend to send the size
1029  // MythSocket::ReadString will drop the connection
1030  if (m_controlSock->ReadStringList(strlist, 1500) &&
1031  !strlist.isEmpty())
1032  {
1033  sent = strlist[0].toInt(); // -1 on backend error
1034  }
1035  else
1036  {
1037  LOG(VB_GENERAL, LOG_ERR,
1038  "RemoteFile::Read(): No response from control socket.");
1039  // If no data was received from control socket, and we got what we asked for
1040  // assume everything is okay
1041  if (recv == size)
1042  {
1043  sent = recv;
1044  }
1045  else
1046  {
1047  sent = -1;
1048  }
1049  // The TCP socket is dropped if there's a timeout, so we reconnect
1050  if (!Resume())
1051  {
1052  sent = -1;
1053  }
1054  }
1055  }
1056 
1057  LOG(VB_NETWORK, LOG_DEBUG,
1058  QString("Read(): reqd=%1, rcvd=%2, rept=%3, error=%4")
1059  .arg(size).arg(recv).arg(sent).arg(error));
1060 
1061  if (sent < 0)
1062  return sent;
1063 
1064  if (error || sent != recv)
1065  {
1066  LOG(VB_GENERAL, LOG_WARNING,
1067  QString("RemoteFile::Read(): sent %1 != recv %2")
1068  .arg(sent).arg(recv));
1069  recv = -1;
1070 
1071  // The TCP socket is dropped if there's a timeout, so we reconnect
1072  if (!Resume())
1073  {
1074  LOG(VB_GENERAL, LOG_WARNING, "RemoteFile::Read(): Resume failed.");
1075  }
1076  else
1077  LOG(VB_GENERAL, LOG_NOTICE, "RemoteFile::Read(): Resume success.");
1078  }
1079  else
1080  {
1081  m_lastPosition += recv;
1082  }
1083 
1084  return recv;
1085 }
1086 
1092 long long RemoteFile::GetFileSize(void) const
1093 {
1094  if (isLocal())
1095  {
1096  if (isOpen() && m_writeMode)
1097  {
1098  m_fileWriter->Flush();
1099  }
1100  if (Exists(m_path))
1101  {
1102  QFileInfo info(m_path);
1103  return info.size();
1104  }
1105  return -1;
1106  }
1107 
1108  QMutexLocker locker(&m_lock);
1109  return m_fileSize;
1110 }
1111 
1121 {
1122  if (isLocal())
1123  {
1124  return GetFileSize();
1125  }
1126 
1127  QMutexLocker locker(&m_lock);
1128 
1129  if (m_completed ||
1131  {
1132  return m_fileSize;
1133  }
1134 
1135  if (!CheckConnection())
1136  {
1137  // Can't establish a new connection, using system one
1138  struct stat fileinfo {};
1139 
1140  if (Exists(m_path, &fileinfo))
1141  {
1142  m_fileSize = fileinfo.st_size;
1143  }
1144  return m_fileSize;
1145  }
1146 
1147  QStringList strlist(m_query.arg(m_recorderNum));
1148  strlist << "REQUEST_SIZE";
1149 
1150  bool ok = m_controlSock->SendReceiveStringList(strlist);
1151 
1152  if (ok && !strlist.isEmpty())
1153  {
1154  bool validate = false;
1155  long long size = strlist[0].toLongLong(&validate);
1156 
1157  if (validate)
1158  {
1159  if (strlist.count() >= 2)
1160  {
1161  m_completed = (strlist[1].toInt() != 0);
1162  }
1163  m_fileSize = size;
1164  }
1165  else
1166  {
1167  struct stat fileinfo {};
1168 
1169  if (Exists(m_path, &fileinfo))
1170  {
1171  m_fileSize = fileinfo.st_size;
1172  }
1173  }
1175  return m_fileSize;
1176  }
1177 
1178  return -1;
1179 }
1180 
1181 bool RemoteFile::SaveAs(QByteArray &data)
1182 {
1183  long long fs = GetRealFileSize();
1184 
1185  if (fs < 0)
1186  return false;
1187 
1188  data.resize(fs);
1189  Read(data.data(), fs);
1190 
1191  return true;
1192 }
1193 
1194 void RemoteFile::SetTimeout(bool fast)
1195 {
1196  if (isLocal())
1197  {
1198  // not much we can do with local accesses
1199  return;
1200  }
1201  if (m_timeoutIsFast == fast)
1202  return;
1203 
1204  QMutexLocker locker(&m_lock);
1205 
1206  // The m_controlSock variable is valid if the CheckConnection
1207  // function returns true. The local case has already been
1208  // handled. The CheckConnection function can call Resume which
1209  // calls Close, which deletes m_controlSock. However, the
1210  // subsequent call to OpenInternal is guaranteed to recreate the
1211  // socket or return false for a non-local connection, and this must
1212  // be a non-local connection if this line of code is executed.
1213  if (!CheckConnection())
1214  {
1215  LOG(VB_NETWORK, LOG_ERR,
1216  "RemoteFile::SetTimeout(): Couldn't connect");
1217  return;
1218  }
1219  if (m_controlSock == nullptr)
1220  return;
1221 
1222  QStringList strlist( m_query.arg(m_recorderNum) );
1223  strlist << "SET_TIMEOUT";
1224  strlist << QString::number((int)fast);
1225 
1227 
1228  m_timeoutIsFast = fast;
1229 }
1230 
1231 QDateTime RemoteFile::LastModified(const QString &url)
1232 {
1233  if (isLocal(url))
1234  {
1235  QFileInfo info(url);
1236  return info.lastModified();
1237  }
1238  QDateTime result;
1239  QUrl qurl(url);
1240  QString filename = qurl.path();
1241  QString sgroup = qurl.userName();
1242 
1243  if (!qurl.fragment().isEmpty() || url.endsWith("#"))
1244  filename = filename + "#" + qurl.fragment();
1245 
1246  if (filename.startsWith("/"))
1247  filename = filename.right(filename.length()-1);
1248 
1249  if (filename.isEmpty() || sgroup.isEmpty())
1250  return result;
1251 
1252  QStringList strlist("QUERY_SG_FILEQUERY");
1253  strlist << qurl.host();
1254  strlist << sgroup;
1255  strlist << filename;
1256 
1258 
1259  if (strlist.size() > 1) {
1260  if (!strlist[1].isEmpty() && (strlist[1].toInt() != -1))
1261  result = MythDate::fromSecsSinceEpoch(strlist[1].toLongLong());
1262  else
1263  result = QDateTime();;
1264  }
1265 
1266  return result;
1267 }
1268 
1269 QDateTime RemoteFile::LastModified(void) const
1270 {
1271  return LastModified(m_path);
1272 }
1273 
1283 QString RemoteFile::FindFile(const QString& filename, const QString& host,
1284  const QString& storageGroup, bool useRegex,
1285  bool allowFallback)
1286 {
1287  QStringList files = RemoteFile::FindFileList(filename, host, storageGroup, useRegex, allowFallback);
1288 
1289  if (!files.isEmpty())
1290  return files[0];
1291 
1292  return QString();
1293 }
1294 
1304 QStringList RemoteFile::FindFileList(const QString& filename, const QString& host,
1305  const QString& storageGroup, bool useRegex,
1306  bool allowFallback)
1307 {
1308  LOG(VB_FILE, LOG_INFO, QString("RemoteFile::FindFile(): looking for '%1' on '%2' in group '%3' "
1309  "(useregex: %4, allowfallback: %5)")
1310  .arg(filename).arg(host).arg(storageGroup)
1311  .arg(useRegex).arg(allowFallback));
1312 
1313  if (filename.isEmpty() || storageGroup.isEmpty())
1314  return QStringList();
1315 
1316  QStringList strList;
1317  QString hostName = host;
1318 
1319  if (hostName.isEmpty())
1320  hostName = gCoreContext->GetMasterHostName();
1321 
1322  // if we are looking for the file on this host just search the local storage group first
1323  if (gCoreContext->IsThisBackend(hostName))
1324  {
1325  // We could have made it this far with an IP when we really want
1326  // a hostname
1327  hostName = gCoreContext->GetHostName();
1328  StorageGroup sgroup(storageGroup, hostName);
1329 
1330  if (useRegex)
1331  {
1332  QFileInfo fi(filename);
1333  QStringList files = sgroup.GetFileList('/' + fi.path());
1334 
1335  LOG(VB_FILE, LOG_INFO, QString("RemoteFile::FindFileList: Looking in dir '%1' for '%2'")
1336  .arg(fi.path()).arg(fi.fileName()));
1337 
1338  for (int x = 0; x < files.size(); x++)
1339  {
1340  LOG(VB_FILE, LOG_INFO, QString("RemoteFile::FindFileList: Found '%1 - %2'")
1341  .arg(x).arg(files[x]));
1342  }
1343 
1344  QStringList filteredFiles = files.filter(QRegularExpression(fi.fileName()));
1345  for (int x = 0; x < filteredFiles.size(); x++)
1346  {
1349  fi.path() + '/' + filteredFiles[x],
1350  storageGroup);
1351  }
1352  }
1353  else
1354  {
1355  if (!sgroup.FindFile(filename).isEmpty())
1356  {
1357  strList << MythCoreContext::GenMythURL(hostName,
1359  filename, storageGroup);
1360  }
1361  }
1362 
1363  if (!strList.isEmpty() || !allowFallback)
1364  return strList;
1365  }
1366 
1367  // if we didn't find any files ask the master BE to find it
1368  if (strList.isEmpty() && !gCoreContext->IsMasterBackend())
1369  {
1370  strList << "QUERY_FINDFILE" << hostName << storageGroup << filename
1371  << (useRegex ? "1" : "0")
1372  << "1";
1373 
1374  if (gCoreContext->SendReceiveStringList(strList))
1375  {
1376  if (!strList.empty() && !strList[0].isEmpty() &&
1377  strList[0] != "NOT FOUND" && !strList[0].startsWith("ERROR: "))
1378  return strList;
1379  }
1380  }
1381 
1382  return QStringList();
1383 }
1384 
1390 bool RemoteFile::SetBlocking(bool block)
1391 {
1392  if (m_fileWriter)
1393  {
1394  return m_fileWriter->SetBlocking(block);
1395  }
1396  return true;
1397 }
1398 
1406 {
1407  if (IsConnected())
1408  {
1409  return true;
1410  }
1411  if (!m_canResume)
1412  {
1413  return false;
1414  }
1415  return Resume(repos);
1416 }
1417 
1423 {
1424  return m_sock && m_controlSock &&
1426 }
1427 
1433 bool RemoteFile::Resume(bool repos)
1434 {
1435  Close(true);
1436  if (!OpenInternal())
1437  return false;
1438 
1439  if (repos)
1440  {
1442  if (SeekInternal(m_lastPosition, SEEK_SET) < 0)
1443  {
1444  Close(true);
1445  LOG(VB_FILE, LOG_ERR,
1446  QString("RemoteFile::Resume: Enable to re-seek into last known "
1447  "position (%1").arg(m_lastPosition));
1448  return false;
1449  }
1450  }
1452  return true;
1453 }
1454 
1455 /* vim: set expandtab tabstop=4 shiftwidth=4: */
RemoteFile::LastModified
QDateTime LastModified(void) const
Definition: remotefile.cpp:1269
RemoteFile::isLocal
bool isLocal(void) const
Definition: remotefile.cpp:117
RemoteFile::OpenInternal
bool OpenInternal(void)
Attempts to resume from a disconnected step.
Definition: remotefile.cpp:269
RemoteFile::SaveAs
bool SaveAs(QByteArray &data)
Definition: remotefile.cpp:1181
ThreadedFileWriter::Seek
long long Seek(long long pos, int whence)
Seek to a position within stream; May be unsafe.
Definition: threadedfilewriter.cpp:297
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:72
MythCoreContext::GetMasterHostName
QString GetMasterHostName(void)
Definition: mythcorecontext.cpp:825
RemoteFile::m_path
QString m_path
Definition: remotefile.h:78
RemoteFile::GetFileSize
long long GetFileSize(void) const
GetFileSize: returns the remote file's size at the time it was first opened Will query the server in ...
Definition: remotefile.cpp:1092
error
static void error(const char *str,...)
Definition: vbi.cpp:42
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
mythdb.h
MythSocket::SendReceiveStringList
bool SendReceiveStringList(QStringList &list, uint min_reply_length=0, uint timeoutMS=kLongTimeout)
Definition: mythsocket.cpp:336
MythCoreContext::SendReceiveStringList
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
Definition: mythcorecontext.cpp:1379
RemoteFile::ReOpen
bool ReOpen(const QString &newFilename)
Definition: remotefile.cpp:341
MythTimer
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:14
RemoteFile::Exists
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:462
discid.disc.read
def read(device=None, features=[])
Definition: disc.py:35
RemoteFile::m_timeoutMs
int m_timeoutMs
Definition: remotefile.h:80
StorageGroup::FindFile
QString FindFile(const QString &filename)
Definition: storagegroup.cpp:602
MythSocket::Reset
void Reset(void)
Definition: mythsocket.cpp:551
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
RemoteFile::Resume
bool Resume(bool repos=true)
Attempts to resume from a disconnected step.
Definition: remotefile.cpp:1433
arg
arg(title).arg(filename).arg(doDelete))
MythTimer::isRunning
bool isRunning(void) const
Returns true if start() or restart() has been called at least once since construction and since any c...
Definition: mythtimer.cpp:134
RemoteFile::m_lastSizeCheck
MythTimer m_lastSizeCheck
Definition: remotefile.h:95
RemoteFile
Definition: remotefile.h:18
RemoteFile::Open
bool Open(void)
Definition: remotefile.cpp:256
ThreadedFileWriter::Flush
void Flush(void)
Allow DiskLoop() to flush buffer completely ignoring low watermark.
Definition: threadedfilewriter.cpp:318
RemoteFile::RemoteFile
RemoteFile(QString url="", bool write=false, bool usereadahead=true, int timeout_ms=2000, const QStringList *possibleAuxiliaryFiles=nullptr)
Definition: remotefile.cpp:73
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
RemoteFile::Write
int Write(const void *data, int size)
Definition: remotefile.cpp:835
RemoteFile::m_fileWriter
ThreadedFileWriter * m_fileWriter
Definition: remotefile.h:100
GetMythDB
MythDB * GetMythDB(void)
Definition: mythdb.cpp:46
RemoteFile::isOpen
bool isOpen(void) const
Definition: remotefile.cpp:247
build_compdb.file
file
Definition: build_compdb.py:55
RemoteFile::m_controlSock
MythSocket * m_controlSock
Definition: remotefile.h:89
RemoteFile::FindFileList
static QStringList FindFileList(const QString &filename, const QString &host, const QString &storageGroup, bool useRegex=false, bool allowFallback=false)
Search all BE's for files in the give storage group.
Definition: remotefile.cpp:1304
MythSocket::IsConnected
bool IsConnected(void) const
Definition: mythsocket.cpp:561
RemoteFile::SetBlocking
bool SetBlocking(bool m_block=true)
Set write blocking mode for the ThreadedFileWriter instance.
Definition: remotefile.cpp:1390
close
#define close
Definition: compat.h:16
RemoteFile::m_canResume
bool m_canResume
Definition: remotefile.h:85
MythSocket
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:27
MythDate::fromSecsSinceEpoch
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(uint seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...
Definition: mythdate.cpp:68
MythCoreContext::IsMasterBackend
bool IsMasterBackend(void)
is this the actual MBE process
Definition: mythcorecontext.cpp:713
threadedfilewriter.h
mythdate.h
StorageGroup::GetFileList
QStringList GetFileList(const QString &Path, bool recursive=false)
Definition: storagegroup.cpp:271
RemoteFile::Seek
long long Seek(long long pos, int whence, long long curpos=-1)
Definition: remotefile.cpp:760
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:778
MythSocket::WriteStringList
bool WriteStringList(const QStringList &list)
Definition: mythsocket.cpp:311
MythSocket::kShortTimeout
static const uint kShortTimeout
Definition: mythsocket.h:71
remotefile.h
MythCoreContext::GetBackendServerPort
int GetBackendServerPort(void)
Returns the locally defined backend control port.
Definition: mythcorecontext.cpp:1082
RemoteFile::m_sock
MythSocket * m_sock
Definition: remotefile.h:90
compat.h
MythCoreContext::GetBackendServerIP
QString GetBackendServerIP(void)
Returns the IP address of the locally defined backend IP.
Definition: mythcorecontext.cpp:1022
MAX_FILE_CHECK
#define MAX_FILE_CHECK
Definition: remotefile.cpp:38
RemoteFile::Reset
void Reset(void)
Definition: remotefile.cpp:747
RemoteFile::SeekInternal
long long SeekInternal(long long pos, int whence, long long curpos=-1)
Definition: remotefile.cpp:767
RemoteFile::GetFileHash
static QString GetFileHash(const QString &url)
Definition: remotefile.cpp:554
filename
QString filename
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:634
RemoteFile::FindFile
static QString FindFile(const QString &filename, const QString &host, const QString &storageGroup, bool useRegex=false, bool allowFallback=false)
Search all BE's for a file in the give storage group.
Definition: remotefile.cpp:1283
storagegroup.h
RemoteFile::m_lock
QMutex m_lock
Definition: remotefile.h:88
RemoteFile::m_auxFiles
QStringList m_auxFiles
Definition: remotefile.h:98
RemoteFile::m_readPosition
long long m_readPosition
Definition: remotefile.h:83
RemoteFile::DeleteFile
static bool DeleteFile(const QString &url)
Definition: remotefile.cpp:419
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
RemoteFile::SetTimeout
void SetTimeout(bool fast)
Definition: remotefile.cpp:1194
RemoteFile::CopyFile
static bool CopyFile(const QString &src, const QString &dst, bool overwrite=false, bool verify=false)
Definition: remotefile.cpp:588
ThreadedFileWriter::Write
int Write(const void *data, uint count)
Writes data to the end of the write buffer.
Definition: threadedfilewriter.cpp:190
RemoteFile::m_lastPosition
long long m_lastPosition
Definition: remotefile.h:84
ThreadedFileWriter
This class supports the writing of recordings to disk.
Definition: threadedfilewriter.h:44
MythTimer::elapsed
int elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:90
MythSocket::Write
int Write(const char *data, int size)
Definition: mythsocket.cpp:524
MythCoreContext::CheckProtoVersion
bool CheckProtoVersion(MythSocket *socket, uint timeout_ms=kMythSocketLongTimeout, bool error_dialog_desired=false)
Definition: mythcorecontext.cpp:1676
mythmiscutil.h
MythCoreContext::ConnectCommandSocket
MythSocket * ConnectCommandSocket(const QString &hostname, int port, const QString &announcement, bool *proto_mismatch=nullptr, int maxConnTry=-1, int setup_timeout=-1)
Definition: mythcorecontext.cpp:445
mythcorecontext.h
RemoteFile::m_completed
bool m_completed
Definition: remotefile.h:94
dir
QDir dir
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1171
O_LARGEFILE
#define O_LARGEFILE
Definition: remotefile.cpp:20
RemoteFile::m_recorderNum
int m_recorderNum
Definition: remotefile.h:86
MythSocket::IsDataAvailable
bool IsDataAvailable(void)
Definition: mythsocket.cpp:567
RemoteFile::MoveFile
static bool MoveFile(const QString &src, const QString &dst, bool overwrite=false)
Definition: remotefile.cpp:678
StorageGroup
Definition: storagegroup.h:12
RemoteFile::m_fileSize
long long m_fileSize
Definition: remotefile.h:81
mythtimer.h
RemoteFile::m_timeoutIsFast
bool m_timeoutIsFast
Definition: remotefile.h:82
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:856
RemoteFile::Close
void Close(bool haslock=false)
Definition: remotefile.cpp:376
ThreadedFileWriter::Open
bool Open(void)
Opens the file we will be writing to.
Definition: threadedfilewriter.cpp:92
RemoteFile::m_writeMode
bool m_writeMode
Definition: remotefile.h:93
musicbrainzngs.caa.hostname
string hostname
Definition: caa.py:17
RemoteFile::m_possibleAuxFiles
QStringList m_possibleAuxFiles
Definition: remotefile.h:97
RemoteFile::IsConnected
bool IsConnected(void)
Check if both the control and data sockets are currently connected.
Definition: remotefile.cpp:1422
ThreadedFileWriter::SetBlocking
bool SetBlocking(bool block=true)
Set write blocking mode While in blocking mode, ThreadedFileWriter::Write will wait for buffers to be...
Definition: threadedfilewriter.cpp:613
MythSocket::ReadStringList
bool ReadStringList(QStringList &list, uint timeoutMS=kShortTimeout)
Definition: mythsocket.cpp:323
RemoteFile::m_query
QString m_query
Definition: remotefile.h:91
FileHash
QString FileHash(const QString &filename)
Definition: mythmiscutil.cpp:593
RemoteFile::m_localFile
int m_localFile
Definition: remotefile.h:99
RemoteFile::m_useReadAhead
bool m_useReadAhead
Definition: remotefile.h:79
mythsocket.h
RemoteFile::~RemoteFile
~RemoteFile()
Definition: remotefile.cpp:94
RemoteSendReceiveStringList
static bool RemoteSendReceiveStringList(const QString &host, QStringList &strlist)
Definition: remotefile.cpp:40
MythCoreContext::IsThisBackend
bool IsThisBackend(const QString &addr)
is this address mapped to this backend host
Definition: mythcorecontext.cpp:734
MythTimer::restart
int restart(void)
Returns milliseconds elapsed since last start() or restart() and resets the count.
Definition: mythtimer.cpp:62
RemoteFile::openSocket
MythSocket * openSocket(bool control)
Definition: remotefile.cpp:122
RemoteFile::CheckConnection
bool CheckConnection(bool repos=true)
Check current connection and re-establish it if lost.
Definition: remotefile.cpp:1405
RemoteFile::Read
int Read(void *data, int size)
Definition: remotefile.cpp:937
RemoteFile::GetRealFileSize
long long GetRealFileSize(void)
GetRealFileSize: returns the current remote file's size.
Definition: remotefile.cpp:1120
MythSocket::Read
int Read(char *data, int size, int max_wait_ms)
Definition: mythsocket.cpp:537