14 #define _CRT_SECURE_NO_WARNINGS
23 #include <arpa/inet.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #define closesocket (::close)
35 #pragma comment(lib, "ws2_32.lib")
38 #ifdef MFEM_USE_GNUTLS
40 #ifndef MFEM_USE_GNUTLS_X509
41 #include <gnutls/openpgp.h>
58 int err_flag = WSAStartup(MAKEWORD(2,2), &wsaData);
61 mfem::out <<
"Error occurred during initialization of WinSock."
70 ~WinsockWrapper() { WSACleanup(); }
73 WinsockWrapper(
const WinsockWrapper&) =
delete;
74 WinsockWrapper& operator=(
const WinsockWrapper&) =
delete;
76 bool Initialized() {
return initialized; }
78 bool initialized =
false;
82 static WinsockWrapper wsInit_;
89 setg(NULL, NULL, NULL);
96 struct sockaddr_in sa;
99 if (!wsInit_.Initialized())
101 mfem_error(
"Attempting to open socket, but Winsock not initialized.");
105 setg(NULL, NULL, NULL);
108 hp = gethostbyname(hostname);
114 memset(&sa, 0,
sizeof(sa));
115 memcpy((
char *)&sa.sin_addr, hp->h_addr, hp->h_length);
116 sa.sin_family = hp->h_addrtype;
117 sa.sin_port = htons(port);
124 #if defined __APPLE__
129 (
char *)(&on),
sizeof(on)) < 0)
138 (
const struct sockaddr *)&sa,
sizeof(sa)) < 0)
161 ssize_t bw, n = pptr() - pbase();
173 mfem::out <<
"Error in send(): " << strerror(errno) << std::endl;
196 mfem::out <<
"Error in recv(): " << strerror(errno) << std::endl;
199 setg(NULL, NULL, NULL);
200 return traits_type::eof();
203 return traits_type::to_int_type(*
ibuf);
210 return traits_type::eof();
212 if (traits_type::eq_int_type(c, traits_type::eof()))
214 return traits_type::not_eof(c);
216 *pptr() = traits_type::to_char_type(c);
225 const std::streamsize bn = egptr() - gptr();
228 traits_type::copy(s__, gptr(), n__);
232 traits_type::copy(s__, gptr(), bn);
233 setg(NULL, NULL, NULL);
234 std::streamsize remain = n__ - bn;
235 char_type *end = s__ + n__;
245 mfem::out <<
"Error in recv(): " << strerror(errno) << std::endl;
248 return (n__ - remain);
259 if (pptr() + n__ <= epptr())
261 traits_type::copy(pptr(), s__, n__);
270 std::streamsize remain = n__;
271 const char_type *end = s__ + n__;
282 mfem::out <<
"Error in send(): " << strerror(errno) << std::endl;
284 return (n__ - remain);
290 traits_type::copy(pptr(), end - remain, remain);
299 listen_socket = socket(PF_INET, SOCK_STREAM, 0);
300 if (listen_socket < 0)
305 if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR,
306 (
char *)(&on),
sizeof(on)) < 0)
308 closesocket(listen_socket);
312 struct sockaddr_in sa;
313 memset(&sa, 0,
sizeof(sa));
314 sa.sin_family = AF_INET;
315 sa.sin_port = htons(port);
316 sa.sin_addr.s_addr = INADDR_ANY;
317 if (bind(listen_socket, (
const struct sockaddr *)&sa,
sizeof(sa)))
319 closesocket(listen_socket);
324 if (listen(listen_socket, backlog) < 0)
326 closesocket(listen_socket);
338 int err_flag = closesocket(listen_socket);
345 return good() ?
::accept(listen_socket, NULL, NULL) : -1;
354 int socketd =
::accept(listen_socket, NULL, NULL);
364 #ifdef MFEM_USE_GNUTLS
366 static void mfem_gnutls_log_func(
int level,
const char *str)
368 mfem::out <<
"GnuTLS <" << level <<
"> " << str << std::flush;
379 gnutls_global_set_log_function(mfem_gnutls_log_func);
400 #if GNUTLS_VERSION_NUMBER >= 0x021200
402 gnutls_sec_param_to_pk_bits(
403 GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY);
405 unsigned bits = 1024;
407 mfem::out <<
"Generating DH params (" << bits <<
" bits) ..."
421 static int mfem_gnutls_verify_callback(gnutls_session_t session)
424 #if GNUTLS_VERSION_NUMBER >= 0x030104
425 const char *hostname = (
const char *) gnutls_session_get_ptr(session);
426 int ret = gnutls_certificate_verify_peers3(session, hostname, &status);
429 mfem::out <<
"Error in gnutls_certificate_verify_peers3:"
430 << gnutls_strerror(ret) << std::endl;
431 return GNUTLS_E_CERTIFICATE_ERROR;
436 gnutls_certificate_type_t type = gnutls_certificate_type_get(session);
437 ret = gnutls_certificate_verification_status_print(status, type, &out, 0);
440 mfem::out <<
"Error in gnutls_certificate_verification_status_print:"
441 << gnutls_strerror(ret) << std::endl;
442 return GNUTLS_E_CERTIFICATE_ERROR;
445 gnutls_free(out.data);
447 #else // --> GNUTLS_VERSION_NUMBER < 0x030104
448 int ret = gnutls_certificate_verify_peers2(session, &status);
451 mfem::out <<
"Error in gnutls_certificate_verify_peers2:"
452 << gnutls_strerror(ret) << std::endl;
453 return GNUTLS_E_CERTIFICATE_ERROR;
457 "The certificate is NOT trusted." :
458 "The certificate is trusted.") << std::endl;
462 return status ? GNUTLS_E_CERTIFICATE_ERROR : 0;
467 const char *privkey_file,
const char *trustedkeys_file,
unsigned int flags)
471 my_flags = status.good() ? flags : 0;
477 gnutls_certificate_allocate_credentials(&
my_cred));
478 status.print_on_error(
"gnutls_certificate_allocate_credentials");
480 if (!status.good()) {
my_cred = NULL; }
483 #ifndef MFEM_USE_GNUTLS_X509
485 gnutls_certificate_set_openpgp_key_file(
486 my_cred, pubkey_file, privkey_file, GNUTLS_OPENPGP_FMT_RAW));
487 status.print_on_error(
"gnutls_certificate_set_openpgp_key_file");
490 gnutls_certificate_set_x509_key_file(
491 my_cred, pubkey_file, privkey_file, GNUTLS_X509_FMT_PEM));
493 status.print_on_error(
"gnutls_certificate_set_x509_key_file");
509 #ifndef MFEM_USE_GNUTLS_X509
511 gnutls_certificate_set_openpgp_keyring_file(
512 my_cred, trustedkeys_file, GNUTLS_OPENPGP_FMT_RAW));
513 status.print_on_error(
"gnutls_certificate_set_openpgp_keyring_file");
516 gnutls_certificate_set_x509_trust_file(
517 my_cred, trustedkeys_file, GNUTLS_X509_FMT_PEM);
519 #ifdef MFEM_USE_GNUTLS_DEBUG
520 mfem::out <<
"[GnuTLS_session_params::GnuTLS_session_params] "
521 "number of trusted certificates = " << num_certs << std::endl;
523 status.set_result(num_certs > 0 ?
524 GNUTLS_E_SUCCESS : GNUTLS_E_CERTIFICATE_ERROR);
525 status.print_on_error(
"gnutls_certificate_set_x509_trust_file");
529 #if GNUTLS_VERSION_NUMBER >= 0x021000
532 gnutls_certificate_set_verify_function(
533 my_cred, mfem_gnutls_verify_callback);
537 if (status.good() && (flags & GNUTLS_SERVER))
543 gnutls_certificate_set_dh_params(
my_cred, dh_params);
550 #ifdef MFEM_USE_GNUTLS_DEBUG
551 mfem::out <<
"[GnuTLS_socketbuf::handshake]" << std::endl;
558 err_flag = gnutls_handshake(session);
559 status.set_result(err_flag);
563 mfem::out <<
"handshake successful, TLS version is "
564 << gnutls_protocol_get_name(
565 gnutls_protocol_get_version(session)) << std::endl;
570 while (err_flag == GNUTLS_E_INTERRUPTED || err_flag == GNUTLS_E_AGAIN);
572 status.print_on_error(
"gnutls_handshake");
576 #if (defined(MSG_NOSIGNAL) && !defined(_WIN32) && !defined(__APPLE__))
577 #define MFEM_USE_GNUTLS_PUSH_FUNCTION
579 static ssize_t mfem_gnutls_push_function(
580 gnutls_transport_ptr_t fd_ptr,
const void *data,
size_t datasize)
582 return send((
int)(
long)fd_ptr, data, datasize, MSG_NOSIGNAL);
588 #ifdef MFEM_USE_GNUTLS_DEBUG
589 mfem::out <<
"[GnuTLS_socketbuf::start_session]" << std::endl;
598 #if GNUTLS_VERSION_NUMBER >= 0x030102
604 status.print_on_error(
"gnutls_init");
610 const char *priorities;
612 if (gnutls_check_version(
"2.12.0") != NULL)
615 #ifndef MFEM_USE_GNUTLS_X509
616 priorities =
"NONE:+VERS-TLS1.2:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:"
617 "+COMP-ALL:+KX-ALL:+CTYPE-OPENPGP:+CURVE-ALL";
619 priorities =
"NONE:+VERS-TLS1.2:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:"
620 "+COMP-ALL:+KX-ALL:+CTYPE-X509:+CURVE-ALL";
626 #ifndef MFEM_USE_GNUTLS_X509
627 priorities =
"NORMAL:-CTYPE-X.509";
629 priorities =
"NORMAL:";
634 gnutls_priority_set_direct(session, priorities, &err_ptr));
635 status.print_on_error(
"gnutls_priority_set_direct");
638 mfem::out <<
"Error ptr = \"" << err_ptr <<
'"' << std::endl;
646 gnutls_credentials_set(
647 session, GNUTLS_CRD_CERTIFICATE,
my_cred));
648 status.print_on_error(
"gnutls_credentials_set");
653 const char *hostname = NULL;
654 gnutls_session_set_ptr(session, (
void*)hostname);
658 gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE);
660 #if GNUTLS_VERSION_NUMBER >= 0x030100
661 gnutls_handshake_set_timeout(
662 session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
668 #if GNUTLS_VERSION_NUMBER >= 0x030109
671 gnutls_transport_set_ptr(session,
678 #if GNUTLS_VERSION_NUMBER < 0x021000
681 status.set_result(mfem_gnutls_verify_callback(session));
689 err_flag = gnutls_bye(session, GNUTLS_SHUT_WR);
691 while (err_flag == GNUTLS_E_AGAIN || err_flag == GNUTLS_E_INTERRUPTED);
696 #ifdef MFEM_USE_GNUTLS_PUSH_FUNCTION
699 gnutls_transport_set_push_function(session, mfem_gnutls_push_function);
713 #ifdef MFEM_USE_GNUTLS_DEBUG
714 mfem::out <<
"[GnuTLS_socketbuf::end_session]" << std::endl;
720 if (
is_open() && status.good())
723 #ifdef MFEM_USE_GNUTLS_DEBUG
724 mfem::out <<
"[GnuTLS_socketbuf::end_session: gnutls_bye]" << std::endl;
730 err_flag = gnutls_bye(session,
732 status.set_result(err_flag);
734 while (err_flag == GNUTLS_E_AGAIN || err_flag == GNUTLS_E_INTERRUPTED);
735 status.print_on_error(
"gnutls_bye");
738 gnutls_deinit(session);
744 #ifdef MFEM_USE_GNUTLS_DEBUG
745 mfem::out <<
"[GnuTLS_socketbuf::attach]" << std::endl;
759 #ifdef MFEM_USE_GNUTLS_DEBUG
760 mfem::out <<
"[GnuTLS_socketbuf::open]" << std::endl;
764 if (err_flag) {
return err_flag; }
768 return status.good() ? 0 : -100;
773 #ifdef MFEM_USE_GNUTLS_DEBUG
774 mfem::out <<
"[GnuTLS_socketbuf::close]" << std::endl;
781 return status.good() ? err_flag : -100;
786 ssize_t bw, n = pptr() - pbase();
787 #ifdef MFEM_USE_GNUTLS_DEBUG
788 mfem::out <<
"[GnuTLS_socketbuf::sync n=" << n <<
']' << std::endl;
793 bw = gnutls_record_send(session, pptr() - n, n);
794 if (bw == GNUTLS_E_INTERRUPTED || bw == GNUTLS_E_AGAIN) {
continue; }
797 status.set_result((
int)bw);
799 status.print_on_error(
"gnutls_record_send");
813 #ifdef MFEM_USE_GNUTLS_DEBUG
814 mfem::out <<
"[GnuTLS_socketbuf::underflow ...]" << std::endl;
821 br = gnutls_record_recv(session,
ibuf,
buflen);
822 if (br == GNUTLS_E_REHANDSHAKE)
827 while (br == GNUTLS_E_INTERRUPTED || br == GNUTLS_E_AGAIN);
828 #ifdef MFEM_USE_GNUTLS_DEBUG
829 mfem::out <<
"[GnuTLS_socketbuf::underflow br=" << br <<
']' << std::endl;
836 status.set_result((
int)br);
838 status.print_on_error(
"gnutls_record_recv");
841 setg(NULL, NULL, NULL);
842 return traits_type::eof();
845 return traits_type::to_int_type(*
ibuf);
850 #ifdef MFEM_USE_GNUTLS_DEBUG
851 mfem::out <<
"[GnuTLS_socketbuf::xsgetn n__=" << n__ <<
']' << std::endl;
855 const std::streamsize bn = egptr() - gptr();
858 traits_type::copy(s__, gptr(), n__);
862 traits_type::copy(s__, gptr(), bn);
863 setg(NULL, NULL, NULL);
864 std::streamsize remain = n__ - bn;
865 char_type *end = s__ + n__;
871 br = gnutls_record_recv(session, end - remain, remain);
872 if (br == GNUTLS_E_REHANDSHAKE)
877 while (br == GNUTLS_E_INTERRUPTED || br == GNUTLS_E_AGAIN);
882 status.set_result((
int)br);
884 status.print_on_error(
"gnutls_record_recv");
887 return (n__ - remain);
897 #ifdef MFEM_USE_GNUTLS_DEBUG
898 mfem::out <<
"[GnuTLS_socketbuf::xsputn n__=" << n__ <<
']' << std::endl;
902 if (pptr() + n__ <= epptr())
904 traits_type::copy(pptr(), s__, n__);
913 std::streamsize remain = n__;
914 const char_type *end = s__ + n__;
917 bw = gnutls_record_send(session, end - remain, remain);
918 if (bw == GNUTLS_E_INTERRUPTED || bw == GNUTLS_E_AGAIN) {
continue; }
919 #ifdef MFEM_USE_GNUTLS_DEBUG
920 mfem::out <<
"[GnuTLS_socketbuf::xsputn bw=" << bw <<
']' << std::endl;
924 status.set_result((
int)bw);
926 status.print_on_error(
"gnutls_record_send");
928 return (n__ - remain);
934 traits_type::copy(pptr(), end - remain, remain);
952 std::string home_dir(getenv(
"HOME"));
953 std::string client_dir = home_dir +
"/.config/glvis/client/";
954 #ifndef MFEM_USE_GNUTLS_X509
955 std::string pubkey = client_dir +
"pubring.gpg";
956 std::string privkey = client_dir +
"secring.gpg";
957 std::string trustedkeys = client_dir +
"trusted-servers.gpg";
959 std::string pubkey = client_dir +
"cert.pem";
960 std::string privkey = client_dir +
"key.pem";
961 std::string trustedkeys = client_dir +
"trusted-servers.pem";
964 *
state, pubkey.c_str(), privkey.c_str(), trustedkeys.c_str(),
968 mfem::out <<
" public key = " << pubkey <<
'\n'
969 <<
" private key = " << privkey <<
'\n'
970 <<
" trusted keys = " << trustedkeys << std::endl;
971 mfem::out <<
"Error setting GLVis client parameters.\n"
972 "Use the following GLVis script to create your GLVis keys:\n"
973 " bash glvis-keygen.sh [\"Your Name\"] [\"Your Email\"]"
998 std::iostream::rdbuf(
buf__);
1002 : std::iostream(0), glvis_client(false)
1008 #endif // MFEM_USE_GNUTLS
1015 #ifdef MFEM_USE_GNUTLS
1018 mfem_error(
"The secure option in class mfem::socketstream can only\n"
1019 "be used when GnuTLS support is enabled.");
1025 std::iostream::rdbuf(
buf__);
1031 #ifdef MFEM_USE_GNUTLS
1033 else { setstate(std::ios::failbit); }
1052 int err_flag =
buf__->
open(hostname, port);
1055 setstate(std::ios::failbit);
1067 #ifdef MFEM_USE_GNUTLS
void set_result(int result)
static GnuTLS_session_params * params
virtual int attach(int sd)
virtual int_type underflow()
static int num_glvis_sockets
gnutls_certificate_credentials_t my_cred
bool is_open()
Returns true if the socket is open and has a valid socket descriptor. Otherwise returns false...
void check_secure_socket()
GnuTLS_session_params(GnuTLS_global_state &state, const char *pubkey_file, const char *privkey_file, const char *trustedkeys_file, unsigned int flags)
int getsocketdescriptor()
Returns the attached socket descriptor.
gnutls_certificate_credentials_t my_cred
void set_socket(bool secure)
gnutls_dh_params_t get_dh_params()
gnutls_dh_params_t dh_params
virtual std::streamsize xsgetn(char_type *s__, std::streamsize n__)
virtual std::streamsize xsputn(const char_type *s__, std::streamsize n__)
virtual int close()
Close the current socket descriptor.
virtual int open(const char hostname[], int port)
Open a socket on the 'port' at 'hostname' and store the socket descriptor. Returns 0 if there is no e...
socketstream(bool secure=secure_default)
Create a socket stream without connecting to a host.
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
virtual int_type underflow()
void set_secure_socket(const GnuTLS_session_params &p)
static GnuTLS_session_params & add_socket()
virtual int_type overflow(int_type c=traits_type::eof())
double p(const Vector &x, double t)
virtual int attach(int sd)
Attach a new socket descriptor to the socketbuf. Returns the old socket descriptor which is NOT close...
virtual std::streamsize xsgetn(char_type *s__, std::streamsize n__)
void print_on_error(const char *msg) const
virtual int open(const char hostname[], int port)
Open a socket on the 'port' at 'hostname' and store the socket descriptor. Returns 0 if there is no e...
socketserver(int port, int backlog=4)
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
static void remove_socket()
virtual int close()
Close the current socket descriptor.
void generate_dh_params()
const GnuTLS_session_params & params
unsigned int get_flags() const
static GnuTLS_global_state * state
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
virtual std::streamsize xsputn(const char_type *s__, std::streamsize n__)