2014-05-29 00:25:28 +08:00
|
|
|
#include "amqp_network.h"
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QtEndian>
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
using namespace QAMQP;
|
|
|
|
|
|
2014-05-30 23:12:09 +08:00
|
|
|
Network::Network(QObject *parent)
|
2014-05-29 00:25:28 +08:00
|
|
|
: QObject(parent)
|
|
|
|
|
{
|
2014-05-29 04:28:45 +08:00
|
|
|
qRegisterMetaType<Frame::Method>("QAMQP::Frame::Method");
|
2014-05-29 00:25:28 +08:00
|
|
|
|
|
|
|
|
buffer_.reserve(Frame::HEADER_SIZE);
|
|
|
|
|
timeOut_ = 1000;
|
|
|
|
|
connect_ = false;
|
|
|
|
|
|
|
|
|
|
initSocket(false);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
Network::~Network()
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
disconnect();
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-30 23:12:09 +08:00
|
|
|
void Network::connectTo(const QString &host, quint16 port)
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
2014-05-31 05:20:11 +08:00
|
|
|
if (!socket_) {
|
2014-05-29 00:25:28 +08:00
|
|
|
qWarning("AMQP: Socket didn't create.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString h(host);
|
|
|
|
|
int p(port);
|
|
|
|
|
connect_ = true;
|
|
|
|
|
if (host.isEmpty())
|
|
|
|
|
h = lastHost_ ;
|
|
|
|
|
if (port == 0)
|
|
|
|
|
p = lastPort_;
|
|
|
|
|
|
|
|
|
|
if (isSsl()) {
|
|
|
|
|
#ifndef QT_NO_SSL
|
2014-05-31 05:20:11 +08:00
|
|
|
static_cast<QSslSocket*>(socket_.data())->connectToHostEncrypted(h, p);
|
2014-05-29 00:25:28 +08:00
|
|
|
#else
|
|
|
|
|
qWarning("AMQP: You library has builded with QT_NO_SSL option.");
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
|
|
|
|
socket_->connectToHost(h, p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastHost_ = h;
|
|
|
|
|
lastPort_ = p;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::disconnect()
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
connect_ = false;
|
|
|
|
|
if (socket_)
|
|
|
|
|
socket_->close();
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::error(QAbstractSocket::SocketError socketError)
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
if (timeOut_ == 0) {
|
|
|
|
|
timeOut_ = 1000;
|
|
|
|
|
} else {
|
|
|
|
|
if (timeOut_ < 120000)
|
|
|
|
|
timeOut_ *= 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(socketError) {
|
|
|
|
|
case QAbstractSocket::ConnectionRefusedError:
|
|
|
|
|
case QAbstractSocket::RemoteHostClosedError:
|
|
|
|
|
case QAbstractSocket::SocketTimeoutError:
|
|
|
|
|
case QAbstractSocket::NetworkError:
|
|
|
|
|
case QAbstractSocket::ProxyConnectionClosedError:
|
|
|
|
|
case QAbstractSocket::ProxyConnectionRefusedError:
|
|
|
|
|
case QAbstractSocket::ProxyConnectionTimeoutError:
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
qWarning() << "AMQP: Socket Error: " << socket_->errorString();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (autoReconnect_ && connect_)
|
|
|
|
|
QTimer::singleShot(timeOut_, this, SLOT(connectTo()));
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::readyRead()
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
while (socket_->bytesAvailable() >= Frame::HEADER_SIZE) {
|
|
|
|
|
char *headerData = buffer_.data();
|
|
|
|
|
socket_->peek(headerData, Frame::HEADER_SIZE);
|
|
|
|
|
const quint32 payloadSize = qFromBigEndian<quint32>(*(quint32*)&headerData[3]);
|
|
|
|
|
const qint64 readSize = Frame::HEADER_SIZE+payloadSize+Frame::FRAME_END_SIZE;
|
|
|
|
|
|
|
|
|
|
if (socket_->bytesAvailable() >= readSize) {
|
|
|
|
|
buffer_.resize(readSize);
|
|
|
|
|
socket_->read(buffer_.data(), readSize);
|
2014-05-30 23:12:09 +08:00
|
|
|
const char *bufferData = buffer_.constData();
|
2014-05-29 00:25:28 +08:00
|
|
|
const quint8 type = *(quint8*)&bufferData[0];
|
|
|
|
|
const quint8 magic = *(quint8*)&bufferData[Frame::HEADER_SIZE+payloadSize];
|
2014-05-29 04:28:45 +08:00
|
|
|
if (magic != Frame::FRAME_END)
|
2014-05-29 00:25:28 +08:00
|
|
|
qWarning() << "Wrong end frame";
|
|
|
|
|
|
|
|
|
|
QDataStream streamB(&buffer_, QIODevice::ReadOnly);
|
2014-05-29 04:28:45 +08:00
|
|
|
switch(Frame::Type(type)) {
|
|
|
|
|
case Frame::ftMethod:
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
2014-05-29 04:28:45 +08:00
|
|
|
Frame::Method frame(streamB);
|
|
|
|
|
if (frame.methodClass() == Frame::fcConnection) {
|
2014-05-29 00:25:28 +08:00
|
|
|
m_pMethodHandlerConnection->_q_method(frame);
|
|
|
|
|
} else {
|
2014-05-31 05:20:11 +08:00
|
|
|
foreach (Frame::MethodHandler *pMethodHandler, m_methodHandlersByChannel[frame.channel()])
|
2014-05-29 00:25:28 +08:00
|
|
|
pMethodHandler->_q_method(frame);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2014-05-29 04:28:45 +08:00
|
|
|
case Frame::ftHeader:
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
2014-05-29 04:28:45 +08:00
|
|
|
Frame::Content frame(streamB);
|
2014-05-31 05:20:11 +08:00
|
|
|
foreach (Frame::ContentHandler *pMethodHandler, m_contentHandlerByChannel[frame.channel()])
|
2014-05-29 00:25:28 +08:00
|
|
|
pMethodHandler->_q_content(frame);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2014-05-29 04:28:45 +08:00
|
|
|
case Frame::ftBody:
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
2014-05-29 04:28:45 +08:00
|
|
|
Frame::ContentBody frame(streamB);
|
2014-05-31 05:20:11 +08:00
|
|
|
foreach (Frame::ContentBodyHandler *pMethodHandler, m_bodyHandlersByChannel[frame.channel()])
|
2014-05-29 00:25:28 +08:00
|
|
|
pMethodHandler->_q_body(frame);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2014-05-29 04:28:45 +08:00
|
|
|
case Frame::ftHeartbeat:
|
2014-05-29 00:25:28 +08:00
|
|
|
qDebug("AMQP: Heartbeat");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
qWarning() << "AMQP: Unknown frame type: " << type;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::sendFrame(const Frame::Base &frame)
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
2014-05-31 05:20:11 +08:00
|
|
|
if (socket_->state() != QAbstractSocket::ConnectedState) {
|
|
|
|
|
qDebug() << Q_FUNC_INFO << "socket not connected: " << socket_->state();
|
|
|
|
|
return;
|
2014-05-29 00:25:28 +08:00
|
|
|
}
|
2014-05-31 05:20:11 +08:00
|
|
|
|
|
|
|
|
QDataStream stream(socket_);
|
|
|
|
|
frame.toStream(stream);
|
2014-05-29 00:25:28 +08:00
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
bool Network::isSsl() const
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
if (socket_)
|
|
|
|
|
return QString(socket_->metaObject()->className()).compare("QSslSocket", Qt::CaseInsensitive) == 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::setSsl(bool value)
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
initSocket(value);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::initSocket(bool ssl)
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
if (socket_) {
|
|
|
|
|
socket_->deleteLater();
|
|
|
|
|
socket_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ssl) {
|
|
|
|
|
#ifndef QT_NO_SSL
|
|
|
|
|
socket_ = new QSslSocket(this);
|
2014-05-30 23:12:09 +08:00
|
|
|
QSslSocket *ssl_= static_cast<QSslSocket*> (socket_.data());
|
2014-05-29 00:25:28 +08:00
|
|
|
ssl_->setProtocol(QSsl::AnyProtocol);
|
|
|
|
|
connect(socket_, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors()));
|
|
|
|
|
connect(socket_, SIGNAL(connected()), this, SLOT(conectionReady()));
|
|
|
|
|
#else
|
|
|
|
|
qWarning("AMQP: You library has builded with QT_NO_SSL option.");
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
|
|
|
|
socket_ = new QTcpSocket(this);
|
|
|
|
|
connect(socket_, SIGNAL(connected()), this, SLOT(conectionReady()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (socket_) {
|
|
|
|
|
connect(socket_, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
|
|
|
|
|
connect(socket_, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
|
|
|
|
connect(socket_, SIGNAL(error(QAbstractSocket::SocketError)),
|
|
|
|
|
this, SLOT(error(QAbstractSocket::SocketError)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::sslErrors()
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
#ifndef QT_NO_SSL
|
|
|
|
|
static_cast<QSslSocket*>(socket_.data())->ignoreSslErrors();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::conectionReady()
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
Q_EMIT connected();
|
|
|
|
|
timeOut_ = 0;
|
|
|
|
|
|
|
|
|
|
char header_[8] = {'A', 'M', 'Q', 'P', 0,0,9,1};
|
|
|
|
|
socket_->write(header_, 8);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
bool Network::autoReconnect() const
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
return autoReconnect_;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::setAutoReconnect(bool value)
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
autoReconnect_ = value;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
QAbstractSocket::SocketState Network::state() const
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
if (socket_)
|
|
|
|
|
return socket_->state();
|
|
|
|
|
return QAbstractSocket::UnconnectedState;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::setMethodHandlerConnection(Frame::MethodHandler *pMethodHandlerConnection)
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
m_pMethodHandlerConnection = pMethodHandlerConnection;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::addMethodHandlerForChannel(Channel channel, Frame::MethodHandler *pHandler)
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
m_methodHandlersByChannel[channel].append(pHandler);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::addContentHandlerForChannel(Channel channel, Frame::ContentHandler *pHandler)
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
m_contentHandlerByChannel[channel].append(pHandler);
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-29 04:28:45 +08:00
|
|
|
void Network::addContentBodyHandlerForChannel(Channel channel, Frame::ContentBodyHandler *pHandler)
|
2014-05-29 00:25:28 +08:00
|
|
|
{
|
|
|
|
|
m_bodyHandlersByChannel[channel].append(pHandler);
|
|
|
|
|
}
|