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