• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • sources
  • kde-4.14
  • kdelibs
  • kdecore
  • network
k3socketbuffer.cpp
Go to the documentation of this file.
1 /* -*- C++ -*-
2  * Copyright (C) 2003 Thiago Macieira <thiago@kde.org>
3  *
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include "k3socketbuffer_p.h"
26 
27 #include <config.h>
28 #include <config-network.h>
29 
30 #include <assert.h>
31 #include <string.h>
32 
33 #include <QMutableListIterator>
34 
35 #include "k3socketbase.h"
36 
37 using namespace KNetwork;
38 using namespace KNetwork::Internal;
39 
40 KSocketBuffer::KSocketBuffer(qint64 size)
41  : m_mutex(QMutex::Recursive), m_offset(0), m_size(size), m_length(0)
42 {
43 }
44 
45 KSocketBuffer::KSocketBuffer(const KSocketBuffer& other)
46  : m_mutex(QMutex::Recursive)
47 {
48  *this = other;
49 }
50 
51 KSocketBuffer::~KSocketBuffer()
52 {
53  // QValueList takes care of deallocating memory
54 }
55 
56 KSocketBuffer& KSocketBuffer::operator=(const KSocketBuffer& other)
57 {
58  QMutexLocker locker1(&m_mutex);
59  QMutexLocker locker2(&other.m_mutex);
60 
61  m_list = other.m_list; // copy-on-write
62  m_offset = other.m_offset;
63  m_size = other.m_size;
64  m_length = other.m_length;
65 
66  return *this;
67 }
68 
69 bool KSocketBuffer::canReadLine() const
70 {
71  QMutexLocker locker(&m_mutex);
72 
73  qint64 offset = m_offset;
74 
75  // walk the buffer
76  for (int i = 0; i < m_list.size(); ++i)
77  {
78  if (m_list.at(i).indexOf('\n', offset) != -1)
79  return true;
80  if (m_list.at(i).indexOf('\r', offset) != -1)
81  return true;
82  offset = 0;
83  }
84 
85  return false; // not found
86 }
87 
88 qint64 KSocketBuffer::readLine(char* data, qint64 maxSize)
89 {
90  if (!canReadLine())
91  return qint64(-1); // empty
92 
93  QMutexLocker locker(&m_mutex);
94 
95  // find the offset of the newline in the buffer
96  qint64 newline = 0;
97  qint64 offset = m_offset;
98 
99  // walk the buffer
100  for (int i = 0; i < m_list.size(); ++i)
101  {
102  int posnl = m_list.at(i).indexOf('\n', offset);
103  if (posnl == -1)
104  {
105  // not found in this one
106  newline += m_list.at(i).size();
107  offset = 0;
108  continue;
109  }
110 
111  // we found it
112  newline += posnl;
113  break;
114  }
115 
116  qint64 bytesToRead = newline + 1 - m_offset;
117  if (bytesToRead > maxSize)
118  bytesToRead = maxSize; // don't read more than maxSize
119 
120  return consumeBuffer(data, bytesToRead);
121 }
122 
123 qint64 KSocketBuffer::length() const
124 {
125  return m_length;
126 }
127 
128 qint64 KSocketBuffer::size() const
129 {
130  return m_size;
131 }
132 
133 bool KSocketBuffer::setSize(qint64 size)
134 {
135  m_size = size;
136  if (size == -1 || m_length < m_size)
137  return true;
138 
139  // size is now smaller than length
140  QMutexLocker locker(&m_mutex);
141 
142  // repeat the test
143  if (m_length < m_size)
144  return true;
145 
146  // discard from the beginning
147  return (m_length - m_size) == consumeBuffer(0L, m_length - m_size, true);
148 }
149 
150 qint64 KSocketBuffer::feedBuffer(const char *data, qint64 len)
151 {
152  if (data == 0L || len == 0)
153  return 0; // nothing to write
154  if (isFull())
155  return -1; // can't write
156 
157  QMutexLocker locker(&m_mutex);
158 
159  // verify if we can add len bytes
160  if (m_size != -1 && (m_size - m_length) < len)
161  len = m_size - m_length;
162 
163  QByteArray a(data, len);
164  m_list.append(a);
165 
166  m_length += len;
167  return len;
168 }
169 
170 qint64 KSocketBuffer::consumeBuffer(char *destbuffer, qint64 maxlen, bool discard)
171 {
172  if (maxlen == 0 || isEmpty())
173  return 0;
174 
175  QMutableListIterator<QByteArray> it(m_list);
176  qint64 offset = m_offset;
177  qint64 copied = 0;
178 
179  // walk the buffer
180  while (it.hasNext() && maxlen)
181  {
182  QByteArray& item = it.next();
183  // calculate how much we'll copy
184  qint64 to_copy = item.size() - offset;
185  if (to_copy > maxlen)
186  to_copy = maxlen;
187 
188  // do the copying
189  if (destbuffer)
190  memcpy(destbuffer + copied, item.data() + offset, to_copy);
191  maxlen -= to_copy;
192  copied += to_copy;
193 
194  if (item.size() - offset > to_copy)
195  {
196  // we did not copy everything
197  offset += to_copy;
198  break;
199  }
200  else
201  {
202  // we copied everything
203  // discard this element;
204  offset = 0;
205  if (discard)
206  it.remove();
207  }
208  }
209 
210  if (discard)
211  {
212  m_offset = offset;
213  m_length -= copied;
214  assert(m_length >= 0);
215  }
216 
217  return copied;
218 }
219 
220 void KSocketBuffer::clear()
221 {
222  QMutexLocker locker(&m_mutex);
223  m_list.clear();
224  m_offset = 0;
225  m_length = 0;
226 }
227 
228 qint64 KSocketBuffer::sendTo(KActiveSocketBase* dev, qint64 len)
229 {
230  if (len == 0 || isEmpty())
231  return 0;
232 
233  QMutexLocker locker(&m_mutex);
234 
235  QMutableListIterator<QByteArray> it(m_list);
236  qint64 offset = m_offset;
237  qint64 written = 0;
238 
239  // walk the buffer
240  while (it.hasNext() && (len || len == -1))
241  {
242  // we have to write each element up to len bytes
243  // but since we can have several very small buffers, we can make things
244  // better by concatenating a few of them into a big buffer
245  // question is: how big should that buffer be? 2 kB should be enough
246 
247  uint bufsize = 1460;
248  if (len != -1 && len < bufsize)
249  bufsize = len;
250  QByteArray buf(bufsize, '\0');
251  qint64 count = 0;
252 
253  while (it.hasNext() && count + (it.peekNext().size() - offset) <= bufsize)
254  {
255  QByteArray& item = it.next();
256  memcpy(buf.data() + count, item.data() + offset, item.size() - offset);
257  count += item.size() - offset;
258  offset = 0;
259  }
260 
261  // see if we can still fit more
262  if (count < bufsize && it.hasNext())
263  {
264  // getting here means this buffer (peekNext) is larger than
265  // (bufsize - count) (even for count == 0).
266  QByteArray& item = it.next();
267  memcpy(buf.data() + count, item.data() + offset, bufsize - count);
268  offset += bufsize - count;
269  count = bufsize;
270  }
271 
272  // now try to write those bytes
273  qint64 wrote = dev->write(buf, count);
274 
275  if (wrote == -1)
276  // error?
277  break;
278 
279  written += wrote;
280  if (wrote != count)
281  // can't fit more?
282  break;
283  }
284 
285  // discard data that has been written
286  // this updates m_length too
287  if (written)
288  consumeBuffer(0L, written);
289 
290  return written;
291 }
292 
293 qint64 KSocketBuffer::receiveFrom(KActiveSocketBase* dev, qint64 len)
294 {
295  if (len == 0 || isFull())
296  return 0;
297 
298  QMutexLocker locker(&m_mutex);
299 
300  if (len == -1)
301  len = dev->bytesAvailable();
302  if (len <= 0)
303  // error or closing socket
304  return len;
305 
306  // see if we can read that much
307  if (m_size != -1 && len > (m_size - m_length))
308  len = m_size - m_length;
309 
310  // here, len contains just as many bytes as we're supposed to read
311 
312  // now do the reading
313  QByteArray a(len, '\0');
314  len = dev->read(a.data(), len);
315 
316  if (len == -1)
317  // error?
318  return -1;
319 
320  // success
321  // resize the buffer and add it
322  a.truncate(len);
323  m_list.append(a);
324  m_length += len;
325  return len;
326 }
KNetwork::Internal::KSocketBuffer::setSize
bool setSize(qint64 size)
Sets the size of the buffer, if allowed.
Definition: k3socketbuffer.cpp:133
QList::clear
void clear()
QMutex
qint64
KNetwork::Internal::KSocketBuffer::canReadLine
bool canReadLine() const
Returns true if a line can be read from the buffer.
Definition: k3socketbuffer.cpp:69
k3socketbuffer_p.h
KNetwork::Internal::KSocketBuffer::m_mutex
QMutex m_mutex
Definition: k3socketbuffer_p.h:166
QByteArray
KNetwork::KActiveSocketBase
Abstract class for active sockets.
Definition: k3socketbase.h:461
QList::at
const T & at(int i) const
KNetwork::Internal::KSocketBuffer::length
qint64 length() const
Returns the number of bytes in the buffer.
Definition: k3socketbuffer.cpp:123
KNetwork::Internal::KSocketBuffer::isFull
bool isFull() const
Returns true if the buffer is full (i.e., cannot receive more data)
Definition: k3socketbuffer_p.h:117
KNetwork::Internal::KSocketBuffer::~KSocketBuffer
~KSocketBuffer()
Virtual destructor.
Definition: k3socketbuffer.cpp:51
KNetwork::Internal::KSocketBuffer::KSocketBuffer
KSocketBuffer(qint64 size=-1)
Default constructor.
Definition: k3socketbuffer.cpp:40
KNetwork::Internal::KSocketBuffer::receiveFrom
qint64 receiveFrom(KActiveSocketBase *device, qint64 len=-1)
Tries to receive len bytes of data from the I/O device.
Definition: k3socketbuffer.cpp:293
KNetwork::Internal::KSocketBuffer::isEmpty
bool isEmpty() const
Returns true if the buffer is empty of data.
Definition: k3socketbuffer_p.h:94
QList::size
int size() const
KNetwork::Internal::KSocketBuffer::feedBuffer
qint64 feedBuffer(const char *data, qint64 len)
Adds data to the end of the buffer.
Definition: k3socketbuffer.cpp:150
KNetwork::Internal::KSocketBuffer::m_length
qint64 m_length
Definition: k3socketbuffer_p.h:171
KNetwork::KActiveSocketBase::read
qint64 read(char *data, qint64 maxlen)
Reads data from the socket.
Definition: k3socketbase.cpp:378
QByteArray::indexOf
int indexOf(char ch, int from) const
QList::append
void append(const T &value)
QByteArray::truncate
void truncate(int pos)
QMutableListIterator::remove
void remove()
KNetwork::Internal::KSocketBuffer::m_list
QList< QByteArray > m_list
Definition: k3socketbuffer_p.h:167
QIODevice::bytesAvailable
virtual qint64 bytesAvailable() const
KNetwork::KActiveSocketBase::write
qint64 write(const char *data, qint64 len)
Writes the given data to the socket.
Definition: k3socketbase.cpp:404
QMutableListIterator::peekNext
T & peekNext() const
QMutableListIterator::hasNext
bool hasNext() const
KNetwork::Internal::KSocketBuffer::sendTo
qint64 sendTo(KActiveSocketBase *device, qint64 len=-1)
Sends at most len bytes of data to the I/O Device.
Definition: k3socketbuffer.cpp:228
k3socketbase.h
QMutexLocker
KNetwork::Internal::KSocketBuffer::readLine
qint64 readLine(char *data, qint64 maxSize)
Reads a line from the buffer and discard it from the buffer.
Definition: k3socketbuffer.cpp:88
QMutableListIterator::next
T & next()
QMutableListIterator
KNetwork::Internal::KSocketBuffer::m_offset
qint64 m_offset
offset of the start of data in the first element
Definition: k3socketbuffer_p.h:168
KNetwork::Internal::KSocketBuffer::operator=
KSocketBuffer & operator=(const KSocketBuffer &other)
Assignment operator.
Definition: k3socketbuffer.cpp:56
QByteArray::data
char * data()
KNetwork::Internal::KSocketBuffer::size
qint64 size() const
Retrieves the buffer size.
Definition: k3socketbuffer.cpp:128
KNetwork::Internal::KSocketBuffer
generic socket buffering code
Definition: k3socketbuffer_p.h:48
KNetwork::Internal::KSocketBuffer::m_size
qint64 m_size
the maximum length of the buffer
Definition: k3socketbuffer_p.h:170
QByteArray::size
int size() const
KNetwork::Internal::KSocketBuffer::consumeBuffer
qint64 consumeBuffer(char *data, qint64 maxlen, bool discard=true)
Consumes data from the beginning of the buffer.
Definition: k3socketbuffer.cpp:170
KNetwork::Internal::KSocketBuffer::clear
void clear()
Clears the buffer.
Definition: k3socketbuffer.cpp:220
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:10 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal