kdecore Library API Documentation

kbufferedsocket.cpp

00001 /* -*- C++ -*- 00002 * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net> 00003 * 00004 * 00005 * Permission is hereby granted, free of charge, to any person obtaining 00006 * a copy of this software and associated documentation files (the 00007 * "Software"), to deal in the Software without restriction, including 00008 * without limitation the rights to use, copy, modify, merge, publish, 00009 * distribute, sublicense, and/or sell copies of the Software, and to 00010 * permit persons to whom the Software is furnished to do so, subject to 00011 * the following conditions: 00012 * 00013 * The above copyright notice and this permission notice shall be included 00014 * in all copies or substantial portions of the Software. 00015 * 00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 00020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 00021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00023 */ 00024 00025 #include <config.h> 00026 00027 #include <qmutex.h> 00028 #include <qtimer.h> 00029 00030 #include "ksocketdevice.h" 00031 #include "ksocketaddress.h" 00032 #include "ksocketbuffer_p.h" 00033 #include "kbufferedsocket.h" 00034 00035 using namespace KNetwork; 00036 using namespace KNetwork::Internal; 00037 00038 class KNetwork::KBufferedSocketPrivate 00039 { 00040 public: 00041 mutable KSocketBuffer *input, *output; 00042 00043 KBufferedSocketPrivate() 00044 { 00045 input = 0L; 00046 output = 0L; 00047 } 00048 }; 00049 00050 KBufferedSocket::KBufferedSocket(const QString& host, const QString& service, 00051 QObject *parent, const char *name) 00052 : KStreamSocket(host, service, parent, name), 00053 d(new KBufferedSocketPrivate) 00054 { 00055 setBlocking(false); 00056 setInputBuffering(true); 00057 setOutputBuffering(true); 00058 } 00059 00060 KBufferedSocket::~KBufferedSocket() 00061 { 00062 closeNow(); 00063 delete d->input; 00064 delete d->output; 00065 delete d; 00066 } 00067 00068 void KBufferedSocket::setSocketDevice(KSocketDevice* device) 00069 { 00070 KStreamSocket::setSocketDevice(device); 00071 device->setBlocking(false); 00072 } 00073 00074 bool KBufferedSocket::setSocketOptions(int opts) 00075 { 00076 if (opts == Blocking) 00077 return false; 00078 00079 opts &= ~Blocking; 00080 return KStreamSocket::setSocketOptions(opts); 00081 } 00082 00083 void KBufferedSocket::close() 00084 { 00085 if (!d->output || d->output->isEmpty()) 00086 closeNow(); 00087 else 00088 { 00089 setState(Closing); 00090 QSocketNotifier *n = socketDevice()->readNotifier(); 00091 if (n) 00092 n->setEnabled(false); 00093 emit stateChanged(Closing); 00094 } 00095 } 00096 00097 Q_LONG KBufferedSocket::bytesAvailable() const 00098 { 00099 if (!d->input) 00100 return KStreamSocket::bytesAvailable(); 00101 00102 return d->input->length(); 00103 } 00104 00105 Q_LONG KBufferedSocket::waitForMore(int msecs, bool *timeout) 00106 { 00107 Q_LONG retval = KStreamSocket::waitForMore(msecs, timeout); 00108 if (d->input) 00109 { 00110 resetError(); 00111 slotReadActivity(); 00112 return bytesAvailable(); 00113 } 00114 return retval; 00115 } 00116 00117 Q_LONG KBufferedSocket::readBlock(char *data, Q_ULONG maxlen) 00118 { 00119 if (d->input) 00120 { 00121 if (d->input->isEmpty()) 00122 { 00123 setError(IO_ReadError, WouldBlock); 00124 emit gotError(WouldBlock); 00125 return -1; 00126 } 00127 resetError(); 00128 return d->input->consumeBuffer(data, maxlen); 00129 } 00130 return KStreamSocket::readBlock(data, maxlen); 00131 } 00132 00133 Q_LONG KBufferedSocket::readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from) 00134 { 00135 from = peerAddress(); 00136 return readBlock(data, maxlen); 00137 } 00138 00139 Q_LONG KBufferedSocket::peekBlock(char *data, Q_ULONG maxlen) 00140 { 00141 if (d->input) 00142 { 00143 if (d->input->isEmpty()) 00144 { 00145 setError(IO_ReadError, WouldBlock); 00146 emit gotError(WouldBlock); 00147 return -1; 00148 } 00149 resetError(); 00150 return d->input->consumeBuffer(data, maxlen, false); 00151 } 00152 return KStreamSocket::peekBlock(data, maxlen); 00153 } 00154 00155 Q_LONG KBufferedSocket::peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from) 00156 { 00157 from = peerAddress(); 00158 return peekBlock(data, maxlen); 00159 } 00160 00161 Q_LONG KBufferedSocket::writeBlock(const char *data, Q_ULONG len) 00162 { 00163 if (state() != Connected) 00164 { 00165 // cannot write now! 00166 setError(IO_WriteError, NotConnected); 00167 return -1; 00168 } 00169 00170 if (d->output) 00171 { 00172 if (d->output->isFull()) 00173 { 00174 setError(IO_WriteError, WouldBlock); 00175 emit gotError(WouldBlock); 00176 return -1; 00177 } 00178 resetError(); 00179 00180 // enable notifier to send data 00181 QSocketNotifier *n = socketDevice()->writeNotifier(); 00182 if (n) 00183 n->setEnabled(true); 00184 00185 return d->output->feedBuffer(data, len); 00186 } 00187 00188 return KStreamSocket::writeBlock(data, len); 00189 } 00190 00191 Q_LONG KBufferedSocket::writeBlock(const char *data, Q_ULONG maxlen, 00192 const KSocketAddress&) 00193 { 00194 // ignore the third parameter 00195 return writeBlock(data, maxlen); 00196 } 00197 00198 void KBufferedSocket::enableRead(bool enable) 00199 { 00200 KStreamSocket::enableRead(enable); 00201 if (!enable && d->input) 00202 { 00203 // reenable it 00204 QSocketNotifier *n = socketDevice()->readNotifier(); 00205 if (n) 00206 n->setEnabled(true); 00207 } 00208 00209 if (enable && state() != Connected && d->input && !d->input->isEmpty()) 00210 // this means the buffer is still dirty 00211 // allow the signal to be emitted 00212 QTimer::singleShot(0, this, SLOT(slotReadActivity())); 00213 } 00214 00215 void KBufferedSocket::enableWrite(bool enable) 00216 { 00217 KStreamSocket::enableWrite(enable); 00218 if (!enable && d->output && !d->output->isEmpty()) 00219 { 00220 // reenable it 00221 QSocketNotifier *n = socketDevice()->writeNotifier(); 00222 if (n) 00223 n->setEnabled(true); 00224 } 00225 } 00226 00227 void KBufferedSocket::stateChanging(SocketState newState) 00228 { 00229 if (newState == Connecting || newState == Connected) 00230 { 00231 // we're going to connect 00232 // make sure the buffers are clean 00233 if (d->input) 00234 d->input->clear(); 00235 if (d->output) 00236 d->output->clear(); 00237 00238 // also, turn on notifiers 00239 enableRead(emitsReadyRead()); 00240 enableWrite(emitsReadyWrite()); 00241 } 00242 KStreamSocket::stateChanging(newState); 00243 } 00244 00245 void KBufferedSocket::setInputBuffering(bool enable) 00246 { 00247 QMutexLocker locker(mutex()); 00248 if (!enable) 00249 { 00250 delete d->input; 00251 d->input = 0L; 00252 } 00253 else if (d->input == 0L) 00254 { 00255 d->input = new KSocketBuffer; 00256 } 00257 } 00258 00259 KIOBufferBase* KBufferedSocket::inputBuffer() 00260 { 00261 return d->input; 00262 } 00263 00264 void KBufferedSocket::setOutputBuffering(bool enable) 00265 { 00266 QMutexLocker locker(mutex()); 00267 if (!enable) 00268 { 00269 delete d->output; 00270 d->output = 0L; 00271 } 00272 else if (d->output == 0L) 00273 { 00274 d->output = new KSocketBuffer; 00275 } 00276 } 00277 00278 KIOBufferBase* KBufferedSocket::outputBuffer() 00279 { 00280 return d->output; 00281 } 00282 00283 Q_ULONG KBufferedSocket::bytesToWrite() const 00284 { 00285 if (!d->output) 00286 return 0; 00287 00288 return d->output->length(); 00289 } 00290 00291 void KBufferedSocket::closeNow() 00292 { 00293 KStreamSocket::close(); 00294 } 00295 00296 bool KBufferedSocket::canReadLine() const 00297 { 00298 if (!d->input) 00299 return false; 00300 00301 return d->input->canReadLine(); 00302 } 00303 00304 QCString KBufferedSocket::readLine() 00305 { 00306 return d->input->readLine(); 00307 } 00308 00309 void KBufferedSocket::slotReadActivity() 00310 { 00311 if (d->input && state() == Connected) 00312 { 00313 mutex()->lock(); 00314 Q_LONG len = d->input->receiveFrom(socketDevice()); 00315 00316 if (len == -1) 00317 { 00318 if (socketDevice()->error() != WouldBlock) 00319 { 00320 // nope, another error! 00321 copyError(); 00322 mutex()->unlock(); 00323 closeNow(); // emits closed 00324 return; 00325 } 00326 } 00327 else if (len == 0) 00328 { 00329 // remotely closed 00330 resetError(); 00331 mutex()->unlock(); 00332 closeNow(); // emits closed 00333 return; 00334 } 00335 00336 // no error 00337 mutex()->unlock(); 00338 } 00339 00340 if (state() == Connected) 00341 KStreamSocket::slotReadActivity(); // this emits readyRead 00342 else if (emitsReadyRead()) // state() != Connected 00343 { 00344 if (d->input && !d->input->isEmpty()) 00345 { 00346 // buffer isn't empty 00347 // keep emitting signals till it is 00348 QTimer::singleShot(0, this, SLOT(slotReadActivity())); 00349 emit readyRead(); 00350 } 00351 } 00352 } 00353 00354 void KBufferedSocket::slotWriteActivity() 00355 { 00356 if (d->output && !d->output->isEmpty() && 00357 (state() == Connected || state() == Closing)) 00358 { 00359 mutex()->lock(); 00360 Q_LONG len = d->output->sendTo(socketDevice()); 00361 00362 if (len == -1) 00363 { 00364 if (socketDevice()->error() != WouldBlock) 00365 { 00366 // nope, another error! 00367 copyError(); 00368 mutex()->unlock(); 00369 closeNow(); 00370 return; 00371 } 00372 } 00373 else if (len == 0) 00374 { 00375 // remotely closed 00376 resetError(); 00377 mutex()->unlock(); 00378 closeNow(); 00379 return; 00380 } 00381 00382 if (d->output->isEmpty()) 00383 // deactivate the notifier until we have something to send 00384 // writeNotifier can't return NULL here 00385 socketDevice()->writeNotifier()->setEnabled(false); 00386 00387 mutex()->unlock(); 00388 emit bytesWritten(len); 00389 } 00390 00391 if (state() != Closing) 00392 KStreamSocket::slotWriteActivity(); 00393 else if (d->output && d->output->isEmpty() && state() == Closing) 00394 { 00395 KStreamSocket::close(); // finished sending data 00396 } 00397 } 00398 00399 #include "kbufferedsocket.moc"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:43:09 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003