MythTV  0.26-pre
filetransfer.cpp
Go to the documentation of this file.
00001 #include <QCoreApplication>
00002 #include <QDateTime>
00003 #include <QFileInfo>
00004 
00005 #include "filetransfer.h"
00006 #include "ringbuffer.h"
00007 #include "mythmiscutil.h"
00008 #include "mythsocket.h"
00009 #include "programinfo.h"
00010 #include "mythlogging.h"
00011 
00012 FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
00013                            bool usereadahead, int timeout_ms) :
00014     readthreadlive(true), readsLocked(false),
00015     rbuffer(RingBuffer::Create(filename, false, usereadahead, timeout_ms, true)),
00016     sock(remote), ateof(false), lock(QMutex::NonRecursive),
00017     refLock(QMutex::NonRecursive), refCount(0), writemode(false)
00018 {
00019     pginfo = new ProgramInfo(filename);
00020     pginfo->MarkAsInUse(true, kFileTransferInUseID);
00021     rbuffer->Start();
00022 }
00023 
00024 FileTransfer::FileTransfer(QString &filename, MythSocket *remote, bool write) :
00025     readthreadlive(true), readsLocked(false),
00026     rbuffer(RingBuffer::Create(filename, write)),
00027     sock(remote), ateof(false), lock(QMutex::NonRecursive),
00028     refLock(QMutex::NonRecursive), refCount(0), writemode(write)
00029 {
00030     pginfo = new ProgramInfo(filename);
00031     pginfo->MarkAsInUse(true, kFileTransferInUseID);
00032 
00033     if (write)
00034         remote->useReadyReadCallback(false);
00035     rbuffer->Start();
00036 }
00037 
00038 FileTransfer::~FileTransfer()
00039 {
00040     Stop();
00041 
00042     if (rbuffer)
00043     {
00044         delete rbuffer;
00045         rbuffer = NULL;
00046     }
00047 
00048     if (pginfo)
00049     {
00050         pginfo->MarkAsInUse(false, kFileTransferInUseID);
00051         delete pginfo;
00052     }
00053 }
00054 
00055 void FileTransfer::UpRef(void)
00056 {
00057     QMutexLocker locker(&refLock);
00058     refCount++;
00059 }
00060 
00061 bool FileTransfer::DownRef(void)
00062 {
00063     int count = 0;
00064     {
00065         QMutexLocker locker(&refLock);
00066         count = --refCount;
00067     }
00068 
00069     if (count < 0)
00070         delete this;
00071     
00072     return (count < 0);
00073 }
00074 
00075 bool FileTransfer::isOpen(void)
00076 {
00077     if (rbuffer && rbuffer->IsOpen())
00078         return true;
00079     return false;
00080 }
00081 
00082 bool FileTransfer::ReOpen(QString newFilename)
00083 {
00084     if (!writemode)
00085         return false;
00086 
00087     if (rbuffer)
00088         return rbuffer->ReOpen(newFilename);
00089 
00090     return false;
00091 }
00092 
00093 void FileTransfer::Stop(void)
00094 {
00095     if (readthreadlive)
00096     {
00097         readthreadlive = false;
00098         LOG(VB_FILE, LOG_INFO, "calling StopReads()");
00099         rbuffer->StopReads();
00100         QMutexLocker locker(&lock);
00101         readsLocked = true;
00102     }
00103 
00104     if (writemode)
00105         rbuffer->WriterFlush();
00106 
00107     if (pginfo)
00108         pginfo->UpdateInUseMark();
00109 }
00110 
00111 void FileTransfer::Pause(void)
00112 {
00113     LOG(VB_FILE, LOG_INFO, "calling StopReads()");
00114     rbuffer->StopReads();
00115     QMutexLocker locker(&lock);
00116     readsLocked = true;
00117 
00118     if (pginfo)
00119         pginfo->UpdateInUseMark();
00120 }
00121 
00122 void FileTransfer::Unpause(void)
00123 {
00124     LOG(VB_FILE, LOG_INFO, "calling StartReads()");
00125     rbuffer->StartReads();
00126     {
00127         QMutexLocker locker(&lock);
00128         readsLocked = false;
00129     }
00130     readsUnlockedCond.wakeAll();
00131 
00132     if (pginfo)
00133         pginfo->UpdateInUseMark();
00134 }
00135 
00136 int FileTransfer::RequestBlock(int size)
00137 {
00138     if (!readthreadlive || !rbuffer)
00139         return -1;
00140 
00141     int tot = 0;
00142     int ret = 0;
00143 
00144     QMutexLocker locker(&lock);
00145     while (readsLocked)
00146         readsUnlockedCond.wait(&lock, 100 /*ms*/);
00147 
00148     requestBuffer.resize(max((size_t)max(size,0) + 128, requestBuffer.size()));
00149     char *buf = &requestBuffer[0];
00150     while (tot < size && !rbuffer->GetStopReads() && readthreadlive)
00151     {
00152         int request = size - tot;
00153 
00154         ret = rbuffer->Read(buf, request);
00155         
00156         if (rbuffer->GetStopReads() || ret <= 0)
00157             break;
00158 
00159         if (!sock->writeData(buf, (uint)ret))
00160         {
00161             tot = -1;
00162             break;
00163         }
00164 
00165         tot += ret;
00166         if (ret < request)
00167             break; // we hit eof
00168     }
00169 
00170     if (pginfo)
00171         pginfo->UpdateInUseMark();
00172 
00173     return (ret < 0) ? -1 : tot;
00174 }
00175 
00176 int FileTransfer::WriteBlock(int size)
00177 {
00178     if (!writemode || !rbuffer)
00179         return -1;
00180 
00181     int tot = 0;
00182     int ret = 0;
00183 
00184     QMutexLocker locker(&lock);
00185 
00186     requestBuffer.resize(max((size_t)max(size,0) + 128, requestBuffer.size()));
00187     char *buf = &requestBuffer[0];
00188     while (tot < size)
00189     {
00190         int request = size - tot;
00191 
00192         if (!sock->readData(buf, (uint)request))
00193             break;
00194 
00195         ret = rbuffer->Write(buf, request);
00196         
00197         if (ret <= 0)
00198             break;
00199 
00200         tot += request;
00201     }
00202 
00203     if (pginfo)
00204         pginfo->UpdateInUseMark();
00205 
00206     return (ret < 0) ? -1 : tot;
00207 }
00208 
00209 long long FileTransfer::Seek(long long curpos, long long pos, int whence)
00210 {
00211     if (pginfo)
00212         pginfo->UpdateInUseMark();
00213 
00214     if (!rbuffer)
00215         return -1;
00216     if (!readthreadlive)
00217         return -1;
00218 
00219     ateof = false;
00220 
00221     Pause();
00222 
00223     if (whence == SEEK_CUR)
00224     {
00225         long long desired = curpos + pos;
00226         long long realpos = rbuffer->GetReadPosition();
00227 
00228         pos = desired - realpos;
00229     }
00230 
00231     long long ret = rbuffer->Seek(pos, whence);
00232 
00233     Unpause();
00234 
00235     if (pginfo)
00236         pginfo->UpdateInUseMark();
00237 
00238     return ret;
00239 }
00240 
00241 uint64_t FileTransfer::GetFileSize(void)
00242 {
00243     if (pginfo)
00244         pginfo->UpdateInUseMark();
00245 
00246     return QFileInfo(rbuffer->GetFilename()).size();
00247 }
00248 
00249 void FileTransfer::SetTimeout(bool fast)
00250 {
00251     if (pginfo)
00252         pginfo->UpdateInUseMark();
00253 
00254     rbuffer->SetOldFile(fast);
00255 }
00256 
00257 /* vim: set expandtab tabstop=4 shiftwidth=4: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends