connection.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2000 Stephan Kulow <coolo@kde.org> 00003 David Faure <faure@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 // $Id$ 00022 00023 #include <config.h> 00024 00025 #include <kde_file.h> 00026 #include <ksock.h> 00027 #include <tqtimer.h> 00028 00029 #include <sys/types.h> 00030 #include <sys/time.h> 00031 00032 #include <errno.h> 00033 #include <fcntl.h> 00034 #include <stdio.h> 00035 #include <stdlib.h> 00036 #include <signal.h> 00037 #include <string.h> 00038 #include <unistd.h> 00039 00040 #include "kio/connection.h" 00041 00042 #include <kdebug.h> 00043 #include <tqsocketnotifier.h> 00044 00045 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) 00046 #define __progname getprogname() 00047 #elif defined(_GNU_SOURCE) && defined(__GLIBC__) 00048 #define __progname program_invocation_short_name 00049 #else 00050 extern char *__progname; 00051 #endif 00052 00053 using namespace KIO; 00054 00055 Connection::Connection() 00056 { 00057 f_out = 0; 00058 fd_in = -1; 00059 socket = 0; 00060 notifier = 0; 00061 receiver = 0; 00062 member = 0; 00063 m_suspended = false; 00064 tasks.setAutoDelete(true); 00065 } 00066 00067 Connection::~Connection() 00068 { 00069 close(); 00070 } 00071 00072 void Connection::suspend() 00073 { 00074 m_suspended = true; 00075 if (notifier) 00076 notifier->setEnabled(false); 00077 } 00078 00079 void Connection::resume() 00080 { 00081 m_suspended = false; 00082 if (notifier) 00083 notifier->setEnabled(true); 00084 } 00085 00086 void Connection::close() 00087 { 00088 delete notifier; 00089 notifier = 0; 00090 delete socket; 00091 socket = 0; 00092 00093 // KSocket has already closed the file descriptor, but we need to 00094 // close the file-stream as well otherwise we leak memory. 00095 // As a result we close the file descriptor twice, but that should 00096 // be harmless 00097 // KDE4: fix this 00098 if (f_out) 00099 fclose(f_out); 00100 f_out = 0; 00101 fd_in = -1; 00102 tasks.clear(); 00103 } 00104 00105 void Connection::send(int cmd, const TQByteArray& data) 00106 { 00107 if (!inited() || tasks.count() > 0) { 00108 Task *task = new Task(); 00109 task->cmd = cmd; 00110 task->data = data; 00111 tasks.append(task); 00112 } else { 00113 sendnow( cmd, data ); 00114 } 00115 } 00116 00117 void Connection::dequeue() 00118 { 00119 if (!inited()) 00120 return; 00121 00122 while (tasks.count()) 00123 { 00124 tasks.first(); 00125 Task *task = tasks.take(); 00126 sendnow( task->cmd, task->data ); 00127 delete task; 00128 } 00129 } 00130 00131 void Connection::init(KSocket *sock) 00132 { 00133 delete notifier; 00134 notifier = 0; 00135 #ifdef Q_OS_UNIX //TODO: not yet available on WIN32 00136 delete socket; 00137 socket = sock; 00138 fd_in = socket->socket(); 00139 f_out = KDE_fdopen( socket->socket(), "wb" ); 00140 #endif 00141 if (receiver && ( fd_in != -1 )) { 00142 notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read); 00143 if ( m_suspended ) { 00144 suspend(); 00145 } 00146 TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member); 00147 } 00148 dequeue(); 00149 } 00150 00151 void Connection::init(int _fd_in, int fd_out) 00152 { 00153 delete notifier; 00154 notifier = 0; 00155 fd_in = _fd_in; 00156 f_out = KDE_fdopen( fd_out, "wb" ); 00157 if (receiver && ( fd_in != -1 )) { 00158 notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read); 00159 if ( m_suspended ) { 00160 suspend(); 00161 } 00162 TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member); 00163 } 00164 dequeue(); 00165 } 00166 00167 00168 void Connection::connect(TQObject *_receiver, const char *_member) 00169 { 00170 receiver = _receiver; 00171 member = _member; 00172 delete notifier; 00173 notifier = 0; 00174 if (receiver && (fd_in != -1 )) { 00175 notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read); 00176 if ( m_suspended ) 00177 suspend(); 00178 TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member); 00179 } 00180 } 00181 00182 bool Connection::sendnow( int _cmd, const TQByteArray &data ) 00183 { 00184 if (f_out == 0) { 00185 return false; 00186 } 00187 00188 if (data.size() > 0xffffff) 00189 return false; 00190 00191 static char buffer[ 64 ]; 00192 sprintf( buffer, "%6x_%2x_", data.size(), _cmd ); 00193 00194 size_t n = fwrite( buffer, 1, 10, f_out ); 00195 00196 if ( n != 10 ) { 00197 kdError(7017) << "Could not send header (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00198 return false; 00199 } 00200 00201 n = fwrite( data.data(), 1, data.size(), f_out ); 00202 00203 if ( n != data.size() ) { 00204 kdError(7017) << "Could not write data (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00205 return false; 00206 } 00207 00208 if (fflush( f_out )) { 00209 kdError(7017) << "Could not write data (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00210 return false; 00211 } 00212 00213 return true; 00214 } 00215 00216 int Connection::read( int* _cmd, TQByteArray &data ) 00217 { 00218 if (fd_in == -1 ) { 00219 kdError(7017) << "read: not yet inited (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00220 return -1; 00221 } 00222 00223 static char buffer[ 10 ]; 00224 00225 again1: 00226 ssize_t n = ::read( fd_in, buffer, 10); 00227 if ( n == -1 && errno == EINTR ) 00228 goto again1; 00229 00230 if ( n == -1) { 00231 kdError(7017) << "Header read failed, errno=" << errno << " (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00232 } 00233 00234 if ( n != 10 ) { 00235 if ( n ) // 0 indicates end of file 00236 kdError(7017) << "Header has invalid size (" << n << ") (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00237 return -1; 00238 } 00239 00240 buffer[ 6 ] = 0; 00241 buffer[ 9 ] = 0; 00242 00243 char *p = buffer; 00244 while( *p == ' ' ) p++; 00245 long int len = strtol( p, 0L, 16 ); 00246 00247 p = buffer + 7; 00248 while( *p == ' ' ) p++; 00249 long int cmd = strtol( p, 0L, 16 ); 00250 00251 data.resize( len ); 00252 00253 if ( len > 0L ) { 00254 size_t bytesToGo = len; 00255 size_t bytesRead = 0; 00256 do { 00257 n = ::read(fd_in, data.data()+bytesRead, bytesToGo); 00258 if (n == -1) { 00259 if (errno == EINTR) 00260 continue; 00261 00262 kdError(7017) << "Data read failed, errno=" << errno << " (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00263 return -1; 00264 } 00265 if ( !n ) { // 0 indicates end of file 00266 kdError(7017) << "Connection ended unexpectedly (" << n << "/" << bytesToGo << ") (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00267 return -1; 00268 } 00269 00270 bytesRead += n; 00271 bytesToGo -= n; 00272 } 00273 while(bytesToGo); 00274 } 00275 00276 *_cmd = cmd; 00277 return len; 00278 } 00279 00280 #include "connection.moc"