/* * bsocket.cpp - TQSocket 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 #include #include #include #include "safedelete.h" #ifndef NO_NDNS #include "ndns.h" #endif #include "srvresolver.h" #ifdef BS_DEBUG #include #endif #define READBUFSIZE 65536 // CS_NAMESPACE_BEGIN class BSocket::Private { public: Private() { qsock = 0; } TQSocket *qsock; int state; #ifndef NO_NDNS NDns ndns; #endif SrvResolver srv; TQString host; int port; SafeDelete sd; }; BSocket::BSocket(TQObject *parent) :ByteStream(parent) { d = new Private; #ifndef NO_NDNS connect(&d->ndns, TQT_SIGNAL(resultsReady()), TQT_SLOT(ndns_done())); #endif connect(&d->srv, TQT_SIGNAL(resultsReady()), TQT_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 TQByteArray 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 TQSocket; d->qsock->setReadBufferSize(READBUFSIZE); connect(d->qsock, TQT_SIGNAL(hostFound()), TQT_SLOT(qs_hostFound())); connect(d->qsock, TQT_SIGNAL(connected()), TQT_SLOT(qs_connected())); connect(d->qsock, TQT_SIGNAL(connectionClosed()), TQT_SLOT(qs_connectionClosed())); connect(d->qsock, TQT_SIGNAL(delayedCloseFinished()), TQT_SLOT(qs_delayedCloseFinished())); connect(d->qsock, TQT_SIGNAL(readyRead()), TQT_SLOT(qs_readyRead())); connect(d->qsock, TQT_SIGNAL(bytesWritten(int)), TQT_SLOT(qs_bytesWritten(int))); connect(d->qsock, TQT_SIGNAL(error(int)), TQT_SLOT(qs_error(int))); } } void BSocket::connectToHost(const TQString &host, TQ_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 TQString &srv, const TQString &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 TQByteArray &a) { if(d->state != Connected) return; #ifdef BS_DEBUG TQCString cs; cs.resize(a.size()+1); memcpy(cs.data(), a.data(), a.size()); TQString s = TQString::fromUtf8(cs); fprintf(stderr, "BSocket: writing [%d]: {%s}\n", a.size(), cs.data()); #endif d->qsock->writeBlock(a.data(), a.size()); } TQByteArray BSocket::read(int bytes) { TQByteArray 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 TQCString cs; cs.resize(block.size()+1); memcpy(cs.data(), block.data(), block.size()); TQString s = TQString::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(); } TQHostAddress BSocket::address() const { if(d->qsock) return d->qsock->address(); else return TQHostAddress(); } TQ_UINT16 BSocket::port() const { if(d->qsock) return d->qsock->port(); else return 0; } TQHostAddress BSocket::peerAddress() const { if(d->qsock) return d->qsock->peerAddress(); else return TQHostAddress(); } TQ_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(); //TQTimer::singleShot(0, this, TQT_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(); //TQTimer::singleShot(0, this, TQT_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 == TQSocket::ErrConnectionRefused || x == TQSocket::ErrHostNotFound)) { d->srv.next(); return; } reset(); if(x == TQSocket::ErrConnectionRefused) error(ErrConnectionRefused); else if(x == TQSocket::ErrHostNotFound) error(ErrHostNotFound); else if(x == TQSocket::ErrSocketRead) error(ErrRead); } // CS_NAMESPACE_END #include "bsocket.moc"