MLIB
Loading...
Searching...
No Matches
wsockstream.h
Go to the documentation of this file.
1/*
2 MLIB Library
3 (c) Mircea Neacsu 2001-2023. Licensed under MIT License.
4 See README file for full license terms.
5*/
6
8#pragma once
9
10#if __has_include("defs.h")
11#include "defs.h"
12#endif
13
14#include "safe_winsock.h"
15#include <iostream>
16
17#include <mlib/errorcode.h>
18#include <mlib/inaddr.h>
19
20#include <assert.h>
21
22namespace mlib {
23
24// clang-format off
26class sock
27{
28public:
31 {
35 };
36
38 enum mflags
39 {
40 none = 0,
41 out_of_band = MSG_OOB,
42 peek = MSG_PEEK,
43 dont_route = MSG_DONTROUTE,
44 wait_all = MSG_WAITALL
45 };
46
47 sock ();
48 explicit sock (SOCKET soc);
49 explicit sock (int type, int domain = AF_INET, int proto = 0);
50 sock (const sock&);
51 sock (sock&&);
52
53 virtual ~sock ();
54 sock& operator= (const sock&);
56
57 HANDLE handle () const;
58 bool operator== (const sock& other) const;
59 bool operator!= (const sock& other) const;
60 operator SOCKET () const;
61
62 virtual erc open (int type, int domain = AF_INET, int proto = 0);
63 virtual erc close ();
64 virtual erc shutdown (shuthow sh) const;
65
66 virtual bool is_open () const;
67 size_t recv (void* buf, size_t maxlen, mflags msgf = mflags::none) const;
68 size_t recvfrom (sockaddr& sa, void* buf, size_t maxlen, mflags msgf = mflags::none) const;
69 size_t send (const void* buf, size_t len, mflags msgf = mflags::none) const;
70 template <typename T>
71 size_t send (std::basic_string<T> buf, mflags msgf = mflags::none) const;
72 size_t sendto (const sockaddr& sa, const void* buf, size_t len, mflags msgf = mflags::none) const;
73 template <typename T>
74 size_t sendto (const sockaddr& sa, std::basic_string<T> buf, mflags msgf = mflags::none) const;
75
76 int sendtimeout (int wp_sec) const;
77 int sendtimeout () const;
78 int recvtimeout (int wp_sec) const;
79 int recvtimeout () const;
80 bool is_readready (int wp_sec, int wp_usec = 0) const;
81 bool is_writeready (int wp_sec, int wp_usec = 0) const;
82 bool is_exceptionpending (int wp_sec, int wp_usec = 0) const;
83 unsigned int nread () const;
84
85 erc bind (const inaddr&) const;
86 erc bind () const;
87 erc connect (const inaddr& peer) const;
88 erc connect (const inaddr& peer, int wp_sec) const;
89 erc listen (int num = SOMAXCONN) const;
90 erc accept (sock& client, inaddr* sa = nullptr) const;
91 erc accept (sock& client, int wp_sec, inaddr* sa = nullptr) const;
92 checked<inaddr> name () const;
93 checked<inaddr> peer () const;
94
95 int getopt (int op, void* buf, int len, int level = SOL_SOCKET) const;
96 erc setopt (int op, void* buf, int len, int level = SOL_SOCKET) const;
97
98 int gettype () const;
99 int clearerror () const;
100 bool debug () const;
101 void debug (bool opt) const;
102 bool reuseaddr () const;
103 void reuseaddr (bool opt) const;
104 bool keepalive () const;
105 void keepalive (bool opt) const;
106 bool dontroute () const;
107 void dontroute (bool opt) const;
108 bool broadcast () const;
109 void broadcast (bool opt) const;
110 bool oobinline () const;
111 void oobinline (bool opt) const;
112 int sendbufsz () const;
113 void sendbufsz (size_t sz) const;
114 int recvbufsz () const;
115 void recvbufsz (size_t sz) const;
116 void blocking (bool on_off);
117 erc setevent (HANDLE evt, long mask) const;
118 long enumevents () const;
119 void linger (bool on_off, unsigned short seconds) const;
120 bool linger (unsigned short* seconds = 0) const;
121
123 static errfac& Errors ();
124
126 static void Errors (errfac& facitlity);
127
128protected:
129 static erc last_error ();
130
131private:
132 struct sock_ref
133 {
134 sock_ref ()
135 : handle{INVALID_SOCKET}
136 , ref_count{1} {};
137 SOCKET handle;
138 int ref_count;
139 }* sl;
140
141 friend class inaddr;
142 friend struct sock_initializer;
143};
144
146inline std::ostream& operator<< (std::ostream& strm, const sock& s)
147{
148 strm << s.handle ();
149 return strm;
150}
151
152// default buffer size
153#if !defined(SOCKBUF_BUFSIZ)
154#define SOCKBUF_BUFSIZ 1024
155#endif
156
158class sockbuf : public sock, public std::streambuf
159{
160public:
161 // constructors
162 sockbuf (SOCKET soc = INVALID_SOCKET);
163 sockbuf (int type, int domain = AF_INET, int proto = 0);
164 sockbuf (const sockbuf&);
165 sockbuf (const sock& soc);
166
167 virtual ~sockbuf ();
168 sockbuf& operator= (const sockbuf&);
169
170protected:
173 virtual int underflow () override;
174 virtual int overflow (int c = EOF) override;
175 virtual int sync () override;
176 virtual std::streambuf* setbuf (char* buf, std::streamsize sz) override;
177 virtual std::streamsize showmanyc () override;
179
180private:
181 enum flags
182 {
183 allocbuf = 0x0002,
184 no_reads = 0x0004,
185 no_writes = 0x0008,
186 eof_seen = 0x0010
187 };
188
189 int x_flags;
190 int ibsize; // input buffer size
191};
192// clang-format on
193
196
203
204template <class strm>
205class generic_sockstream : public strm
206{
207public:
210 : strm (new sockbuf ()){};
211
214 : strm (new sockbuf (sb)){};
215
218 : strm (new sockbuf (s)){};
219
221 generic_sockstream (int type, int domain = AF_INET, int proto = 0)
222 : strm (new sockbuf (type, domain, proto)){};
223
225 generic_sockstream (const inaddr& remote, int type = SOCK_STREAM);
226
228
231 {
232 return (sockbuf*)std::ios::rdbuf ();
233 }
234
236 {
237 return rdbuf ();
238 }
239};
240
241template <class strm>
243 : strm (new sockbuf ())
244{
245 rdbuf ()->open (type);
246 rdbuf ()->connect (remote);
247}
248
249template <class strm>
251{
252 delete std::ios::rdbuf ();
253}
254
257
260
263
265
266/*---------------------- support classes ------------------------------------*/
268static struct sock_initializer
269{
270 sock_initializer ();
271 ~sock_initializer ();
272} sock_nifty_counter;
273
274/*==================== INLINE FUNCTIONS ===========================*/
275
277inline sock::sock ()
278 : sl{nullptr}
279{}
280
282inline HANDLE sock::handle () const
283{
284 return sl ? (HANDLE)sl->handle : INVALID_HANDLE_VALUE;
285}
286
288inline sock::operator SOCKET () const
289{
290 return sl ? sl->handle : INVALID_SOCKET;
291}
292
294inline bool sock::is_open () const
295{
296 return sl && sl->handle != INVALID_SOCKET;
297}
298
300inline erc sock::connect (const inaddr& peer) const
301{
302 if (!sl || sl->handle == INVALID_SOCKET)
303 return erc (WSAENOTSOCK, Errors());
304
305 int ret = ::connect (sl->handle, peer, sizeof (peer));
306 if (ret == SOCKET_ERROR)
307 return last_error ();
308
309 return erc::success;
310}
311
313inline erc sock::accept (sock& client, inaddr* addr) const
314{
315 if (!sl || sl->handle == INVALID_SOCKET)
316 return erc (WSAENOTSOCK, Errors());
317
318 sockaddr sa;
319 int len = sizeof (sa);
320 client = sock (::accept (sl->handle, &sa, &len));
321 if (addr)
322 *addr = sa;
323 return erc ();
324}
325
327inline erc sock::listen (int num) const
328{
329 if (!sl || sl->handle == INVALID_SOCKET)
330 return erc (WSAENOTSOCK, Errors());
331
332 ::listen (sl->handle, num);
333 return last_error ();
334}
335
344template <typename T>
345size_t sock::send (std::basic_string<T> buf, mflags msgf) const
346{
347 return send (buf.c_str (), buf.size () * sizeof (T), msgf);
348}
349
359template <typename T>
360size_t sock::sendto (const sockaddr& sa, std::basic_string<T> buf, mflags msgf) const
361{
362 return sendto (sa, buf.c_str (), buf.size () * sizeof (T), msgf);
363}
364
370inline int sock::sendtimeout (int wp_sec) const
371{
372 if (!sl || sl->handle == INVALID_SOCKET)
373 return erc (WSAENOTSOCK, Errors());
374
375 int oldwtmo;
376 int optlen = sizeof (int);
377 getsockopt (sl->handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&oldwtmo, &optlen);
378 wp_sec *= 1000;
379 setsockopt (sl->handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&wp_sec, optlen);
380 return oldwtmo / 1000;
381}
382
384inline int sock::sendtimeout () const
385{
386 if (!sl || sl->handle == INVALID_SOCKET)
387 return erc (WSAENOTSOCK, Errors());
388
389 int oldwtmo;
390 int optlen = sizeof (int);
391 getsockopt (sl->handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&oldwtmo, &optlen);
392 return oldwtmo / 1000;
393}
394
400inline int sock::recvtimeout (int wp_sec) const
401{
402 if (!sl || sl->handle == INVALID_SOCKET)
403 return erc (WSAENOTSOCK, Errors());
404
405 int oldrtmo;
406 int optlen = sizeof (int);
407 getsockopt (sl->handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&oldrtmo, &optlen);
408 wp_sec *= 1000;
409 setsockopt (sl->handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&wp_sec, optlen);
410 return oldrtmo / 1000;
411}
412
414inline int sock::recvtimeout () const
415{
416 if (!sl || sl->handle == INVALID_SOCKET)
417 return erc (WSAENOTSOCK, Errors());
418
419 int oldrtmo;
420 int optlen = sizeof (int);
421 getsockopt (sl->handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&oldrtmo, &optlen);
422 return oldrtmo / 1000;
423}
424
434inline int sock::getopt (int op, void* buf, int len, int level) const
435{
436 if (!sl || sl->handle == INVALID_SOCKET)
437 return erc (WSAENOTSOCK, Errors());
438
439 int rlen = len;
440 if (::getsockopt (sl->handle, level, op, (char*)buf, &rlen) == SOCKET_ERROR)
441 last_error ().raise ();
442 return rlen;
443}
444
452inline erc sock::setopt (int op, void* buf, int len, int level) const
453{
454 if (!sl || sl->handle == INVALID_SOCKET)
455 return erc (WSAENOTSOCK, Errors());
456
457 if (::setsockopt (sl->handle, level, op, (char*)buf, len) == SOCKET_ERROR)
458 return last_error ();
459
460 return erc::success;
461}
462
466inline int sock::gettype () const
467{
468 int ty = 0;
469 getopt (SO_TYPE, &ty, sizeof (ty));
470 return ty;
471}
472
482inline int sock::clearerror () const
483{
484 int err = 0;
485 getopt (SO_ERROR, &err, sizeof (err));
486 return err;
487}
488
490inline bool sock::debug () const
491{
492 BOOL old;
493 getopt (SO_DEBUG, &old, sizeof (old));
494 return (old != FALSE);
495}
496
498inline void sock::debug (bool b) const
499{
500 BOOL opt = b;
501 setopt (SO_DEBUG, &opt, sizeof (opt));
502}
503
505inline bool sock::reuseaddr () const
506{
507 BOOL old;
508 getopt (SO_REUSEADDR, &old, sizeof (old));
509 return (old != FALSE);
510}
511
513inline void sock::reuseaddr (bool b) const
514{
515 BOOL opt = b;
516 setopt (SO_REUSEADDR, &opt, sizeof (opt));
517}
518
520inline bool sock::keepalive () const
521{
522 BOOL old;
523 getopt (SO_KEEPALIVE, &old, sizeof (old));
524 return (old != FALSE);
525}
526
528inline void sock::keepalive (bool b) const
529{
530 BOOL opt = b;
531 setopt (SO_KEEPALIVE, &opt, sizeof (opt));
532}
533
535inline bool sock::dontroute () const
536{
537 BOOL old;
538 getopt (SO_DONTROUTE, &old, sizeof (old));
539 return (old != FALSE);
540}
541
543inline void sock::dontroute (bool b) const
544{
545 BOOL opt = b;
546 setopt (SO_DONTROUTE, &opt, sizeof (opt));
547}
548
550inline bool sock::broadcast () const
551{
552 BOOL old;
553 getopt (SO_BROADCAST, &old, sizeof (old));
554 return (old != FALSE);
555}
556
563inline void sock::broadcast (bool b) const
564{
565 BOOL opt = b;
566 setopt (SO_BROADCAST, &opt, sizeof (opt));
567}
568
573inline bool sock::oobinline () const
574{
575 BOOL old;
576 getopt (SO_OOBINLINE, &old, sizeof (old));
577 return (old != FALSE);
578}
579
584inline void sock::oobinline (bool b) const
585{
586 BOOL opt = b;
587 setopt (SO_OOBINLINE, &opt, sizeof (opt));
588}
589
591inline int sock::sendbufsz () const
592{
593 int old = 0;
594 getopt (SO_SNDBUF, &old, sizeof (old));
595 return old;
596}
597
599inline void sock::sendbufsz (size_t sz) const
600{
601 setopt (SO_SNDBUF, &sz, sizeof (sz));
602}
603
605inline int sock::recvbufsz () const
606{
607 int old = 0;
608 getopt (SO_RCVBUF, &old, sizeof (old));
609 return old;
610}
611
613inline void sock::recvbufsz (size_t sz) const
614{
615 setopt (SO_RCVBUF, &sz, sizeof (sz));
616}
617
623inline void sock::blocking (bool on_off)
624{
625 if (!sl || sl->handle == INVALID_SOCKET)
626 throw erc (WSAENOTSOCK, Errors());
627
628 unsigned long mode = on_off ? 0 : 1;
629 if (ioctlsocket (sl->handle, FIONBIO, &mode) == SOCKET_ERROR)
630 last_error ().raise ();
631}
632
648inline erc sock::setevent (HANDLE evt, long mask) const
649{
650 if (!sl || sl->handle == INVALID_SOCKET)
651 return erc (WSAENOTSOCK, Errors());
652
653 if (WSAEventSelect (sl->handle, (WSAEVENT)evt, mask) == SOCKET_ERROR)
654 return last_error ();
655 return erc::success;
656}
657
664inline long sock::enumevents () const
665{
666 if (!sl || sl->handle == INVALID_SOCKET)
667 throw erc (WSAENOTSOCK, Errors());
668
669 WSANETWORKEVENTS netev;
670 if (WSAEnumNetworkEvents (sl->handle, NULL, &netev) == SOCKET_ERROR)
671 last_error ().raise ();
672 return netev.lNetworkEvents;
673}
674
676inline void sock::linger (bool on_off, unsigned short seconds) const
677{
678 struct linger opt;
679 opt.l_onoff = on_off;
680 opt.l_linger = seconds;
681 setopt (SO_LINGER, &opt, sizeof (opt));
682}
683
685inline bool sock::linger (unsigned short* seconds) const
686{
687 struct linger opt;
688 getopt (SO_LINGER, &opt, sizeof (opt));
689 if (seconds)
690 *seconds = opt.l_linger;
691 return (opt.l_onoff == 0);
692}
693
696{
697 int code = WSAGetLastError ();
698 if (!code)
699 return erc::success;
700 else
701 return erc (code, Errors());
702}
703
710inline bool sock::operator== (const sock& other) const
711{
712 return (sl == other.sl);
713}
714
720inline bool sock::operator!= (const sock& other) const
721{
722 return !operator== (other);
723}
724
726inline sock::mflags operator| (sock::mflags f1, sock::mflags f2)
727{
728 return (sock::mflags) ((int)f1 | (int)f2);
729}
730
731} // namespace mlib
objects returned as a function result or thrown directly.
Definition errorcode.h:68
static erc success
The SUCCESS indicator.
Definition errorcode.h:116
void raise() const
Definition errorcode.h:598
An error facility routes a group of errors handled in a similar manner.
Definition errorcode.h:136
An IO stream using a sockbuf object as the underlying streambuf.
Definition wsockstream.h:206
generic_sockstream(const sockbuf &sb)
Create from an existing sockbuf.
Definition wsockstream.h:213
sockbuf * operator->()
Return the buffer used by this stream.
Definition wsockstream.h:235
generic_sockstream(int type, int domain=AF_INET, int proto=0)
Create a SOCK_STREAM or SOCK_DGRAM stream.
Definition wsockstream.h:221
generic_sockstream()
Default constructor.
Definition wsockstream.h:209
~generic_sockstream()
Create a SOCK_STREAM connected to a remote peer.
Definition wsockstream.h:250
sockbuf * rdbuf()
Return the buffer used by this stream.
Definition wsockstream.h:230
generic_sockstream(const sock &s)
Create from an existing socket.
Definition wsockstream.h:217
generic_sockstream(const inaddr &remote, int type=SOCK_STREAM)
Create a SOCK_STREAM connected to a remote peer.
Definition wsockstream.h:242
sockaddr wrapper
Definition inaddr.h:23
Encapsulation of a Windows socket.
Definition wsockstream.h:27
bool is_readready(int wp_sec, int wp_usec=0) const
Check if socket is "readable".
Definition wsockstream.cpp:489
bool broadcast() const
Return "broadcast" option.
Definition wsockstream.h:550
int recvtimeout() const
Returns the send timeout value.
Definition wsockstream.h:414
bool reuseaddr() const
Return the "reuse address" flag.
Definition wsockstream.h:505
bool dontroute() const
Return status of "don't route" flag.
Definition wsockstream.h:535
long enumevents() const
Indicates which of the FD_XXX network events have occurred.
Definition wsockstream.h:664
checked< inaddr > peer() const
Retrieves the name of the peer to which the socket is connected.
Definition wsockstream.cpp:247
mflags
Flags for send/receive operations.
Definition wsockstream.h:39
@ dont_route
data should not be routed
Definition wsockstream.h:43
@ peek
don't remove data from the input queue
Definition wsockstream.h:42
@ none
no flags
Definition wsockstream.h:40
@ out_of_band
send out of band data
Definition wsockstream.h:41
@ wait_all
wait until buffer full or connection closed
Definition wsockstream.h:44
int clearerror() const
Return and clear the socket error flag.
Definition wsockstream.h:482
erc listen(int num=SOMAXCONN) const
Places the socket in a state in which it is listening for incoming connections.
Definition wsockstream.h:327
void linger(bool on_off, unsigned short seconds) const
Turn on or off linger mode and lingering timeout.
Definition wsockstream.h:676
erc bind() const
Associates a local address with the socket.
Definition wsockstream.cpp:278
bool operator==(const sock &other) const
Equality comparison operator.
Definition wsockstream.h:710
erc setopt(int op, void *buf, int len, int level=SOL_SOCKET) const
Set a socket option.
Definition wsockstream.h:452
int recvbufsz() const
Return buffer size for receive operations.
Definition wsockstream.h:605
checked< inaddr > name() const
Return the local name for the object.
Definition wsockstream.cpp:232
virtual bool is_open() const
Check if socket is opened.
Definition wsockstream.h:294
erc connect(const inaddr &peer) const
Establishes a connection to specified peer.
Definition wsockstream.h:300
int getopt(int op, void *buf, int len, int level=SOL_SOCKET) const
Returns a socket option.
Definition wsockstream.h:434
void blocking(bool on_off)
Change blocking mode.
Definition wsockstream.h:623
size_t sendto(const sockaddr &sa, const void *buf, size_t len, mflags msgf=mflags::none) const
Send data to a peer.
Definition wsockstream.cpp:451
int gettype() const
Return socket type (SOCK_DGRAM or SOCK_STREAM)
Definition wsockstream.h:466
bool debug() const
Return the debug flag.
Definition wsockstream.h:490
virtual erc close()
Close socket.
Definition wsockstream.cpp:204
bool oobinline() const
Return the status of the OOB_INLINE flag.
Definition wsockstream.h:573
unsigned int nread() const
Return number of characters waiting in socket's buffer.
Definition wsockstream.cpp:566
size_t recv(void *buf, size_t maxlen, mflags msgf=mflags::none) const
Receives data from socket.
Definition wsockstream.cpp:351
sock()
Default constructor creates a closed socket.
Definition wsockstream.h:277
size_t send(const void *buf, size_t len, mflags msgf=mflags::none) const
Send data to the connected peer.
Definition wsockstream.cpp:415
bool operator!=(const sock &other) const
Inequality comparison operator.
Definition wsockstream.h:720
shuthow
operation blocked by shutdown function
Definition wsockstream.h:31
@ shut_readwrite
blocked for both
Definition wsockstream.h:34
@ shut_read
blocked for reading
Definition wsockstream.h:32
@ shut_write
blocked for writing
Definition wsockstream.h:33
int sendtimeout() const
Returns the send timeout value.
Definition wsockstream.h:384
size_t recvfrom(sockaddr &sa, void *buf, size_t maxlen, mflags msgf=mflags::none) const
Receives data from socket.
Definition wsockstream.cpp:383
virtual erc open(int type, int domain=AF_INET, int proto=0)
Open the socket.
Definition wsockstream.cpp:183
virtual erc shutdown(shuthow sh) const
Disables sends or receives on socket.
Definition wsockstream.cpp:582
int sendbufsz() const
Return buffer size for send operations.
Definition wsockstream.h:591
bool is_exceptionpending(int wp_sec, int wp_usec=0) const
Check if socket has OOB data or any exceptional error conditions.
Definition wsockstream.cpp:544
HANDLE handle() const
Retrieve Windows socket handle.
Definition wsockstream.h:282
static errfac & Errors()
Return error facility used by all sock-derived classes.
Definition wsockstream.cpp:38
erc accept(sock &client, inaddr *sa=nullptr) const
Permits an incoming connection attempt on the socket.
Definition wsockstream.h:313
virtual ~sock()
Destructor.
Definition wsockstream.cpp:164
erc setevent(HANDLE evt, long mask) const
Associate an event object with this socket.
Definition wsockstream.h:648
static erc last_error()
Return an error code with the value returned by WSAGetLastError.
Definition wsockstream.h:695
bool is_writeready(int wp_sec, int wp_usec=0) const
Check if socket is "writable".
Definition wsockstream.cpp:520
bool keepalive() const
Return "keep alive" flag.
Definition wsockstream.h:520
sock & operator=(const sock &)
Assignment operator.
Definition wsockstream.cpp:131
Provide functions required by streambuf interface using an underlying socket.
Definition wsockstream.h:159
virtual int overflow(int c=EOF) override
If c == EOF or buffer full, return sync(); otherwise insert c into the buffer and return c.
Definition wsockstream.cpp:779
sockbuf(SOCKET soc=INVALID_SOCKET)
Build a sockbuf object from an existing socket.
Definition wsockstream.cpp:626
virtual ~sockbuf()
Destructor.
Definition wsockstream.cpp:672
virtual int sync() override
Return 0 if all chars flushed or -1 if error.
Definition wsockstream.cpp:691
virtual std::streamsize showmanyc() override
Return number of characters available in socket buffer.
Definition wsockstream.cpp:810
sockbuf & operator=(const sockbuf &)
Assignment operator.
Definition wsockstream.cpp:663
virtual std::streambuf * setbuf(char *buf, std::streamsize sz) override
Change buffering mode.
Definition wsockstream.cpp:713
virtual int underflow() override
underflow
Definition wsockstream.cpp:745
@ seconds
Degrees, minutes, seconds format (DD°MM'SS.sss")
Definition convert.h:247
Definition of erc and erfac classes.
Definition of inaddr class.
std::ostream & operator<<(std::ostream &strm, const mlib::inaddr &addr)
Serialize an address as '<hostname>:<port>'.
Definition inaddr.h:127
generic_sockstream< std::iostream > sockstream
Bidirectional socket stream.
Definition wsockstream.h:262
generic_sockstream< std::ostream > osockstream
Output socket stream.
Definition wsockstream.h:259
generic_sockstream< std::istream > isockstream
Input socket stream.
Definition wsockstream.h:256