ksocketbuffer.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 <assert.h> 00028 #include <string.h> 00029 00030 #include "ksocketbase.h" 00031 #include "ksocketbuffer_p.h" 00032 00033 using namespace KNetwork; 00034 using namespace KNetwork::Internal; 00035 00036 KSocketBuffer::KSocketBuffer(TQ_LONG size) 00037 : m_mutex(true), m_offset(0), m_size(size), m_length(0) 00038 { 00039 } 00040 00041 KSocketBuffer::KSocketBuffer(const KSocketBuffer& other) 00042 : KIOBufferBase(other), m_mutex(true) 00043 { 00044 *this = other; 00045 } 00046 00047 KSocketBuffer::~KSocketBuffer() 00048 { 00049 // TQValueList takes care of deallocating memory 00050 } 00051 00052 KSocketBuffer& KSocketBuffer::operator=(const KSocketBuffer& other) 00053 { 00054 TQMutexLocker locker1(&m_mutex); 00055 TQMutexLocker locker2(&other.m_mutex); 00056 00057 KIOBufferBase::operator=(other); 00058 00059 m_list = other.m_list; // copy-on-write 00060 m_offset = other.m_offset; 00061 m_size = other.m_size; 00062 m_length = other.m_length; 00063 00064 return *this; 00065 } 00066 00067 bool KSocketBuffer::canReadLine() const 00068 { 00069 TQMutexLocker locker(&m_mutex); 00070 00071 TQValueListConstIterator<TQByteArray> it = m_list.constBegin(), 00072 end = m_list.constEnd(); 00073 TQIODevice::Offset offset = m_offset; 00074 00075 // walk the buffer 00076 for ( ; it != end; ++it) 00077 { 00078 if ((*it).find('\n', offset) != -1) 00079 return true; 00080 if ((*it).find('\r', offset) != -1) 00081 return true; 00082 offset = 0; 00083 } 00084 00085 return false; // not found 00086 } 00087 00088 TQCString KSocketBuffer::readLine() 00089 { 00090 if (!canReadLine()) 00091 return TQCString(); // empty 00092 00093 TQMutexLocker locker(&m_mutex); 00094 00095 // find the offset of the newline in the buffer 00096 int newline = 0; 00097 TQValueListConstIterator<TQByteArray> it = m_list.constBegin(), 00098 end = m_list.constEnd(); 00099 TQIODevice::Offset offset = m_offset; 00100 00101 // walk the buffer 00102 for ( ; it != end; ++it) 00103 { 00104 int posnl = (*it).find('\n', offset); 00105 if (posnl == -1) 00106 { 00107 // not found in this one 00108 newline += (*it).size(); 00109 offset = 0; 00110 continue; 00111 } 00112 00113 // we found it 00114 newline += posnl; 00115 break; 00116 } 00117 00118 TQCString result(newline + 2 - m_offset); 00119 consumeBuffer(result.data(), newline + 1 - m_offset); 00120 return result; 00121 } 00122 00123 TQ_LONG KSocketBuffer::length() const 00124 { 00125 return m_length; 00126 } 00127 00128 TQ_LONG KSocketBuffer::size() const 00129 { 00130 return m_size; 00131 } 00132 00133 bool KSocketBuffer::setSize(TQ_LONG size) 00134 { 00135 m_size = size; 00136 if (size == -1 || m_length < m_size) 00137 return true; 00138 00139 // size is now smaller than length 00140 TQMutexLocker locker(&m_mutex); 00141 00142 // repeat the test 00143 if (m_length < m_size) 00144 return true; 00145 00146 // discard from the beginning 00147 return (m_length - m_size) == consumeBuffer(0L, m_length - m_size, true); 00148 } 00149 00150 TQ_LONG KSocketBuffer::feedBuffer(const char *data, TQ_LONG len) 00151 { 00152 if (data == 0L || len == 0) 00153 return 0; // nothing to write 00154 if (isFull()) 00155 return -1; // can't write 00156 00157 TQMutexLocker locker(&m_mutex); 00158 00159 // verify if we can add len bytes 00160 if (m_size != -1 && (m_size - m_length) < len) 00161 len = m_size - m_length; 00162 00163 TQByteArray a(len); 00164 a.duplicate(data, len); 00165 m_list.append(a); 00166 00167 m_length += len; 00168 return len; 00169 } 00170 00171 TQ_LONG KSocketBuffer::consumeBuffer(char *destbuffer, TQ_LONG maxlen, bool discard) 00172 { 00173 if (maxlen == 0 || isEmpty()) 00174 return 0; 00175 00176 TQValueListIterator<TQByteArray> it = m_list.begin(), 00177 end = m_list.end(); 00178 TQIODevice::Offset offset = m_offset; 00179 TQ_LONG copied = 0; 00180 00181 // walk the buffer 00182 while (it != end && maxlen) 00183 { 00184 // calculate how much we'll copy 00185 size_t to_copy = (*it).size() - offset; 00186 if (to_copy > (size_t)maxlen) 00187 to_copy = maxlen; 00188 00189 // do the copying 00190 if (destbuffer) 00191 memcpy(destbuffer + copied, (*it).data() + offset, to_copy); 00192 maxlen -= to_copy; 00193 copied += to_copy; 00194 00195 if ((*it).size() - offset > to_copy) 00196 { 00197 // we did not copy everything 00198 offset += to_copy; 00199 break; 00200 } 00201 else 00202 { 00203 // we copied everything 00204 // discard this element; 00205 offset = 0; 00206 if (discard) 00207 it = m_list.remove(it); 00208 else 00209 ++it; 00210 } 00211 } 00212 00213 if (discard) 00214 { 00215 m_offset = offset; 00216 m_length -= copied; 00217 assert(m_length >= 0); 00218 } 00219 00220 return copied; 00221 } 00222 00223 void KSocketBuffer::clear() 00224 { 00225 TQMutexLocker locker(&m_mutex); 00226 m_list.clear(); 00227 m_offset = 0; 00228 m_length = 0; 00229 } 00230 00231 TQ_LONG KSocketBuffer::sendTo(KActiveSocketBase* dev, TQ_LONG len) 00232 { 00233 if (len == 0 || isEmpty()) 00234 return 0; 00235 00236 TQMutexLocker locker(&m_mutex); 00237 00238 TQValueListIterator<TQByteArray> it = m_list.begin(), 00239 end = m_list.end(); 00240 TQIODevice::Offset offset = m_offset; 00241 TQ_LONG written = 0; 00242 00243 // walk the buffer 00244 while (it != end && (len || len == -1)) 00245 { 00246 // we have to write each element up to len bytes 00247 // but since we can have several very small buffers, we can make things 00248 // better by concatenating a few of them into a big buffer 00249 // question is: how big should that buffer be? 2 kB should be enough 00250 00251 TQ_ULONG bufsize = 1460; 00252 if ((len != -1) && ((TQ_ULONG)len < bufsize)) { 00253 bufsize = len; 00254 } 00255 TQByteArray buf(bufsize); 00256 TQ_LONG count = 0; 00257 00258 while (it != end && count + ((*it).size() - offset) <= bufsize) 00259 { 00260 memcpy(buf.data() + count, (*it).data() + offset, (*it).size() - offset); 00261 count += (*it).size() - offset; 00262 offset = 0; 00263 ++it; 00264 } 00265 00266 // see if we can still fit more 00267 if ((TQ_ULONG)count < bufsize && it != end) 00268 { 00269 // getting here means this buffer (*it) is larger than 00270 // (bufsize - count) (even for count == 0). 00271 memcpy(buf.data() + count, (*it).data() + offset, bufsize - count); 00272 offset += bufsize - count; 00273 count = bufsize; 00274 } 00275 00276 // now try to write those bytes 00277 TQ_LONG wrote = dev->tqwriteBlock(buf, count); 00278 00279 if (wrote == -1) 00280 // error? 00281 break; 00282 00283 written += wrote; 00284 if (wrote != count) 00285 // can't fit more? 00286 break; 00287 } 00288 00289 // discard data that has been written 00290 // this updates m_length too 00291 if (written) 00292 consumeBuffer(0L, written); 00293 00294 return written; 00295 } 00296 00297 TQ_LONG KSocketBuffer::receiveFrom(KActiveSocketBase* dev, TQ_LONG len) 00298 { 00299 if (len == 0 || isFull()) 00300 return 0; 00301 00302 TQMutexLocker locker(&m_mutex); 00303 00304 if (len == -1) 00305 len = dev->bytesAvailable(); 00306 if (len <= 0) 00307 // error or closing socket 00308 return len; 00309 00310 // see if we can read that much 00311 if (m_size != -1 && len > (m_size - m_length)) 00312 len = m_size - m_length; 00313 00314 // here, len contains just as many bytes as we're supposed to read 00315 00316 // now do the reading 00317 TQByteArray a(len); 00318 len = dev->tqreadBlock(a.data(), len); 00319 00320 if (len == -1) 00321 // error? 00322 return -1; 00323 00324 // success 00325 // resize the buffer and add it 00326 a.truncate(len); 00327 m_list.append(a); 00328 m_length += len; 00329 return len; 00330 }