00001 #include <qurl.h>
00002
00003 #include <unistd.h>
00004
00005 #include <iostream>
00006 using namespace std;
00007
00008 #include "remotefile.h"
00009 #include "util.h"
00010 #include "mythcontext.h"
00011 #include "mythsocket.h"
00012 #include "compat.h"
00013
00014 RemoteFile::RemoteFile(const QString &_path, bool useRA, int _retries) :
00015 path(_path),
00016 usereadahead(useRA), retries(_retries),
00017 filesize(-1), timeoutisfast(false),
00018 readposition(0), recordernum(0),
00019 lock(false),
00020 controlSock(NULL), sock(NULL),
00021 query("QUERY_FILETRANSFER %1")
00022 {
00023 Open();
00024 }
00025
00026 RemoteFile::~RemoteFile()
00027 {
00028 Close();
00029 if (controlSock)
00030 controlSock->DownRef();
00031 if (sock)
00032 sock->DownRef();
00033 }
00034
00035 MythSocket *RemoteFile::openSocket(bool control)
00036 {
00037 QUrl qurl(path);
00038
00039 QString host = qurl.host();
00040 int port = qurl.port();
00041 QString dir = qurl.path();
00042
00043 MythSocket *lsock = new MythSocket();
00044 QString stype = (control) ? "control socket" : "file data socket";
00045
00046 if (!lsock->connect(host, port))
00047 {
00048 VERBOSE(VB_IMPORTANT,
00049 QString("RemoteFile::openSocket(%1): \n"
00050 "\t\t\tCould not connect to server \"%2\" @ port %3")
00051 .arg(stype).arg(host).arg(port));
00052 lsock->DownRef();
00053 return NULL;
00054 }
00055
00056 QString hostname = gContext->GetHostName();
00057
00058 QStringList strlist;
00059
00060 if (control)
00061 {
00062 strlist = QString("ANN Playback %1 %2").arg(hostname).arg(false);
00063 lsock->writeStringList(strlist);
00064 lsock->readStringList(strlist, true);
00065 }
00066 else
00067 {
00068 strlist = QString("ANN FileTransfer %1 %2 %3")
00069 .arg(hostname).arg(usereadahead).arg(retries);
00070 strlist << QString("%1").arg(dir);
00071
00072 lsock->writeStringList(strlist);
00073 lsock->readStringList(strlist, true);
00074
00075 if (strlist.size() < 4)
00076 {
00077 VERBOSE(VB_IMPORTANT,
00078 QString("RemoteFile::openSocket(%1): "
00079 "Did not get proper responce from %3:%4")
00080 .arg(stype).arg(dir).arg(host).arg(port));
00081
00082 return NULL;
00083 }
00084
00085 recordernum = strlist[1].toInt();
00086 filesize = decodeLongLong(strlist, 2);
00087 }
00088
00089 return lsock;
00090 }
00091
00092 bool RemoteFile::Open(void)
00093 {
00094 controlSock = openSocket(true);
00095 sock = openSocket(false);
00096 return isOpen();
00097 }
00098
00099 void RemoteFile::Close(void)
00100 {
00101 if (!controlSock)
00102 return;
00103
00104 QStringList strlist = QString(query).arg(recordernum);
00105 strlist << "DONE";
00106
00107 lock.lock();
00108 controlSock->writeStringList(strlist);
00109 if (!controlSock->readStringList(strlist, true))
00110 {
00111 VERBOSE(VB_IMPORTANT, "Remote file timeout.");
00112 }
00113
00114 if (sock)
00115 {
00116 sock->DownRef();
00117 sock = NULL;
00118 }
00119 if (controlSock)
00120 {
00121 controlSock->DownRef();
00122 controlSock = NULL;
00123 }
00124
00125 lock.unlock();
00126 }
00127
00128 void RemoteFile::Reset(void)
00129 {
00130 if (!sock)
00131 {
00132 VERBOSE(VB_NETWORK, "RemoteFile::Reset(): Called with no socket");
00133 return;
00134 }
00135
00136 while (sock->bytesAvailable() > 0)
00137 {
00138 int avail;
00139 char *trash;
00140
00141 lock.lock();
00142 avail = sock->bytesAvailable();
00143 trash = new char[avail + 1];
00144 sock->readBlock(trash, avail);
00145 delete [] trash;
00146 lock.unlock();
00147
00148 VERBOSE(VB_NETWORK, QString ("%1 bytes available during reset.")
00149 .arg(avail));
00150 usleep(30000);
00151 }
00152 }
00153
00154 long long RemoteFile::Seek(long long pos, int whence, long long curpos)
00155 {
00156 if (!sock)
00157 {
00158 VERBOSE(VB_NETWORK, "RemoteFile::Seek(): Called with no socket");
00159 return 0;
00160 }
00161
00162 if (!sock->isOpen() || sock->error())
00163 return 0;
00164
00165 if (!controlSock->isOpen() || controlSock->error())
00166 return 0;
00167
00168 QStringList strlist = QString(query).arg(recordernum);
00169 strlist << "SEEK";
00170 encodeLongLong(strlist, pos);
00171 strlist << QString::number(whence);
00172 if (curpos > 0)
00173 encodeLongLong(strlist, curpos);
00174 else
00175 encodeLongLong(strlist, readposition);
00176
00177 lock.lock();
00178 controlSock->writeStringList(strlist);
00179 controlSock->readStringList(strlist);
00180 lock.unlock();
00181
00182 long long retval = decodeLongLong(strlist, 0);
00183 readposition = retval;
00184
00185 Reset();
00186
00187 return retval;
00188 }
00189
00190 int RemoteFile::Read(void *data, int size)
00191 {
00192 int recv = 0;
00193 int sent = 0;
00194 unsigned zerocnt = 0;
00195 bool error = false;
00196 bool response = false;
00197
00198 if (!sock)
00199 {
00200 VERBOSE(VB_NETWORK, "RemoteFile::Read(): Called with no socket");
00201 return -1;
00202 }
00203
00204 if (!sock->isOpen() || sock->error())
00205 return -1;
00206
00207 if (!controlSock->isOpen() || controlSock->error())
00208 return -1;
00209
00210 lock.lock();
00211
00212 if (sock->bytesAvailable() > 0)
00213 {
00214 VERBOSE(VB_NETWORK,
00215 "RemoteFile::Read(): Read socket not empty to start!");
00216 while (sock->waitForMore(5) > 0)
00217 {
00218 int avail = sock->bytesAvailable();
00219 char *trash = new char[avail + 1];
00220 sock->readBlock(trash, avail);
00221 delete [] trash;
00222 }
00223 }
00224
00225 if (controlSock->bytesAvailable() > 0)
00226 {
00227 VERBOSE(VB_NETWORK,
00228 "RemoteFile::Read(): Control socket not empty to start!");
00229 QStringList tempstrlist;
00230 controlSock->readStringList(tempstrlist);
00231 }
00232
00233 QStringList strlist = QString(query).arg(recordernum);
00234 strlist << "REQUEST_BLOCK";
00235 strlist << QString::number(size);
00236 controlSock->writeStringList(strlist);
00237
00238 sent = size;
00239
00240 while (recv < sent && !error && zerocnt++ < 50)
00241 {
00242 while (recv < sent && sock->waitForMore(200) > 0)
00243 {
00244 int ret = sock->readBlock(((char *)data) + recv, sent - recv);
00245 if (ret > 0)
00246 {
00247 recv += ret;
00248 }
00249 else if (sock->error() != MythSocket::NoError)
00250 {
00251 VERBOSE(VB_IMPORTANT, "RemoteFile::Read(): socket error");
00252 error = true;
00253 break;
00254 }
00255 }
00256
00257 if (controlSock->bytesAvailable() > 0)
00258 {
00259 controlSock->readStringList(strlist, true);
00260 sent = strlist[0].toInt();
00261 response = true;
00262 }
00263 }
00264
00265 if (!error && !response)
00266 {
00267 if (controlSock->readStringList(strlist, true))
00268 {
00269 sent = strlist[0].toInt();
00270 }
00271 else
00272 {
00273 VERBOSE(VB_IMPORTANT,
00274 "RemoteFile::Read(): No response from control socket.");
00275 sent = -1;
00276 }
00277 }
00278
00279 lock.unlock();
00280
00281 VERBOSE(VB_NETWORK, QString("Read(): reqd=%1, rcvd=%2, rept=%3, error=%4")
00282 .arg(size).arg(recv).arg(sent).arg(error));
00283
00284 if (sent < 0)
00285 return sent;
00286
00287 if (error || sent != recv)
00288 recv = -1;
00289
00290 return recv;
00291 }
00292
00293 bool RemoteFile::SaveAs(QByteArray &data)
00294 {
00295 if (filesize < 0)
00296 return false;
00297
00298 data.resize(filesize);
00299 Read(data.data(), filesize);
00300
00301 return true;
00302 }
00303
00304 void RemoteFile::SetTimeout(bool fast)
00305 {
00306 if (timeoutisfast == fast)
00307 return;
00308
00309 if (!sock)
00310 {
00311 VERBOSE(VB_NETWORK, "RemoteFile::Seek(): Called with no socket");
00312 return;
00313 }
00314
00315 if (!sock->isOpen() || sock->error())
00316 return;
00317
00318 if (!controlSock->isOpen() || controlSock->error())
00319 return;
00320
00321 QStringList strlist = QString(query).arg(recordernum);
00322 strlist << "SET_TIMEOUT";
00323 strlist << QString::number((int)fast);
00324
00325 lock.lock();
00326 controlSock->writeStringList(strlist);
00327 controlSock->readStringList(strlist);
00328 lock.unlock();
00329
00330 timeoutisfast = fast;
00331 }
00332