14#define _CRT_SECURE_NO_WARNINGS
25#include <sys/socket.h>
27#define closesocket (::close)
35#pragma comment(lib, "ws2_32.lib")
40#ifndef MFEM_USE_GNUTLS_X509
41#include <gnutls/openpgp.h>
58 int err_flag = WSAStartup(MAKEWORD(2,2), &wsaData);
61 mfem::err <<
"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;
82static WinsockWrapper wsInit_;
89 setg(NULL, NULL, NULL);
96 struct addrinfo hints, *res, *rp;
98 if (!wsInit_.Initialized())
100 mfem_error(
"Attempting to open socket, but Winsock not initialized.");
104 setg(NULL, NULL, NULL);
107 hints.ai_family = AF_UNSPEC;
108 hints.ai_socktype = SOCK_STREAM;
110 hints.ai_protocol = 0;
112 hints.ai_addrlen = 0;
113 hints.ai_canonname = NULL;
114 hints.ai_addr = NULL;
115 hints.ai_next = NULL;
117 std::string portStr = std::to_string(port);
118 int s = getaddrinfo(hostname, portStr.c_str(), &hints, &res);
122 mfem::err <<
"Error in getaddrinfo(): code = " << s << std::endl;
128 for (rp = res; rp != NULL; rp = rp->ai_next)
141 &on,
sizeof(on)) < 0)
150 static_cast<socklen_t>(rp->ai_addrlen)) < 0)
177 ssize_t bw, n = pptr() - pbase();
189 mfem::err <<
"Error in send(): " << strerror(errno) << std::endl;
212 mfem::err <<
"Error in recv(): " << strerror(errno) << std::endl;
215 setg(NULL, NULL, NULL);
216 return traits_type::eof();
219 return traits_type::to_int_type(*
ibuf);
226 return traits_type::eof();
228 if (traits_type::eq_int_type(c, traits_type::eof()))
230 return traits_type::not_eof(c);
232 *pptr() = traits_type::to_char_type(c);
241 const std::streamsize bn = egptr() - gptr();
244 traits_type::copy(s__, gptr(), n__);
248 traits_type::copy(s__, gptr(), bn);
249 setg(NULL, NULL, NULL);
250 std::streamsize remain = n__ - bn;
251 char_type *end = s__ + n__;
261 mfem::err <<
"Error in recv(): " << strerror(errno) << std::endl;
264 return (n__ - remain);
275 if (pptr() + n__ <= epptr())
277 traits_type::copy(pptr(), s__, n__);
286 std::streamsize remain = n__;
287 const char_type *end = s__ + n__;
298 mfem::err <<
"Error in send(): " << strerror(errno) << std::endl;
300 return (n__ - remain);
306 traits_type::copy(pptr(), end - remain, remain);
315 listen_socket = socket(PF_INET, SOCK_STREAM, 0);
316 if (listen_socket < 0)
321 if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR,
322 (
char *)(&on),
sizeof(on)) < 0)
324 closesocket(listen_socket);
328 struct sockaddr_in sa;
329 memset(&sa, 0,
sizeof(sa));
330 sa.sin_family = AF_INET;
331 sa.sin_port = htons(port);
332 sa.sin_addr.s_addr = INADDR_ANY;
333 if (bind(listen_socket, (
const struct sockaddr *)&sa,
sizeof(sa)))
335 closesocket(listen_socket);
340 if (listen(listen_socket, backlog) < 0)
342 closesocket(listen_socket);
354 int err_flag = closesocket(listen_socket);
361 return good() ?
::accept(listen_socket, NULL, NULL) : -1;
370 int socketd =
::accept(listen_socket, NULL, NULL);
380#ifdef MFEM_USE_GNUTLS
382static void mfem_gnutls_log_func(
int level,
const char *str)
384 mfem::out <<
"GnuTLS <" << level <<
"> " << str << std::flush;
395 gnutls_global_set_log_function(mfem_gnutls_log_func);
416#if GNUTLS_VERSION_NUMBER >= 0x021200
418 gnutls_sec_param_to_pk_bits(
419 GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY);
421 unsigned bits = 1024;
423 mfem::out <<
"Generating DH params (" << bits <<
" bits) ..."
437static int mfem_gnutls_verify_callback(gnutls_session_t session)
440#if GNUTLS_VERSION_NUMBER >= 0x030104
441 const char *hostname = (
const char *) gnutls_session_get_ptr(session);
442 int ret = gnutls_certificate_verify_peers3(session, hostname, &status);
445 mfem::err <<
"Error in gnutls_certificate_verify_peers3:"
446 << gnutls_strerror(ret) << std::endl;
447 return GNUTLS_E_CERTIFICATE_ERROR;
451 gnutls_datum_t status_str;
452 gnutls_certificate_type_t type = gnutls_certificate_type_get(session);
453 ret = gnutls_certificate_verification_status_print(
454 status, type, &status_str, 0);
457 mfem::err <<
"Error in gnutls_certificate_verification_status_print:"
458 << gnutls_strerror(ret) << std::endl;
459 return GNUTLS_E_CERTIFICATE_ERROR;
461 mfem::out << status_str.data << std::endl;
462 gnutls_free(status_str.data);
465 int ret = gnutls_certificate_verify_peers2(session, &status);
468 mfem::err <<
"Error in gnutls_certificate_verify_peers2:"
469 << gnutls_strerror(ret) << std::endl;
470 return GNUTLS_E_CERTIFICATE_ERROR;
474 "The certificate is NOT trusted." :
475 "The certificate is trusted.") << std::endl;
479 return status ? GNUTLS_E_CERTIFICATE_ERROR : 0;
484 const char *privkey_file,
const char *trustedkeys_file,
unsigned int flags)
494 gnutls_certificate_allocate_credentials(&
my_cred));
500#ifndef MFEM_USE_GNUTLS_X509
502 gnutls_certificate_set_openpgp_key_file(
503 my_cred, pubkey_file, privkey_file, GNUTLS_OPENPGP_FMT_RAW));
507 gnutls_certificate_set_x509_key_file(
508 my_cred, pubkey_file, privkey_file, GNUTLS_X509_FMT_PEM));
526#ifndef MFEM_USE_GNUTLS_X509
528 gnutls_certificate_set_openpgp_keyring_file(
529 my_cred, trustedkeys_file, GNUTLS_OPENPGP_FMT_RAW));
533 gnutls_certificate_set_x509_trust_file(
534 my_cred, trustedkeys_file, GNUTLS_X509_FMT_PEM);
536#ifdef MFEM_USE_GNUTLS_DEBUG
537 mfem::out <<
"[GnuTLS_session_params::GnuTLS_session_params] "
538 "number of trusted certificates = " << num_certs << std::endl;
541 GNUTLS_E_SUCCESS : GNUTLS_E_CERTIFICATE_ERROR);
546#if GNUTLS_VERSION_NUMBER >= 0x021000
549 gnutls_certificate_set_verify_function(
550 my_cred, mfem_gnutls_verify_callback);
560 gnutls_certificate_set_dh_params(
my_cred, dh_params);
567#ifdef MFEM_USE_GNUTLS_DEBUG
568 mfem::out <<
"[GnuTLS_socketbuf::handshake]" << std::endl;
575 err_flag = gnutls_handshake(
session);
580 mfem::out <<
"handshake successful, TLS version is "
581 << gnutls_protocol_get_name(
582 gnutls_protocol_get_version(
session)) << std::endl;
587 while (err_flag == GNUTLS_E_INTERRUPTED || err_flag == GNUTLS_E_AGAIN);
593#if (defined(MSG_NOSIGNAL) && !defined(_WIN32) && !defined(__APPLE__))
594#define MFEM_USE_GNUTLS_PUSH_FUNCTION
596static ssize_t mfem_gnutls_push_function(
597 gnutls_transport_ptr_t fd_ptr,
const void *data,
size_t datasize)
599 return send((
int)(
long)fd_ptr, data, datasize, MSG_NOSIGNAL);
605#ifdef MFEM_USE_GNUTLS_DEBUG
606 mfem::out <<
"[GnuTLS_socketbuf::start_session]" << std::endl;
615#if GNUTLS_VERSION_NUMBER >= 0x030102
627 const char *priorities;
629 if (gnutls_check_version(
"2.12.0") != NULL)
632#ifndef MFEM_USE_GNUTLS_X509
633 priorities =
"NONE:+VERS-TLS1.2:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:"
634 "+COMP-ALL:+KX-ALL:+CTYPE-OPENPGP:+CURVE-ALL";
636 priorities =
"NONE:+VERS-TLS1.2:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:"
637 "+COMP-ALL:+KX-ALL:+CTYPE-X509:+CURVE-ALL";
643#ifndef MFEM_USE_GNUTLS_X509
644 priorities =
"NORMAL:-CTYPE-X.509";
646 priorities =
"NORMAL:";
651 gnutls_priority_set_direct(
session, priorities, &err_ptr));
655 mfem::err <<
"Error ptr = \"" << err_ptr <<
'"' << std::endl;
663 gnutls_credentials_set(
670 const char *hostname = NULL;
671 gnutls_session_set_ptr(
session, (
void*)hostname);
675 gnutls_certificate_server_set_request(
session, GNUTLS_CERT_REQUIRE);
677#if GNUTLS_VERSION_NUMBER >= 0x030100
678 gnutls_handshake_set_timeout(
679 session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
685#if GNUTLS_VERSION_NUMBER >= 0x030109
688 gnutls_transport_set_ptr(
session,
695#if GNUTLS_VERSION_NUMBER < 0x021000
706 err_flag = gnutls_bye(
session, GNUTLS_SHUT_WR);
708 while (err_flag == GNUTLS_E_AGAIN || err_flag == GNUTLS_E_INTERRUPTED);
713#ifdef MFEM_USE_GNUTLS_PUSH_FUNCTION
716 gnutls_transport_set_push_function(
session, mfem_gnutls_push_function);
730#ifdef MFEM_USE_GNUTLS_DEBUG
731 mfem::out <<
"[GnuTLS_socketbuf::end_session]" << std::endl;
740#ifdef MFEM_USE_GNUTLS_DEBUG
741 mfem::out <<
"[GnuTLS_socketbuf::end_session: gnutls_bye]" << std::endl;
751 while (err_flag == GNUTLS_E_AGAIN || err_flag == GNUTLS_E_INTERRUPTED);
761#ifdef MFEM_USE_GNUTLS_DEBUG
762 mfem::out <<
"[GnuTLS_socketbuf::attach]" << std::endl;
776#ifdef MFEM_USE_GNUTLS_DEBUG
777 mfem::out <<
"[GnuTLS_socketbuf::open]" << std::endl;
781 if (err_flag) {
return err_flag; }
790#ifdef MFEM_USE_GNUTLS_DEBUG
791 mfem::out <<
"[GnuTLS_socketbuf::close]" << std::endl;
803 ssize_t bw, n = pptr() - pbase();
804#ifdef MFEM_USE_GNUTLS_DEBUG
805 mfem::out <<
"[GnuTLS_socketbuf::sync n=" << n <<
']' << std::endl;
810 bw = gnutls_record_send(
session, pptr() - n, n);
811 if (bw == GNUTLS_E_INTERRUPTED || bw == GNUTLS_E_AGAIN) {
continue; }
830#ifdef MFEM_USE_GNUTLS_DEBUG
831 mfem::out <<
"[GnuTLS_socketbuf::underflow ...]" << std::endl;
839 if (br == GNUTLS_E_REHANDSHAKE)
844 while (br == GNUTLS_E_INTERRUPTED || br == GNUTLS_E_AGAIN);
845#ifdef MFEM_USE_GNUTLS_DEBUG
846 mfem::out <<
"[GnuTLS_socketbuf::underflow br=" << br <<
']' << std::endl;
858 setg(NULL, NULL, NULL);
859 return traits_type::eof();
862 return traits_type::to_int_type(*
ibuf);
867#ifdef MFEM_USE_GNUTLS_DEBUG
868 mfem::out <<
"[GnuTLS_socketbuf::xsgetn n__=" << n__ <<
']' << std::endl;
872 const std::streamsize bn = egptr() - gptr();
875 traits_type::copy(s__, gptr(), n__);
879 traits_type::copy(s__, gptr(), bn);
880 setg(NULL, NULL, NULL);
881 std::streamsize remain = n__ - bn;
882 char_type *end = s__ + n__;
888 br = gnutls_record_recv(
session, end - remain, remain);
889 if (br == GNUTLS_E_REHANDSHAKE)
894 while (br == GNUTLS_E_INTERRUPTED || br == GNUTLS_E_AGAIN);
904 return (n__ - remain);
914#ifdef MFEM_USE_GNUTLS_DEBUG
915 mfem::out <<
"[GnuTLS_socketbuf::xsputn n__=" << n__ <<
']' << std::endl;
919 if (pptr() + n__ <= epptr())
921 traits_type::copy(pptr(), s__, n__);
930 std::streamsize remain = n__;
931 const char_type *end = s__ + n__;
934 bw = gnutls_record_send(
session, end - remain, remain);
935 if (bw == GNUTLS_E_INTERRUPTED || bw == GNUTLS_E_AGAIN) {
continue; }
936#ifdef MFEM_USE_GNUTLS_DEBUG
937 mfem::out <<
"[GnuTLS_socketbuf::xsputn bw=" << bw <<
']' << std::endl;
945 return (n__ - remain);
951 traits_type::copy(pptr(), end - remain, remain);
969 std::string home_dir(
GetEnv(
"HOME"));
970 std::string client_dir = home_dir +
"/.config/glvis/client/";
971#ifndef MFEM_USE_GNUTLS_X509
972 std::string pubkey = client_dir +
"pubring.gpg";
973 std::string privkey = client_dir +
"secring.gpg";
974 std::string trustedkeys = client_dir +
"trusted-servers.gpg";
976 std::string pubkey = client_dir +
"cert.pem";
977 std::string privkey = client_dir +
"key.pem";
978 std::string trustedkeys = client_dir +
"trusted-servers.pem";
981 *
state, pubkey.c_str(), privkey.c_str(), trustedkeys.c_str(),
985 mfem::err <<
" public key = " << pubkey <<
'\n'
986 <<
" private key = " << privkey <<
'\n'
987 <<
" trusted keys = " << trustedkeys << std::endl;
988 mfem::err <<
"Error setting GLVis client parameters.\n"
989 "Use the following GLVis script to create your GLVis keys:\n"
990 " bash glvis-keygen.sh [\"Your Name\"] [\"Your Email\"]"
1015 std::iostream::rdbuf(
buf__);
1019 : std::iostream(0), glvis_client(false)
1032#ifdef MFEM_USE_GNUTLS
1035 mfem_error(
"The secure option in class mfem::socketstream can only\n"
1036 "be used when GnuTLS support is enabled.");
1042 std::iostream::rdbuf(
buf__);
1048#ifdef MFEM_USE_GNUTLS
1050 else { setstate(std::ios::failbit); }
1069 int err_flag =
buf__->
open(hostname, port);
1072 setstate(std::ios::failbit);
1084#ifdef MFEM_USE_GNUTLS
void generate_dh_params()
gnutls_dh_params_t get_dh_params()
gnutls_dh_params_t dh_params
unsigned int get_flags() const
GnuTLS_global_state & state
GnuTLS_session_params(GnuTLS_global_state &state, const char *pubkey_file, const char *privkey_file, const char *trustedkeys_file, unsigned int flags)
gnutls_certificate_credentials_t my_cred
int close() override
Close the current socket descriptor.
gnutls_certificate_credentials_t my_cred
int attach(int sd) override
std::streamsize xsputn(const char_type *s__, std::streamsize n__) override
int open(const char hostname[], int port) override
Open a socket on the 'port' at 'hostname' and store the socket descriptor. Returns 0 if there is no e...
std::streamsize xsgetn(char_type *s__, std::streamsize n__) override
const GnuTLS_session_params & params
int_type underflow() override
void set_result(int result)
void print_on_error(const char *msg) const
virtual int attach(int sd)
Attach a new socket descriptor to the socketbuf. Returns the old socket descriptor which is NOT close...
virtual int_type overflow(int_type c=traits_type::eof())
virtual std::streamsize xsputn(const char_type *s__, std::streamsize n__)
virtual int close()
Close the current socket descriptor.
virtual int_type underflow()
virtual std::streamsize xsgetn(char_type *s__, std::streamsize n__)
bool is_open()
Returns true if the socket is open and has a valid socket descriptor. Otherwise returns false.
int getsocketdescriptor()
Returns the attached 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...
socketserver(int port, int backlog=4)
void set_secure_socket(const GnuTLS_session_params &p)
void set_socket(bool secure)
static GnuTLS_session_params * params
socketstream(bool secure=secure_default)
Create a socket stream without connecting to a host.
static int num_glvis_sockets
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
static GnuTLS_session_params & add_socket()
static GnuTLS_global_state * state
static void remove_socket()
void check_secure_socket()
void mfem_error(const char *msg)
const char * GetEnv(const char *name)
Wrapper for std::getenv.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
real_t p(const Vector &x, real_t t)