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 "tdeio/connection.h" 00041 00042 #include <kdebug.h> 00043 #include <tqsocketnotifier.h> 00044 00045 #if defined(__OpenBSD__) || defined(__FreeBSD__) 00046 #define __progname getprogname() 00047 #else 00048 extern char *__progname; 00049 #endif 00050 00051 using namespace TDEIO; 00052 00053 Connection::Connection() 00054 { 00055 f_out = 0; 00056 fd_in = -1; 00057 socket = 0; 00058 notifier = 0; 00059 receiver = 0; 00060 member = 0; 00061 m_suspended = false; 00062 tasks.setAutoDelete(true); 00063 } 00064 00065 Connection::~Connection() 00066 { 00067 close(); 00068 } 00069 00070 void Connection::suspend() 00071 { 00072 m_suspended = true; 00073 if (notifier) 00074 notifier->setEnabled(false); 00075 } 00076 00077 void Connection::resume() 00078 { 00079 m_suspended = false; 00080 if (notifier) 00081 notifier->setEnabled(true); 00082 } 00083 00084 void Connection::close() 00085 { 00086 delete notifier; 00087 notifier = 0; 00088 delete socket; 00089 socket = 0; 00090 00091 // TDESocket has already closed the file descriptor, but we need to 00092 // close the file-stream as well otherwise we leak memory. 00093 // As a result we close the file descriptor twice, but that should 00094 // be harmless 00095 // KDE4: fix this 00096 if (f_out) 00097 fclose(f_out); 00098 f_out = 0; 00099 fd_in = -1; 00100 tasks.clear(); 00101 } 00102 00103 void Connection::send(int cmd, const TQByteArray& data) 00104 { 00105 if (!inited() || tasks.count() > 0) { 00106 Task *task = new Task(); 00107 task->cmd = cmd; 00108 task->data = data; 00109 tasks.append(task); 00110 } else { 00111 sendnow( cmd, data ); 00112 } 00113 } 00114 00115 void Connection::dequeue() 00116 { 00117 if (!inited()) 00118 return; 00119 00120 while (tasks.count()) 00121 { 00122 tasks.first(); 00123 Task *task = tasks.take(); 00124 sendnow( task->cmd, task->data ); 00125 delete task; 00126 } 00127 } 00128 00129 void Connection::init(TDESocket *sock) 00130 { 00131 delete notifier; 00132 notifier = 0; 00133 #ifdef Q_OS_UNIX //TODO: not yet available on WIN32 00134 delete socket; 00135 socket = sock; 00136 fd_in = socket->socket(); 00137 f_out = KDE_fdopen( socket->socket(), "wb" ); 00138 #endif 00139 if (receiver && ( fd_in != -1 )) { 00140 notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read); 00141 if ( m_suspended ) { 00142 suspend(); 00143 } 00144 TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member); 00145 } 00146 dequeue(); 00147 } 00148 00149 void Connection::init(int _fd_in, int fd_out) 00150 { 00151 delete notifier; 00152 notifier = 0; 00153 fd_in = _fd_in; 00154 f_out = KDE_fdopen( fd_out, "wb" ); 00155 if (receiver && ( fd_in != -1 )) { 00156 notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read); 00157 if ( m_suspended ) { 00158 suspend(); 00159 } 00160 TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member); 00161 } 00162 dequeue(); 00163 } 00164 00165 00166 void Connection::connect(TQObject *_receiver, const char *_member) 00167 { 00168 receiver = _receiver; 00169 member = _member; 00170 delete notifier; 00171 notifier = 0; 00172 if (receiver && (fd_in != -1 )) { 00173 notifier = new TQSocketNotifier(fd_in, TQSocketNotifier::Read); 00174 if ( m_suspended ) 00175 suspend(); 00176 TQObject::connect(notifier, TQT_SIGNAL(activated(int)), receiver, member); 00177 } 00178 } 00179 00180 bool Connection::sendnow( int _cmd, const TQByteArray &data ) 00181 { 00182 if (f_out == 0) { 00183 return false; 00184 } 00185 00186 if (data.size() > 0xffffff) 00187 return false; 00188 00189 static char buffer[ 64 ]; 00190 sprintf( buffer, "%6x_%2x_", data.size(), _cmd ); 00191 00192 size_t n = fwrite( buffer, 1, 10, f_out ); 00193 00194 if ( n != 10 ) { 00195 kdError(7017) << "Could not send header (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00196 return false; 00197 } 00198 00199 n = fwrite( data.data(), 1, data.size(), f_out ); 00200 00201 if ( n != data.size() ) { 00202 kdError(7017) << "Could not write data (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00203 return false; 00204 } 00205 00206 if (fflush( f_out )) { 00207 kdError(7017) << "Could not write data (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00208 return false; 00209 } 00210 00211 return true; 00212 } 00213 00214 int Connection::read( int* _cmd, TQByteArray &data ) 00215 { 00216 if (fd_in == -1 ) { 00217 kdError(7017) << "read: not yet inited (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00218 return -1; 00219 } 00220 00221 static char buffer[ 10 ]; 00222 00223 again1: 00224 ssize_t n = ::read( fd_in, buffer, 10); 00225 if ( n == -1 && errno == EINTR ) 00226 goto again1; 00227 00228 if ( n == -1) { 00229 kdError(7017) << "Header read failed, errno=" << errno << " (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00230 } 00231 00232 if ( n != 10 ) { 00233 if ( n ) // 0 indicates end of file 00234 kdError(7017) << "Header has invalid size (" << n << ") (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00235 return -1; 00236 } 00237 00238 buffer[ 6 ] = 0; 00239 buffer[ 9 ] = 0; 00240 00241 char *p = buffer; 00242 while( *p == ' ' ) p++; 00243 long int len = strtol( p, 0L, 16 ); 00244 00245 p = buffer + 7; 00246 while( *p == ' ' ) p++; 00247 long int cmd = strtol( p, 0L, 16 ); 00248 00249 data.resize( len ); 00250 00251 if ( len > 0L ) { 00252 size_t bytesToGo = len; 00253 size_t bytesRead = 0; 00254 do { 00255 n = ::read(fd_in, data.data()+bytesRead, bytesToGo); 00256 if (n == -1) { 00257 if (errno == EINTR) 00258 continue; 00259 00260 kdError(7017) << "Data read failed, errno=" << errno << " (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00261 return -1; 00262 } 00263 if ( !n ) { // 0 indicates end of file 00264 kdError(7017) << "Connection ended unexpectedly (" << n << "/" << bytesToGo << ") (pid " << getpid() << " process \"" << __progname << "\")" << endl; 00265 return -1; 00266 } 00267 00268 bytesRead += n; 00269 bytesToGo -= n; 00270 } 00271 while(bytesToGo); 00272 } 00273 00274 *_cmd = cmd; 00275 return len; 00276 } 00277 00278 #include "connection.moc"