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