diff options
Diffstat (limited to 'tdeio/tdeio/connection.cpp')
-rw-r--r-- | tdeio/tdeio/connection.cpp | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/tdeio/tdeio/connection.cpp b/tdeio/tdeio/connection.cpp new file mode 100644 index 000000000..cbe737693 --- /dev/null +++ b/tdeio/tdeio/connection.cpp @@ -0,0 +1,273 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Stephan Kulow <coolo@kde.org> + David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// $Id$ + +#include <config.h> + +#include <kde_file.h> +#include <ksock.h> +#include <tqtimer.h> + +#include <sys/types.h> +#include <sys/signal.h> +#include <sys/time.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> + +#include "tdeio/connection.h" + +#include <kdebug.h> +#include <tqsocketnotifier.h> + +using namespace TDEIO; + +Connection::Connection() +{ + f_out = 0; + fd_in = -1; + socket = 0; + notifier = 0; + receiver = 0; + member = 0; + m_suspended = false; + tasks.setAutoDelete(true); +} + +Connection::~Connection() +{ + close(); +} + +void Connection::suspend() +{ + m_suspended = true; + if (notifier) + notifier->setEnabled(false); +} + +void Connection::resume() +{ + m_suspended = false; + if (notifier) + notifier->setEnabled(true); +} + +void Connection::close() +{ + delete notifier; + notifier = 0; + delete socket; + socket = 0; + + // TDESocket has already closed the file descriptor, but we need to + // close the file-stream as well otherwise we leak memory. + // As a result we close the file descriptor twice, but that should + // be harmless + // KDE4: fix this + if (f_out) + fclose(f_out); + f_out = 0; + fd_in = -1; + tasks.clear(); +} + +void Connection::send(int cmd, const TQByteArray& data) +{ + if (!inited() || tasks.count() > 0) { + Task *task = new Task(); + task->cmd = cmd; + task->data = data; + tasks.append(task); + } else { + sendnow( cmd, data ); + } +} + +void Connection::dequeue() +{ + if (!inited()) + return; + + while (tasks.count()) + { + tasks.first(); + Task *task = tasks.take(); + sendnow( task->cmd, task->data ); + delete task; + } +} + +void Connection::init(TDESocket *sock) +{ + delete notifier; + notifier = 0; +#ifdef Q_OS_UNIX //TODO: not yet available on WIN32 + delete socket; + socket = sock; + fd_in = socket->socket(); + f_out = KDE_fdopen( socket->socket(), "wb" ); +#endif + if (receiver && ( fd_in != -1 )) { + notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read); + if ( m_suspended ) { + suspend(); + } + TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member); + } + dequeue(); +} + +void Connection::init(int _fd_in, int fd_out) +{ + delete notifier; + notifier = 0; + fd_in = _fd_in; + f_out = KDE_fdopen( fd_out, "wb" ); + if (receiver && ( fd_in != -1 )) { + notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read); + if ( m_suspended ) { + suspend(); + } + TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member); + } + dequeue(); +} + + +void Connection::connect(TQObject *_receiver, const char *_member) +{ + receiver = _receiver; + member = _member; + delete notifier; + notifier = 0; + if (receiver && (fd_in != -1 )) { + notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read); + if ( m_suspended ) + suspend(); + TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member); + } +} + +bool Connection::sendnow( int _cmd, const TQByteArray &data ) +{ + if (f_out == 0) { + return false; + } + + if (data.size() > 0xffffff) + return false; + + static char buffer[ 64 ]; + sprintf( buffer, "%6x_%2x_", data.size(), _cmd ); + + size_t n = fwrite( buffer, 1, 10, f_out ); + + if ( n != 10 ) { + kdError(7017) << "Could not send header" << endl; + return false; + } + + n = fwrite( data.data(), 1, data.size(), f_out ); + + if ( n != data.size() ) { + kdError(7017) << "Could not write data" << endl; + return false; + } + + if (fflush( f_out )) { + kdError(7017) << "Could not write data" << endl; + return false; + } + + return true; +} + +int Connection::read( int* _cmd, TQByteArray &data ) +{ + if (fd_in == -1 ) { + kdError(7017) << "read: not yet inited" << endl; + return -1; + } + + static char buffer[ 10 ]; + + again1: + ssize_t n = ::read( fd_in, buffer, 10); + if ( n == -1 && errno == EINTR ) + goto again1; + + if ( n == -1) { + kdError(7017) << "Header read failed, errno=" << errno << endl; + } + + if ( n != 10 ) { + if ( n ) // 0 indicates end of file + kdError(7017) << "Header has invalid size (" << n << ")" << endl; + return -1; + } + + buffer[ 6 ] = 0; + buffer[ 9 ] = 0; + + char *p = buffer; + while( *p == ' ' ) p++; + long int len = strtol( p, 0L, 16 ); + + p = buffer + 7; + while( *p == ' ' ) p++; + long int cmd = strtol( p, 0L, 16 ); + + data.resize( len ); + + if ( len > 0L ) { + size_t bytesToGo = len; + size_t bytesRead = 0; + do { + n = ::read(fd_in, data.data()+bytesRead, bytesToGo); + if (n == -1) { + if (errno == EINTR) + continue; + + kdError(7017) << "Data read failed, errno=" << errno << endl; + return -1; + } + if ( !n ) { // 0 indicates end of file + kdError(7017) << "Connection ended unexpectedly (" << n << "/" << bytesToGo << ")" << endl; + return -1; + } + + bytesRead += n; + bytesToGo -= n; + } + while(bytesToGo); + } + + *_cmd = cmd; + return len; +} + +#include "connection.moc" |