join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
socket.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_SOCKET_HPP
26#define JOIN_CORE_SOCKET_HPP
27
28// libjoin.
29#include <join/protocol.hpp>
30#include <join/endpoint.hpp>
31#include <join/openssl.hpp>
32#include <join/utils.hpp>
33#include <join/error.hpp>
34
35// Libraries.
36#include <openssl/err.h>
37
38// C++.
39#include <type_traits>
40#include <iostream>
41
42// C.
43#include <netinet/tcp.h>
44#include <linux/icmp.h>
45#include <sys/ioctl.h>
46#include <sys/stat.h>
47#include <fnmatch.h>
48#include <cassert>
49#include <fcntl.h>
50#include <poll.h>
51
52namespace join
53{
57 template <class Protocol>
59 {
60 public:
61 using Ptr = std::unique_ptr<BasicSocket<Protocol>>;
62 using Endpoint = typename Protocol::Endpoint;
63
67 enum Mode
68 {
71 };
72
96
108
114 {
115 }
116
122 : _mode (mode)
123 {
124 }
125
130 BasicSocket (const BasicSocket& other) = delete;
131
137 BasicSocket& operator= (const BasicSocket& other) = delete;
138
144 : _state (other._state)
145 , _mode (other._mode)
146 , _handle (other._handle)
147 , _protocol (other._protocol)
148 {
149 other._state = State::Closed;
150 other._mode = Mode::NonBlocking;
151 other._handle = -1;
152 other._protocol = Protocol ();
153 }
154
161 {
162 this->close ();
163
164 this->_state = other._state;
165 this->_mode = other._mode;
166 this->_handle = other._handle;
167 this->_protocol = other._protocol;
168
169 other._state = State::Closed;
170 other._mode = Mode::NonBlocking;
171 other._handle = -1;
172 other._protocol = Protocol ();
173
174 return *this;
175 }
176
180 virtual ~BasicSocket ()
181 {
182 if (this->_handle != -1)
183 {
184 ::close (this->_handle);
185 }
186 }
187
193 virtual int open (const Protocol& protocol = Protocol ()) noexcept
194 {
195 if (this->_state != State::Closed)
196 {
197 lastError = make_error_code (Errc::InUse);
198 return -1;
199 }
200
201 if (this->_mode == Mode::NonBlocking)
202 this->_handle = ::socket (protocol.family (), protocol.type () | SOCK_NONBLOCK, protocol.protocol ());
203 else
204 this->_handle = ::socket (protocol.family (), protocol.type (), protocol.protocol ());
205
206 if (this->_handle == -1)
207 {
208 lastError = std::error_code (errno, std::generic_category ());
209 this->close ();
210 return -1;
211 }
212
214 this->_protocol = protocol;
215
216 return 0;
217 }
218
222 virtual void close () noexcept
223 {
224 if (this->_state != State::Closed)
225 {
226 ::close (this->_handle);
227 this->_state = State::Closed;
228 this->_handle = -1;
229 }
230 }
231
237 virtual int bind (const Endpoint& endpoint) noexcept
238 {
239 if ((this->_state == State::Closed) && (this->open (endpoint.protocol ()) == -1))
240 {
241 return -1;
242 }
243
244 if (endpoint.protocol ().family () == AF_PACKET)
245 {
246 if (reinterpret_cast<const struct sockaddr_ll*> (endpoint.addr ())->sll_ifindex == 0)
247 {
248 lastError = std::make_error_code (std::errc::no_such_device);
249 return -1;
250 }
251 }
252 else if ((endpoint.protocol ().family () == AF_INET6) || (endpoint.protocol ().family () == AF_INET))
253 {
254 this->setOption (Option::ReuseAddr, 1);
255 }
256 else if (endpoint.protocol ().family () == AF_UNIX)
257 {
258 ::unlink (endpoint.device ().c_str ());
259 }
260
261 if (::bind (this->_handle, endpoint.addr (), endpoint.length ()) == -1)
262 {
263 lastError = std::error_code (errno, std::generic_category ());
264 return -1;
265 }
266
267 return 0;
268 }
269
274 virtual int canRead () const noexcept
275 {
276 int available = 0;
277
278 // check if data can be read in the socket internal buffer.
279 if (::ioctl (this->_handle, FIONREAD, &available) == -1)
280 {
281 lastError = std::error_code (errno, std::generic_category ());
282 return -1;
283 }
284
285 return available;
286 }
287
293 virtual bool waitReadyRead (int timeout = 0) const noexcept
294 {
295 return (this->wait (true, false, timeout) == 0);
296 }
297
304 virtual int read (char* data, unsigned long maxSize) noexcept
305 {
306 struct iovec iov;
307 iov.iov_base = data;
308 iov.iov_len = maxSize;
309
310 struct msghdr message;
311 message.msg_name = nullptr;
312 message.msg_namelen = 0;
313 message.msg_iov = &iov;
314 message.msg_iovlen = 1;
315 message.msg_control = nullptr;
316 message.msg_controllen = 0;
317
318 int size = ::recvmsg (this->_handle, &message, 0);
319 if (size < 1)
320 {
321 if (size == -1)
322 {
323 lastError = std::error_code (errno, std::generic_category ());
324 }
325 else
326 {
328 }
329 return -1;
330 }
331
332 return size;
333 }
334
340 virtual bool waitReadyWrite (int timeout = 0) const noexcept
341 {
342 return (this->wait (false, true, timeout) == 0);
343 }
344
351 virtual int write (const char* data, unsigned long maxSize) noexcept
352 {
353 struct iovec iov;
354 iov.iov_base = const_cast<char*> (data);
355 iov.iov_len = maxSize;
356
357 struct msghdr message;
358 message.msg_name = nullptr;
359 message.msg_namelen = 0;
360 message.msg_iov = &iov;
361 message.msg_iovlen = 1;
362 message.msg_control = nullptr;
363 message.msg_controllen = 0;
364
365 int result = ::sendmsg (this->_handle, &message, 0);
366 if (result == -1)
367 {
368 lastError = std::error_code (errno, std::generic_category ());
369 return -1;
370 }
371
372 return result;
373 }
374
379 void setMode (Mode mode) noexcept
380 {
381 this->_mode = mode;
382
383 if (this->_state != State::Closed)
384 {
385 int flags = ::fcntl (this->_handle, F_GETFL, 0);
386
387 if (this->_mode == Mode::NonBlocking)
388 {
389 flags = flags | O_NONBLOCK;
390 }
391 else
392 {
393 flags = flags & ~O_NONBLOCK;
394 }
395
396 ::fcntl (this->_handle, F_SETFL, flags);
397 }
398 }
399
406 virtual int setOption (Option option, int value) noexcept
407 {
408 int optlevel, optname;
409
410 switch (option)
411 {
413 optlevel = SOL_SOCKET;
414 optname = SO_KEEPALIVE;
415 break;
416
418 optlevel = SOL_SOCKET;
419 optname = SO_SNDBUF;
420 break;
421
423 optlevel = SOL_SOCKET;
424 optname = SO_RCVBUF;
425 break;
426
428 optlevel = SOL_SOCKET;
429 optname = SO_TIMESTAMP;
430 break;
431
433 optlevel = SOL_SOCKET;
434 optname = SO_REUSEADDR;
435 break;
436
438 optlevel = SOL_SOCKET;
439 optname = SO_REUSEPORT;
440 break;
441
443 optlevel = SOL_SOCKET;
444 optname = SO_BROADCAST;
445 break;
446
447 case Option::AuxData:
448 optlevel = SOL_PACKET;
449 optname = PACKET_AUXDATA;
450 break;
451
452 default:
454 return -1;
455 }
456
457 int result = ::setsockopt (this->_handle, optlevel, optname, &value, sizeof (value));
458 if (result == -1)
459 {
460 lastError = std::error_code (errno, std::generic_category ());
461 return -1;
462 }
463
464 return 0;
465 }
466
471 Endpoint localEndpoint () const noexcept
472 {
473 struct sockaddr_storage sa;
474 socklen_t sa_len = sizeof (struct sockaddr_storage);
475
476 if (::getsockname (this->_handle, reinterpret_cast<struct sockaddr*> (&sa), &sa_len) == -1)
477 {
478 return {};
479 }
480
481 return Endpoint (reinterpret_cast<struct sockaddr*> (&sa), sa_len);
482 }
483
488 bool opened () const noexcept
489 {
490 return (this->_state != State::Closed);
491 }
492
497 virtual bool encrypted () const noexcept
498 {
499 return false;
500 }
501
506 int family () const noexcept
507 {
508 return this->_protocol.family ();
509 }
510
515 int type () const noexcept
516 {
517 return this->_protocol.type ();
518 }
519
524 int protocol () const noexcept
525 {
526 return this->_protocol.protocol ();
527 }
528
533 int handle () const noexcept
534 {
535 return this->_handle;
536 }
537
545 static uint16_t checksum (const uint16_t* data, size_t len, uint16_t current = 0)
546 {
547 uint32_t sum = current;
548
549 while (len > 1)
550 {
551 sum += *data++;
552 len -= 2;
553 }
554
555 if (len == 1)
556 {
557#if __BYTE_ORDER == __LITTLE_ENDIAN
558 sum += *reinterpret_cast<const uint8_t*> (data);
559#else
560 sum += *reinterpret_cast<const uint8_t*> (data) << 8;
561#endif
562 }
563
564 sum = (sum >> 16) + (sum & 0xffff);
565 sum += (sum >> 16);
566
567 return static_cast<uint16_t> (~sum);
568 }
569
570 protected:
578 int wait (bool wantRead, bool wantWrite, int timeout) const noexcept
579 {
580 struct pollfd handle = {.fd = this->_handle, .events = 0, .revents = 0};
581
582 if (wantRead)
583 {
584 handle.events |= POLLIN;
585 }
586
587 if (wantWrite)
588 {
589 handle.events |= POLLOUT;
590 }
591
592 int nset = (handle.fd > -1) ? ::poll (&handle, 1, timeout == 0 ? -1 : timeout) : -1;
593 if (nset != 1)
594 {
595 if (nset == -1)
596 {
597 if (handle.fd == -1)
598 {
599 errno = EBADF;
600 }
601 lastError = std::error_code (errno, std::generic_category ());
602 }
603 else
604 {
605 lastError = make_error_code (Errc::TimedOut);
606 }
607
608 return -1;
609 }
610
611 return 0;
612 }
613
616
619
621 int _handle = -1;
622
624 Protocol _protocol;
625 };
626
633 template <class Protocol>
634 constexpr bool operator< (const BasicSocket<Protocol>& a, const BasicSocket<Protocol>& b) noexcept
635 {
636 return a.handle () < b.handle ();
637 }
638
642 template <class Protocol>
643 class BasicDatagramSocket : public BasicSocket<Protocol>
644 {
645 public:
646 using Ptr = std::unique_ptr<BasicDatagramSocket<Protocol>>;
650 using Endpoint = typename Protocol::Endpoint;
651
659
664 BasicDatagramSocket (Mode mode, int ttl = 60)
665 : BasicSocket<Protocol> (mode)
666 , _ttl (ttl)
667 {
668 }
669
675
682
688 : BasicSocket<Protocol> (std::move (other))
689 , _remote (std::move (other._remote))
690 , _ttl (other._ttl)
691 {
692 other._ttl = 60;
693 }
694
701 {
702 BasicSocket<Protocol>::operator= (std::move (other));
703
704 _remote = std::move (other._remote);
705 _ttl = other._ttl;
706
707 other._ttl = 60;
708
709 return *this;
710 }
711
715 virtual ~BasicDatagramSocket () = default;
716
722 virtual int open (const Protocol& protocol = Protocol ()) noexcept override
723 {
725 if (result == -1)
726 {
727 return -1;
728 }
729
730 int off = 0;
731
732 if ((protocol.protocol () == IPPROTO_UDP) || (protocol.protocol () == IPPROTO_TCP))
733 {
734 if ((protocol.family () == AF_INET6) &&
735 (::setsockopt (this->_handle, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof (off)) == -1))
736 {
737 lastError = std::error_code (errno, std::generic_category ());
738 this->close ();
739 return -1;
740 }
741 }
742
743 if ((protocol.protocol () == IPPROTO_ICMPV6) || (protocol.protocol () == IPPROTO_ICMP))
744 {
745 if ((protocol.family () == AF_INET) &&
746 (::setsockopt (this->_handle, IPPROTO_IP, IP_HDRINCL, &off, sizeof (off)) == -1))
747 {
748 lastError = std::error_code (errno, std::generic_category ());
749 this->close ();
750 return -1;
751 }
752
753 this->setOption (Option::MulticastTtl, this->_ttl);
754 this->setOption (Option::Ttl, this->_ttl);
755 }
756
757 return 0;
758 }
759
765 virtual int bindToDevice (const std::string& device) noexcept
766 {
767 if (this->_state == State::Closed)
768 {
770 return -1;
771 }
772
773 if (this->_state == State::Connected)
774 {
775 lastError = make_error_code (Errc::InUse);
776 return -1;
777 }
778
779 if ((this->_protocol.family () == AF_INET6) || (this->_protocol.family () == AF_INET))
780 {
781 this->setOption (Option::ReuseAddr, 1);
782 }
783
784 int result = setsockopt (this->_handle, SOL_SOCKET, SO_BINDTODEVICE, device.c_str (), device.size ());
785 if (result == -1)
786 {
787 lastError = std::error_code (errno, std::generic_category ());
788 return -1;
789 }
790
791 return 0;
792 }
793
799 virtual int connect (const Endpoint& endpoint)
800 {
801 if ((this->_state != State::Closed) && (this->_state != State::Disconnected))
802 {
803 lastError = make_error_code (Errc::InUse);
804 return -1;
805 }
806
807 if ((this->_state == State::Closed) && (this->open (endpoint.protocol ()) == -1))
808 {
809 return -1;
810 }
811
812 int result = ::connect (this->_handle, endpoint.addr (), endpoint.length ());
813
814 this->_state = State::Connecting;
815 this->_remote = endpoint;
816
817 if (result == -1)
818 {
819 lastError = std::error_code (errno, std::generic_category ());
820 if (lastError != std::errc::operation_in_progress)
821 {
822 this->close ();
823 }
824 return -1;
825 }
826
827 this->_state = State::Connected;
828
829 return 0;
830 }
831
836 virtual int disconnect ()
837 {
838 if (this->_state == State::Connected)
839 {
840 struct sockaddr_storage nullAddr;
841 ::memset (&nullAddr, 0, sizeof (nullAddr));
842
843 nullAddr.ss_family = AF_UNSPEC;
844
845 int result = ::connect (this->_handle, reinterpret_cast<struct sockaddr*> (&nullAddr),
846 sizeof (struct sockaddr_storage));
847 if (result == -1)
848 {
849 if (errno != EAFNOSUPPORT)
850 {
851 lastError = std::error_code (errno, std::generic_category ());
852 return -1;
853 }
854 }
855
856 this->_state = State::Disconnected;
857 this->_remote = {};
858 }
859
860 return 0;
861 }
862
866 virtual void close () noexcept override
867 {
869 this->_remote = {};
870 }
871
878 virtual int read (char* data, unsigned long maxSize) noexcept override
879 {
880 return BasicSocket<Protocol>::read (data, maxSize);
881 }
882
890 virtual int readFrom (char* data, unsigned long maxSize, Endpoint* endpoint = nullptr) noexcept
891 {
892 struct sockaddr_storage sa;
893 socklen_t sa_len = sizeof (struct sockaddr_storage);
894
895 int size = ::recvfrom (this->_handle, data, maxSize, 0, reinterpret_cast<struct sockaddr*> (&sa), &sa_len);
896 if (size < 1)
897 {
898 if (size == -1)
899 {
900 lastError = std::error_code (errno, std::generic_category ());
901 }
902 else
903 {
905 this->_state = State::Disconnected;
906 }
907
908 return -1;
909 }
910
911 if (endpoint != nullptr)
912 {
913 *endpoint = Endpoint (reinterpret_cast<struct sockaddr*> (&sa), sa_len);
914 }
915
916 return size;
917 }
918
925 virtual int write (const char* data, unsigned long maxSize) noexcept override
926 {
927 return BasicSocket<Protocol>::write (data, maxSize);
928 }
929
937 virtual int writeTo (const char* data, unsigned long maxSize, const Endpoint& endpoint) noexcept
938 {
939 if ((this->_state == State::Closed) && (this->open (endpoint.protocol ()) == -1))
940 {
941 return -1;
942 }
943
944 int result = ::sendto (this->_handle, data, maxSize, 0, endpoint.addr (), endpoint.length ());
945 if (result < 0)
946 {
947 lastError = std::error_code (errno, std::generic_category ());
948 return -1;
949 }
950
951 return result;
952 }
953
960 virtual int setOption (Option option, int value) noexcept override
961 {
962 if (this->_state == State::Closed)
963 {
965 return -1;
966 }
967
968 int optlevel, optname;
969
970 switch (option)
971 {
972 case Option::Ttl:
973 if (this->family () == AF_INET6)
974 {
975 optlevel = IPPROTO_IPV6;
976 optname = IPV6_UNICAST_HOPS;
977 }
978 else
979 {
980 optlevel = IPPROTO_IP;
981 optname = IP_TTL;
982 }
983 break;
984
985 case Option::MulticastLoop:
986 if (this->family () == AF_INET6)
987 {
988 optlevel = IPPROTO_IPV6;
989 optname = IPV6_MULTICAST_LOOP;
990 }
991 else
992 {
993 optlevel = IPPROTO_IP;
994 optname = IP_MULTICAST_LOOP;
995 }
996 break;
997
998 case Option::MulticastTtl:
999 if (this->family () == AF_INET6)
1000 {
1001 optlevel = IPPROTO_IPV6;
1002 optname = IPV6_MULTICAST_HOPS;
1003 }
1004 else
1005 {
1006 optlevel = IPPROTO_IP;
1007 optname = IP_MULTICAST_TTL;
1008 }
1009 break;
1010
1011 case Option::PathMtuDiscover:
1012 if (this->family () == AF_INET6)
1013 {
1014 optlevel = IPPROTO_IPV6;
1015 optname = IPV6_MTU_DISCOVER;
1016 }
1017 else
1018 {
1019 optlevel = IPPROTO_IP;
1020 optname = IP_MTU_DISCOVER;
1021 }
1022 break;
1023
1024 case Option::RcvError:
1025 if (this->family () == AF_INET6)
1026 {
1027 optlevel = IPPROTO_IPV6;
1028 optname = IPV6_RECVERR;
1029 }
1030 else
1031 {
1032 optlevel = IPPROTO_IP;
1033 optname = IP_RECVERR;
1034 }
1035 break;
1036
1037 default:
1038 return BasicSocket<Protocol>::setOption (option, value);
1039 }
1040
1041 int result = ::setsockopt (this->_handle, optlevel, optname, &value, sizeof (value));
1042 if (result == -1)
1043 {
1044 lastError = std::error_code (errno, std::generic_category ());
1045 return -1;
1046 }
1047
1048 return 0;
1049 }
1050
1055 const Endpoint& remoteEndpoint () const noexcept
1056 {
1057 return this->_remote;
1058 }
1059
1064 virtual bool connected () noexcept
1065 {
1066 return (this->_state == State::Connected);
1067 }
1068
1073 int mtu () const
1074 {
1075 if (this->_state == State::Closed)
1076 {
1078 return -1;
1079 }
1080
1081 int result = -1, value = -1;
1082 socklen_t valueLen = sizeof (value);
1083
1084 if (this->_protocol.family () == AF_INET6)
1085 {
1086 result = ::getsockopt (this->_handle, IPPROTO_IPV6, IPV6_MTU, &value, &valueLen);
1087 }
1088 else if (this->_protocol.family () == AF_INET)
1089 {
1090 result = ::getsockopt (this->_handle, IPPROTO_IP, IP_MTU, &value, &valueLen);
1091 }
1092 else
1093 {
1095 return -1;
1096 }
1097
1098 if (result == -1)
1099 {
1100 lastError = std::error_code (errno, std::generic_category ());
1101 return -1;
1102 }
1103
1104 return value;
1105 }
1106
1111 int ttl () const noexcept
1112 {
1113 return this->_ttl;
1114 }
1115
1116 protected:
1119
1121 int _ttl = 60;
1122 };
1123
1130 template <class Protocol>
1132 {
1133 return a.handle () < b.handle ();
1134 }
1135
1139 template <class Protocol>
1141 {
1142 public:
1143 using Ptr = std::unique_ptr<BasicStreamSocket<Protocol>>;
1147 using Endpoint = typename Protocol::Endpoint;
1148
1156
1162 : BasicDatagramSocket<Protocol> (mode)
1163 {
1164 }
1165
1170 BasicStreamSocket (const BasicStreamSocket& other) = delete;
1171
1178
1184 : BasicDatagramSocket<Protocol> (std::move (other))
1185 {
1186 }
1187
1194 {
1196
1197 return *this;
1198 }
1199
1203 virtual ~BasicStreamSocket () = default;
1204
1210 virtual bool waitConnected (int timeout = 0)
1211 {
1212 if (this->_state != State::Connected)
1213 {
1214 if (this->_state != State::Connecting)
1215 {
1217 return false;
1218 }
1219
1220 if (!this->waitReadyWrite (timeout))
1221 {
1222 return false;
1223 }
1224
1225 return connected ();
1226 }
1227
1228 return true;
1229 }
1230
1235 virtual int disconnect () override
1236 {
1237 if (this->_state == State::Connected)
1238 {
1239 ::shutdown (this->_handle, SHUT_WR);
1240 this->_state = State::Disconnecting;
1241 }
1242
1243 if (this->_state == State::Disconnecting)
1244 {
1245 char buffer[4096];
1246 // closing before reading can make the client
1247 // not see all of our output.
1248 // we have to do a "lingering close"
1249 for (;;)
1250 {
1251 int result = this->read (buffer, sizeof (buffer));
1252 if (result <= 0)
1253 {
1254 if ((result == -1) && (lastError == Errc::TemporaryError))
1255 {
1256 return -1;
1257 }
1258
1259 break;
1260 }
1261 }
1262
1263 ::shutdown (this->_handle, SHUT_RD);
1264 this->_state = State::Disconnected;
1265 }
1266
1267 this->close ();
1268
1269 return 0;
1270 }
1271
1277 virtual bool waitDisconnected (int timeout = 0)
1278 {
1279 if ((this->_state != State::Disconnected) && (this->_state != State::Closed))
1280 {
1281 if (this->_state != State::Disconnecting)
1282 {
1284 return false;
1285 }
1286
1287 auto start = std::chrono::steady_clock::now ();
1288 int elapsed = 0;
1289
1290 while ((lastError == Errc::TemporaryError) && (elapsed <= timeout))
1291 {
1292 if (!this->waitReadyRead (timeout - elapsed))
1293 {
1294 return false;
1295 }
1296
1297 if (this->disconnect () == 0)
1298 {
1299 return true;
1300 }
1301
1302 if (timeout)
1303 {
1304 elapsed = std::chrono::duration_cast<std::chrono::milliseconds> (
1305 std::chrono::steady_clock::now () - start)
1306 .count ();
1307 }
1308 }
1309
1310 return false;
1311 }
1312
1313 return true;
1314 }
1315
1323 int readExactly (char* data, unsigned long size, int timeout = 0)
1324 {
1325 unsigned long numRead = 0;
1326
1327 while (numRead < size)
1328 {
1329 int result = this->read (data + numRead, size - numRead);
1330 if (result == -1)
1331 {
1332 if (lastError == Errc::TemporaryError)
1333 {
1334 if (this->waitReadyRead (timeout))
1335 continue;
1336 }
1337
1338 return -1;
1339 }
1340
1341 numRead += result;
1342 }
1343
1344 return 0;
1345 }
1346
1354 int readExactly (std::string& data, unsigned long size, int timeout = 0)
1355 {
1356 data.resize (size);
1357 return readExactly (&data[0], size, timeout);
1358 }
1359
1367 int writeExactly (const char* data, unsigned long size, int timeout = 0)
1368 {
1369 unsigned long numWrite = 0;
1370
1371 while (numWrite < size)
1372 {
1373 int result = this->write (data + numWrite, size - numWrite);
1374 if (result == -1)
1375 {
1376 if (lastError == Errc::TemporaryError)
1377 {
1378 if (this->waitReadyWrite (timeout))
1379 continue;
1380 }
1381
1382 return -1;
1383 }
1384
1385 numWrite += result;
1386 }
1387
1388 return 0;
1389 }
1390
1397 virtual int setOption (Option option, int value) noexcept override
1398 {
1399 if (this->_state == State::Closed)
1400 {
1402 return -1;
1403 }
1404
1405 int optlevel, optname;
1406
1407 switch (option)
1408 {
1409 case Option::NoDelay:
1410 optlevel = IPPROTO_TCP;
1411 optname = TCP_NODELAY;
1412 break;
1413
1414 case Option::KeepIdle:
1415 optlevel = IPPROTO_TCP;
1416 optname = TCP_KEEPIDLE;
1417 break;
1418
1419 case Option::KeepIntvl:
1420 optlevel = IPPROTO_TCP;
1421 optname = TCP_KEEPINTVL;
1422 break;
1423
1424 case Option::KeepCount:
1425 optlevel = IPPROTO_TCP;
1426 optname = TCP_KEEPCNT;
1427 break;
1428
1429 default:
1430 return BasicDatagramSocket<Protocol>::setOption (option, value);
1431 }
1432
1433 int result = ::setsockopt (this->_handle, optlevel, optname, &value, sizeof (value));
1434 if (result == -1)
1435 {
1436 lastError = std::error_code (errno, std::generic_category ());
1437 return -1;
1438 }
1439
1440 return 0;
1441 }
1442
1447 virtual bool connecting () const noexcept
1448 {
1449 return (this->_state == State::Connecting);
1450 }
1451
1456 virtual bool connected () noexcept override
1457 {
1458 if (this->_state == State::Connected)
1459 {
1460 return true;
1461 }
1462 else if (this->_state != State::Connecting)
1463 {
1464 return false;
1465 }
1466
1467 int optval;
1468 socklen_t optlen = sizeof (optval);
1469
1470 int result = ::getsockopt (this->_handle, SOL_SOCKET, SO_ERROR, &optval, &optlen);
1471 if ((result == -1) || (optval != 0))
1472 {
1473 return false;
1474 }
1475
1476 this->_state = State::Connected;
1477
1478 return true;
1479 }
1480
1482 friend class BasicStreamAcceptor<Protocol>;
1483 };
1484
1491 template <class Protocol>
1492 constexpr bool operator< (const BasicStreamSocket<Protocol>& a, const BasicStreamSocket<Protocol>& b) noexcept
1493 {
1494 return a.handle () < b.handle ();
1495 }
1496
1500 enum class TlsErrc
1501 {
1504 };
1505
1509 class TlsCategory : public std::error_category
1510 {
1511 public:
1516 virtual const char* name () const noexcept;
1517
1523 virtual std::string message (int code) const;
1524 };
1525
1530 const std::error_category& getTlsCategory ();
1531
1537 std::error_code make_error_code (TlsErrc code);
1538
1544 std::error_condition make_error_condition (TlsErrc code);
1545
1549 template <class Protocol>
1550 class BasicTlsSocket : public BasicStreamSocket<Protocol>
1551 {
1552 public:
1553 using Ptr = std::unique_ptr<BasicTlsSocket<Protocol>>;
1557 using Endpoint = typename Protocol::Endpoint;
1558
1564 {
1565 }
1566
1572 : BasicStreamSocket<Protocol> (mode)
1573 , _tlsContext (SSL_CTX_new (TLS_client_method ()))
1574 {
1575 // enable the OpenSSL bug workaround options.
1576 SSL_CTX_set_options (this->_tlsContext.get (), SSL_OP_ALL);
1577
1578 // disallow compression.
1579 SSL_CTX_set_options (this->_tlsContext.get (), SSL_OP_NO_COMPRESSION);
1580
1581 // disallow usage of SSLv2, SSLv3, TLSv1 and TLSv1.1 which are considered insecure.
1582 SSL_CTX_set_options (this->_tlsContext.get (),
1583 SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
1584
1585 // setup write mode.
1586 SSL_CTX_set_mode (this->_tlsContext.get (),
1587 SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
1588
1589 // automatically renegotiates.
1590 SSL_CTX_set_mode (this->_tlsContext.get (), SSL_MODE_AUTO_RETRY);
1591
1592 // set session cache mode to client by default.
1593 SSL_CTX_set_session_cache_mode (this->_tlsContext.get (), SSL_SESS_CACHE_CLIENT);
1594
1595 // no verification by default.
1596 SSL_CTX_set_verify (this->_tlsContext.get (), SSL_VERIFY_NONE, nullptr);
1597
1598 // set default TLSv1.2 and below cipher suites.
1599 SSL_CTX_set_cipher_list (this->_tlsContext.get (), join::defaultCipher.c_str ());
1600
1601 // set default TLSv1.3 cipher suites.
1602 SSL_CTX_set_ciphersuites (this->_tlsContext.get (), join::defaultCipher_1_3.c_str ());
1603 }
1604
1610 : BasicTlsSocket (Mode::NonBlocking, std::move (tlsContext))
1611 {
1612 }
1613
1620 : BasicStreamSocket<Protocol> (mode)
1621 , _tlsContext (std::move (tlsContext))
1622 {
1623 if (this->_tlsContext == nullptr)
1624 {
1625 throw std::invalid_argument ("OpenSSL context is invalid");
1626 }
1627 }
1628
1633 BasicTlsSocket (const BasicTlsSocket& other) = delete;
1634
1641
1647 : BasicStreamSocket<Protocol> (std::move (other))
1648 , _tlsContext (std::move (other._tlsContext))
1649 , _tlsHandle (std::move (other._tlsHandle))
1650 , _tlsState (other._tlsState)
1651 {
1652 if (this->_tlsHandle)
1653 {
1654 SSL_set_app_data (this->_tlsHandle.get (), this);
1655 }
1656
1657 other._tlsState = TlsState::NonEncrypted;
1658 }
1659
1666 {
1667 BasicStreamSocket<Protocol>::operator= (std::move (other));
1668
1669 this->_tlsContext = std::move (other._tlsContext);
1670 this->_tlsHandle = std::move (other._tlsHandle);
1671 this->_tlsState = other._tlsState;
1672
1673 if (this->_tlsHandle)
1674 {
1675 SSL_set_app_data (this->_tlsHandle.get (), this);
1676 }
1677
1678 other._tlsState = TlsState::NonEncrypted;
1679
1680 return *this;
1681 }
1682
1686 virtual ~BasicTlsSocket () = default;
1687
1693 virtual int connectEncrypted (const Endpoint& endpoint)
1694 {
1695 if (this->connect (endpoint) == -1)
1696 {
1697 return -1;
1698 }
1699
1700 if (this->startEncryption () == -1)
1701 {
1702 if (lastError != Errc::TemporaryError)
1703 {
1704 this->close ();
1705 }
1706 return -1;
1707 }
1708
1709 return 0;
1710 }
1711
1717 {
1718 if (this->encrypted () == false)
1719 {
1720 this->_tlsHandle.reset (SSL_new (this->_tlsContext.get ()));
1721 if (this->_tlsHandle == nullptr)
1722 {
1723 lastError = make_error_code (Errc::OutOfMemory);
1724 return -1;
1725 }
1726
1727 if (SSL_set_fd (this->_tlsHandle.get (), this->_handle) != 1)
1728 {
1729 lastError = make_error_code (Errc::InvalidParam);
1730 this->_tlsHandle.reset ();
1731 return -1;
1732 }
1733
1734 if (SSL_is_server (this->_tlsHandle.get ()) == 0)
1735 {
1736 if (!this->_remote.hostname ().empty () &&
1737 (SSL_set_tlsext_host_name (this->_tlsHandle.get (), this->_remote.hostname ().c_str ()) != 1))
1738 {
1739 lastError = make_error_code (Errc::InvalidParam);
1740 this->_tlsHandle.reset ();
1741 return -1;
1742 }
1743
1744 SSL_set_connect_state (this->_tlsHandle.get ());
1745 }
1746 else
1747 {
1748 SSL_set_accept_state (this->_tlsHandle.get ());
1749 }
1750
1751 SSL_set_app_data (this->_tlsHandle.get (), this);
1752
1753#ifdef DEBUG
1754 SSL_set_info_callback (this->_tlsHandle.get (), infoWrapper);
1755#endif
1756
1757 return startHandshake ();
1758 }
1759
1760 return 0;
1761 }
1762
1768 virtual bool waitEncrypted (int timeout = 0)
1769 {
1770 if (this->encrypted () == false)
1771 {
1772 if (this->_state == State::Connecting)
1773 {
1774 if (!this->waitConnected (timeout))
1775 {
1776 return false;
1777 }
1778
1779 if (this->startEncryption () == 0)
1780 {
1781 return true;
1782 }
1783 }
1784
1785 while ((lastError == Errc::TemporaryError) &&
1786 (SSL_want_read (this->_tlsHandle.get ()) || SSL_want_write (this->_tlsHandle.get ())))
1787 {
1788 if (this->wait (SSL_want_read (this->_tlsHandle.get ()), SSL_want_write (this->_tlsHandle.get ()),
1789 timeout) == -1)
1790 {
1791 return false;
1792 }
1793
1794 if (this->startHandshake () == 0)
1795 {
1796 return true;
1797 }
1798 }
1799
1800 return false;
1801 }
1802
1803 return true;
1804 }
1805
1810 virtual int disconnect () override
1811 {
1812 if (this->encrypted ())
1813 {
1814 // check if the close_notify alert was already sent.
1815 if ((SSL_get_shutdown (this->_tlsHandle.get ()) & SSL_SENT_SHUTDOWN) == false)
1816 {
1817 // send the close_notify alert to the peer.
1818 int result = SSL_shutdown (this->_tlsHandle.get ());
1819 if (result < 0)
1820 {
1821 // shutdown was not successful.
1822 switch (SSL_get_error (this->_tlsHandle.get (), result))
1823 {
1824 case SSL_ERROR_WANT_READ:
1825 case SSL_ERROR_WANT_WRITE:
1826 // SSL_shutdown want read or want write.
1828 break;
1829 case SSL_ERROR_SYSCALL:
1830 // an error occurred at the socket level.
1831 switch (errno)
1832 {
1833 case 0:
1834 case ECONNRESET:
1835 case EPIPE:
1838 this->_state = State::Disconnected;
1839 break;
1840 default:
1841 lastError = std::error_code (errno, std::generic_category ());
1842 break;
1843 }
1844 break;
1845 default:
1846 // SSL protocol error.
1847#ifdef DEBUG
1848 std::cout << ERR_reason_error_string (ERR_get_error ()) << std::endl;
1849#endif
1851 break;
1852 }
1853
1854 return -1;
1855 }
1856 else if (result == 1)
1857 {
1858 // shutdown was successfully completed.
1859 // close_notify alert was sent and the peer's close_notify alert was received.
1861 }
1862 else
1863 {
1864 // shutdown is not yet finished.
1865 // the close_notify was sent but the peer did not send it back yet.
1866 // SSL_read must be called to do a bidirectional shutdown.
1867 }
1868 }
1869 }
1870
1872 }
1873
1877 virtual void close () noexcept override
1878 {
1881 this->_tlsHandle.reset ();
1882 }
1883
1889 virtual bool waitReadyRead (int timeout = 0) const noexcept override
1890 {
1891 if (this->encrypted () &&
1892 (SSL_want_read (this->_tlsHandle.get ()) || SSL_want_write (this->_tlsHandle.get ())))
1893 {
1894 return (this->wait (SSL_want_read (this->_tlsHandle.get ()), SSL_want_write (this->_tlsHandle.get ()),
1895 timeout) == 0);
1896 }
1897
1899 }
1900
1905 virtual int canRead () const noexcept override
1906 {
1907 if (this->encrypted ())
1908 {
1909 return SSL_pending (this->_tlsHandle.get ());
1910 }
1911
1913 }
1914
1921 virtual int read (char* data, unsigned long maxSize) noexcept override
1922 {
1923 if (this->encrypted ())
1924 {
1925 // read data.
1926 int result = SSL_read (this->_tlsHandle.get (), data, int (maxSize));
1927 if (result < 1)
1928 {
1929 switch (SSL_get_error (this->_tlsHandle.get (), result))
1930 {
1931 case SSL_ERROR_WANT_READ:
1932 case SSL_ERROR_WANT_WRITE:
1933 case SSL_ERROR_WANT_X509_LOOKUP:
1934 // SSL_read want read, want write or want lookup.
1936 break;
1937 case SSL_ERROR_ZERO_RETURN:
1938 // a close notify alert was received.
1939 // we have to answer by sending a close notify alert too.
1941 if (SSL_get_shutdown (this->_tlsHandle.get ()) & SSL_SENT_SHUTDOWN)
1942 {
1944 }
1945 break;
1946 case SSL_ERROR_SYSCALL:
1947 // an error occurred at the socket level.
1948 switch (errno)
1949 {
1950 case 0:
1951 case ECONNRESET:
1952 case EPIPE:
1955 this->_state = State::Disconnected;
1956 break;
1957 default:
1958 lastError = std::error_code (errno, std::generic_category ());
1959 break;
1960 }
1961 break;
1962 default:
1963 // SSL protocol error.
1964#ifdef DEBUG
1965 std::cout << ERR_reason_error_string (ERR_get_error ()) << std::endl;
1966#endif
1968 break;
1969 }
1970
1971 return -1;
1972 }
1973
1974 return result;
1975 }
1976
1977 return BasicStreamSocket<Protocol>::read (data, maxSize);
1978 }
1979
1985 virtual bool waitReadyWrite (int timeout = 0) const noexcept override
1986 {
1987 if (this->encrypted () &&
1988 (SSL_want_read (this->_tlsHandle.get ()) || SSL_want_write (this->_tlsHandle.get ())))
1989 {
1990 return (this->wait (SSL_want_read (this->_tlsHandle.get ()), SSL_want_write (this->_tlsHandle.get ()),
1991 timeout) == 0);
1992 }
1993
1995 }
1996
2003 virtual int write (const char* data, unsigned long maxSize) noexcept override
2004 {
2005 if (this->encrypted ())
2006 {
2007 // write data.
2008 int result = SSL_write (this->_tlsHandle.get (), data, int (maxSize));
2009 if (result < 1)
2010 {
2011 switch (SSL_get_error (this->_tlsHandle.get (), result))
2012 {
2013 case SSL_ERROR_WANT_READ:
2014 case SSL_ERROR_WANT_WRITE:
2015 case SSL_ERROR_WANT_X509_LOOKUP:
2016 // SSL_write want read, want write or want lookup.
2018 break;
2019 case SSL_ERROR_ZERO_RETURN:
2020 // a close notify alert was received.
2021 // we have to answer by sending a close notify alert too.
2023 if (SSL_get_shutdown (this->_tlsHandle.get ()) & SSL_SENT_SHUTDOWN)
2024 {
2026 }
2027 break;
2028 case SSL_ERROR_SYSCALL:
2029 // an error occurred at the socket level.
2030 switch (errno)
2031 {
2032 case 0:
2033 case ECONNRESET:
2034 case EPIPE:
2037 this->_state = State::Disconnected;
2038 break;
2039 default:
2040 lastError = std::error_code (errno, std::generic_category ());
2041 break;
2042 }
2043 break;
2044 default:
2045 // SSL protocol error.
2046#ifdef DEBUG
2047 std::cout << ERR_reason_error_string (ERR_get_error ()) << std::endl;
2048#endif
2050 break;
2051 }
2052
2053 return -1;
2054 }
2055
2056 return result;
2057 }
2058
2059 return BasicStreamSocket<Protocol>::write (data, maxSize);
2060 }
2061
2066 virtual bool encrypted () const noexcept override
2067 {
2068 return (this->_tlsState == TlsState::Encrypted);
2069 }
2070
2077 int setCertificate (const std::string& cert, const std::string& key = "")
2078 {
2079 if (((this->_tlsHandle)
2080 ? SSL_use_certificate_file (this->_tlsHandle.get (), cert.c_str (), SSL_FILETYPE_PEM)
2081 : SSL_CTX_use_certificate_file (this->_tlsContext.get (), cert.c_str (), SSL_FILETYPE_PEM)) == 0)
2082 {
2083 lastError = make_error_code (Errc::InvalidParam);
2084 return -1;
2085 }
2086
2087 if (key.size ())
2088 {
2089 if (((this->_tlsHandle)
2090 ? SSL_use_PrivateKey_file (this->_tlsHandle.get (), key.c_str (), SSL_FILETYPE_PEM)
2091 : SSL_CTX_use_PrivateKey_file (this->_tlsContext.get (), key.c_str (), SSL_FILETYPE_PEM)) == 0)
2092 {
2093 lastError = make_error_code (Errc::InvalidParam);
2094 return -1;
2095 }
2096 }
2097
2098 if (((this->_tlsHandle) ? SSL_check_private_key (this->_tlsHandle.get ())
2099 : SSL_CTX_check_private_key (this->_tlsContext.get ())) == 0)
2100 {
2101 lastError = make_error_code (Errc::InvalidParam);
2102 return -1;
2103 }
2104
2105 return 0;
2106 }
2107
2113 int setCaPath (const std::string& caPath)
2114 {
2115 struct stat st;
2116 if (stat (caPath.c_str (), &st) != 0 || !S_ISDIR (st.st_mode) ||
2117 SSL_CTX_load_verify_locations (this->_tlsContext.get (), nullptr, caPath.c_str ()) == 0)
2118 {
2119 lastError = make_error_code (Errc::InvalidParam);
2120 return -1;
2121 }
2122
2123 return 0;
2124 }
2125
2131 int setCaFile (const std::string& caFile)
2132 {
2133 struct stat st;
2134 if (stat (caFile.c_str (), &st) != 0 || !S_ISREG (st.st_mode) ||
2135 SSL_CTX_load_verify_locations (this->_tlsContext.get (), caFile.c_str (), nullptr) == 0)
2136 {
2137 lastError = make_error_code (Errc::InvalidParam);
2138 return -1;
2139 }
2140
2141 return 0;
2142 }
2143
2149 void setVerify (bool verify, int depth = -1) noexcept
2150 {
2151 if (verify == true)
2152 {
2153 SSL_CTX_set_verify (this->_tlsContext.get (), SSL_VERIFY_PEER, verifyWrapper);
2154 SSL_CTX_set_verify_depth (this->_tlsContext.get (), depth);
2155 }
2156 else
2157 {
2158 SSL_CTX_set_verify (this->_tlsContext.get (), SSL_VERIFY_NONE, nullptr);
2159 }
2160 }
2161
2167 int setCipher (const std::string& cipher)
2168 {
2169 if (((this->_tlsHandle) ? SSL_set_cipher_list (this->_tlsHandle.get (), cipher.c_str ())
2170 : SSL_CTX_set_cipher_list (this->_tlsContext.get (), cipher.c_str ())) == 0)
2171 {
2172 lastError = make_error_code (Errc::InvalidParam);
2173 return -1;
2174 }
2175
2176 return 0;
2177 }
2178
2184 int setCipher_1_3 (const std::string& cipher)
2185 {
2186 if (((this->_tlsHandle) ? SSL_set_ciphersuites (this->_tlsHandle.get (), cipher.c_str ())
2187 : SSL_CTX_set_ciphersuites (this->_tlsContext.get (), cipher.c_str ())) == 0)
2188 {
2189 lastError = make_error_code (Errc::InvalidParam);
2190 return -1;
2191 }
2192
2193 return 0;
2194 }
2195
2201 int setAlpnProtocols (const std::vector<std::string>& protocols)
2202 {
2203 std::vector<uint8_t> wire;
2204 wire.reserve (256);
2205
2206 for (auto const& proto : protocols)
2207 {
2208 wire.push_back (static_cast<uint8_t> (proto.size ()));
2209 wire.insert (wire.end (), proto.begin (), proto.end ());
2210 }
2211
2212 if (SSL_CTX_set_alpn_protos (this->_tlsContext.get (), wire.data (),
2213 static_cast<unsigned int> (wire.size ())) != 0)
2214 {
2215 lastError = make_error_code (Errc::InvalidParam);
2216 return -1;
2217 }
2218
2219 return 0;
2220 }
2221
2222 protected:
2231
2237 {
2238 // start the SSL handshake.
2239 int result = SSL_do_handshake (this->_tlsHandle.get ());
2240 if (result < 1)
2241 {
2242 switch (SSL_get_error (this->_tlsHandle.get (), result))
2243 {
2244 case SSL_ERROR_WANT_READ:
2245 case SSL_ERROR_WANT_WRITE:
2246 case SSL_ERROR_WANT_X509_LOOKUP:
2247 // SSL_do_handshake want read or want write.
2249 break;
2250 case SSL_ERROR_ZERO_RETURN:
2251 // a close notify alert was received.
2252 // we have to answer by sending a close notify alert too.
2254 break;
2255 case SSL_ERROR_SYSCALL:
2256 // an error occurred at the socket level.
2257 switch (errno)
2258 {
2259 case 0:
2260 case ECONNRESET:
2261 case EPIPE:
2263 this->_state = State::Disconnected;
2264 break;
2265 default:
2266 lastError = std::error_code (errno, std::generic_category ());
2267 break;
2268 }
2269 break;
2270 default:
2271 // SSL protocol error.
2272#ifdef DEBUG
2273 std::cout << ERR_reason_error_string (ERR_get_error ()) << std::endl;
2274#endif
2276 break;
2277 }
2278
2279 return -1;
2280 }
2281
2283
2284 return 0;
2285 }
2286
2293 static void infoWrapper (const SSL* ssl, int where, int ret)
2294 {
2295 assert (ssl);
2296 static_cast<BasicTlsSocket<Protocol>*> (SSL_get_app_data (ssl))->infoCallback (where, ret);
2297 }
2298
2304 void infoCallback (int where, int ret) const
2305 {
2306 if (where & SSL_CB_ALERT)
2307 {
2308 std::cout << "SSL/TLS Alert ";
2309 (where & SSL_CB_READ) ? std::cout << "[read] " : std::cout << "[write] ";
2310 std::cout << SSL_alert_type_string_long (ret) << ":";
2311 std::cout << SSL_alert_desc_string_long (ret);
2312 std::cout << std::endl;
2313 }
2314 else if (where & SSL_CB_LOOP)
2315 {
2316 std::cout << "SSL/TLS State ";
2317 (SSL_in_connect_init (this->_tlsHandle.get ())) ? std::cout << "[connect] "
2318 : (SSL_in_accept_init (this->_tlsHandle.get ())) ? std::cout << "[accept] "
2319 : std::cout << "[undefined] ";
2320 std::cout << SSL_state_string_long (this->_tlsHandle.get ());
2321 std::cout << std::endl;
2322 }
2323 else if (where & SSL_CB_HANDSHAKE_START)
2324 {
2325 std::cout << "SSL/TLS Handshake [Start] " << SSL_state_string_long (this->_tlsHandle.get ())
2326 << std::endl;
2327 }
2328 else if (where & SSL_CB_HANDSHAKE_DONE)
2329 {
2330 std::cout << "SSL/TLS Handshake [Done] " << SSL_state_string_long (this->_tlsHandle.get ())
2331 << std::endl;
2332 std::cout << SSL_CTX_sess_number (this->_tlsContext.get ()) << " items in the session cache"
2333 << std::endl;
2334 std::cout << SSL_CTX_sess_connect (this->_tlsContext.get ()) << " client connects" << std::endl;
2335 std::cout << SSL_CTX_sess_connect_good (this->_tlsContext.get ()) << " client connects that finished"
2336 << std::endl;
2337 std::cout << SSL_CTX_sess_connect_renegotiate (this->_tlsContext.get ())
2338 << " client renegotiations requested" << std::endl;
2339 std::cout << SSL_CTX_sess_accept (this->_tlsContext.get ()) << " server connects" << std::endl;
2340 std::cout << SSL_CTX_sess_accept_good (this->_tlsContext.get ()) << " server connects that finished"
2341 << std::endl;
2342 std::cout << SSL_CTX_sess_accept_renegotiate (this->_tlsContext.get ())
2343 << " server renegotiations requested" << std::endl;
2344 std::cout << SSL_CTX_sess_hits (this->_tlsContext.get ()) << " session cache hits" << std::endl;
2345 std::cout << SSL_CTX_sess_cb_hits (this->_tlsContext.get ()) << " external session cache hits"
2346 << std::endl;
2347 std::cout << SSL_CTX_sess_misses (this->_tlsContext.get ()) << " session cache misses" << std::endl;
2348 std::cout << SSL_CTX_sess_timeouts (this->_tlsContext.get ()) << " session cache timeouts" << std::endl;
2349 std::cout << "negotiated " << SSL_get_cipher (this->_tlsHandle.get ()) << " cipher suite" << std::endl;
2350 }
2351 }
2352
2359 static int verifyWrapper (int preverified, X509_STORE_CTX* context)
2360 {
2361 SSL* ssl = static_cast<SSL*> (X509_STORE_CTX_get_ex_data (context, SSL_get_ex_data_X509_STORE_CTX_idx ()));
2362
2363 assert (ssl);
2364 return static_cast<BasicTlsSocket<Protocol>*> (SSL_get_app_data (ssl))
2365 ->verifyCallback (preverified, context);
2366 }
2367
2374 int verifyCallback (int preverified, X509_STORE_CTX* context) const
2375 {
2376 int maxDepth = SSL_get_verify_depth (this->_tlsHandle.get ());
2377 int dpth = X509_STORE_CTX_get_error_depth (context);
2378
2379#ifdef DEBUG
2380 std::cout << "verification started at depth=" << dpth << std::endl;
2381#endif
2382
2383 // catch a too long certificate chain.
2384 if ((maxDepth >= 0) && (dpth > maxDepth))
2385 {
2386 preverified = 0;
2387 X509_STORE_CTX_set_error (context, X509_V_ERR_CERT_CHAIN_TOO_LONG);
2388 }
2389
2390 if (!preverified)
2391 {
2392#ifdef DEBUG
2393 std::cout << "verification failed at depth=" << dpth << " - "
2394 << X509_verify_cert_error_string (X509_STORE_CTX_get_error (context)) << std::endl;
2395#endif
2396 return 0;
2397 }
2398
2399 // check the certificate host name.
2400 if (!verifyCert (context))
2401 {
2402#ifdef DEBUG
2403 std::cout << "rejected by CERT at depth=" << dpth << std::endl;
2404#endif
2405 return 0;
2406 }
2407
2408 // check the revocation list.
2409 /*if (!verifyCrl (context))
2410 {
2411 #ifdef DEBUG
2412 std::cout << "rejected by CRL at depth=" << dpth << std::endl;
2413 #endif
2414 return 0;
2415 }*/
2416
2417 // check ocsp.
2418 /*if (!verifyOcsp (context))
2419 {
2420 #ifdef DEBUG
2421 std::cout << "rejected by OCSP at depth=" << dpth << std::endl;
2422 #endif
2423 return 0;
2424 }*/
2425
2426#ifdef DEBUG
2427 std::cout << "certificate accepted at depth=" << dpth << std::endl;
2428#endif
2429
2430 return 1;
2431 }
2432
2438 int verifyCert (X509_STORE_CTX* context) const
2439 {
2440 int depth = X509_STORE_CTX_get_error_depth (context);
2441 X509* cert = X509_STORE_CTX_get_current_cert (context);
2442
2443 char buf[256];
2444 X509_NAME_oneline (X509_get_subject_name (cert), buf, sizeof (buf));
2445#ifdef DEBUG
2446 std::cout << "subject=" << buf << std::endl;
2447#endif
2448
2449 // check the certificate host name
2450 if (depth == 0)
2451 {
2452 // confirm a match between the hostname and the hostnames listed in the certificate.
2453 if (!checkHostName (cert))
2454 {
2455#ifdef DEBUG
2456 std::cout << "no match for hostname in the certificate" << std::endl;
2457#endif
2458 return 0;
2459 }
2460 }
2461
2462 return 1;
2463 }
2464
2470 bool checkHostName (X509* certificate) const
2471 {
2472 bool match = false;
2473
2474 // get alternative names.
2475 join::StackOfGeneralNamePtr altnames (reinterpret_cast<STACK_OF (GENERAL_NAME)*> (
2476 X509_get_ext_d2i (certificate, NID_subject_alt_name, 0, 0)));
2477 if (altnames)
2478 {
2479 for (int i = 0; (i < sk_GENERAL_NAME_num (altnames.get ())) && !match; ++i)
2480 {
2481 // get a handle to alternative name.
2482 GENERAL_NAME* current_name = sk_GENERAL_NAME_value (altnames.get (), i);
2483
2484 if (current_name->type == GEN_DNS)
2485 {
2486 // get data and length.
2487 const char* host = reinterpret_cast<const char*> (ASN1_STRING_get0_data (current_name->d.ia5));
2488 size_t len = size_t (ASN1_STRING_length (current_name->d.ia5));
2489 std::string pattern (host, host + len), serverName (this->_remote.hostname ());
2490
2491 // strip off trailing dots.
2492 if (pattern.back () == '.')
2493 {
2494 pattern.pop_back ();
2495 }
2496
2497 if (serverName.back () == '.')
2498 {
2499 serverName.pop_back ();
2500 }
2501
2502 // compare to pattern.
2503 if (fnmatch (pattern.c_str (), serverName.c_str (), 0) == 0)
2504 {
2505 // an alternative name matched the server hostname.
2506 match = true;
2507 }
2508 }
2509 }
2510 }
2511
2512 return match;
2513 }
2514
2520 /*int verifyCrl ([[maybe_unused]]X509_STORE_CTX *context) const
2521 {
2522 return 1;
2523 }*/
2524
2530 /*int verifyOcsp ([[maybe_unused]]X509_STORE_CTX *context) const
2531 {
2532 return 1;
2533 }*/
2534
2537
2540
2543
2545 friend class BasicTlsAcceptor<Protocol>;
2546 };
2547
2554 template <class Protocol>
2555 constexpr bool operator< (const BasicTlsSocket<Protocol>& a, const BasicTlsSocket<Protocol>& b) noexcept
2556 {
2557 return a.handle () < b.handle ();
2558 }
2559}
2560
2561namespace std
2562{
2564 template <>
2565 struct is_error_condition_enum<join::TlsErrc> : public true_type
2566 {
2567 };
2568}
2569
2570#endif
basic datagram socket class.
Definition socket.hpp:644
virtual ~BasicDatagramSocket()=default
Destroy the instance.
BasicDatagramSocket(const BasicDatagramSocket &other)=delete
Copy constructor.
typename BasicSocket< Protocol >::Option Option
Definition socket.hpp:648
BasicDatagramSocket(Mode mode, int ttl=60)
Create instance specifying the mode.
Definition socket.hpp:664
const Endpoint & remoteEndpoint() const noexcept
determine the remote endpoint associated with this socket.
Definition socket.hpp:1055
virtual int connect(const Endpoint &endpoint)
make a connection to the given endpoint.
Definition socket.hpp:799
virtual int bindToDevice(const std::string &device) noexcept
assigns the specified device to the socket.
Definition socket.hpp:765
std::unique_ptr< BasicDatagramSocket< Protocol > > Ptr
Definition socket.hpp:646
virtual bool connected() noexcept
check if the socket is connected.
Definition socket.hpp:1064
virtual int setOption(Option option, int value) noexcept override
set the given option to the given value.
Definition socket.hpp:960
Endpoint _remote
remote endpoint.
Definition socket.hpp:1118
virtual int read(char *data, unsigned long maxSize) noexcept override
read data.
Definition socket.hpp:878
int _ttl
packet time to live.
Definition socket.hpp:1121
virtual int write(const char *data, unsigned long maxSize) noexcept override
write data.
Definition socket.hpp:925
virtual void close() noexcept override
close the socket handle.
Definition socket.hpp:866
typename Protocol::Endpoint Endpoint
Definition socket.hpp:650
BasicDatagramSocket(int ttl=60)
Default constructor.
Definition socket.hpp:655
typename BasicSocket< Protocol >::State State
Definition socket.hpp:649
int mtu() const
get socket mtu.
Definition socket.hpp:1073
BasicDatagramSocket & operator=(const BasicDatagramSocket &other)=delete
Copy assignment operator.
virtual int readFrom(char *data, unsigned long maxSize, Endpoint *endpoint=nullptr) noexcept
read data on the socket.
Definition socket.hpp:890
virtual int writeTo(const char *data, unsigned long maxSize, const Endpoint &endpoint) noexcept
write data on the socket.
Definition socket.hpp:937
virtual int disconnect()
shutdown the connection.
Definition socket.hpp:836
typename BasicSocket< Protocol >::Mode Mode
Definition socket.hpp:647
virtual int open(const Protocol &protocol=Protocol()) noexcept override
open socket using the given protocol.
Definition socket.hpp:722
BasicDatagramSocket(BasicDatagramSocket &&other)
Move constructor.
Definition socket.hpp:687
int ttl() const noexcept
returns the Time-To-Live value.
Definition socket.hpp:1111
basic socket class.
Definition socket.hpp:59
bool opened() const noexcept
check if the socket is opened.
Definition socket.hpp:488
BasicSocket & operator=(const BasicSocket &other)=delete
copy assignment operator.
virtual int open(const Protocol &protocol=Protocol()) noexcept
open socket using the given protocol.
Definition socket.hpp:193
static uint16_t checksum(const uint16_t *data, size_t len, uint16_t current=0)
get standard 1s complement checksum.
Definition socket.hpp:545
void setMode(Mode mode) noexcept
set the socket to the non-blocking or blocking mode.
Definition socket.hpp:379
State
socket states.
Definition socket.hpp:101
@ Disconnected
Definition socket.hpp:105
@ Connecting
Definition socket.hpp:102
@ Disconnecting
Definition socket.hpp:104
@ Closed
Definition socket.hpp:106
@ Connected
Definition socket.hpp:103
Protocol _protocol
protocol.
Definition socket.hpp:624
virtual int setOption(Option option, int value) noexcept
set the given option to the given value.
Definition socket.hpp:406
Mode _mode
socket mode.
Definition socket.hpp:618
virtual void close() noexcept
close the socket.
Definition socket.hpp:222
int family() const noexcept
get socket address family.
Definition socket.hpp:506
Mode
socket modes.
Definition socket.hpp:68
@ Blocking
Definition socket.hpp:69
@ NonBlocking
Definition socket.hpp:70
virtual bool waitReadyRead(int timeout=0) const noexcept
block until new data is available for reading.
Definition socket.hpp:293
std::unique_ptr< BasicSocket< Protocol > > Ptr
Definition socket.hpp:61
virtual ~BasicSocket()
destroy the socket instance.
Definition socket.hpp:180
virtual int bind(const Endpoint &endpoint) noexcept
assigns the specified endpoint to the socket.
Definition socket.hpp:237
BasicSocket()
default constructor.
Definition socket.hpp:112
int type() const noexcept
get the protocol communication semantic.
Definition socket.hpp:515
State _state
socket state.
Definition socket.hpp:615
typename Protocol::Endpoint Endpoint
Definition socket.hpp:62
virtual bool encrypted() const noexcept
check if the socket is secure.
Definition socket.hpp:497
Option
socket options.
Definition socket.hpp:77
@ MulticastTtl
Definition socket.hpp:91
@ SndBuffer
Definition socket.hpp:83
@ Ttl
Definition socket.hpp:89
@ Broadcast
Definition socket.hpp:88
@ RcvError
Definition socket.hpp:93
@ ReusePort
Definition socket.hpp:87
@ MulticastLoop
Definition socket.hpp:90
@ KeepAlive
Definition socket.hpp:79
@ ReuseAddr
Definition socket.hpp:86
@ KeepCount
Definition socket.hpp:82
@ KeepIntvl
Definition socket.hpp:81
@ AuxData
Definition socket.hpp:94
@ PathMtuDiscover
Definition socket.hpp:92
@ NoDelay
Definition socket.hpp:78
@ TimeStamp
Definition socket.hpp:85
@ KeepIdle
Definition socket.hpp:80
@ RcvBuffer
Definition socket.hpp:84
Endpoint localEndpoint() const noexcept
determine the local endpoint associated with this socket.
Definition socket.hpp:471
virtual bool waitReadyWrite(int timeout=0) const noexcept
block until at least one byte can be written.
Definition socket.hpp:340
BasicSocket(BasicSocket &&other)
move constructor.
Definition socket.hpp:143
int handle() const noexcept
get socket native handle.
Definition socket.hpp:533
virtual int read(char *data, unsigned long maxSize) noexcept
read data.
Definition socket.hpp:304
virtual int write(const char *data, unsigned long maxSize) noexcept
write data.
Definition socket.hpp:351
BasicSocket(Mode mode)
create socket instance specifying the mode.
Definition socket.hpp:121
int wait(bool wantRead, bool wantWrite, int timeout) const noexcept
wait for the socket handle to become ready.
Definition socket.hpp:578
int protocol() const noexcept
get socket protocol.
Definition socket.hpp:524
int _handle
socket handle.
Definition socket.hpp:621
virtual int canRead() const noexcept
get the number of readable bytes.
Definition socket.hpp:274
BasicSocket(const BasicSocket &other)=delete
copy constructor.
basic stream acceptor class.
Definition protocol.hpp:52
basic stream socket class.
Definition socket.hpp:1141
virtual ~BasicStreamSocket()=default
destroy the instance.
virtual int setOption(Option option, int value) noexcept override
set the given option to the given value.
Definition socket.hpp:1397
virtual bool connecting() const noexcept
check if the socket is connecting.
Definition socket.hpp:1447
BasicStreamSocket(const BasicStreamSocket &other)=delete
copy constructor.
BasicStreamSocket(BasicStreamSocket &&other)
move constructor.
Definition socket.hpp:1183
virtual bool waitConnected(int timeout=0)
block until connected.
Definition socket.hpp:1210
int readExactly(std::string &data, unsigned long size, int timeout=0)
read data until size is reached or an error occurred.
Definition socket.hpp:1354
typename BasicDatagramSocket< Protocol >::Mode Mode
Definition socket.hpp:1144
int writeExactly(const char *data, unsigned long size, int timeout=0)
write data until size is reached or an error occurred.
Definition socket.hpp:1367
BasicStreamSocket(Mode mode)
create instance specifying the mode.
Definition socket.hpp:1161
typename Protocol::Endpoint Endpoint
Definition socket.hpp:1147
std::unique_ptr< BasicStreamSocket< Protocol > > Ptr
Definition socket.hpp:1143
BasicStreamSocket & operator=(const BasicStreamSocket &other)=delete
copy assignment operator.
typename BasicDatagramSocket< Protocol >::Option Option
Definition socket.hpp:1145
virtual bool connected() noexcept override
check if the socket is connected.
Definition socket.hpp:1456
virtual bool waitDisconnected(int timeout=0)
wait until the connection as been shut down.
Definition socket.hpp:1277
virtual int disconnect() override
shutdown the connection.
Definition socket.hpp:1235
BasicStreamSocket()
default constructor.
Definition socket.hpp:1152
int readExactly(char *data, unsigned long size, int timeout=0)
read data until size is reached or an error occurred.
Definition socket.hpp:1323
typename BasicDatagramSocket< Protocol >::State State
Definition socket.hpp:1146
basic TLS acceptor class.
Definition protocol.hpp:54
basic TLS socket class.
Definition socket.hpp:1551
BasicTlsSocket()
default constructor.
Definition socket.hpp:1562
BasicTlsSocket & operator=(const BasicTlsSocket &other)=delete
copy assignment operator.
int setCaFile(const std::string &caFile)
set the location of the trusted CA certificate file.
Definition socket.hpp:2131
virtual int canRead() const noexcept override
get the number of readable bytes.
Definition socket.hpp:1905
int startEncryption()
start socket encryption (perform TLS handshake).
Definition socket.hpp:1716
virtual bool encrypted() const noexcept override
check if the socket is secure.
Definition socket.hpp:2066
BasicTlsSocket(Mode mode, join::SslCtxPtr tlsContext)
Create socket instance specifying the socket mode and TLS context.
Definition socket.hpp:1619
join::SslCtxPtr _tlsContext
verify certificate revocation using CRL.
Definition socket.hpp:2536
virtual int read(char *data, unsigned long maxSize) noexcept override
read data on the socket.
Definition socket.hpp:1921
join::SslPtr _tlsHandle
TLS handle.
Definition socket.hpp:2539
virtual bool waitEncrypted(int timeout=0)
wait until TLS handshake is performed or timeout occur (non blocking socket).
Definition socket.hpp:1768
int verifyCallback(int preverified, X509_STORE_CTX *context) const
trusted CA certificates verification callback.
Definition socket.hpp:2374
virtual bool waitReadyRead(int timeout=0) const noexcept override
block until new data is available for reading.
Definition socket.hpp:1889
int verifyCert(X509_STORE_CTX *context) const
verify certificate validity.
Definition socket.hpp:2438
void infoCallback(int where, int ret) const
state information callback.
Definition socket.hpp:2304
int setAlpnProtocols(const std::vector< std::string > &protocols)
set the ALPN protocols list.
Definition socket.hpp:2201
std::unique_ptr< BasicTlsSocket< Protocol > > Ptr
Definition socket.hpp:1553
BasicTlsSocket(Mode mode)
create instance specifying the mode.
Definition socket.hpp:1571
TlsState
TLS state.
Definition socket.hpp:2227
@ Encrypted
Definition socket.hpp:2228
@ NonEncrypted
Definition socket.hpp:2229
TlsState _tlsState
TLS state.
Definition socket.hpp:2542
bool checkHostName(X509 *certificate) const
confirm a match between the hostname contacted and the hostnames listed in the certificate.
Definition socket.hpp:2470
virtual int disconnect() override
shutdown the connection.
Definition socket.hpp:1810
int setCertificate(const std::string &cert, const std::string &key="")
set the certificate and the private key.
Definition socket.hpp:2077
void setVerify(bool verify, int depth=-1) noexcept
Enable/Disable the verification of the peer certificate.
Definition socket.hpp:2149
virtual bool waitReadyWrite(int timeout=0) const noexcept override
block until until at least one byte can be written on the socket.
Definition socket.hpp:1985
int setCipher(const std::string &cipher)
set the cipher list (TLSv1.2 and below).
Definition socket.hpp:2167
typename BasicStreamSocket< Protocol >::State State
Definition socket.hpp:1556
typename Protocol::Endpoint Endpoint
Definition socket.hpp:1557
virtual void close() noexcept override
close the socket handle.
Definition socket.hpp:1877
int setCipher_1_3(const std::string &cipher)
set the cipher list (TLSv1.3).
Definition socket.hpp:2184
virtual ~BasicTlsSocket()=default
destroy the instance.
int setCaPath(const std::string &caPath)
set the location of the trusted CA certificates.
Definition socket.hpp:2113
BasicTlsSocket(const BasicTlsSocket &other)=delete
copy constructor.
int startHandshake()
Start SSL handshake.
Definition socket.hpp:2236
virtual int connectEncrypted(const Endpoint &endpoint)
make an encrypted connection to the given endpoint.
Definition socket.hpp:1693
typename BasicStreamSocket< Protocol >::Option Option
Definition socket.hpp:1555
static void infoWrapper(const SSL *ssl, int where, int ret)
c style callback wrapper for the state information callback.
Definition socket.hpp:2293
virtual int write(const char *data, unsigned long maxSize) noexcept override
write data on the socket.
Definition socket.hpp:2003
BasicTlsSocket(join::SslCtxPtr tlsContext)
create instance specifying TLS context.
Definition socket.hpp:1609
typename BasicStreamSocket< Protocol >::Mode Mode
Definition socket.hpp:1554
static int verifyWrapper(int preverified, X509_STORE_CTX *context)
c style callback wrapper for the Trusted CA certificates verification callback.
Definition socket.hpp:2359
BasicTlsSocket(BasicTlsSocket &&other)
move constructor.
Definition socket.hpp:1646
TLS error category.
Definition socket.hpp:1510
virtual std::string message(int code) const
translate digest error code to human readable error string.
Definition socket.cpp:44
virtual const char * name() const noexcept
get digest error category name.
Definition socket.cpp:35
const std::string key(65, 'a')
key.
Definition acceptor.hpp:32
bool operator<(const BasicUnixEndpoint< Protocol > &a, const BasicUnixEndpoint< Protocol > &b) noexcept
compare if endpoint is lower.
Definition endpoint.hpp:207
std::unique_ptr< SSL_CTX, SslCtxDelete > SslCtxPtr
Definition openssl.hpp:240
std::unique_ptr< STACK_OF(GENERAL_NAME), StackOfGeneralNameDelete > StackOfGeneralNamePtr
Definition openssl.hpp:210
const std::string defaultCipher_1_3
Definition openssl.cpp:40
TlsErrc
TLS error codes.
Definition socket.hpp:1501
const std::error_category & getTlsCategory()
get error category.
Definition socket.cpp:61
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:150
const std::string defaultCipher
Definition openssl.cpp:36
std::unique_ptr< SSL, SslDelete > SslPtr
Definition openssl.hpp:225
std::error_condition make_error_condition(join::Errc code) noexcept
Create an std::error_condition object.
Definition error.cpp:159
Definition error.hpp:137