You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kopete/protocols/jabber/libiris/cutestuff/network/bsocket.cpp

395 lines
7.3 KiB

/*
* bsocket.cpp - QSocket wrapper based on Bytestream with SRV DNS support
* Copyright (C) 2003 Justin Karneges
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include"bsocket.h"
#include<qcstring.h>
#include<qsocket.h>
#include<qdns.h>
#include<qguardedptr.h>
#include"safedelete.h"
#ifndef NO_NDNS
#include"ndns.h"
#endif
#include"srvresolver.h"
#ifdef BS_DEBUG
#include<stdio.h>
#endif
#define READBUFSIZE 65536
// CS_NAMESPACE_BEGIN
class BSocket::Private
{
public:
Private()
{
qsock = 0;
}
QSocket *qsock;
int state;
#ifndef NO_NDNS
NDns ndns;
#endif
SrvResolver srv;
QString host;
int port;
SafeDelete sd;
};
BSocket::BSocket(QObject *parent)
:ByteStream(parent)
{
d = new Private;
#ifndef NO_NDNS
connect(&d->ndns, SIGNAL(resultsReady()), SLOT(ndns_done()));
#endif
connect(&d->srv, SIGNAL(resultsReady()), SLOT(srv_done()));
reset();
}
BSocket::~BSocket()
{
reset(true);
delete d;
}
void BSocket::reset(bool clear)
{
if(d->qsock) {
d->qsock->disconnect(this);
if(!clear && d->qsock->isOpen()) {
// move remaining into the local queue
QByteArray block(d->qsock->bytesAvailable());
d->qsock->readBlock(block.data(), block.size());
appendRead(block);
}
d->sd.deleteLater(d->qsock);
d->qsock = 0;
}
else {
if(clear)
clearReadBuffer();
}
if(d->srv.isBusy())
d->srv.stop();
#ifndef NO_NDNS
if(d->ndns.isBusy())
d->ndns.stop();
#endif
d->state = Idle;
}
void BSocket::ensureSocket()
{
if(!d->qsock) {
d->qsock = new QSocket;
#if QT_VERSION >= 0x030200
d->qsock->setReadBufferSize(READBUFSIZE);
#endif
connect(d->qsock, SIGNAL(hostFound()), SLOT(qs_hostFound()));
connect(d->qsock, SIGNAL(connected()), SLOT(qs_connected()));
connect(d->qsock, SIGNAL(connectionClosed()), SLOT(qs_connectionClosed()));
connect(d->qsock, SIGNAL(delayedCloseFinished()), SLOT(qs_delayedCloseFinished()));
connect(d->qsock, SIGNAL(readyRead()), SLOT(qs_readyRead()));
connect(d->qsock, SIGNAL(bytesWritten(int)), SLOT(qs_bytesWritten(int)));
connect(d->qsock, SIGNAL(error(int)), SLOT(qs_error(int)));
}
}
void BSocket::connectToHost(const QString &host, Q_UINT16 port)
{
reset(true);
d->host = host;
d->port = port;
#ifdef NO_NDNS
d->state = Connecting;
do_connect();
#else
d->state = HostLookup;
d->ndns.resolve(d->host);
#endif
}
void BSocket::connectToServer(const QString &srv, const QString &type)
{
reset(true);
d->state = HostLookup;
d->srv.resolve(srv, type, "tcp");
}
int BSocket::socket() const
{
if(d->qsock)
return d->qsock->socket();
else
return -1;
}
void BSocket::setSocket(int s)
{
reset(true);
ensureSocket();
d->state = Connected;
d->qsock->setSocket(s);
}
int BSocket::state() const
{
return d->state;
}
bool BSocket::isOpen() const
{
if(d->state == Connected)
return true;
else
return false;
}
void BSocket::close()
{
if(d->state == Idle)
return;
if(d->qsock) {
d->qsock->close();
d->state = Closing;
if(d->qsock->bytesToWrite() == 0)
reset();
}
else {
reset();
}
}
void BSocket::write(const QByteArray &a)
{
if(d->state != Connected)
return;
#ifdef BS_DEBUG
QCString cs;
cs.resize(a.size()+1);
memcpy(cs.data(), a.data(), a.size());
QString s = QString::fromUtf8(cs);
fprintf(stderr, "BSocket: writing [%d]: {%s}\n", a.size(), cs.data());
#endif
d->qsock->writeBlock(a.data(), a.size());
}
QByteArray BSocket::read(int bytes)
{
QByteArray block;
if(d->qsock) {
int max = bytesAvailable();
if(bytes <= 0 || bytes > max)
bytes = max;
block.resize(bytes);
d->qsock->readBlock(block.data(), block.size());
}
else
block = ByteStream::read(bytes);
#ifdef BS_DEBUG
QCString cs;
cs.resize(block.size()+1);
memcpy(cs.data(), block.data(), block.size());
QString s = QString::fromUtf8(cs);
fprintf(stderr, "BSocket: read [%d]: {%s}\n", block.size(), s.latin1());
#endif
return block;
}
int BSocket::bytesAvailable() const
{
if(d->qsock)
return d->qsock->bytesAvailable();
else
return ByteStream::bytesAvailable();
}
int BSocket::bytesToWrite() const
{
if(!d->qsock)
return 0;
return d->qsock->bytesToWrite();
}
QHostAddress BSocket::address() const
{
if(d->qsock)
return d->qsock->address();
else
return QHostAddress();
}
Q_UINT16 BSocket::port() const
{
if(d->qsock)
return d->qsock->port();
else
return 0;
}
QHostAddress BSocket::peerAddress() const
{
if(d->qsock)
return d->qsock->peerAddress();
else
return QHostAddress();
}
Q_UINT16 BSocket::peerPort() const
{
if(d->qsock)
return d->qsock->port();
else
return 0;
}
void BSocket::srv_done()
{
if(d->srv.failed()) {
#ifdef BS_DEBUG
fprintf(stderr, "BSocket: Error resolving hostname.\n");
#endif
error(ErrHostNotFound);
return;
}
d->host = d->srv.resultAddress().toString();
d->port = d->srv.resultPort();
do_connect();
//QTimer::singleShot(0, this, SLOT(do_connect()));
//hostFound();
}
void BSocket::ndns_done()
{
#ifndef NO_NDNS
if(d->ndns.result()) {
d->host = d->ndns.resultString();
d->state = Connecting;
do_connect();
//QTimer::singleShot(0, this, SLOT(do_connect()));
//hostFound();
}
else {
#ifdef BS_DEBUG
fprintf(stderr, "BSocket: Error resolving hostname.\n");
#endif
error(ErrHostNotFound);
}
#endif
}
void BSocket::do_connect()
{
#ifdef BS_DEBUG
fprintf(stderr, "BSocket: Connecting to %s:%d\n", d->host.latin1(), d->port);
#endif
ensureSocket();
d->qsock->connectToHost(d->host, d->port);
}
void BSocket::qs_hostFound()
{
//SafeDeleteLock s(&d->sd);
}
void BSocket::qs_connected()
{
d->state = Connected;
#ifdef BS_DEBUG
fprintf(stderr, "BSocket: Connected.\n");
#endif
SafeDeleteLock s(&d->sd);
connected();
}
void BSocket::qs_connectionClosed()
{
#ifdef BS_DEBUG
fprintf(stderr, "BSocket: Connection Closed.\n");
#endif
SafeDeleteLock s(&d->sd);
reset();
connectionClosed();
}
void BSocket::qs_delayedCloseFinished()
{
#ifdef BS_DEBUG
fprintf(stderr, "BSocket: Delayed Close Finished.\n");
#endif
SafeDeleteLock s(&d->sd);
reset();
delayedCloseFinished();
}
void BSocket::qs_readyRead()
{
SafeDeleteLock s(&d->sd);
readyRead();
}
void BSocket::qs_bytesWritten(int x)
{
#ifdef BS_DEBUG
fprintf(stderr, "BSocket: BytesWritten [%d].\n", x);
#endif
SafeDeleteLock s(&d->sd);
bytesWritten(x);
}
void BSocket::qs_error(int x)
{
#ifdef BS_DEBUG
fprintf(stderr, "BSocket: Error.\n");
#endif
SafeDeleteLock s(&d->sd);
// connection error during SRV host connect? try next
if(d->state == HostLookup && (x == QSocket::ErrConnectionRefused || x == QSocket::ErrHostNotFound)) {
d->srv.next();
return;
}
reset();
if(x == QSocket::ErrConnectionRefused)
error(ErrConnectionRefused);
else if(x == QSocket::ErrHostNotFound)
error(ErrHostNotFound);
else if(x == QSocket::ErrSocketRead)
error(ErrRead);
}
// CS_NAMESPACE_END
#include "bsocket.moc"