tools/qtestlib/wince/cetcpsync/qtcesterconnection.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 #include "qtcesterconnection.h"
       
    42 #include <transfer_global.h>
       
    43 #include <QtCore/QDir>
       
    44 #include <QtCore/QFile>
       
    45 #include <QtCore/QFileInfo>
       
    46 #include <QtNetwork/QTcpSocket>
       
    47 #include <QtNetwork/QHostAddress>
       
    48 
       
    49 extern void debugOutput(const QString& text, int level);
       
    50 
       
    51 #pragma warning(disable:4996)
       
    52 
       
    53 #define END_ERROR(s, a) \
       
    54             if(a) qDebug() << a; \
       
    55             _freeSocket(s); \
       
    56             return false;
       
    57 
       
    58 QtCesterConnection::QtCesterConnection()
       
    59         : AbstractRemoteConnection()
       
    60 {
       
    61 }
       
    62 
       
    63 QtCesterConnection::~QtCesterConnection()
       
    64 {
       
    65 }
       
    66 
       
    67 bool QtCesterConnection::connect(QVariantList&)
       
    68 {
       
    69     // We connect with each command, so this is always true
       
    70     // The command itself will fail then
       
    71     connected = true;
       
    72     return true;
       
    73 }
       
    74 
       
    75 void QtCesterConnection::disconnect()
       
    76 {
       
    77     connected = false;
       
    78 }
       
    79 
       
    80 bool QtCesterConnection::isConnected() const
       
    81 {
       
    82     return connected;
       
    83 }
       
    84 
       
    85 bool QtCesterConnection::copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists)
       
    86 {
       
    87     debugOutput( qPrintable(QString::fromLatin1("Copy File: %1 -> %2").arg(localSource).arg(deviceDest)),0);
       
    88     QFile localFile(localSource);
       
    89     QFileInfo info(localSource);
       
    90     if (!localFile.exists() || !localFile.open(QIODevice::ReadOnly)) {
       
    91         qDebug() << "Could not open File!";
       
    92         return false;
       
    93     }
       
    94     
       
    95     QTcpSocket* socket = 0;
       
    96     if (!_initCommand(socket, COMMAND_CREATE_FILE)) {
       
    97         END_ERROR(socket, "Could not initialized command");
       
    98     }
       
    99     
       
   100     CreateFileOptions option;
       
   101     strcpy(option.fileName, qPrintable(deviceDest));
       
   102 #ifdef Q_OS_WIN
       
   103     // Copy FileTime for update verification
       
   104     FILETIME creationTime, accessTime, writeTime;
       
   105     HANDLE localHandle = CreateFile(localSource.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
       
   106     if (localHandle != INVALID_HANDLE_VALUE) {
       
   107         if (GetFileTime(localHandle, &creationTime, &accessTime, &writeTime)) {
       
   108             LocalFileTimeToFileTime(&writeTime, &writeTime);
       
   109             option.fileTime = writeTime;
       
   110         }
       
   111         CloseHandle(localHandle);
       
   112     }
       
   113     DWORD attributes = GetFileAttributes(localSource.utf16());
       
   114     if (attributes != -1 )
       
   115         option.fileAttributes = attributes;
       
   116 #endif
       
   117     option.fileSize = info.size();
       
   118     option.overwriteExisting = !failIfExists;
       
   119     
       
   120     if (!_sendData(socket, (char*) &option, sizeof(option))) {
       
   121         END_ERROR(socket, "Could not send options...");
       
   122     }
       
   123 
       
   124     if (!_checkResult(socket)) {
       
   125         END_ERROR(socket, "Server did not accept configuration");
       
   126     }
       
   127     
       
   128     int bytesWritten = 0;
       
   129     const int bufferSize = 1024;
       
   130     QByteArray data;
       
   131     while (bytesWritten < option.fileSize) {
       
   132         data = localFile.read(bufferSize);
       
   133         bytesWritten += data.size();
       
   134 #ifdef Q_OS_WIN
       
   135         wprintf( L"%s -> %s (%d / %d) %d %%\r", localSource.utf16() , deviceDest.utf16(),
       
   136                  bytesWritten , option.fileSize, (100*bytesWritten)/option.fileSize );
       
   137 #endif
       
   138         if (!_sendData(socket, data.constData(), data.size())) {
       
   139             END_ERROR(socket, "Error during file transfer");
       
   140         }
       
   141         if (!_checkResult(socket)) {
       
   142             END_ERROR(socket, "Got some strange result");
       
   143         }
       
   144     }
       
   145 #ifdef Q_OS_WIN
       
   146     wprintf( L"\n"); // We should jump to next line...
       
   147 #endif
       
   148     if (bytesWritten != option.fileSize) {
       
   149         END_ERROR(socket, "Did not send sufficient data");
       
   150     }
       
   151     _freeSocket(socket);
       
   152     return true;
       
   153 }
       
   154 
       
   155 bool QtCesterConnection::copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive)
       
   156 {
       
   157     QTcpSocket* socket = NULL;
       
   158     QFileInfo info(localSource);
       
   159     if (!info.exists() || !info.isDir()) {
       
   160         END_ERROR(socket, "Input directory invalid");
       
   161     }
       
   162     
       
   163     createDirectory(deviceDest, true);
       
   164     QDir dir(localSource);
       
   165     QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
       
   166     foreach(QFileInfo item, list) {
       
   167         QString targetName = deviceDest + QLatin1String("\\") + item.fileName();
       
   168         if (item.isDir()) {
       
   169             if (recursive) {
       
   170                 if (!copyDirectoryToDevice(item.absoluteFilePath() , targetName, recursive))
       
   171                     return false;
       
   172             }
       
   173         } else {
       
   174             if (!copyFileToDevice(item.absoluteFilePath(), targetName))
       
   175                 return false;
       
   176         }
       
   177     }
       
   178     return true;
       
   179 }
       
   180 
       
   181 bool QtCesterConnection::copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists)
       
   182 {
       
   183     QFile targetFile(localDest);
       
   184     QTcpSocket* socket = 0;
       
   185     if (targetFile.exists() && failIfExists) {
       
   186         END_ERROR(socket, "Local file not supposed to be overwritten");
       
   187     }
       
   188     
       
   189     if (!targetFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
       
   190         END_ERROR(socket, "Could not open local file for writing");
       
   191     }
       
   192     
       
   193     if (!_initCommand(socket, COMMAND_READ_FILE)) {
       
   194         END_ERROR(socket, "Could not establish connection");
       
   195     }
       
   196     
       
   197     ReadFileOptions option;
       
   198     strcpy(option.fileName, qPrintable(deviceSource));
       
   199     if (!_sendData(socket, (char*) &option, sizeof(option))) {
       
   200         END_ERROR(socket, "Could not send options");
       
   201     }
       
   202     
       
   203     QByteArray data;
       
   204     if (!_receiveData(socket, data)) {
       
   205         END_ERROR(socket, "Did not receive any data");
       
   206     }
       
   207     
       
   208     ReadFileReply* reply = (ReadFileReply*) data.data();
       
   209     if (!reply->fileValid) {
       
   210         END_ERROR(socket, "Requested file invalid");
       
   211     }
       
   212     
       
   213     int fileSize = reply->fileSize;
       
   214     int currentSize = 0;
       
   215     // ### TODO: make a little bit more error-prone
       
   216     do {
       
   217         _sendData(socket, COMMAND_SUCCESS, strlen(COMMAND_SUCCESS));
       
   218         _receiveData(socket, data);
       
   219         currentSize += data.size();
       
   220         targetFile.write(data);
       
   221     } while(currentSize < fileSize);
       
   222     
       
   223     _freeSocket(socket);
       
   224     targetFile.close();
       
   225     return true;
       
   226 }
       
   227  
       
   228 bool QtCesterConnection::copyDirectoryFromDevice(const QString& /*deviceSource*/
       
   229                                                  , const QString& /*localDest*/
       
   230                                                  , bool /*recursive*/)
       
   231 {
       
   232     qDebug() << "To be implemented!! Should not be needed for autotest system";
       
   233     exit(-1);
       
   234     return false;
       
   235 }
       
   236 
       
   237 bool QtCesterConnection::copyFile(const QString &srcFile, const QString &destFile, bool failIfExists)
       
   238 {
       
   239     QTcpSocket* socket = 0;
       
   240     if (!_initCommand(socket, COMMAND_COPY_FILE)) {
       
   241         END_ERROR(socket, "Could not establish connection for copy");
       
   242     }
       
   243     
       
   244     CopyFileOptions option;
       
   245     strcpy(option.from, qPrintable(srcFile));
       
   246     strcpy(option.to, qPrintable(destFile));
       
   247     option.overwriteExisting = !failIfExists;
       
   248     if (!_sendData(socket, (char*) &option, sizeof(option))) {
       
   249         END_ERROR(socket, "Could not send copy options");
       
   250     }
       
   251     
       
   252     if (!_checkResult(socket)) {
       
   253         END_ERROR(socket, "Copy failed");
       
   254     }
       
   255     
       
   256     _freeSocket(socket);
       
   257     return true;
       
   258 }
       
   259 
       
   260 bool QtCesterConnection::copyDirectory(const QString &srcDirectory, const QString &destDirectory,
       
   261                                       bool recursive)
       
   262 {
       
   263     QTcpSocket* socket = 0;
       
   264     if (!_initCommand(socket, COMMAND_COPY_DIRECTORY)) {
       
   265         END_ERROR(socket, "Could not establish connection for dir copy");
       
   266     }
       
   267     
       
   268     CopyDirectoryOptions option;
       
   269     strcpy(option.from, qPrintable(srcDirectory));
       
   270     strcpy(option.to, qPrintable(destDirectory));
       
   271     option.recursive = recursive;
       
   272     if (!_sendData(socket, (char*) &option, sizeof(option))) {
       
   273         END_ERROR(socket, "Could not send dir copy options");
       
   274     }
       
   275     
       
   276     if (!_checkResult(socket)) {
       
   277         END_ERROR(socket, "Dir Copy failed");
       
   278     }
       
   279     
       
   280     _freeSocket(socket);
       
   281     return true;
       
   282 }
       
   283 
       
   284 bool QtCesterConnection::deleteFile(const QString &fileName)
       
   285 {
       
   286     QTcpSocket* socket = 0;
       
   287     if (!_initCommand(socket, COMMAND_DELETE_FILE)) {
       
   288         END_ERROR(socket, "Could not establish connection for file deletion");
       
   289     }
       
   290     
       
   291     DeleteFileOptions option;
       
   292     strcpy(option.fileName, qPrintable(fileName));
       
   293     if (!_sendData(socket, (char*) &option, sizeof(option))) {
       
   294         END_ERROR(socket, "Could not send file options");
       
   295     }
       
   296     
       
   297     if (!_checkResult(socket)) {
       
   298         //END_ERROR(socket, "File Deletion failed");
       
   299         // This is actually not an error so ignore it.
       
   300     }
       
   301     
       
   302     _freeSocket(socket);
       
   303     return true;
       
   304 }
       
   305 
       
   306 bool QtCesterConnection::deleteDirectory(const QString &directory, bool recursive, bool failIfContentExists)
       
   307 {
       
   308     QTcpSocket* socket = 0;
       
   309     if (!_initCommand(socket, COMMAND_DELETE_DIRECTORY)) {
       
   310         END_ERROR(socket, "Could not establish connection for dir deletion");
       
   311     }
       
   312     
       
   313     DeleteDirectoryOptions option;
       
   314     strcpy(option.dirName, qPrintable(directory));
       
   315     option.recursive = recursive;
       
   316     option.failIfContentExists = failIfContentExists;
       
   317     if (!_sendData(socket, (char*) &option, sizeof(option))) {
       
   318         END_ERROR(socket, "Could not send dir options");
       
   319     }
       
   320     
       
   321     if (!_checkResult(socket)) {
       
   322         // we do not write an error as this will fail a lot on recursive.
       
   323         END_ERROR(socket, 0);
       
   324     }
       
   325     
       
   326     _freeSocket(socket);
       
   327     return true;
       
   328 }
       
   329 
       
   330 bool QtCesterConnection::execute(QString program,
       
   331                                  QString arguments,
       
   332                                  int timeout,
       
   333                                  int *returnValue)
       
   334 {
       
   335     QTcpSocket* socket = 0;
       
   336     if (!_initCommand(socket, COMMAND_EXECUTE)) {
       
   337         END_ERROR(socket, "Could not establish connection for dir deletion");
       
   338     }
       
   339 
       
   340     ExecuteOptions options;
       
   341     strcpy(options.appName, qPrintable(program));
       
   342     QStringList argList = arguments.split(QLatin1Char(' '));
       
   343     options.argumentsCount = qMin(argList.size(), MAX_ARGUMENTS);
       
   344     options.waitForFinished = true;
       
   345     options.timeout = timeout;
       
   346     if (!_sendData(socket, (char*) &options, sizeof(options))) {
       
   347         END_ERROR(socket, "Could not send dir options");
       
   348     }
       
   349     if (!_checkResult(socket)) {
       
   350         END_ERROR(socket, "Did not receive an answer");
       
   351     }
       
   352 
       
   353     for (int i=0; i < options.argumentsCount; ++i) {
       
   354         char someData[MAX_NAME_LENGTH];
       
   355         strcpy(someData, qPrintable(argList[i]));
       
   356         if (!_sendData(socket, someData, MAX_NAME_LENGTH)) {
       
   357             END_ERROR(socket, "Could not send argument");
       
   358         }
       
   359         if (!_checkResult(socket)) {
       
   360             END_ERROR(socket, "Failure in argument send");
       
   361         }
       
   362     }
       
   363 
       
   364     // trigger the startup
       
   365     if (!_sendData(socket, COMMAND_SUCCESS, strlen(COMMAND_SUCCESS))) {
       
   366         END_ERROR(socket, "Could not trigger startup");
       
   367     }
       
   368     
       
   369     const int waitTime = 60 * 60 * 1000;
       
   370     if (!socket->waitForReadyRead(waitTime)) {
       
   371         END_ERROR(socket, "Process timed out");
       
   372     }
       
   373     
       
   374     QByteArray result = socket->readAll();
       
   375     if (result != COMMAND_SUCCESS) {
       
   376         if (returnValue)
       
   377             *returnValue = -1; // just some at least
       
   378         END_ERROR(socket, "Application did not start or returned error");
       
   379     }
       
   380     
       
   381     if (returnValue)
       
   382         *returnValue = 0;
       
   383     _freeSocket(socket);
       
   384     return true;
       
   385 }
       
   386 
       
   387 bool QtCesterConnection::createDirectory(const QString &path, bool deleteBefore)
       
   388 {
       
   389     if (deleteBefore)
       
   390         deleteDirectory(path, true, true);
       
   391     
       
   392     QTcpSocket* socket = 0;
       
   393     if (!_initCommand(socket, COMMAND_CREATE_DIRECTORY)) {
       
   394         END_ERROR(socket, "Could not establish connection for dir creation");
       
   395     }
       
   396     
       
   397     CreateDirectoryOptions option;
       
   398     strcpy(option.dirName, qPrintable(path));
       
   399     option.recursively = true;
       
   400     if (!_sendData(socket, (char*) &option, sizeof(option))) {
       
   401         END_ERROR(socket, "Could not send dir options");
       
   402     }
       
   403     
       
   404     if (!_checkResult(socket)) {
       
   405         END_ERROR(socket, "Dir creation failed");
       
   406     }
       
   407     
       
   408     _freeSocket(socket);
       
   409     return true;
       
   410 }
       
   411 
       
   412 bool QtCesterConnection::timeStampForLocalFileTime(FILETIME* fTime) const
       
   413 {
       
   414     if (!fTime)
       
   415         return false;
       
   416     
       
   417     FILETIME copyTime = *fTime;
       
   418     LocalFileTimeToFileTime(&copyTime, &copyTime);
       
   419     
       
   420     QTcpSocket* socket = 0;
       
   421     if (!_initCommand(socket, COMMAND_TIME_STAMP)) {
       
   422         END_ERROR(socket, "Could not establish time stamp connection");
       
   423     }
       
   424     
       
   425     if (!_sendData(socket, (char*) &copyTime, sizeof(copyTime))) {
       
   426         END_ERROR(socket, "Could not send stamp time");
       
   427     }
       
   428     
       
   429     QByteArray data;
       
   430     if (!_receiveData(socket, data)) {
       
   431         END_ERROR(socket, "Did not receive time stamp or connection interrupted");
       
   432     }
       
   433     
       
   434     copyTime = *((FILETIME*)data.data());
       
   435     if (copyTime.dwLowDateTime == -1 && copyTime.dwHighDateTime == -1) {
       
   436         END_ERROR(socket, "remote Time stamp failed!");
       
   437     }
       
   438     
       
   439     *fTime = copyTime;
       
   440     _freeSocket(socket);
       
   441     return true;
       
   442 }
       
   443 
       
   444 bool QtCesterConnection::fileCreationTime(const QString &fileName, FILETIME* deviceCreationTime) const
       
   445 {
       
   446     if (!deviceCreationTime)
       
   447         return false;
       
   448     
       
   449     QTcpSocket* socket = 0;
       
   450     if (!_initCommand(socket, COMMAND_FILE_TIME)) {
       
   451         END_ERROR(socket, "Could not establish connection for file time access");
       
   452     }
       
   453     
       
   454     FileTimeOptions option;
       
   455     strcpy(option.fileName, qPrintable(fileName));
       
   456     if (!_sendData(socket, (char*) &option, sizeof(option))) {
       
   457         END_ERROR(socket, "Could not send file time name");
       
   458     }
       
   459     
       
   460     QByteArray data;
       
   461     if (!_receiveData(socket, data)) {
       
   462         END_ERROR(socket, "File Time request failed");
       
   463     }
       
   464     
       
   465     FILETIME* resultTime = (FILETIME*) data.data();
       
   466     if (resultTime->dwLowDateTime == -1 && resultTime->dwHighDateTime == -1) {
       
   467         END_ERROR(socket, 0);
       
   468         debugOutput("Could not access file time", 0);
       
   469     }
       
   470     
       
   471     *deviceCreationTime = *resultTime;
       
   472     _freeSocket(socket);
       
   473     return true;
       
   474 }
       
   475 
       
   476 bool QtCesterConnection::_createSocket(QTcpSocket*& result) const
       
   477 {
       
   478     QTcpSocket* sock = new QTcpSocket();
       
   479     QByteArray ipAddress = qgetenv("DEVICE_IP");
       
   480     if (ipAddress.isEmpty()) {
       
   481         qWarning("Error: You need to have DEVICE_IP set");
       
   482         exit(0);
       
   483     }
       
   484     sock->connectToHost(QHostAddress(QString(ipAddress)), 12145);
       
   485     
       
   486     if (!sock->waitForConnected()) {
       
   487         qDebug() << "connection timeout...";
       
   488         result = NULL;
       
   489         return false;
       
   490     }
       
   491     result = sock;
       
   492     return true;
       
   493 }
       
   494 
       
   495 void QtCesterConnection::_freeSocket(QTcpSocket*& sock) const
       
   496 {
       
   497     if (!sock)
       
   498         return;
       
   499     if (sock->state() == QAbstractSocket::ConnectedState) {
       
   500         sock->disconnectFromHost();
       
   501         // seems like no need to wait
       
   502         //sock->waitForDisconnected();
       
   503     }
       
   504     delete sock;
       
   505     sock = NULL;
       
   506 #ifdef Q_OS_WIN
       
   507     Sleep(100);
       
   508 #endif
       
   509 }
       
   510 
       
   511 bool QtCesterConnection::_initCommand(QTcpSocket*& sock, const char* command) const
       
   512 {
       
   513     QTcpSocket* socket = NULL;
       
   514     if (!_createSocket(socket)) {
       
   515         END_ERROR(socket, "Could not connect to server");
       
   516     }
       
   517     
       
   518     if (!_sendData(socket, command, strlen(command)) || 
       
   519         !_checkResult(socket)) {
       
   520         END_ERROR(socket, "Cound not send command");
       
   521     }
       
   522     sock = socket;
       
   523     return true;
       
   524 }
       
   525 
       
   526 bool QtCesterConnection::_sendData(QTcpSocket*& sock, const char* data, int dataSize) const
       
   527 {
       
   528     int amount = sock->write(data, dataSize);
       
   529     if (amount != dataSize) {
       
   530         fprintf(stderr, "*******COULD NOT SEND ENOUGH DATA*************\n");
       
   531     }
       
   532     return sock->waitForBytesWritten();
       
   533 }
       
   534 
       
   535 bool QtCesterConnection::_receiveData(QTcpSocket*& sock, QByteArray& data) const
       
   536 {
       
   537     if (!sock->waitForReadyRead()) {
       
   538         qDebug() << "did not receive any data";
       
   539         return false;
       
   540     }
       
   541     data = sock->readAll();
       
   542     return true;
       
   543 }
       
   544 
       
   545 bool QtCesterConnection::_checkResult(QTcpSocket*& sock) const
       
   546 {
       
   547     QByteArray response;
       
   548     if (!_receiveData(sock, response) || response != COMMAND_SUCCESS)
       
   549         return false;
       
   550     return true;
       
   551 }
       
   552