MLIB
Loading...
Searching...
No Matches
sock.h
1#pragma once
2
3#if __has_include("defs.h")
4#include "defs.h"
5#endif
6
7#include "safe_winsock.h"
8#include "errorcode.h"
9#include "inaddr.h"
10#include "tvops.h"
11
12namespace mlib {
13
14// clang-format off
18class sock
19{
20public:
22 enum type
23 {
24 stream = SOCK_STREAM,
25 dgram = SOCK_DGRAM,
26 raw = SOCK_RAW
27 };
28
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 (type t, int domain = AF_INET, int proto = 0);
50 sock (const sock&);
51 sock (sock&&);
52
53 virtual ~sock ();
54 sock& operator= (const sock&);
56 HANDLE handle () const;
57 bool operator== (const sock& other) const;
58 bool operator!= (const sock& other) const;
59 operator SOCKET () const;
60
61 virtual erc open (type t, int domain = AF_INET, int proto = 0);
62 virtual void 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 void sendtimeout (std::chrono::milliseconds tmo) const;
76 std::chrono::milliseconds sendtimeout () const;
77 void recvtimeout (std::chrono::milliseconds tmo) const;
78 std::chrono::milliseconds recvtimeout () const;
79 bool is_readready (std::chrono::milliseconds tmo = std::chrono::milliseconds{0}) const;
80 bool is_writeready (std::chrono::milliseconds tmo = std::chrono::milliseconds{0}) const;
81 bool is_exceptionpending (std::chrono::milliseconds tmo = std::chrono::milliseconds{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, std::chrono::milliseconds tmo) const;
88 bool connected () const;
89 erc listen (int num = SOMAXCONN) const;
90 erc accept (sock& client, inaddr* sa = nullptr) const;
91 erc accept (sock& client, std::chrono::milliseconds tmo, 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#ifdef _WIN32
118 erc setevent (HANDLE evt, long mask) const;
119 long enumevents () const;
120#endif
121 void linger (bool on_off, unsigned short seconds) const;
122 bool linger (unsigned short* seconds = 0) const;
123 void nodelay (bool on_off);
124 bool nodelay () const;
125
127 static errfac& Errors ();
128
130 static void Errors (errfac& facitlity);
131
132protected:
133 static erc last_error ();
134
135private:
136 struct sock_ref
137 {
138 sock_ref ()
139 : handle{INVALID_SOCKET}
140 , ref_count{1} {};
141 SOCKET handle;
142 int ref_count;
143 }* sl;
144
145 friend class inaddr;
146 friend struct sock_initializer;
147};
148
149/*---------------------- support classes ------------------------------------*/
152struct sock_initializer
153{
154 sock_initializer ();
155 ~sock_initializer ();
156};
157inline sock_initializer sock_nifty_counter;
158
159
160/*==================== INLINE FUNCTIONS ===========================*/
161
163inline
165 : sl{nullptr}
166{}
167
169inline
170HANDLE sock::handle () const
171{
172 return sl ? (HANDLE)(std::intptr_t)sl->handle : INVALID_HANDLE_VALUE;
173}
174
176inline
177sock::operator SOCKET () const
178{
179 return sl ? sl->handle : INVALID_SOCKET;
180}
181
183inline
184bool sock::is_open () const
185{
186 return sl && sl->handle != INVALID_SOCKET;
187}
188
190inline
191erc sock::connect (const inaddr& peer) const
192{
193 if (!sl || sl->handle == INVALID_SOCKET)
194 return erc (WSAENOTSOCK, Errors());
195
196 int ret = ::connect (sl->handle, peer, sizeof (peer));
197 if (ret == INVALID_SOCKET)
198 return last_error ();
199
200 return erc::success;
201}
202
204inline
205bool sock::connected () const
206{
207 return is_writeready ();
208}
209
211inline
212erc sock::accept (sock& client, inaddr* addr) const
213{
214 if (!sl || sl->handle == INVALID_SOCKET)
215 return erc (WSAENOTSOCK, Errors());
216
217 sockaddr sa;
218 socklen_t len = sizeof (sa);
219 client = sock (::accept (sl->handle, &sa, &len));
220 if (addr)
221 *addr = sa;
222 return erc ();
223}
224
226inline
227erc sock::listen (int num) const
228{
229 if (!sl || sl->handle == INVALID_SOCKET)
230 return erc (WSAENOTSOCK, Errors());
231
232 ::listen (sl->handle, num);
233 return last_error ();
234}
235
244template <typename T>
245size_t sock::send (std::basic_string<T> buf, mflags msgf) const
246{
247 return send (buf.c_str (), buf.size () * sizeof (T), msgf);
248}
249
259template <typename T>
260size_t sock::sendto (const sockaddr& sa, std::basic_string<T> buf, mflags msgf) const
261{
262 return sendto (sa, buf.c_str (), buf.size () * sizeof (T), msgf);
263}
264
269inline
270void sock::sendtimeout (std::chrono::milliseconds tmo) const
271{
272 assert (sl && sl->handle != INVALID_SOCKET);
273
274#ifdef _WIN32
275 socklen_t optlen = sizeof (int);
276 int par = (int)tmo.count();
277#else
278 socklen_t optlen = sizeof(timeval);
279 timeval par = from_chrono (tmo);
280#endif
281 setsockopt (sl->handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&par, optlen);
282}
283
285inline
286std::chrono::milliseconds sock::sendtimeout () const
287{
288 assert (sl && sl->handle != INVALID_SOCKET);
289
290#ifdef _WIN32
291 socklen_t optlen = sizeof (int);
292 int tmo;
293 getsockopt (sl->handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&tmo, &optlen);
294 return std::chrono::milliseconds(tmo);
295#else
296 socklen_t optlen = sizeof(timeval);
297 timeval tv;
298 getsockopt (sl->handle, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, &optlen);
299 return std::chrono::duration_cast<std::chrono::milliseconds>(to_chrono (tv));
300#endif
301}
302
307inline
308void sock::recvtimeout (std::chrono::milliseconds tmo) const
309{
310 assert (sl && sl->handle != INVALID_SOCKET);
311#ifdef _WIN32
312 socklen_t optlen = sizeof (int);
313 int par = (int)tmo.count();
314#else
315 socklen_t optlen = sizeof(timeval);
316 timeval par = from_chrono (tmo);
317#endif
318 setsockopt (sl->handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&par, optlen);
319}
320
322inline
323std::chrono::milliseconds sock::recvtimeout () const
324{
325 assert (sl && sl->handle != INVALID_SOCKET);
326#ifdef _WIN32
327 socklen_t optlen = sizeof (int);
328 int tmo;
329 getsockopt (sl->handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&tmo, &optlen);
330 return std::chrono::milliseconds (tmo);
331#else
332 socklen_t optlen = sizeof(timeval);
333 timeval tv;
334 getsockopt (sl->handle, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, &optlen);
335 return std::chrono::duration_cast<std::chrono::milliseconds> (to_chrono(tv));
336#endif
337}
338
348inline
349int sock::getopt (int op, void* buf, int len, int level) const
350{
351 if (!sl || sl->handle == INVALID_SOCKET)
352 return erc (WSAENOTSOCK, Errors());
353
354 socklen_t rlen = len;
355 if (::getsockopt (sl->handle, level, op, (char*)buf, &rlen) == SOCKET_ERROR)
356 last_error ().raise ();
357 return rlen;
358}
359
367inline
368erc sock::setopt (int op, void* buf, int len, int level) const
369{
370 if (!sl || sl->handle == INVALID_SOCKET)
371 return erc (WSAENOTSOCK, Errors());
372
373 if (::setsockopt (sl->handle, level, op, (char*)buf, len) == SOCKET_ERROR)
374 return last_error ();
375
376 return erc::success;
377}
378
382inline
383int sock::gettype () const
384{
385 int ty = 0;
386 getopt (SO_TYPE, &ty, sizeof (ty));
387 return ty;
388}
389
399inline
401{
402 int err = 0;
403 getopt (SO_ERROR, &err, sizeof (err));
404 return err;
405}
406
408inline
409bool sock::debug () const
410{
411 BOOL old;
412 getopt (SO_DEBUG, &old, sizeof (old));
413 return (old != 0);
414}
415
417inline
418void sock::debug (bool b) const
419{
420 BOOL opt = b;
421 setopt (SO_DEBUG, &opt, sizeof (opt));
422}
423
425inline
426bool sock::reuseaddr () const
427{
428 BOOL old;
429 getopt (SO_REUSEADDR, &old, sizeof (old));
430 return (old != 0);
431}
432
434inline
435void sock::reuseaddr (bool b) const
436{
437 BOOL opt = b;
438 setopt (SO_REUSEADDR, &opt, sizeof (opt));
439}
440
442inline
443bool sock::keepalive () const
444{
445 BOOL old;
446 getopt (SO_KEEPALIVE, &old, sizeof (old));
447 return (old != 0);
448}
449
451inline
452void sock::keepalive (bool b) const
453{
454 BOOL opt = b;
455 setopt (SO_KEEPALIVE, &opt, sizeof (opt));
456}
457
459inline
460bool sock::dontroute () const
461{
462 BOOL old;
463 getopt (SO_DONTROUTE, &old, sizeof (old));
464 return (old != 0);
465}
466
468inline
469void sock::dontroute (bool b) const
470{
471 BOOL opt = b;
472 setopt (SO_DONTROUTE, &opt, sizeof (opt));
473}
474
476inline
477bool sock::broadcast () const
478{
479 BOOL old;
480 getopt (SO_BROADCAST, &old, sizeof (old));
481 return (old != 0);
482}
483
490inline
491void sock::broadcast (bool b) const
492{
493 BOOL opt = b;
494 setopt (SO_BROADCAST, &opt, sizeof (opt));
495}
496
501inline
502bool sock::oobinline () const
503{
504 BOOL old;
505 getopt (SO_OOBINLINE, &old, sizeof (old));
506 return (old != 0);
507}
508
513inline
514void sock::oobinline (bool b) const
515{
516 BOOL opt = b;
517 setopt (SO_OOBINLINE, &opt, sizeof (opt));
518}
519
521inline
522int sock::sendbufsz () const
523{
524 int old = 0;
525 getopt (SO_SNDBUF, &old, sizeof (old));
526 return old;
527}
528
530inline
531void sock::sendbufsz (size_t sz) const
532{
533 setopt (SO_SNDBUF, &sz, sizeof (sz));
534}
535
537inline
538int sock::recvbufsz () const
539{
540 int old = 0;
541 getopt (SO_RCVBUF, &old, sizeof (old));
542 return old;
543}
544
546inline
547void sock::recvbufsz (size_t sz) const
548{
549 setopt (SO_RCVBUF, &sz, sizeof (sz));
550}
551
557inline
558void sock::blocking (bool on_off)
559{
560 if (!sl || sl->handle == INVALID_SOCKET)
561 throw erc (WSAENOTSOCK, Errors());
562
563 unsigned long mode = on_off ? 0 : 1;
564 if (ioctlsocket (sl->handle, FIONBIO, &mode) == SOCKET_ERROR)
565 last_error ().raise ();
566}
567
568#ifdef _WIN32
584inline
585erc sock::setevent (HANDLE evt, long mask) const
586{
587 if (!sl || sl->handle == INVALID_SOCKET)
588 return erc (WSAENOTSOCK, Errors());
589
590 if (WSAEventSelect (sl->handle, (WSAEVENT)evt, mask) == SOCKET_ERROR)
591 return last_error ();
592 return erc::success;
593}
594
601inline
602long sock::enumevents () const
603{
604 if (!sl || sl->handle == INVALID_SOCKET)
605 throw erc (WSAENOTSOCK, Errors());
606
607 WSANETWORKEVENTS netev;
608 if (WSAEnumNetworkEvents (sl->handle, NULL, &netev) == SOCKET_ERROR)
609 last_error ().raise ();
610 return netev.lNetworkEvents;
611}
612#endif
613
615inline
616void sock::linger (bool on_off, unsigned short seconds) const
617{
618 struct linger opt;
619 opt.l_onoff = on_off;
620 opt.l_linger = seconds;
621 setopt (SO_LINGER, &opt, sizeof (opt));
622}
623
625inline
626bool sock::linger (unsigned short* seconds) const
627{
628 struct linger opt;
629 getopt (SO_LINGER, &opt, sizeof (opt));
630 if (seconds)
631 *seconds = opt.l_linger;
632 return (opt.l_onoff == 0);
633}
634
636inline
637void sock::nodelay (bool on_off)
638{
639 int value = on_off;
640 setopt (TCP_NODELAY, &value, sizeof (int), IPPROTO_TCP);
641}
642
644inline
645bool sock::nodelay () const
646{
647 int value;
648 getopt (TCP_NODELAY, &value, sizeof (int), IPPROTO_TCP);
649 return (value != 0);
650}
651
653inline
655{
656#ifdef _WIN32
657 int code = WSAGetLastError ();
658#else
659 int code = errno;
660#endif
661 if (!code)
662 return erc::success;
663 else
664 return erc (code, Errors());
665}
666
673inline
674bool sock::operator== (const sock& other) const
675{
676 return (sl == other.sl);
677}
678
684inline
685bool sock::operator!= (const sock& other) const
686{
687 return !operator== (other);
688}
689
691inline
692sock::mflags operator| (sock::mflags f1, sock::mflags f2)
693{
694 return (sock::mflags) ((int)f1 | (int)f2);
695}
696
697} // namespace mlib
698
700inline
701std::ostream& operator<< (std::ostream& strm, const mlib::sock& s)
702{
703 strm << s.handle ();
704 return strm;
705}
706
objects returned as a function result or thrown directly.
Definition errorcode.h:73
static erc success
The SUCCESS indicator.
Definition errorcode.h:121
void raise() const
Definition errorcode.h:603
We keep a reference counter associated with each sock object because it is more expensive to duplicat...
Definition sock.h:19
bool broadcast() const
Return "broadcast" option.
Definition sock.h:477
bool reuseaddr() const
Return the "reuse address" flag.
Definition sock.h:426
bool dontroute() const
Return status of "don't route" flag.
Definition sock.h:460
checked< inaddr > peer() const
Retrieves the name of the peer to which the socket is connected.
Definition sock.cpp:229
mflags
Flags for send/receive operations.
Definition sock.h:39
@ dont_route
data should not be routed
Definition sock.h:43
@ peek
don't remove data from the input queue
Definition sock.h:42
@ none
no flags
Definition sock.h:40
@ out_of_band
send out of band data
Definition sock.h:41
@ wait_all
wait until buffer full or connection closed
Definition sock.h:44
int clearerror() const
Return and clear the socket error flag.
Definition sock.h:400
erc listen(int num=SOMAXCONN) const
Places the socket in a state in which it is listening for incoming connections.
Definition sock.h:227
void linger(bool on_off, unsigned short seconds) const
Turn on or off linger mode and lingering timeout.
Definition sock.h:616
erc bind() const
Associates a local address with the socket.
Definition sock.cpp:261
bool operator==(const sock &other) const
Equality comparison operator.
Definition sock.h:674
bool is_writeready(std::chrono::milliseconds tmo=std::chrono::milliseconds{0}) const
Check if socket is "writable".
Definition sock.cpp:505
erc setopt(int op, void *buf, int len, int level=SOL_SOCKET) const
Set a socket option.
Definition sock.h:368
int recvbufsz() const
Return buffer size for receive operations.
Definition sock.h:538
checked< inaddr > name() const
Return the local name for the object.
Definition sock.cpp:214
virtual bool is_open() const
Check if socket is opened.
Definition sock.h:184
erc connect(const inaddr &peer) const
Establishes a connection to specified peer.
Definition sock.h:191
int getopt(int op, void *buf, int len, int level=SOL_SOCKET) const
Returns a socket option.
Definition sock.h:349
void blocking(bool on_off)
Change blocking mode.
Definition sock.h:558
size_t sendto(const sockaddr &sa, const void *buf, size_t len, mflags msgf=mflags::none) const
Send data to a peer.
Definition sock.cpp:438
int gettype() const
Return socket type (SOCK_DGRAM or SOCK_STREAM)
Definition sock.h:383
std::chrono::milliseconds sendtimeout() const
Returns the send timeout value.
Definition sock.h:286
bool debug() const
Return the debug flag.
Definition sock.h:409
bool is_readready(std::chrono::milliseconds tmo=std::chrono::milliseconds{0}) const
Check if socket is "readable".
Definition sock.cpp:476
bool oobinline() const
Return the status of the OOB_INLINE flag.
Definition sock.h:502
unsigned int nread() const
Return number of characters waiting in socket's buffer.
Definition sock.cpp:549
size_t recv(void *buf, size_t maxlen, mflags msgf=mflags::none) const
Receives data from socket.
Definition sock.cpp:338
sock()
Default constructor creates a closed socket.
Definition sock.h:164
size_t send(const void *buf, size_t len, mflags msgf=mflags::none) const
Send data to the connected peer.
Definition sock.cpp:402
bool operator!=(const sock &other) const
Inequality comparison operator.
Definition sock.h:685
type
socket types
Definition sock.h:23
shuthow
operation blocked by shutdown function
Definition sock.h:31
@ shut_readwrite
blocked for both
Definition sock.h:34
@ shut_read
blocked for reading
Definition sock.h:32
@ shut_write
blocked for writing
Definition sock.h:33
size_t recvfrom(sockaddr &sa, void *buf, size_t maxlen, mflags msgf=mflags::none) const
Receives data from socket.
Definition sock.cpp:370
bool connected() const
Check is socket is connected.
Definition sock.h:205
virtual erc shutdown(shuthow sh) const
Disables sends or receives on socket.
Definition sock.cpp:565
int sendbufsz() const
Return buffer size for send operations.
Definition sock.h:522
HANDLE handle() const
Retrieve Windows socket handle.
Definition sock.h:170
static errfac & Errors()
Return error facility used by all sock-derived classes.
Definition sock.cpp:36
erc accept(sock &client, inaddr *sa=nullptr) const
Permits an incoming connection attempt on the socket.
Definition sock.h:212
virtual ~sock()
Destructor.
Definition sock.cpp:159
bool is_exceptionpending(std::chrono::milliseconds tmo=std::chrono::milliseconds{0}) const
Check if socket has OOB data or any exceptional error conditions.
Definition sock.cpp:528
static erc last_error()
Return an error code with the value returned by WSAGetLastError.
Definition sock.h:654
bool keepalive() const
Return "keep alive" flag.
Definition sock.h:443
virtual void close()
Close socket.
Definition sock.cpp:184
virtual erc open(type t, int domain=AF_INET, int proto=0)
Open the socket.
Definition sock.cpp:170
std::chrono::milliseconds recvtimeout() const
Returns the send timeout value.
Definition sock.h:323
bool nodelay() const
Return status of TCP_NODELAY option.
Definition sock.h:645
sock & operator=(const sock &)
Assignment operator.
Definition sock.cpp:126
@ seconds
Degrees, minutes, seconds format (DD°MM'SS.sss")
Definition convert.h:249
Definition of mlib::erc and mlib::errfac classes.
std::chrono::microseconds to_chrono(const timeval &tv)
Conversion to a chrono duration in microseconds.
Definition tvops.h:200
timeval from_chrono(const T &dur)
Conversion from a chrono duration.
Definition tvops.h:190
Definition of mlib::inaddr class.
Definition sock.h:153
Operations on timeval structure.