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)
33 #pragma comment(lib, "ws2_32.lib")
36 #ifdef MFEM_USE_GNUTLS
38 #ifndef MFEM_USE_GNUTLS_X509
39 #include <gnutls/openpgp.h>
56 int err = WSAStartup(MAKEWORD(2,2), &wsaData);
59 mfem::out <<
"Error occured during initialization of WinSock."
68 ~WinsockWrapper() { WSACleanup(); }
71 WinsockWrapper(
const WinsockWrapper&) =
delete;
72 WinsockWrapper& operator=(
const WinsockWrapper&) =
delete;
74 bool Initialized() {
return initialized; }
76 bool initialized =
false;
80 static WinsockWrapper wsInit_;
87 setg(NULL, NULL, NULL);
94 struct sockaddr_in sa;
97 if (!wsInit_.Initialized())
99 mfem_error(
"Attempting to open socket, but Winsock not initialized.");
103 setg(NULL, NULL, NULL);
106 hp = gethostbyname(hostname);
112 memset(&sa, 0,
sizeof(sa));
113 memcpy((
char *)&sa.sin_addr, hp->h_addr, hp->h_length);
114 sa.sin_family = hp->h_addrtype;
115 sa.sin_port = htons(port);
122 #if defined __APPLE__
127 (
char *)(&on),
sizeof(on)) < 0)
136 (
const struct sockaddr *)&sa,
sizeof(sa)) < 0)
159 ssize_t bw, n = pptr() - pbase();
171 mfem::out <<
"Error in send(): " << strerror(errno) << std::endl;
194 mfem::out <<
"Error in recv(): " << strerror(errno) << std::endl;
197 setg(NULL, NULL, NULL);
198 return traits_type::eof();
201 return traits_type::to_int_type(*
ibuf);
208 return traits_type::eof();
210 if (traits_type::eq_int_type(c, traits_type::eof()))
212 return traits_type::not_eof(c);
214 *pptr() = traits_type::to_char_type(c);
223 const std::streamsize bn = egptr() - gptr();
226 traits_type::copy(s__, gptr(), n__);
230 traits_type::copy(s__, gptr(), bn);
231 setg(NULL, NULL, NULL);
232 std::streamsize remain = n__ - bn;
233 char_type *end = s__ + n__;
243 mfem::out <<
"Error in recv(): " << strerror(errno) << std::endl;
246 return (n__ - remain);
257 if (pptr() + n__ <= epptr())
259 traits_type::copy(pptr(), s__, n__);
268 std::streamsize remain = n__;
269 const char_type *end = s__ + n__;
280 mfem::out <<
"Error in send(): " << strerror(errno) << std::endl;
282 return (n__ - remain);
288 traits_type::copy(pptr(), end - remain, remain);
297 listen_socket = socket(PF_INET, SOCK_STREAM, 0);
298 if (listen_socket < 0)
303 if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR,
304 (
char *)(&on),
sizeof(on)) < 0)
306 closesocket(listen_socket);
310 struct sockaddr_in sa;
311 memset(&sa, 0,
sizeof(sa));
312 sa.sin_family = AF_INET;
313 sa.sin_port = htons(port);
314 sa.sin_addr.s_addr = INADDR_ANY;
315 if (bind(listen_socket, (
const struct sockaddr *)&sa,
sizeof(sa)))
317 closesocket(listen_socket);
322 if (listen(listen_socket, backlog) < 0)
324 closesocket(listen_socket);
336 int err = closesocket(listen_socket);
343 return good() ?
::accept(listen_socket, NULL, NULL) : -1;
352 int socketd =
::accept(listen_socket, NULL, NULL);
362 #ifdef MFEM_USE_GNUTLS
364 static void mfem_gnutls_log_func(
int level,
const char *str)
366 mfem::out <<
"GnuTLS <" << level <<
"> " << str << std::flush;
377 gnutls_global_set_log_function(mfem_gnutls_log_func);
398 #if GNUTLS_VERSION_NUMBER >= 0x021200
400 gnutls_sec_param_to_pk_bits(
401 GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY);
403 unsigned bits = 1024;
405 mfem::out <<
"Generating DH params (" << bits <<
" bits) ..."
419 static int mfem_gnutls_verify_callback(gnutls_session_t session)
422 #if GNUTLS_VERSION_NUMBER >= 0x030104
423 const char *hostname = (
const char *) gnutls_session_get_ptr(session);
424 int ret = gnutls_certificate_verify_peers3(session, hostname, &status);
427 mfem::out <<
"Error in gnutls_certificate_verify_peers3:"
428 << gnutls_strerror(ret) << std::endl;
429 return GNUTLS_E_CERTIFICATE_ERROR;
434 gnutls_certificate_type_t type = gnutls_certificate_type_get(session);
435 ret = gnutls_certificate_verification_status_print(status, type, &out, 0);
438 mfem::out <<
"Error in gnutls_certificate_verification_status_print:"
439 << gnutls_strerror(ret) << std::endl;
440 return GNUTLS_E_CERTIFICATE_ERROR;
443 gnutls_free(out.data);
445 #else // --> GNUTLS_VERSION_NUMBER < 0x030104
446 int ret = gnutls_certificate_verify_peers2(session, &status);
449 mfem::out <<
"Error in gnutls_certificate_verify_peers2:"
450 << gnutls_strerror(ret) << std::endl;
451 return GNUTLS_E_CERTIFICATE_ERROR;
455 "The certificate is NOT trusted." :
456 "The certificate is trusted.") << std::endl;
460 return status ? GNUTLS_E_CERTIFICATE_ERROR : 0;
465 const char *privkey_file,
const char *trustedkeys_file,
unsigned int flags)
469 my_flags = status.good() ? flags : 0;
475 gnutls_certificate_allocate_credentials(&
my_cred));
476 status.print_on_error(
"gnutls_certificate_allocate_credentials");
478 if (!status.good()) {
my_cred = NULL; }
481 #ifndef MFEM_USE_GNUTLS_X509
483 gnutls_certificate_set_openpgp_key_file(
484 my_cred, pubkey_file, privkey_file, GNUTLS_OPENPGP_FMT_RAW));
485 status.print_on_error(
"gnutls_certificate_set_openpgp_key_file");
488 gnutls_certificate_set_x509_key_file(
489 my_cred, pubkey_file, privkey_file, GNUTLS_X509_FMT_PEM));
491 status.print_on_error(
"gnutls_certificate_set_x509_key_file");
507 #ifndef MFEM_USE_GNUTLS_X509
509 gnutls_certificate_set_openpgp_keyring_file(
510 my_cred, trustedkeys_file, GNUTLS_OPENPGP_FMT_RAW));
511 status.print_on_error(
"gnutls_certificate_set_openpgp_keyring_file");
514 gnutls_certificate_set_x509_trust_file(
515 my_cred, trustedkeys_file, GNUTLS_X509_FMT_PEM);
517 #ifdef MFEM_USE_GNUTLS_DEBUG
518 mfem::out <<
"[GnuTLS_session_params::GnuTLS_session_params] "
519 "number of trusted certificates = " << num_certs << std::endl;
521 status.set_result(num_certs > 0 ?
522 GNUTLS_E_SUCCESS : GNUTLS_E_CERTIFICATE_ERROR);
523 status.print_on_error(
"gnutls_certificate_set_x509_trust_file");
527 #if GNUTLS_VERSION_NUMBER >= 0x021000
530 gnutls_certificate_set_verify_function(
531 my_cred, mfem_gnutls_verify_callback);
535 if (status.good() && (flags & GNUTLS_SERVER))
541 gnutls_certificate_set_dh_params(
my_cred, dh_params);
548 #ifdef MFEM_USE_GNUTLS_DEBUG
549 mfem::out <<
"[GnuTLS_socketbuf::handshake]" << std::endl;
556 err = gnutls_handshake(session);
557 status.set_result(err);
561 mfem::out <<
"handshake successful, TLS version is "
562 << gnutls_protocol_get_name(
563 gnutls_protocol_get_version(session)) << std::endl;
568 while (err == GNUTLS_E_INTERRUPTED || err == GNUTLS_E_AGAIN);
570 status.print_on_error(
"gnutls_handshake");
574 #if (defined(MSG_NOSIGNAL) && !defined(_WIN32) && !defined(__APPLE__))
575 #define MFEM_USE_GNUTLS_PUSH_FUNCTION
577 static ssize_t mfem_gnutls_push_function(
578 gnutls_transport_ptr_t fd_ptr,
const void *data,
size_t datasize)
580 return send((
int)(
long)fd_ptr, data, datasize, MSG_NOSIGNAL);
586 #ifdef MFEM_USE_GNUTLS_DEBUG
587 mfem::out <<
"[GnuTLS_socketbuf::start_session]" << std::endl;
596 #if GNUTLS_VERSION_NUMBER >= 0x030102
602 status.print_on_error(
"gnutls_init");
608 const char *priorities;
610 if (gnutls_check_version(
"2.12.0") != NULL)
613 #ifndef MFEM_USE_GNUTLS_X509
614 priorities =
"NONE:+VERS-TLS1.2:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:"
615 "+COMP-ALL:+KX-ALL:+CTYPE-OPENPGP:+CURVE-ALL";
617 priorities =
"NONE:+VERS-TLS1.2:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:"
618 "+COMP-ALL:+KX-ALL:+CTYPE-X509:+CURVE-ALL";
624 #ifndef MFEM_USE_GNUTLS_X509
625 priorities =
"NORMAL:-CTYPE-X.509";
627 priorities =
"NORMAL:";
632 gnutls_priority_set_direct(session, priorities, &err_ptr));
633 status.print_on_error(
"gnutls_priority_set_direct");
636 mfem::out <<
"Error ptr = \"" << err_ptr <<
'"' << std::endl;
644 gnutls_credentials_set(
645 session, GNUTLS_CRD_CERTIFICATE,
my_cred));
646 status.print_on_error(
"gnutls_credentials_set");
651 const char *hostname = NULL;
652 gnutls_session_set_ptr(session, (
void*)hostname);
656 gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE);
658 #if GNUTLS_VERSION_NUMBER >= 0x030100
659 gnutls_handshake_set_timeout(
660 session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
666 #if GNUTLS_VERSION_NUMBER >= 0x030109
669 gnutls_transport_set_ptr(session,
676 #if GNUTLS_VERSION_NUMBER < 0x021000
679 status.set_result(mfem_gnutls_verify_callback(session));
687 err = gnutls_bye(session, GNUTLS_SHUT_WR);
689 while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED);
694 #ifdef MFEM_USE_GNUTLS_PUSH_FUNCTION
697 gnutls_transport_set_push_function(session, mfem_gnutls_push_function);
711 #ifdef MFEM_USE_GNUTLS_DEBUG
712 mfem::out <<
"[GnuTLS_socketbuf::end_session]" << std::endl;
718 if (
is_open() && status.good())
721 #ifdef MFEM_USE_GNUTLS_DEBUG
722 mfem::out <<
"[GnuTLS_socketbuf::end_session: gnutls_bye]" << std::endl;
728 err = gnutls_bye(session, GNUTLS_SHUT_WR);
729 status.set_result(err);
731 while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED);
732 status.print_on_error(
"gnutls_bye");
735 gnutls_deinit(session);
741 #ifdef MFEM_USE_GNUTLS_DEBUG
742 mfem::out <<
"[GnuTLS_socketbuf::attach]" << std::endl;
756 #ifdef MFEM_USE_GNUTLS_DEBUG
757 mfem::out <<
"[GnuTLS_socketbuf::open]" << std::endl;
761 if (err) {
return err; }
765 return status.good() ? 0 : -100;
770 #ifdef MFEM_USE_GNUTLS_DEBUG
771 mfem::out <<
"[GnuTLS_socketbuf::close]" << std::endl;
778 return status.good() ? err : -100;
783 ssize_t bw, n = pptr() - pbase();
784 #ifdef MFEM_USE_GNUTLS_DEBUG
785 mfem::out <<
"[GnuTLS_socketbuf::sync n=" << n <<
']' << std::endl;
790 bw = gnutls_record_send(session, pptr() - n, n);
791 if (bw == GNUTLS_E_INTERRUPTED || bw == GNUTLS_E_AGAIN) {
continue; }
794 status.set_result((
int)bw);
796 status.print_on_error(
"gnutls_record_send");
810 #ifdef MFEM_USE_GNUTLS_DEBUG
811 mfem::out <<
"[GnuTLS_socketbuf::underflow ...]" << std::endl;
818 br = gnutls_record_recv(session,
ibuf,
buflen);
819 if (br == GNUTLS_E_REHANDSHAKE)
824 while (br == GNUTLS_E_INTERRUPTED || br == GNUTLS_E_AGAIN);
825 #ifdef MFEM_USE_GNUTLS_DEBUG
826 mfem::out <<
"[GnuTLS_socketbuf::underflow br=" << br <<
']' << std::endl;
833 status.set_result((
int)br);
835 status.print_on_error(
"gnutls_record_recv");
838 setg(NULL, NULL, NULL);
839 return traits_type::eof();
842 return traits_type::to_int_type(*
ibuf);
847 #ifdef MFEM_USE_GNUTLS_DEBUG
848 mfem::out <<
"[GnuTLS_socketbuf::xsgetn n__=" << n__ <<
']' << std::endl;
852 const std::streamsize bn = egptr() - gptr();
855 traits_type::copy(s__, gptr(), n__);
859 traits_type::copy(s__, gptr(), bn);
860 setg(NULL, NULL, NULL);
861 std::streamsize remain = n__ - bn;
862 char_type *end = s__ + n__;
868 br = gnutls_record_recv(session, end - remain, remain);
869 if (br == GNUTLS_E_REHANDSHAKE)
874 while (br == GNUTLS_E_INTERRUPTED || br == GNUTLS_E_AGAIN);
879 status.set_result((
int)br);
881 status.print_on_error(
"gnutls_record_recv");
884 return (n__ - remain);
894 #ifdef MFEM_USE_GNUTLS_DEBUG
895 mfem::out <<
"[GnuTLS_socketbuf::xsputn n__=" << n__ <<
']' << std::endl;
899 if (pptr() + n__ <= epptr())
901 traits_type::copy(pptr(), s__, n__);
910 std::streamsize remain = n__;
911 const char_type *end = s__ + n__;
914 bw = gnutls_record_send(session, end - remain, remain);
915 if (bw == GNUTLS_E_INTERRUPTED || bw == GNUTLS_E_AGAIN) {
continue; }
916 #ifdef MFEM_USE_GNUTLS_DEBUG
917 mfem::out <<
"[GnuTLS_socketbuf::xsputn bw=" << bw <<
']' << std::endl;
921 status.set_result((
int)bw);
923 status.print_on_error(
"gnutls_record_send");
925 return (n__ - remain);
931 traits_type::copy(pptr(), end - remain, remain);
949 std::string home_dir(getenv(
"HOME"));
950 std::string client_dir = home_dir +
"/.config/glvis/client/";
951 #ifndef MFEM_USE_GNUTLS_X509
952 std::string pubkey = client_dir +
"pubring.gpg";
953 std::string privkey = client_dir +
"secring.gpg";
954 std::string trustedkeys = client_dir +
"trusted-servers.gpg";
956 std::string pubkey = client_dir +
"cert.pem";
957 std::string privkey = client_dir +
"key.pem";
958 std::string trustedkeys = client_dir +
"trusted-servers.pem";
961 *
state, pubkey.c_str(), privkey.c_str(), trustedkeys.c_str(),
965 mfem::out <<
" public key = " << pubkey <<
'\n'
966 <<
" private key = " << privkey <<
'\n'
967 <<
" trusted keys = " << trustedkeys << std::endl;
968 mfem::out <<
"Error setting GLVis client parameters.\n"
969 "Use the following GLVis script to create your GLVis keys:\n"
970 " bash glvis-keygen.sh [\"Your Name\"] [\"Your Email\"]"
995 std::iostream::rdbuf(
buf__);
999 : std::iostream(0), glvis_client(false)
1005 #endif // MFEM_USE_GNUTLS
1012 #ifdef MFEM_USE_GNUTLS
1015 mfem_error(
"The secure option in class mfem::socketstream can only\n"
1016 "be used when GnuTLS support is enabled.");
1022 std::iostream::rdbuf(
buf__);
1028 #ifdef MFEM_USE_GNUTLS
1030 else { setstate(std::ios::failbit); }
1052 setstate(std::ios::failbit);
1064 #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...
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
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__)