join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
socket_stream.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_SOCKET_STREAM_HPP
26#define JOIN_CORE_SOCKET_STREAM_HPP
27
28// libjoin.
30
31// C++.
32#include <streambuf>
33#include <utility>
34#include <chrono>
35#include <memory>
36
37namespace join
38{
42 template <class Protocol>
43 class BasicSocketStreambuf : public std::streambuf
44 {
45 public:
46 using Endpoint = typename Protocol::Endpoint;
47 using Socket = typename Protocol::Socket;
48 using TimePoint = typename Socket::TimePoint;
49
54 : _buf (std::make_unique<char[]> (2 * _bufsize))
55 , _socket (Socket::Mode::NonBlocking)
56 {
57 }
58
64 : _buf (std::make_unique<char[]> (2 * _bufsize))
65 , _socket (std::move (socket))
66 {
67 }
68
74
81
87 : std::streambuf (std::move (other))
88 , _buf (std::move (other._buf))
89 , _timeout (other._timeout)
90 , _socket (std::move (other._socket))
91 {
92 }
93
100 {
101 close ();
102
103 std::streambuf::operator= (std::move (other));
104 _buf = std::move (other._buf);
105 _timeout = other._timeout;
106 _socket = std::move (other._socket);
107
108 return *this;
109 }
110
115 {
116 if (_socket.connected ())
117 {
118 overflow (traits_type::eof ());
119 }
120 }
121
128 {
129 if (_socket.bind (endpoint) == -1)
130 {
131 return nullptr;
132 }
133
134 return this;
135 }
136
143 {
144 if (_socket.connect (endpoint) == -1)
145 {
146 if (lastError != Errc::TemporaryError)
147 {
148 return nullptr;
149 }
150
151 if (!_socket.waitConnected (deadline ()))
152 {
153 _socket.close ();
154 return nullptr;
155 }
156 }
157
158 return this;
159 }
160
166 {
167 if (_socket.connected () && (overflow (traits_type::eof ()) == traits_type::eof ()))
168 {
169 return nullptr;
170 }
171
172 if (_socket.disconnect () == -1)
173 {
174 if (lastError != Errc::TemporaryError)
175 {
176 return nullptr;
177 }
178
179 if (!_socket.waitDisconnected (deadline ()))
180 {
181 return nullptr;
182 }
183 }
184
185 return this;
186 }
187
192 void close ()
193 {
194 _socket.close ();
195 }
196
201 void timeout (std::chrono::nanoseconds timeout)
202 {
204 }
205
210 std::chrono::nanoseconds timeout () const
211 {
212 return _timeout;
213 }
214
219 TimePoint deadline () const noexcept
220 {
221 return (_timeout == std::chrono::nanoseconds::zero ()) ? TimePoint::max ()
222 : std::chrono::steady_clock::now () + _timeout;
223 }
224
230 {
231 return _socket;
232 }
233
234 protected:
239 virtual int_type underflow () override
240 {
241 if (!_socket.connected ())
242 {
244 return traits_type::eof ();
245 }
246
247 if (eback () == nullptr)
248 {
249 setg (_buf.get (), _buf.get (), _buf.get ());
250 }
251
252 if (gptr () == egptr ())
253 {
254 for (;;)
255 {
256 ssize_t nread = _socket.read (eback (), _bufsize);
257 if (nread == -1)
258 {
259 if (lastError == Errc::TemporaryError)
260 {
261 if (_socket.waitReadyRead (deadline ()))
262 {
263 continue;
264 }
265 }
266 _socket.close ();
267 return traits_type::eof ();
268 }
269
270 setg (eback (), eback (), eback () + nread);
271 break;
272 }
273 }
274
275 return traits_type::to_int_type (*gptr ());
276 }
277
283 virtual int_type overflow (int_type c = traits_type::eof ()) override
284 {
285 if (!_socket.connected ())
286 {
288 return traits_type::eof ();
289 }
290
291 if (pbase () == nullptr)
292 {
293 setp (_buf.get () + _bufsize, _buf.get () + (2 * _bufsize));
294 }
295
296 if ((pptr () == epptr ()) || (c == traits_type::eof ()))
297 {
298 std::streamsize pending = pptr () - pbase ();
299 if (pending)
300 {
301 if (_socket.writeExactly (pbase (), pending, deadline ()) == -1)
302 {
303 _socket.close ();
304 return traits_type::eof ();
305 }
306 }
307
308 setp (pbase (), pbase () + _bufsize);
309
310 if (c == traits_type::eof ())
311 {
312 return traits_type::not_eof (c);
313 }
314 }
315
316 return sputc (traits_type::to_char_type (c));
317 }
318
323 virtual int_type sync () override
324 {
325 if (!_socket.connected () || (overflow () == traits_type::eof ()))
326 {
327 return -1;
328 }
329 return 0;
330 }
331
333 static const std::streamsize _bufsize = 4096;
334
336 std::unique_ptr<char[]> _buf;
337
339 std::chrono::nanoseconds _timeout = std::chrono::seconds (30);
340
343 };
344
348 template <class Protocol>
349 class BasicSocketStream : public std::iostream
350 {
351 public:
353 using Endpoint = typename Protocol::Endpoint;
354 using Socket = typename Protocol::Socket;
355
360 : std::iostream (&_sockbuf)
361 {
362 }
363
369 : std::iostream (&_sockbuf)
370 , _sockbuf (std::move (socket))
371 {
372 }
373
378 BasicSocketStream (const BasicSocketStream& other) = delete;
379
386
392 : std::iostream (std::move (other))
393 , _sockbuf (std::move (other._sockbuf))
394 {
395 set_rdbuf (&_sockbuf);
396 }
397
404 {
405 std::iostream::operator= (std::move (other));
406 _sockbuf = std::move (other._sockbuf);
407 return *this;
408 }
409
413 virtual ~BasicSocketStream () = default;
414
420 virtual void bind (const Endpoint& endpoint)
421 {
422 if (_sockbuf.bind (endpoint) == nullptr)
423 {
424 setstate (std::ios_base::failbit);
425 }
426 }
427
433 virtual void connect (const Endpoint& endpoint)
434 {
435 if (_sockbuf.connect (endpoint) == nullptr)
436 {
437 setstate (std::ios_base::failbit);
438 }
439 }
440
445 virtual void disconnect ()
446 {
447 if (_sockbuf.disconnect () == nullptr)
448 {
449 setstate (std::ios_base::failbit);
450 }
451 }
452
457 virtual void close ()
458 {
459 _sockbuf.close ();
460 }
461
467 {
468 return _sockbuf.socket ().localEndpoint ();
469 }
470
476 {
477 return _sockbuf.socket ().remoteEndpoint ();
478 }
479
484 bool opened ()
485 {
486 return _sockbuf.socket ().opened ();
487 }
488
493 bool connected ()
494 {
495 return _sockbuf.socket ().connected ();
496 }
497
502 void timeout (std::chrono::nanoseconds timeout)
503 {
505 }
506
511 std::chrono::nanoseconds timeout () const
512 {
513 return _sockbuf.timeout ();
514 }
515
521 {
522 return _sockbuf.socket ();
523 }
524
525 protected:
528 };
529}
530
531#endif
socket stream class.
Definition socket_stream.hpp:350
typename Protocol::Endpoint Endpoint
Definition socket_stream.hpp:353
Endpoint remoteEndpoint()
determine the remote endpoint associated with this socket.
Definition socket_stream.hpp:475
BasicSocketStream(const BasicSocketStream &other)=delete
copy constructor.
BasicSocketStream()
default constructor.
Definition socket_stream.hpp:359
virtual ~BasicSocketStream()=default
destroy the socket stream instance.
BasicSocketStream(BasicSocketStream &&other)
move constructor.
Definition socket_stream.hpp:391
Socket & socket()
get the nested socket.
Definition socket_stream.hpp:520
typename Protocol::Socket Socket
Definition socket_stream.hpp:354
SocketStreambuf _sockbuf
associated stream buffer.
Definition socket_stream.hpp:527
BasicSocketStream(Socket &&socket)
construct the socket stream by moving an existing socket in.
Definition socket_stream.hpp:368
bool opened()
check if the socket is opened.
Definition socket_stream.hpp:484
void timeout(std::chrono::nanoseconds timeout)
set the socket timeout.
Definition socket_stream.hpp:502
Endpoint localEndpoint()
determine the local endpoint associated with this socket.
Definition socket_stream.hpp:466
bool connected()
check if the socket is connected.
Definition socket_stream.hpp:493
virtual void connect(const Endpoint &endpoint)
make a connection to the given endpoint.
Definition socket_stream.hpp:433
virtual void bind(const Endpoint &endpoint)
assigns the specified endpoint to the socket.
Definition socket_stream.hpp:420
BasicSocketStream & operator=(const BasicSocketStream &other)=delete
copy assignment operator.
virtual void close()
close the connection.
Definition socket_stream.hpp:457
virtual void disconnect()
shutdown the connection.
Definition socket_stream.hpp:445
std::chrono::nanoseconds timeout() const
get the current timeout duration.
Definition socket_stream.hpp:511
socket stream buffer class.
Definition socket_stream.hpp:44
std::chrono::nanoseconds timeout() const
get the current timeout duration.
Definition socket_stream.hpp:210
BasicSocketStreambuf()
default constructor.
Definition socket_stream.hpp:53
typename Protocol::Endpoint Endpoint
Definition socket_stream.hpp:46
BasicSocketStreambuf * connect(const Endpoint &endpoint)
make a connection to the given endpoint.
Definition socket_stream.hpp:142
virtual ~BasicSocketStreambuf()
destroy the socket stream buffer instance.
Definition socket_stream.hpp:114
BasicSocketStreambuf(Socket &&socket)
construct the socket stream buffer by moving an existing socket in.
Definition socket_stream.hpp:63
Socket & socket()
get the nested socket.
Definition socket_stream.hpp:229
TimePoint deadline() const noexcept
get the deadline of an operation started now.
Definition socket_stream.hpp:219
static const std::streamsize _bufsize
internal buffer size.
Definition socket_stream.hpp:333
Socket _socket
internal socket.
Definition socket_stream.hpp:342
virtual int_type underflow() override
reads characters from the associated input sequence to the get area.
Definition socket_stream.hpp:239
BasicSocketStreambuf * disconnect()
shutdown the connection.
Definition socket_stream.hpp:165
BasicSocketStreambuf * bind(const Endpoint &endpoint)
assigns the specified endpoint to the socket.
Definition socket_stream.hpp:127
typename Socket::TimePoint TimePoint
Definition socket_stream.hpp:48
void close()
close the connection.
Definition socket_stream.hpp:192
BasicSocketStreambuf & operator=(const BasicSocketStreambuf &other)=delete
copy assignment operator.
BasicSocketStreambuf(const BasicSocketStreambuf &other)=delete
copy constructor.
virtual int_type overflow(int_type c=traits_type::eof()) override
writes characters to the associated output sequence from the put area.
Definition socket_stream.hpp:283
typename Protocol::Socket Socket
Definition socket_stream.hpp:47
void timeout(std::chrono::nanoseconds timeout)
set the socket timeout.
Definition socket_stream.hpp:201
std::chrono::nanoseconds _timeout
timeout, zero when the stream operations are not time bounded.
Definition socket_stream.hpp:339
std::unique_ptr< char[]> _buf
internal buffer.
Definition socket_stream.hpp:336
BasicSocketStreambuf(BasicSocketStreambuf &&other)
move constructor.
Definition socket_stream.hpp:86
virtual int_type sync() override
synchronizes the buffers with the associated character sequence.
Definition socket_stream.hpp:323
Definition acceptor.hpp:32
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
Definition error.hpp:144