File indexing completed on 2024-12-08 12:17:40
0001 /* -*- C++ -*- 0002 * Copyright (C) 2003 Thiago Macieira <thiago@kde.org> 0003 * 0004 * 0005 * Permission is hereby granted, free of charge, to any person obtaining 0006 * a copy of this software and associated documentation files (the 0007 * "Software"), to deal in the Software without restriction, including 0008 * without limitation the rights to use, copy, modify, merge, publish, 0009 * distribute, sublicense, and/or sell copies of the Software, and to 0010 * permit persons to whom the Software is furnished to do so, subject to 0011 * the following conditions: 0012 * 0013 * The above copyright notice and this permission notice shall be included 0014 * in all copies or substantial portions of the Software. 0015 * 0016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 0017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 0018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 0019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 0020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 0021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 0022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0023 */ 0024 0025 #include "k3socketbuffer_p.h" 0026 0027 #include <config-network.h> 0028 0029 #include <assert.h> 0030 #include <string.h> 0031 0032 #include <QMutableListIterator> 0033 0034 #include "k3socketbase.h" 0035 0036 using namespace KNetwork; 0037 using namespace KNetwork::Internal; 0038 0039 KSocketBuffer::KSocketBuffer(qint64 size) 0040 : m_mutex(QMutex::Recursive), m_offset(0), m_size(size), m_length(0) 0041 { 0042 } 0043 0044 KSocketBuffer::KSocketBuffer(const KSocketBuffer &other) 0045 : m_mutex(QMutex::Recursive) 0046 { 0047 *this = other; 0048 } 0049 0050 KSocketBuffer::~KSocketBuffer() 0051 { 0052 // QValueList takes care of deallocating memory 0053 } 0054 0055 KSocketBuffer &KSocketBuffer::operator=(const KSocketBuffer &other) 0056 { 0057 QMutexLocker locker1(&m_mutex); 0058 QMutexLocker locker2(&other.m_mutex); 0059 0060 m_list = other.m_list; // copy-on-write 0061 m_offset = other.m_offset; 0062 m_size = other.m_size; 0063 m_length = other.m_length; 0064 0065 return *this; 0066 } 0067 0068 bool KSocketBuffer::canReadLine() const 0069 { 0070 QMutexLocker locker(&m_mutex); 0071 0072 qint64 offset = m_offset; 0073 0074 // walk the buffer 0075 for (int i = 0; i < m_list.size(); ++i) { 0076 if (m_list.at(i).indexOf('\n', offset) != -1) { 0077 return true; 0078 } 0079 if (m_list.at(i).indexOf('\r', offset) != -1) { 0080 return true; 0081 } 0082 offset = 0; 0083 } 0084 0085 return false; // not found 0086 } 0087 0088 qint64 KSocketBuffer::readLine(char *data, qint64 maxSize) 0089 { 0090 if (!canReadLine()) { 0091 return qint64(-1); // empty 0092 } 0093 0094 QMutexLocker locker(&m_mutex); 0095 0096 // find the offset of the newline in the buffer 0097 qint64 newline = 0; 0098 qint64 offset = m_offset; 0099 0100 // walk the buffer 0101 for (int i = 0; i < m_list.size(); ++i) { 0102 int posnl = m_list.at(i).indexOf('\n', offset); 0103 if (posnl == -1) { 0104 // not found in this one 0105 newline += m_list.at(i).size(); 0106 offset = 0; 0107 continue; 0108 } 0109 0110 // we found it 0111 newline += posnl; 0112 break; 0113 } 0114 0115 qint64 bytesToRead = newline + 1 - m_offset; 0116 if (bytesToRead > maxSize) { 0117 bytesToRead = maxSize; // don't read more than maxSize 0118 } 0119 0120 return consumeBuffer(data, bytesToRead); 0121 } 0122 0123 qint64 KSocketBuffer::length() const 0124 { 0125 return m_length; 0126 } 0127 0128 qint64 KSocketBuffer::size() const 0129 { 0130 return m_size; 0131 } 0132 0133 bool KSocketBuffer::setSize(qint64 size) 0134 { 0135 m_size = size; 0136 if (size == -1 || m_length < m_size) { 0137 return true; 0138 } 0139 0140 // size is now smaller than length 0141 QMutexLocker locker(&m_mutex); 0142 0143 // repeat the test 0144 if (m_length < m_size) { 0145 return true; 0146 } 0147 0148 // discard from the beginning 0149 return (m_length - m_size) == consumeBuffer(nullptr, m_length - m_size, true); 0150 } 0151 0152 qint64 KSocketBuffer::feedBuffer(const char *data, qint64 len) 0153 { 0154 if (data == nullptr || len == 0) { 0155 return 0; // nothing to write 0156 } 0157 if (isFull()) { 0158 return -1; // can't write 0159 } 0160 0161 QMutexLocker locker(&m_mutex); 0162 0163 // verify if we can add len bytes 0164 if (m_size != -1 && (m_size - m_length) < len) { 0165 len = m_size - m_length; 0166 } 0167 0168 QByteArray a(data, len); 0169 m_list.append(a); 0170 0171 m_length += len; 0172 return len; 0173 } 0174 0175 qint64 KSocketBuffer::consumeBuffer(char *destbuffer, qint64 maxlen, bool discard) 0176 { 0177 if (maxlen == 0 || isEmpty()) { 0178 return 0; 0179 } 0180 0181 QMutableListIterator<QByteArray> it(m_list); 0182 qint64 offset = m_offset; 0183 qint64 copied = 0; 0184 0185 // walk the buffer 0186 while (it.hasNext() && maxlen) { 0187 QByteArray &item = it.next(); 0188 // calculate how much we'll copy 0189 qint64 to_copy = item.size() - offset; 0190 if (to_copy > maxlen) { 0191 to_copy = maxlen; 0192 } 0193 0194 // do the copying 0195 if (destbuffer) { 0196 memcpy(destbuffer + copied, item.data() + offset, to_copy); 0197 } 0198 maxlen -= to_copy; 0199 copied += to_copy; 0200 0201 if (item.size() - offset > to_copy) { 0202 // we did not copy everything 0203 offset += to_copy; 0204 break; 0205 } else { 0206 // we copied everything 0207 // discard this element; 0208 offset = 0; 0209 if (discard) { 0210 it.remove(); 0211 } 0212 } 0213 } 0214 0215 if (discard) { 0216 m_offset = offset; 0217 m_length -= copied; 0218 assert(m_length >= 0); 0219 } 0220 0221 return copied; 0222 } 0223 0224 void KSocketBuffer::clear() 0225 { 0226 QMutexLocker locker(&m_mutex); 0227 m_list.clear(); 0228 m_offset = 0; 0229 m_length = 0; 0230 } 0231 0232 qint64 KSocketBuffer::sendTo(KActiveSocketBase *dev, qint64 len) 0233 { 0234 if (len == 0 || isEmpty()) { 0235 return 0; 0236 } 0237 0238 QMutexLocker locker(&m_mutex); 0239 0240 QMutableListIterator<QByteArray> it(m_list); 0241 qint64 offset = m_offset; 0242 qint64 written = 0; 0243 0244 // walk the buffer 0245 while (it.hasNext() && (len || len == -1)) { 0246 // we have to write each element up to len bytes 0247 // but since we can have several very small buffers, we can make things 0248 // better by concatenating a few of them into a big buffer 0249 // question is: how big should that buffer be? 2 kB should be enough 0250 0251 uint bufsize = 1460; 0252 if (len != -1 && len < bufsize) { 0253 bufsize = len; 0254 } 0255 QByteArray buf(bufsize, '\0'); 0256 qint64 count = 0; 0257 0258 while (it.hasNext() && count + (it.peekNext().size() - offset) <= bufsize) { 0259 QByteArray &item = it.next(); 0260 memcpy(buf.data() + count, item.data() + offset, item.size() - offset); 0261 count += item.size() - offset; 0262 offset = 0; 0263 } 0264 0265 // see if we can still fit more 0266 if (count < bufsize && it.hasNext()) { 0267 // getting here means this buffer (peekNext) is larger than 0268 // (bufsize - count) (even for count == 0). 0269 QByteArray &item = it.next(); 0270 memcpy(buf.data() + count, item.data() + offset, bufsize - count); 0271 offset += bufsize - count; 0272 count = bufsize; 0273 } 0274 0275 // now try to write those bytes 0276 qint64 wrote = dev->write(buf, count); 0277 0278 if (wrote == -1) 0279 // error? 0280 { 0281 break; 0282 } 0283 0284 written += wrote; 0285 if (wrote != count) 0286 // can't fit more? 0287 { 0288 break; 0289 } 0290 } 0291 0292 // discard data that has been written 0293 // this updates m_length too 0294 if (written) { 0295 consumeBuffer(nullptr, written); 0296 } 0297 0298 return written; 0299 } 0300 0301 qint64 KSocketBuffer::receiveFrom(KActiveSocketBase *dev, qint64 len) 0302 { 0303 if (len == 0 || isFull()) { 0304 return 0; 0305 } 0306 0307 QMutexLocker locker(&m_mutex); 0308 0309 if (len == -1) { 0310 len = dev->bytesAvailable(); 0311 } 0312 if (len <= 0) 0313 // error or closing socket 0314 { 0315 return len; 0316 } 0317 0318 // see if we can read that much 0319 if (m_size != -1 && len > (m_size - m_length)) { 0320 len = m_size - m_length; 0321 } 0322 0323 // here, len contains just as many bytes as we're supposed to read 0324 0325 // now do the reading 0326 QByteArray a(len, '\0'); 0327 len = dev->read(a.data(), len); 0328 0329 if (len == -1) 0330 // error? 0331 { 0332 return -1; 0333 } 0334 0335 // success 0336 // resize the buffer and add it 0337 a.truncate(len); 0338 m_list.append(a); 0339 m_length += len; 0340 return len; 0341 }