File indexing completed on 2024-07-21 12:07:30

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 }