MLIB
Loading...
Searching...
No Matches
sockbuf.h
Go to the documentation of this file.
1/*
2 Copyright (c) Mircea Neacsu (2014-2025) Licensed under MIT License.
3 This file is part of MLIB project. See LICENSE file for full license terms.
4*/
5
7
8#pragma once
9
10#if __has_include("defs.h")
11#include "defs.h"
12#endif
13
14#include "safe_winsock.h"
15#include "sock.h"
16#include "trace.h"
17#include <iostream>
18
19namespace mlib {
20
21#if !defined(SOCKBUF_BUFSIZ)
23#define SOCKBUF_BUFSIZ 1024
24#endif
25
55
56template <typename T>
57class sockbuf : public sock, public std::basic_streambuf<T>
58{
59public:
60 // constructors
61
64 : sock ()
65 , x_flags (0)
66 {
68 }
69
71 sockbuf (sock::type t, int domain, int proto)
72 : sock(t, domain, proto)
73 , x_flags (0)
74 {
76 }
77
79 sockbuf (const sock& s)
80 : sock (s)
81 , x_flags (0)
82 {
84 }
85
87 sockbuf (const sockbuf<T>& sb)
88 : sock (sb)
89 , x_flags (sb.x_flags)
90 {
91 if (x_flags & flags::allocbuf)
92 setbuf (0, (int)(const_cast<sockbuf<T>&> (sb).epptr () - const_cast<sockbuf<T>&> (sb).pbase ()));
93 }
94
98 {
100 std::basic_streambuf<T>::operator= (rhs);
101 x_flags = (x_flags & flags::allocbuf) | (rhs.x_flags & ~flags::allocbuf);
102 return *this;
103 }
104
107 {
108 if (is_open ())
109 {
110 overflow ();
111 shutdown (shut_readwrite).deactivate (); // ignore any errors
112 close ();
113 }
114
115 if (x_flags & flags::allocbuf)
116 {
117 delete[] std::basic_streambuf<T>::pbase ();
118 delete[] std::basic_streambuf<T>::eback ();
119 }
120 }
121
122
123protected:
124 using int_type = std::char_traits<T>::int_type;
127
128 int_type underflow () override
129 {
130 if (x_flags & flags::no_reads)
131 return EOF; // reads blocked for this socket
132
133 if (std::basic_streambuf<T>::gptr () < std::basic_streambuf<T>::egptr ())
134 return *(unsigned char*)std::basic_streambuf<T>::gptr (); // return available char from buffer
135
136 if (std::basic_streambuf<T>::eback ())
137 {
138 // buffered mode
139 size_t rval = recv (std::basic_streambuf<T>::eback (), ibsize);
140 if (rval != (size_t)EOF)
141 {
142 std::basic_streambuf<T>::setg (std::basic_streambuf<T>::eback (),
143 std::basic_streambuf<T>::eback (),
144 std::basic_streambuf<T>::eback () + rval);
145 return rval ? *(unsigned char*)std::basic_streambuf<T>::gptr () : EOF;
146 }
147 return EOF;
148 }
149 else
150 {
151 // unbuffered mode
152 unsigned char ch;
153 size_t rval = recv (&ch, 1);
154 if (rval == (size_t)EOF || rval == 0)
155 return EOF;
156 return ch;
157 }
158 }
159
164 int_type overflow (int_type c = EOF) override
165 {
166 if (x_flags & flags::no_writes)
167 return EOF; // socket blocked for writing, can't do anything
168
169 if (sync () == EOF) // flush output
170 return EOF;
171
172 if (c == EOF)
173 return EOF;
174
175 if (std::basic_streambuf<T>::pbase ())
176 {
177 // buffered mode
178 *std::basic_streambuf<T>::pptr () = (T)c;
179 std::basic_streambuf<T>::pbump (1);
180 }
181 else
182 {
183 // unbuffered mode
184 unsigned char ch = (unsigned char)c;
185 size_t rval = send (&ch, 1);
186 if (rval == (size_t)EOF || rval == 0)
187 return EOF;
188 }
189 return c;
190 }
191
193 int sync () override
194 {
195 if (std::basic_streambuf<T>::pptr () <= std::basic_streambuf<T>::pbase ())
196 return 0; // unbuffered or empty buffer
197 if (!(x_flags & flags::no_writes))
198 {
199 size_t wlen = std::basic_streambuf<T>::pptr () - std::basic_streambuf<T>::pbase ();
200 size_t wval = send (std::basic_streambuf<T>::pbase (), wlen);
201 std::basic_streambuf<T>::setp (std::basic_streambuf<T>::pbase (),
202 std::basic_streambuf<T>::epptr ());
203 if (wval == wlen)
204 return 0;
205 TRACE ("sockbuf::sync failed - wanted %d sent %d", wlen, wval);
206 }
207 return -1;
208 }
209
216 std::basic_streambuf<T>* setbuf (T* buf, std::streamsize sz) override
217 {
218 overflow (EOF); // flush current output buffer
219
220 // switch to unbuffered mode
221 if (x_flags & flags::allocbuf)
222 {
223 delete[] std::basic_streambuf<T>::eback ();
224 delete[] std::basic_streambuf<T>::pbase ();
225 }
226 std::basic_streambuf<T>::setp (NULL, NULL);
227 std::basic_streambuf<T>::setg (NULL, NULL, NULL);
228 x_flags &= ~flags::allocbuf;
229 ibsize = 0;
230 if (!buf)
231 {
232 // automatic buffer - allocate separate input and output buffers
233 x_flags |= flags::allocbuf;
234 T* ptr = new T[(size_t)sz + 1];
235 std::basic_streambuf<T>::setp (ptr, ptr + sz);
236 ptr = new T[(size_t)sz];
237 std::basic_streambuf<T>::setg (ptr, ptr + sz, ptr + sz);
238 ibsize = (int)sz;
239 }
240 else
241 std::basic_streambuf<T>::setp (buf,
242 buf + sz - 1); // user specified buffer used only for output
243 return this;
244 }
245
247 std::streamsize showmanyc () override
248 {
249 return nread ();
250 }
251
253private:
254 enum flags
255 {
256 allocbuf = 0x0002,
257 no_reads = 0x0004,
258 no_writes = 0x0008,
259 eof_seen = 0x0010
260 };
261
262 int x_flags;
263 int ibsize; // input buffer size
264};
265
266} // namespace mlib
void deactivate() const
Marks error code as inactive.
Definition errorcode.h:659
virtual bool is_open() const
Check if socket is opened.
Definition sock.h:183
unsigned int nread() const
Return number of characters waiting in socket's buffer.
Definition sock.cpp:563
size_t recv(void *buf, size_t maxlen, mflags msgf=mflags::none) const
Receives data from socket.
Definition sock.cpp:352
sock()
Default constructor creates a closed socket.
Definition sock.h:163
size_t send(const void *buf, size_t len, mflags msgf=mflags::none) const
Send data to the connected peer.
Definition sock.cpp:416
type
socket types
Definition sock.h:23
@ shut_readwrite
blocked for both
Definition sock.h:34
virtual erc shutdown(shuthow sh) const
Disables sends or receives on socket.
Definition sock.cpp:579
virtual void close()
Close socket.
Definition sock.cpp:200
sock & operator=(const sock &)
Assignment operator.
Definition sock.cpp:129
std::basic_streambuf< T > * setbuf(T *buf, std::streamsize sz) override
Change buffering mode.
Definition sockbuf.h:216
~sockbuf()
Destructor.
Definition sockbuf.h:106
sockbuf< T > & operator=(const sockbuf< T > &rhs)
Definition sockbuf.h:97
int sync() override
Return 0 if all chars flushed or -1 if error.
Definition sockbuf.h:193
sockbuf()
Default constructor.
Definition sockbuf.h:63
int_type underflow() override
If c == EOF or buffer full, return sync(); otherwise insert c into the buffer and return c
Definition sockbuf.h:128
sockbuf(sock::type t, int domain, int proto)
Build a sockbuf object and the attached socket with the given parameters.
Definition sockbuf.h:71
sockbuf(const sock &s)
Build a sockbuf object from a sock base.
Definition sockbuf.h:79
sockbuf(const sockbuf< T > &sb)
Copy constructor.
Definition sockbuf.h:87
int_type overflow(int_type c=EOF) override
If c == EOF or buffer full, return sync(); otherwise insert c into the buffer and return c
Definition sockbuf.h:164
std::streamsize showmanyc() override
Return number of characters available in socket buffer.
Definition sockbuf.h:247
#define SOCKBUF_BUFSIZ
Default buffer size for socket streams.
Definition sockbuf.h:23
definition of TRACE macro