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 );
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;
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