blobiohandler.cpp

00001 /*
00002  * This file is part of signon
00003  *
00004  * Copyright (C) 2009-2011 Nokia Corporation.
00005  *
00006  * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com>
00007  * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public License
00011  * version 2.1 as published by the Free Software Foundation.
00012  *
00013  * This library is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00021  * 02110-1301 USA
00022  */
00023 
00024 #include "blobiohandler.h"
00025 
00026 #include <QBuffer>
00027 #include <QDebug>
00028 
00029 #include "SignOn/signonplugincommon.h"
00030 
00031 #define SIGNON_IPC_BUFFER_PAGE_SIZE 16384
00032 
00033 using namespace SignOn;
00034 
00035 BlobIOHandler::BlobIOHandler(QIODevice *readChannel,
00036                              QIODevice *writeChannel,
00037                              QObject *parent)
00038     : QObject(parent),
00039       m_readChannel(readChannel),
00040       m_writeChannel(writeChannel),
00041       m_readNotifier(0),
00042       m_blobSize(-1)
00043 {
00044 }
00045 
00046 void BlobIOHandler::setReadChannelSocketNotifier(QSocketNotifier *notifier)
00047 {
00048     if (notifier == 0)
00049         return;
00050 
00051     m_readNotifier = notifier;
00052 }
00053 
00054 bool BlobIOHandler::sendData(const QVariantMap &map)
00055 {
00056     if (m_writeChannel == 0) {
00057         TRACE() << "NULL write channel.";
00058         return false;
00059     }
00060 
00061     QDataStream stream(m_writeChannel);
00062     QByteArray ba = variantMapToByteArray(map);
00063     stream << ba.size();
00064 
00065     QVector<QByteArray> pages = pageByteArray(ba);
00066     for (int i = 0; i < pages.count(); ++i)
00067         stream << pages[i];
00068 
00069     return true;
00070 }
00071 
00072 void BlobIOHandler::setReadNotificationEnabled(bool enabled)
00073 {
00074     if (enabled) {
00075         if (m_readNotifier != 0) {
00076             m_readNotifier->setEnabled(true);
00077             connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(readBlob()));
00078         } else {
00079             connect(m_readChannel, SIGNAL(readyRead()), this, SLOT(readBlob()));
00080         }
00081     } else {
00082         if (m_readNotifier != 0) {
00083             disconnect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(readBlob()));
00084             m_readNotifier->setEnabled(false);
00085         } else {
00086             disconnect(m_readChannel, SIGNAL(readyRead()), this, SLOT(readBlob()));
00087         }
00088     }
00089 }
00090 
00091 void BlobIOHandler::receiveData(int expectedDataSize)
00092 {
00093     m_blobBuffer.clear();
00094     m_blobSize = expectedDataSize;
00095 
00096     //Enable read notification only if more than 1 BLOB page is to be received
00097     //This does not allow duplicate read attempts if only 1 page is available
00098     if (m_blobSize > SIGNON_IPC_BUFFER_PAGE_SIZE)
00099         setReadNotificationEnabled(true);
00100 
00101     readBlob();
00102 }
00103 
00104 void BlobIOHandler::readBlob()
00105 {
00106     QDataStream in(m_readChannel);
00107 
00108     QByteArray fractionBa;
00109     in >> fractionBa;
00110     m_blobBuffer.append(fractionBa);
00111 
00112     //Avoid infinite loops if the other party behaves badly
00113     if ((fractionBa.size() == 0) && (m_blobBuffer.size() < m_blobSize)) {
00114         setReadNotificationEnabled(false);
00115         emit error();
00116         return;
00117     }
00118 
00119     if (m_blobBuffer.size() == m_blobSize) {
00120         QVariantMap sessionDataMap;
00121         sessionDataMap = byteArrayToVariantMap(m_blobBuffer);
00122 
00123         if (m_blobSize > SIGNON_IPC_BUFFER_PAGE_SIZE)
00124             setReadNotificationEnabled(false);
00125 
00126         emit dataReceived(sessionDataMap);
00127     }
00128 }
00129 
00130 QByteArray BlobIOHandler::variantMapToByteArray(const QVariantMap &map)
00131 {
00132     QBuffer buffer;
00133     if (!buffer.open(QIODevice::WriteOnly))
00134         BLAME() << "Buffer opening failed.";
00135 
00136     QDataStream stream(&buffer);
00137     stream << map;
00138     buffer.close();
00139 
00140     return buffer.data();
00141 }
00142 
00143 QVariantMap BlobIOHandler::byteArrayToVariantMap(const QByteArray &array)
00144 {
00145     QByteArray nonConst = array;
00146     QBuffer buffer(&nonConst);
00147     if (!buffer.open(QIODevice::ReadOnly))
00148         BLAME() << "Buffer opening failed.";
00149 
00150     buffer.reset();
00151     QDataStream stream(&buffer);
00152     QVariantMap map;
00153     stream >> map;
00154     buffer.close();
00155 
00156     return map;
00157 }
00158 
00159 QVector<QByteArray> BlobIOHandler::pageByteArray(const QByteArray &array)
00160 {
00161     QVector<QByteArray> dataPages;
00162     QByteArray ba = array;
00163     QBuffer pagingBuffer(&ba);
00164 
00165     if (!pagingBuffer.open(QIODevice::ReadOnly))
00166         BLAME() << "Error while paging BLOB. Buffer opening failed.";
00167 
00168     while (!pagingBuffer.atEnd()) {
00169         QByteArray page = pagingBuffer.read(SIGNON_IPC_BUFFER_PAGE_SIZE);
00170         dataPages.append(page);
00171     }
00172     pagingBuffer.close();
00173 
00174     return dataPages;
00175 }