SocketTransport.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2005-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 
00023 #include "Qt.h"
00024 #include "SocketTransport.h"
00025 #include "Imports.cpp"
00026 
00028 
00034 SocketTransport::SocketTransport (Socket *socketToUse,
00035                                   SocketBuffer *socketBufferToUse,
00036                                   TransportStatus *statusReceiver)
00037     : socket (socketToUse),
00038       socketBuffer (socketBufferToUse),
00039       status (statusReceiver),
00040       state (DisconnectedState),
00041       hasCalledWriteBufferToSocket (false),
00042       hasCalledReadBufferFromSocket (false)
00043 {
00044 }
00045 
00047 
00050 SocketTransport::~SocketTransport()
00051 {
00052 }
00053 
00055 
00067 void SocketTransport::connectToNode (const Uri &nodeAddress)
00068 {
00069     Q_ASSERT (state == DisconnectedState);
00070 
00071     QHostAddress hostAddress (QString (nodeAddress.host()));
00072     qint16 port = nodeAddress.port().toUShort();
00073     Q_ASSERT (!hostAddress.isNull());
00074     Q_ASSERT (port != 0);
00075 
00076     state = ConnectingState;
00077     socket->connectToHost (hostAddress, port);
00078 }
00079 
00081 
00087 void SocketTransport::disconnectFromNode()
00088 {
00089     Q_ASSERT (state == ConnectedState);
00090 
00091     state = DisconnectingState;
00092     socket->disconnectFromHost();
00093 }
00094 
00096 
00099 void SocketTransport::abort()
00100 {
00101     if (state != DisconnectedState) {
00102         state = DisconnectingState;
00103         socket->abort();
00104     }
00105 }
00106 
00108 
00111 void SocketTransport::socketConnected()
00112 {
00113     // The connected() signal should be emitted only once!
00114     if (state == ConnectingState) {
00115         state = ConnectedState;
00116         status->transportConnected (this);
00117     }
00118 }
00119 
00121 
00124 void SocketTransport::socketDisconnected()
00125 {
00126     // The disconnected() signal should be emitted only once!
00127     if (state != DisconnectedState) {
00128         state = DisconnectedState;
00129         status->transportDisconnected (this);
00130     }
00131 }
00132 
00134 
00137 void SocketTransport::socketError()
00138 {
00139     // \todo this if should be analysed. Check exactly how QTcpSocket and
00140     // QUdpSocket behave! Does abort() emit disconnected() if a connection
00141     // was never established? The integration test indicates the if
00142     // is correct...
00143     if (state == ConnectingState) {
00144         abort();
00145         socketDisconnected();
00146     }
00147     if (state != DisconnectedState)
00148         abort();
00149 }
00150 
00152 
00159 void SocketTransport::socketRead()
00160 {
00161     Q_ASSERT (state == ConnectedState);
00162     tryReadBufferFromSocket (true);
00163 }
00164 
00166 
00174 void SocketTransport::socketWritten()
00175 {
00176     Q_ASSERT (state == ConnectedState);
00177     tryWriteBufferToSocket (true);
00178 }
00179 
00180 bool SocketTransport::canRead (int count) const
00181 {
00182     Q_ASSERT (state == ConnectedState || state == DisconnectingState);
00183     return socketBuffer->canRead (count);
00184 }
00185 
00186 QByteArray SocketTransport::peek (int count) const
00187 {
00188     Q_ASSERT (state == ConnectedState || state == DisconnectingState);
00189     return socketBuffer->peek (count);
00190 }
00191 
00192 QByteArray SocketTransport::peekAtMost (int count) const
00193 {
00194     Q_ASSERT (state == ConnectedState || state == DisconnectingState);
00195     return socketBuffer->peekAtMost (count);
00196 }
00197 
00198 QByteArray SocketTransport::peekTo (const QByteArray &delimiter) const
00199 {
00200     Q_ASSERT (state == ConnectedState || state == DisconnectingState);
00201     return socketBuffer->peekTo (delimiter);
00202 }
00203 
00204 QByteArray SocketTransport::peekAll() const
00205 {
00206     Q_ASSERT (state == ConnectedState || state == DisconnectingState);
00207     return socketBuffer->peekAll();
00208 }
00209 
00210 QByteArray SocketTransport::read (int count)
00211 {
00212     Q_ASSERT (state == ConnectedState || state == DisconnectingState);
00213     QByteArray bytes = socketBuffer->read (count);
00214     tryReadBufferFromSocket (false); // must be the same in all read variants!
00215     return bytes;
00216 }
00217 
00218 QByteArray SocketTransport::readAtMost (int count)
00219 {
00220     Q_ASSERT (state == ConnectedState || state == DisconnectingState);
00221     QByteArray bytes = socketBuffer->readAtMost (count);
00222     tryReadBufferFromSocket (false); // must be the same in all read variants!
00223     return bytes;
00224 }
00225 
00226 QByteArray SocketTransport::readTo (const QByteArray &delimiter)
00227 {
00228     Q_ASSERT (state == ConnectedState || state == DisconnectingState);
00229     QByteArray bytes = socketBuffer->readTo (delimiter);
00230     tryReadBufferFromSocket (false); // must be the same in all read variants!
00231     return bytes;
00232 }
00233 
00234 QByteArray SocketTransport::readAll()
00235 {
00236     Q_ASSERT (state == ConnectedState || state == DisconnectingState);
00237     QByteArray bytes = socketBuffer->readAll();
00238     tryReadBufferFromSocket (false); // must be the same in all read variants!
00239     return bytes;
00240 }
00241 
00242 bool SocketTransport::canWrite (int count) const
00243 {
00244     Q_ASSERT (state == ConnectedState);
00245     return socketBuffer->canWrite (count);
00246 }
00247 
00248 bool SocketTransport::write (const QByteArray &bytes, bool flush)
00249 {
00250     Q_ASSERT (state == ConnectedState);
00251     bool hasWritten = socketBuffer->write (bytes, flush);
00252     // \todo Should we schedule a delayed call to tryWriteBufferToSocket()?
00253     // This way we could buffer more and then pass all to the OS at once -
00254     // could improve network performance especially if we write() small chunks
00255     // at a time.
00256     tryWriteBufferToSocket (false);
00257     return hasWritten;
00258 }
00259 
00260 // NodeAddress SocketTransport::ownNodeAddress() const
00261 // {
00262 //  return NodeAddress(); // \todo
00263 // }
00264 //
00265 // NodeAddress SocketTransport::remoteNodeAddress() const
00266 // {
00267 //  return NodeAddress(); // \todo
00268 // }
00269 
00270 void SocketTransport::tryWriteBufferToSocket (bool canSendReadyWrite)
00271 {
00272     if (!hasCalledWriteBufferToSocket) {
00273         hasCalledWriteBufferToSocket = true;
00274 
00275         socketBuffer->tryWriteTo (socket);
00276 
00277         hasCalledWriteBufferToSocket = false;
00278 
00279         if (canSendReadyWrite)
00280             status->transportReadyWrite (this);
00281     }
00282 }
00283 
00284 void SocketTransport::tryReadBufferFromSocket (bool canSendReadyRead)
00285 {
00286     if (!hasCalledReadBufferFromSocket) {
00287         hasCalledReadBufferFromSocket = true;
00288 
00289         socketBuffer->tryReadFrom (socket);
00290 
00291         hasCalledReadBufferFromSocket = false;
00292 
00293         if (canSendReadyRead)
00294             status->transportReadyRead (this);
00295     }
00296 }
00297 
00298 void SocketTransport::setTransportStatus (TransportStatus *newStatus)
00299 {
00300     status = newStatus;
00301 }