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
61 virtual erc open (int type, int domain = AF_INET, int proto = 0);
62 virtual erc close ();
63 virtual erc shutdown (shuthow sh) const;
64
65 virtual bool is_open () const;
66 size_t recv (void* buf, size_t maxlen, mflags msgf = mflags::none) const;
67 size_t recvfrom (sockaddr& sa, void* buf, size_t maxlen, mflags msgf = mflags::none) const;
68 size_t send (const void* buf, size_t len, mflags msgf = mflags::none) const;
69 template <typename T>
70 size_t send (std::basic_string<T> buf, mflags msgf = mflags::none) const;
71 size_t sendto (const sockaddr& sa, const void* buf, size_t len, mflags msgf = mflags::none) const;
72 template <typename T>
73 size_t sendto (const sockaddr& sa, std::basic_string<T> buf, mflags msgf = mflags::none) const;
74
75 int sendtimeout (int wp_sec) const;
76 int sendtimeout () const;
77 int recvtimeout (int wp_sec) const;
78 int recvtimeout () const;
79 bool is_readready (int wp_sec, int wp_usec = 0) const;
80 bool is_writeready (int wp_sec, int wp_usec = 0) const;
81 bool is_exceptionpending (int wp_sec, int wp_usec = 0) const;
82 unsigned int nread () const;
83
84 erc bind (const inaddr&) const;
85 erc bind () const;
86 erc connect (const inaddr& peer) const;
87 erc connect (const inaddr& peer, int wp_sec) const;
88 erc listen (int num = SOMAXCONN) const;
89 erc accept (sock& client, inaddr* sa = nullptr) const;
90 erc accept (sock& client, int wp_sec, inaddr* sa = nullptr) const;
91 erc name (inaddr& addr) const;
92 erc peer (inaddr& addr) const;
93
94 int getopt (int op, void* buf, int len, int level = SOL_SOCKET) const;
95 erc setopt (int op, void* buf, int len, int level = SOL_SOCKET) const;
96
97 int gettype () const;
98 int clearerror () const;
99 bool debug () const;
100 void debug (bool opt) const;
101 bool reuseaddr () const;
102 void reuseaddr (bool opt) const;
103 bool keepalive () const;
104 void keepalive (bool opt) const;
105 bool dontroute () const;
106 void dontroute (bool opt) const;
107 bool broadcast () const;
108 void broadcast (bool opt) const;
109 bool oobinline () const;
110 void oobinline (bool opt) const;
111 int sendbufsz () const;
112 void sendbufsz (size_t sz) const;
113 int recvbufsz () const;
114 void recvbufsz (size_t sz) const;
115 void blocking (bool on_off);
116 erc setevent (HANDLE evt, long mask) const;
117 long enumevents () const;
118 void linger (bool on_off, unsigned short seconds) const;
119 bool linger (unsigned short* seconds = 0) const;
120
122 static errfac& Errors ();
123
125 static void Errors (errfac& facitlity);
126
127protected:
128 static erc last_error ();
129
130private:
131 struct sock_ref
132 {
133 sock_ref ()
134 : handle{INVALID_SOCKET}
135 , ref_count{1} {};
136 SOCKET handle;
137 int ref_count;
138 }* sl;
139
140 friend class inaddr;
141 friend struct sock_initializer;
142};
143
145inline std::ostream& operator<< (std::ostream& strm, const sock& s)
146{
147 strm << s.handle ();
148 return strm;
149}
150
151// default buffer size
152#if !defined(SOCKBUF_BUFSIZ)
153#define SOCKBUF_BUFSIZ 1024
154#endif
155
157class sockbuf : public sock, public std::streambuf
158{
159public:
160 // constructors
161 sockbuf (SOCKET soc = INVALID_SOCKET);
162 sockbuf (int type, int domain = AF_INET, int proto = 0);
163 sockbuf (const sockbuf&);
164 sockbuf (const sock& soc);
165
166 virtual ~sockbuf ();
167 sockbuf& operator= (const sockbuf&);
168
169protected:
172 virtual int underflow () override;
173 virtual int overflow (int c = EOF) override;
174 virtual int sync () override;
175 virtual std::streambuf* setbuf (char* buf, std::streamsize sz) override;
176 virtual std::streamsize showmanyc () override;
178
179private:
180 enum flags
181 {
182 allocbuf = 0x0002,
183 no_reads = 0x0004,
184 no_writes = 0x0008,
185 eof_seen = 0x0010
186 };
187
188 int x_flags;
189 int ibsize; // input buffer size
190};
191// clang-format on
192
195
203template <class strm>
204class generic_sockstream : public strm
205{
206public:
209 : strm (new sockbuf ()){};
210
213 : strm (new sockbuf (sb)){};
214
217 : strm (new sockbuf (s)){};
218
220 generic_sockstream (int type, int domain = AF_INET, int proto = 0)
221 : strm (new sockbuf (type, domain, proto)){};
222
224 generic_sockstream (const inaddr& remote, int type = SOCK_STREAM);
225
227
230 {
231 return (sockbuf*)std::ios::rdbuf ();
232 }
235 {
236 return rdbuf ();
237 }
238};
239
240template <class strm>
242 : strm (new sockbuf ())
243{
244 rdbuf ()->open (type);
245 rdbuf ()->connect (remote);
246}
247
248template <class strm>
250{
251 delete std::ios::rdbuf ();
252}
253
256
259
262
264
265/*---------------------- support classes ------------------------------------*/
267static struct sock_initializer
268{
269 sock_initializer ();
270 ~sock_initializer ();
271} sock_nifty_counter;
272
273/*==================== INLINE FUNCTIONS ===========================*/
274
276inline sock::sock ()
277 : sl{nullptr}
278{}
279
281inline HANDLE sock::handle () const
282{
283 return sl ? (HANDLE)sl->handle : INVALID_HANDLE_VALUE;
284}
285
287inline bool sock::is_open () const
288{
289 return sl && sl->handle != INVALID_SOCKET;
290}
291
293inline erc sock::connect (const inaddr& peer) const
294{
295 if (!sl || sl->handle == INVALID_SOCKET)
296 return erc (WSAENOTSOCK, Errors());
297
298 int ret = ::connect (sl->handle, peer, sizeof (peer));
299 if (ret == SOCKET_ERROR)
300 return last_error ();
301
302 return erc::success;
303}
304
306inline erc sock::accept (sock& client, inaddr* addr) const
307{
308 if (!sl || sl->handle == INVALID_SOCKET)
309 return erc (WSAENOTSOCK, Errors());
310
311 sockaddr sa;
312 int len = sizeof (sa);
313 client = sock (::accept (sl->handle, &sa, &len));
314 if (addr)
315 *addr = sa;
316 return erc ();
317}
318
320inline erc sock::listen (int num) const
321{
322 if (!sl || sl->handle == INVALID_SOCKET)
323 return erc (WSAENOTSOCK, Errors());
324
325 ::listen (sl->handle, num);
326 return last_error ();
327}
328
337template <typename T>
338size_t sock::send (std::basic_string<T> buf, mflags msgf) const
339{
340 return send (buf.c_str (), buf.size () * sizeof (T), msgf);
341}
342
352template <typename T>
353size_t sock::sendto (const sockaddr& sa, std::basic_string<T> buf, mflags msgf) const
354{
355 return sendto (sa, buf.c_str (), buf.size () * sizeof (T), msgf);
356}
357
363inline int sock::sendtimeout (int wp_sec) const
364{
365 if (!sl || sl->handle == INVALID_SOCKET)
366 return erc (WSAENOTSOCK, Errors());
367
368 int oldwtmo;
369 int optlen = sizeof (int);
370 getsockopt (sl->handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&oldwtmo, &optlen);
371 wp_sec *= 1000;
372 setsockopt (sl->handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&wp_sec, optlen);
373 return oldwtmo / 1000;
374}
375
377inline int sock::sendtimeout () const
378{
379 if (!sl || sl->handle == INVALID_SOCKET)
380 return erc (WSAENOTSOCK, Errors());
381
382 int oldwtmo;
383 int optlen = sizeof (int);
384 getsockopt (sl->handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&oldwtmo, &optlen);
385 return oldwtmo / 1000;
386}
387
393inline int sock::recvtimeout (int wp_sec) const
394{
395 if (!sl || sl->handle == INVALID_SOCKET)
396 return erc (WSAENOTSOCK, Errors());
397
398 int oldrtmo;
399 int optlen = sizeof (int);
400 getsockopt (sl->handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&oldrtmo, &optlen);
401 wp_sec *= 1000;
402 setsockopt (sl->handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&wp_sec, optlen);
403 return oldrtmo / 1000;
404}
405
407inline int sock::recvtimeout () const
408{
409 if (!sl || sl->handle == INVALID_SOCKET)
410 return erc (WSAENOTSOCK, Errors());
411
412 int oldrtmo;
413 int optlen = sizeof (int);
414 getsockopt (sl->handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&oldrtmo, &optlen);
415 return oldrtmo / 1000;
416}
417
427inline int sock::getopt (int op, void* buf, int len, int level) const
428{
429 if (!sl || sl->handle == INVALID_SOCKET)
430 return erc (WSAENOTSOCK, Errors());
431
432 int rlen = len;
433 if (::getsockopt (sl->handle, level, op, (char*)buf, &rlen) == SOCKET_ERROR)
434 last_error ().raise ();
435 return rlen;
436}
437
445inline erc sock::setopt (int op, void* buf, int len, int level) const
446{
447 if (!sl || sl->handle == INVALID_SOCKET)
448 return erc (WSAENOTSOCK, Errors());
449
450 if (::setsockopt (sl->handle, level, op, (char*)buf, len) == SOCKET_ERROR)
451 return last_error ();
452
453 return erc::success;
454}
455
459inline int sock::gettype () const
460{
461 int ty = 0;
462 getopt (SO_TYPE, &ty, sizeof (ty));
463 return ty;
464}
465
475inline int sock::clearerror () const
476{
477 int err = 0;
478 getopt (SO_ERROR, &err, sizeof (err));
479 return err;
480}
481
483inline bool sock::debug () const
484{
485 BOOL old;
486 getopt (SO_DEBUG, &old, sizeof (old));
487 return (old != FALSE);
488}
489
491inline void sock::debug (bool b) const
492{
493 BOOL opt = b;
494 setopt (SO_DEBUG, &opt, sizeof (opt));
495}
496
498inline bool sock::reuseaddr () const
499{
500 BOOL old;
501 getopt (SO_REUSEADDR, &old, sizeof (old));
502 return (old != FALSE);
503}
504
506inline void sock::reuseaddr (bool b) const
507{
508 BOOL opt = b;
509 setopt (SO_REUSEADDR, &opt, sizeof (opt));
510}
511
513inline bool sock::keepalive () const
514{
515 BOOL old;
516 getopt (SO_KEEPALIVE, &old, sizeof (old));
517 return (old != FALSE);
518}
519
521inline void sock::keepalive (bool b) const
522{
523 BOOL opt = b;
524 setopt (SO_KEEPALIVE, &opt, sizeof (opt));
525}
526
528inline bool sock::dontroute () const
529{
530 BOOL old;
531 getopt (SO_DONTROUTE, &old, sizeof (old));
532 return (old != FALSE);
533}
534
536inline void sock::dontroute (bool b) const
537{
538 BOOL opt = b;
539 setopt (SO_DONTROUTE, &opt, sizeof (opt));
540}
541
543inline bool sock::broadcast () const
544{
545 BOOL old;
546 getopt (SO_BROADCAST, &old, sizeof (old));
547 return (old != FALSE);
548}
549
556inline void sock::broadcast (bool b) const
557{
558 BOOL opt = b;
559 setopt (SO_BROADCAST, &opt, sizeof (opt));
560}
561
566inline bool sock::oobinline () const
567{
568 BOOL old;
569 getopt (SO_OOBINLINE, &old, sizeof (old));
570 return (old != FALSE);
571}
572
577inline void sock::oobinline (bool b) const
578{
579 BOOL opt = b;
580 setopt (SO_OOBINLINE, &opt, sizeof (opt));
581}
582
584inline int sock::sendbufsz () const
585{
586 int old = 0;
587 getopt (SO_SNDBUF, &old, sizeof (old));
588 return old;
589}
590
592inline void sock::sendbufsz (size_t sz) const
593{
594 setopt (SO_SNDBUF, &sz, sizeof (sz));
595}
596
598inline int sock::recvbufsz () const
599{
600 int old = 0;
601 getopt (SO_RCVBUF, &old, sizeof (old));
602 return old;
603}
604
606inline void sock::recvbufsz (size_t sz) const
607{
608 setopt (SO_RCVBUF, &sz, sizeof (sz));
609}
610
616inline void sock::blocking (bool on_off)
617{
618 if (!sl || sl->handle == INVALID_SOCKET)
619 throw erc (WSAENOTSOCK, Errors());
620
621 unsigned long mode = on_off ? 0 : 1;
622 if (ioctlsocket (sl->handle, FIONBIO, &mode) == SOCKET_ERROR)
623 last_error ().raise ();
624}
625
641inline erc sock::setevent (HANDLE evt, long mask) const
642{
643 if (!sl || sl->handle == INVALID_SOCKET)
644 return erc (WSAENOTSOCK, Errors());
645
646 if (WSAEventSelect (sl->handle, (WSAEVENT)evt, mask) == SOCKET_ERROR)
647 return last_error ();
648 return erc::success;
649}
650
657inline long sock::enumevents () const
658{
659 if (!sl || sl->handle == INVALID_SOCKET)
660 throw erc (WSAENOTSOCK, Errors());
661
662 WSANETWORKEVENTS netev;
663 if (WSAEnumNetworkEvents (sl->handle, NULL, &netev) == SOCKET_ERROR)
664 last_error ().raise ();
665 return netev.lNetworkEvents;
666}
667
669inline void sock::linger (bool on_off, unsigned short seconds) const
670{
671 struct linger opt;
672 opt.l_onoff = on_off;
673 opt.l_linger = seconds;
674 setopt (SO_LINGER, &opt, sizeof (opt));
675}
676
678inline bool sock::linger (unsigned short* seconds) const
679{
680 struct linger opt;
681 getopt (SO_LINGER, &opt, sizeof (opt));
682 if (seconds)
683 *seconds = opt.l_linger;
684 return (opt.l_onoff == 0);
685}
686
689{
690 int code = WSAGetLastError ();
691 if (!code)
692 return erc::success;
693 else
694 return erc (code, Errors());
695}
696
703inline bool sock::operator== (const sock& other) const
704{
705 return (sl == other.sl);
706}
707
713inline bool sock::operator!= (const sock& other) const
714{
715 return !operator== (other);
716}
717
719inline sock::mflags operator| (sock::mflags f1, sock::mflags f2)
720{
721 return (sock::mflags) ((int)f1 | (int)f2);
722}
723
724} // 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:205
generic_sockstream(const sockbuf &sb)
Create from an existing sockbuf.
Definition wsockstream.h:212
sockbuf * operator->()
Return the buffer used by this stream.
Definition wsockstream.h:234
generic_sockstream(int type, int domain=AF_INET, int proto=0)
Create a SOCK_STREAM or SOCK_DGRAM stream.
Definition wsockstream.h:220
generic_sockstream()
Default constructor.
Definition wsockstream.h:208
~generic_sockstream()
Create a SOCK_STREAM connected to a remote peer.
Definition wsockstream.h:249
sockbuf * rdbuf()
Return the buffer used by this stream.
Definition wsockstream.h:229
generic_sockstream(const sock &s)
Create from an existing socket.
Definition wsockstream.h:216
generic_sockstream(const inaddr &remote, int type=SOCK_STREAM)
Create a SOCK_STREAM connected to a remote peer.
Definition wsockstream.h:241
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:493
bool broadcast() const
Return "broadcast" option.
Definition wsockstream.h:543
int recvtimeout() const
Returns the send timeout value.
Definition wsockstream.h:407
bool reuseaddr() const
Return the "reuse address" flag.
Definition wsockstream.h:498
bool dontroute() const
Return status of "don't route" flag.
Definition wsockstream.h:528
long enumevents() const
Indicates which of the FD_XXX network events have occurred.
Definition wsockstream.h:657
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:475
erc listen(int num=SOMAXCONN) const
Places the socket in a state in which it is listening for incoming connections.
Definition wsockstream.h:320
void linger(bool on_off, unsigned short seconds) const
Turn on or off linger mode and lingering timeout.
Definition wsockstream.h:669
erc bind() const
Associates a local address with the socket.
Definition wsockstream.cpp:282
bool operator==(const sock &other) const
Equality comparison operator.
Definition wsockstream.h:703
erc setopt(int op, void *buf, int len, int level=SOL_SOCKET) const
Set a socket option.
Definition wsockstream.h:445
int recvbufsz() const
Return buffer size for receive operations.
Definition wsockstream.h:598
virtual bool is_open() const
Check if socket is opened.
Definition wsockstream.h:287
erc connect(const inaddr &peer) const
Establishes a connection to specified peer.
Definition wsockstream.h:293
int getopt(int op, void *buf, int len, int level=SOL_SOCKET) const
Returns a socket option.
Definition wsockstream.h:427
void blocking(bool on_off)
Change blocking mode.
Definition wsockstream.h:616
erc name(inaddr &addr) const
Return the local name for the object.
Definition wsockstream.cpp:232
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:455
int gettype() const
Return socket type (SOCK_DGRAM or SOCK_STREAM)
Definition wsockstream.h:459
bool debug() const
Return the debug flag.
Definition wsockstream.h:483
virtual erc close()
Close socket.
Definition wsockstream.cpp:204
bool oobinline() const
Return the status of the OOB_INLINE flag.
Definition wsockstream.h:566
unsigned int nread() const
Return number of characters waiting in socket's buffer.
Definition wsockstream.cpp:570
size_t recv(void *buf, size_t maxlen, mflags msgf=mflags::none) const
Receives data from socket.
Definition wsockstream.cpp:355
sock()
Default constructor creates a closed socket.
Definition wsockstream.h:276
size_t send(const void *buf, size_t len, mflags msgf=mflags::none) const
Send data to the connected peer.
Definition wsockstream.cpp:419
bool operator!=(const sock &other) const
Inequality comparison operator.
Definition wsockstream.h:713
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:377
size_t recvfrom(sockaddr &sa, void *buf, size_t maxlen, mflags msgf=mflags::none) const
Receives data from socket.
Definition wsockstream.cpp:387
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:586
int sendbufsz() const
Return buffer size for send operations.
Definition wsockstream.h:584
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:548
HANDLE handle() const
Retrieve Windows socket handle.
Definition wsockstream.h:281
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:306
virtual ~sock()
Destructor.
Definition wsockstream.cpp:164
erc peer(inaddr &addr) const
Retrieves the name of the peer to which the socket is connected.
Definition wsockstream.cpp:249
erc setevent(HANDLE evt, long mask) const
Associate an event object with this socket.
Definition wsockstream.h:641
static erc last_error()
Return an error code with the value returned by WSAGetLastError.
Definition wsockstream.h:688
bool is_writeready(int wp_sec, int wp_usec=0) const
Check if socket is "writable".
Definition wsockstream.cpp:524
bool keepalive() const
Return "keep alive" flag.
Definition wsockstream.h:513
sock & operator=(const sock &)
Assignment operator.
Definition wsockstream.cpp:131
Provide functions required by streambuf interface using an underlying socket.
Definition wsockstream.h:158
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:783
virtual ~sockbuf()
Destructor.
Definition wsockstream.cpp:676
virtual int sync() override
Return 0 if all chars flushed or -1 if error.
Definition wsockstream.cpp:695
virtual std::streamsize showmanyc() override
Return number of characters available in socket buffer.
Definition wsockstream.cpp:814
sockbuf & operator=(const sockbuf &)
Assignment operator.
Definition wsockstream.cpp:667
virtual std::streambuf * setbuf(char *buf, std::streamsize sz) override
Change buffering mode.
Definition wsockstream.cpp:717
virtual int underflow() override
underflow
Definition wsockstream.cpp:749
Definition of erc and erfac classes.
@ seconds
Degrees, minutes, seconds format (DD°MM'SS.sss")
Definition convert.h:247
Definition of inaddr class.
std::ostream & operator<<(std::ostream &strm, const mlib::inaddr &addr)
Serialize an address as '<hostname>:<port>'.
Definition inaddr.h:122