summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/inspsocket.h119
-rw-r--r--include/iohook.h3
-rw-r--r--include/modules/ssl.h25
3 files changed, 139 insertions, 8 deletions
diff --git a/include/inspsocket.h b/include/inspsocket.h
index 221b92cc6..53eca2e91 100644
--- a/include/inspsocket.h
+++ b/include/inspsocket.h
@@ -103,14 +103,119 @@ class CoreExport SocketTimeout : public Timer
*/
class CoreExport StreamSocket : public EventHandler
{
+ public:
+ /** Socket send queue
+ */
+ class SendQueue
+ {
+ public:
+ /** One element of the queue, a continuous buffer
+ */
+ typedef std::string Element;
+
+ /** Sequence container of buffers in the queue
+ */
+ typedef std::deque<Element> Container;
+
+ /** Container iterator
+ */
+ typedef Container::const_iterator const_iterator;
+
+ SendQueue() : nbytes(0) { }
+
+ /** Return whether the queue is empty
+ * @return True if the queue is empty, false otherwise
+ */
+ bool empty() const { return (nbytes == 0); }
+
+ /** Get the number of individual buffers in the queue
+ * @return Number of individual buffers in the queue
+ */
+ Container::size_type size() const { return data.size(); }
+
+ /** Get the number of queued bytes
+ * @return Size in bytes of the data in the queue
+ */
+ size_t bytes() const { return nbytes; }
+
+ /** Get the first buffer of the queue
+ * @return A reference to the first buffer in the queue
+ */
+ const Element& front() const { return data.front(); }
+
+ /** Get an iterator to the first buffer in the queue.
+ * The returned iterator cannot be used to make modifications to the queue,
+ * for that purpose the member functions push_*(), pop_front(), erase_front() and clear() can be used.
+ * @return Iterator referring to the first buffer in the queue, or end() if there are no elements.
+ */
+ const_iterator begin() const { return data.begin(); }
+
+ /** Get an iterator to the (theoretical) buffer one past the end of the queue.
+ * @return Iterator referring to one element past the end of the container
+ */
+ const_iterator end() const { return data.end(); }
+
+ /** Remove the first buffer in the queue
+ */
+ void pop_front()
+ {
+ nbytes -= data.front().length();
+ data.pop_front();
+ }
+
+ /** Remove bytes from the beginning of the first buffer
+ * @param n Number of bytes to remove
+ */
+ void erase_front(Element::size_type n)
+ {
+ nbytes -= n;
+ data.front().erase(0, n);
+ }
+
+ /** Insert a new buffer at the beginning of the queue
+ * @param newdata Data to add
+ */
+ void push_front(const Element& newdata)
+ {
+ data.push_front(newdata);
+ nbytes += newdata.length();
+ }
+
+ /** Insert a new buffer at the end of the queue
+ * @param newdata Data to add
+ */
+ void push_back(const Element& newdata)
+ {
+ data.push_back(newdata);
+ nbytes += newdata.length();
+ }
+
+ /** Clear the queue
+ */
+ void clear()
+ {
+ data.clear();
+ nbytes = 0;
+ }
+
+ private:
+ /** Private send queue. Note that individual strings may be shared.
+ */
+ Container data;
+
+ /** Length, in bytes, of the sendq
+ */
+ size_t nbytes;
+ };
+
+ private:
/** The IOHook that handles raw I/O for this socket, or NULL */
IOHook* iohook;
- /** Private send queue. Note that individual strings may be shared
+ /** Send queue of the socket
*/
- std::deque<std::string> sendq;
- /** Length, in bytes, of the sendq */
- size_t sendq_len;
+ SendQueue sendq;
+
/** Error - if nonempty, the socket is dead, and this is the reason. */
std::string error;
@@ -126,7 +231,7 @@ class CoreExport StreamSocket : public EventHandler
protected:
std::string recvq;
public:
- StreamSocket() : iohook(NULL), sendq_len(0) {}
+ StreamSocket() : iohook(NULL) { }
IOHook* GetIOHook() const;
void AddIOHook(IOHook* hook);
void DelIOHook();
@@ -169,7 +274,9 @@ class CoreExport StreamSocket : public EventHandler
*/
bool GetNextLine(std::string& line, char delim = '\n');
/** Useful for implementing sendq exceeded */
- inline size_t getSendQSize() const { return sendq_len; }
+ size_t getSendQSize() const { return sendq.size(); }
+
+ SendQueue& GetSendQ() { return sendq; }
/**
* Close the socket, remove from socket engine, etc
diff --git a/include/iohook.h b/include/iohook.h
index ce7ca2a1b..cf27fcb0c 100644
--- a/include/iohook.h
+++ b/include/iohook.h
@@ -66,11 +66,10 @@ class IOHook : public classbase
* Called when a hooked stream has data to write, or when the socket
* engine returns it as writable
* @param sock The socket in question
- * @param sendq Data to send to the socket
* @return 1 if the sendq has been completely emptied, 0 if there is
* still data to send, and -1 if there was an error
*/
- virtual int OnStreamSocketWrite(StreamSocket* sock, std::string& sendq) = 0;
+ virtual int OnStreamSocketWrite(StreamSocket* sock) = 0;
/** Called immediately before any socket is closed. When this event is called, shutdown()
* has not yet been called on the socket.
diff --git a/include/modules/ssl.h b/include/modules/ssl.h
index 0f58e0b7b..67bfc7b2e 100644
--- a/include/modules/ssl.h
+++ b/include/modules/ssl.h
@@ -138,6 +138,31 @@ class SSLIOHook : public IOHook
*/
reference<ssl_cert> certificate;
+ /** Reduce elements in a send queue by appending later elements to the first element until there are no more
+ * elements to append or a desired length is reached
+ * @param sendq SendQ to work on
+ * @param targetsize Target size of the front element
+ */
+ static void FlattenSendQueue(StreamSocket::SendQueue& sendq, size_t targetsize)
+ {
+ if ((sendq.size() <= 1) || (sendq.front().length() >= targetsize))
+ return;
+
+ // Avoid multiple repeated SSL encryption invocations
+ // This adds a single copy of the queue, but avoids
+ // much more overhead in terms of system calls invoked
+ // by an IOHook.
+ std::string tmp;
+ tmp.reserve(std::min(targetsize, sendq.bytes())+1);
+ do
+ {
+ tmp.append(sendq.front());
+ sendq.pop_front();
+ }
+ while (!sendq.empty() && tmp.length() < targetsize);
+ sendq.push_front(tmp);
+ }
+
public:
SSLIOHook(IOHookProvider* hookprov)
: IOHook(hookprov)