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>
53 setg(NULL, NULL, NULL);
60 struct sockaddr_in sa;
64 setg(NULL, NULL, NULL);
67 hp = gethostbyname(hostname);
73 memset(&sa, 0,
sizeof(sa));
74 memcpy((
char *)&sa.sin_addr, hp->h_addr, hp->h_length);
75 sa.sin_family = hp->h_addrtype;
76 sa.sin_port = htons(port);
88 (
char *)(&on),
sizeof(on)) < 0)
97 (
const struct sockaddr *)&sa,
sizeof(sa)) < 0)
120 ssize_t bw, n = pptr() - pbase();
132 mfem::out <<
"Error in send(): " << strerror(errno) << std::endl;
155 mfem::out <<
"Error in recv(): " << strerror(errno) << std::endl;
158 setg(NULL, NULL, NULL);
159 return traits_type::eof();
162 return traits_type::to_int_type(*
ibuf);
169 return traits_type::eof();
171 if (traits_type::eq_int_type(c, traits_type::eof()))
173 return traits_type::not_eof(c);
175 *pptr() = traits_type::to_char_type(c);
184 const std::streamsize bn = egptr() - gptr();
187 traits_type::copy(__s, gptr(), __n);
191 traits_type::copy(__s, gptr(), bn);
192 setg(NULL, NULL, NULL);
193 std::streamsize remain = __n - bn;
194 char_type *end = __s + __n;
204 mfem::out <<
"Error in recv(): " << strerror(errno) << std::endl;
207 return (__n - remain);
218 if (pptr() + __n <= epptr())
220 traits_type::copy(pptr(), __s, __n);
229 std::streamsize remain = __n;
230 const char_type *end = __s + __n;
241 mfem::out <<
"Error in send(): " << strerror(errno) << std::endl;
243 return (__n - remain);
249 traits_type::copy(pptr(), end - remain, remain);
258 listen_socket = socket(PF_INET, SOCK_STREAM, 0);
259 if (listen_socket < 0)
264 if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR,
265 (
char *)(&on),
sizeof(on)) < 0)
267 closesocket(listen_socket);
271 struct sockaddr_in sa;
272 memset(&sa, 0,
sizeof(sa));
273 sa.sin_family = AF_INET;
274 sa.sin_port = htons(port);
275 sa.sin_addr.s_addr = INADDR_ANY;
276 if (bind(listen_socket, (
const struct sockaddr *)&sa,
sizeof(sa)))
278 closesocket(listen_socket);
283 if (listen(listen_socket, backlog) < 0)
285 closesocket(listen_socket);
297 int err = closesocket(listen_socket);
304 return good() ?
::accept(listen_socket, NULL, NULL) : -1;
313 int socketd =
::accept(listen_socket, NULL, NULL);
323 #ifdef MFEM_USE_GNUTLS
325 static void mfem_gnutls_log_func(
int level,
const char *str)
327 mfem::out <<
"GnuTLS <" << level <<
"> " << str << std::flush;
338 gnutls_global_set_log_function(mfem_gnutls_log_func);
359 #if GNUTLS_VERSION_NUMBER >= 0x021200
361 gnutls_sec_param_to_pk_bits(
362 GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY);
364 unsigned bits = 1024;
366 mfem::out <<
"Generating DH params (" << bits <<
" bits) ..."
380 static int mfem_gnutls_verify_callback(gnutls_session_t session)
383 #if GNUTLS_VERSION_NUMBER >= 0x030104
384 const char *hostname = (
const char *) gnutls_session_get_ptr(session);
385 int ret = gnutls_certificate_verify_peers3(session, hostname, &status);
388 mfem::out <<
"Error in gnutls_certificate_verify_peers3:"
389 << gnutls_strerror(ret) << std::endl;
390 return GNUTLS_E_CERTIFICATE_ERROR;
395 gnutls_certificate_type_t type = gnutls_certificate_type_get(session);
396 ret = gnutls_certificate_verification_status_print(status, type, &out, 0);
399 mfem::out <<
"Error in gnutls_certificate_verification_status_print:"
400 << gnutls_strerror(ret) << std::endl;
401 return GNUTLS_E_CERTIFICATE_ERROR;
404 gnutls_free(out.data);
406 #else // --> GNUTLS_VERSION_NUMBER < 0x030104
407 int ret = gnutls_certificate_verify_peers2(session, &status);
410 mfem::out <<
"Error in gnutls_certificate_verify_peers2:"
411 << gnutls_strerror(ret) << std::endl;
412 return GNUTLS_E_CERTIFICATE_ERROR;
416 "The certificate is NOT trusted." :
417 "The certificate is trusted.") << std::endl;
421 return status ? GNUTLS_E_CERTIFICATE_ERROR : 0;
426 const char *privkey_file,
const char *trustedkeys_file,
unsigned int flags)
430 my_flags = status.good() ? flags : 0;
436 gnutls_certificate_allocate_credentials(&
my_cred));
437 status.print_on_error(
"gnutls_certificate_allocate_credentials");
439 if (!status.good()) {
my_cred = NULL; }
442 #ifndef MFEM_USE_GNUTLS_X509
444 gnutls_certificate_set_openpgp_key_file(
445 my_cred, pubkey_file, privkey_file, GNUTLS_OPENPGP_FMT_RAW));
446 status.print_on_error(
"gnutls_certificate_set_openpgp_key_file");
449 gnutls_certificate_set_x509_key_file(
450 my_cred, pubkey_file, privkey_file, GNUTLS_X509_FMT_PEM));
452 status.print_on_error(
"gnutls_certificate_set_x509_key_file");
468 #ifndef MFEM_USE_GNUTLS_X509
470 gnutls_certificate_set_openpgp_keyring_file(
471 my_cred, trustedkeys_file, GNUTLS_OPENPGP_FMT_RAW));
472 status.print_on_error(
"gnutls_certificate_set_openpgp_keyring_file");
475 gnutls_certificate_set_x509_trust_file(
476 my_cred, trustedkeys_file, GNUTLS_X509_FMT_PEM);
478 #ifdef MFEM_USE_GNUTLS_DEBUG
479 mfem::out <<
"[GnuTLS_session_params::GnuTLS_session_params] "
480 "number of trusted certificates = " << num_certs << std::endl;
482 status.set_result(num_certs > 0 ?
483 GNUTLS_E_SUCCESS : GNUTLS_E_CERTIFICATE_ERROR);
484 status.print_on_error(
"gnutls_certificate_set_x509_trust_file");
488 #if GNUTLS_VERSION_NUMBER >= 0x021000
491 gnutls_certificate_set_verify_function(
492 my_cred, mfem_gnutls_verify_callback);
496 if (status.good() && (flags & GNUTLS_SERVER))
502 gnutls_certificate_set_dh_params(
my_cred, dh_params);
509 #ifdef MFEM_USE_GNUTLS_DEBUG
510 mfem::out <<
"[GnuTLS_socketbuf::handshake]" << std::endl;
517 err = gnutls_handshake(session);
518 status.set_result(err);
522 mfem::out <<
"handshake successful, TLS version is "
523 << gnutls_protocol_get_name(
524 gnutls_protocol_get_version(session)) << std::endl;
529 while (err == GNUTLS_E_INTERRUPTED || err == GNUTLS_E_AGAIN);
531 status.print_on_error(
"gnutls_handshake");
535 #if (defined(MSG_NOSIGNAL) && !defined(_WIN32) && !defined(__APPLE__))
536 #define MFEM_USE_GNUTLS_PUSH_FUNCTION
538 static ssize_t mfem_gnutls_push_function(
539 gnutls_transport_ptr_t fd_ptr,
const void *data,
size_t datasize)
541 return send((
int)(
long)fd_ptr, data, datasize, MSG_NOSIGNAL);
547 #ifdef MFEM_USE_GNUTLS_DEBUG
548 mfem::out <<
"[GnuTLS_socketbuf::start_session]" << std::endl;
557 #if GNUTLS_VERSION_NUMBER >= 0x030102
563 status.print_on_error(
"gnutls_init");
569 const char *priorities;
571 if (gnutls_check_version(
"2.12.0") != NULL)
574 #ifndef MFEM_USE_GNUTLS_X509
575 priorities =
"NONE:+VERS-TLS1.2:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:"
576 "+COMP-ALL:+KX-ALL:+CTYPE-OPENPGP:+CURVE-ALL";
578 priorities =
"NONE:+VERS-TLS1.2:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:"
579 "+COMP-ALL:+KX-ALL:+CTYPE-X509:+CURVE-ALL";
585 #ifndef MFEM_USE_GNUTLS_X509
586 priorities =
"NORMAL:-CTYPE-X.509";
588 priorities =
"NORMAL:";
593 gnutls_priority_set_direct(session, priorities, &err_ptr));
594 status.print_on_error(
"gnutls_priority_set_direct");
597 mfem::out <<
"Error ptr = \"" << err_ptr <<
'"' << std::endl;
605 gnutls_credentials_set(
606 session, GNUTLS_CRD_CERTIFICATE,
my_cred));
607 status.print_on_error(
"gnutls_credentials_set");
612 const char *hostname = NULL;
613 gnutls_session_set_ptr(session, (
void*)hostname);
617 gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE);
619 #if GNUTLS_VERSION_NUMBER >= 0x030100
620 gnutls_handshake_set_timeout(
621 session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
627 #if GNUTLS_VERSION_NUMBER >= 0x030109
630 gnutls_transport_set_ptr(session,
637 #if GNUTLS_VERSION_NUMBER < 0x021000
640 status.set_result(mfem_gnutls_verify_callback(session));
648 err = gnutls_bye(session, GNUTLS_SHUT_WR);
650 while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED);
655 #ifdef MFEM_USE_GNUTLS_PUSH_FUNCTION
658 gnutls_transport_set_push_function(session, mfem_gnutls_push_function);
672 #ifdef MFEM_USE_GNUTLS_DEBUG
673 mfem::out <<
"[GnuTLS_socketbuf::end_session]" << std::endl;
679 if (
is_open() && status.good())
682 #ifdef MFEM_USE_GNUTLS_DEBUG
683 mfem::out <<
"[GnuTLS_socketbuf::end_session: gnutls_bye]" << std::endl;
689 err = gnutls_bye(session, GNUTLS_SHUT_WR);
690 status.set_result(err);
692 while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED);
693 status.print_on_error(
"gnutls_bye");
696 gnutls_deinit(session);
702 #ifdef MFEM_USE_GNUTLS_DEBUG
703 mfem::out <<
"[GnuTLS_socketbuf::attach]" << std::endl;
717 #ifdef MFEM_USE_GNUTLS_DEBUG
718 mfem::out <<
"[GnuTLS_socketbuf::open]" << std::endl;
722 if (err) {
return err; }
726 return status.good() ? 0 : -100;
731 #ifdef MFEM_USE_GNUTLS_DEBUG
732 mfem::out <<
"[GnuTLS_socketbuf::close]" << std::endl;
739 return status.good() ? err : -100;
744 ssize_t bw, n = pptr() - pbase();
745 #ifdef MFEM_USE_GNUTLS_DEBUG
746 mfem::out <<
"[GnuTLS_socketbuf::sync n=" << n <<
']' << std::endl;
751 bw = gnutls_record_send(session, pptr() - n, n);
752 if (bw == GNUTLS_E_INTERRUPTED || bw == GNUTLS_E_AGAIN) {
continue; }
755 status.set_result((
int)bw);
757 status.print_on_error(
"gnutls_record_send");
771 #ifdef MFEM_USE_GNUTLS_DEBUG
772 mfem::out <<
"[GnuTLS_socketbuf::underflow ...]" << std::endl;
779 br = gnutls_record_recv(session,
ibuf,
buflen);
780 if (br == GNUTLS_E_REHANDSHAKE)
785 while (br == GNUTLS_E_INTERRUPTED || br == GNUTLS_E_AGAIN);
786 #ifdef MFEM_USE_GNUTLS_DEBUG
787 mfem::out <<
"[GnuTLS_socketbuf::underflow br=" << br <<
']' << std::endl;
794 status.set_result((
int)br);
796 status.print_on_error(
"gnutls_record_recv");
799 setg(NULL, NULL, NULL);
800 return traits_type::eof();
803 return traits_type::to_int_type(*
ibuf);
808 #ifdef MFEM_USE_GNUTLS_DEBUG
809 mfem::out <<
"[GnuTLS_socketbuf::xsgetn __n=" << __n <<
']' << std::endl;
813 const std::streamsize bn = egptr() - gptr();
816 traits_type::copy(__s, gptr(), __n);
820 traits_type::copy(__s, gptr(), bn);
821 setg(NULL, NULL, NULL);
822 std::streamsize remain = __n - bn;
823 char_type *end = __s + __n;
829 br = gnutls_record_recv(session, end - remain, remain);
830 if (br == GNUTLS_E_REHANDSHAKE)
835 while (br == GNUTLS_E_INTERRUPTED || br == GNUTLS_E_AGAIN);
840 status.set_result((
int)br);
842 status.print_on_error(
"gnutls_record_recv");
845 return (__n - remain);
855 #ifdef MFEM_USE_GNUTLS_DEBUG
856 mfem::out <<
"[GnuTLS_socketbuf::xsputn __n=" << __n <<
']' << std::endl;
860 if (pptr() + __n <= epptr())
862 traits_type::copy(pptr(), __s, __n);
871 std::streamsize remain = __n;
872 const char_type *end = __s + __n;
875 bw = gnutls_record_send(session, end - remain, remain);
876 if (bw == GNUTLS_E_INTERRUPTED || bw == GNUTLS_E_AGAIN) {
continue; }
877 #ifdef MFEM_USE_GNUTLS_DEBUG
878 mfem::out <<
"[GnuTLS_socketbuf::xsputn bw=" << bw <<
']' << std::endl;
882 status.set_result((
int)bw);
884 status.print_on_error(
"gnutls_record_send");
886 return (__n - remain);
892 traits_type::copy(pptr(), end - remain, remain);
910 std::string home_dir(getenv(
"HOME"));
911 std::string client_dir = home_dir +
"/.config/glvis/client/";
912 #ifndef MFEM_USE_GNUTLS_X509
913 std::string pubkey = client_dir +
"pubring.gpg";
914 std::string privkey = client_dir +
"secring.gpg";
915 std::string trustedkeys = client_dir +
"trusted-servers.gpg";
917 std::string pubkey = client_dir +
"cert.pem";
918 std::string privkey = client_dir +
"key.pem";
919 std::string trustedkeys = client_dir +
"trusted-servers.pem";
922 *
state, pubkey.c_str(), privkey.c_str(), trustedkeys.c_str(),
926 mfem::out <<
" public key = " << pubkey <<
'\n'
927 <<
" private key = " << privkey <<
'\n'
928 <<
" trusted keys = " << trustedkeys << std::endl;
929 mfem::out <<
"Error setting GLVis client parameters.\n"
930 "Use the following GLVis script to create your GLVis keys:\n"
931 " bash glvis-keygen.sh [\"Your Name\"] [\"Your Email\"]"
956 std::iostream::rdbuf(
buf__);
960 : std::iostream(0), glvis_client(false)
966 #endif // MFEM_USE_GNUTLS
973 #ifdef MFEM_USE_GNUTLS
976 mfem_error(
"The secure option in class mfem::socketstream can only\n"
977 "be used when GnuTLS support is enabled.");
983 std::iostream::rdbuf(
buf__);
989 #ifdef MFEM_USE_GNUTLS
991 else { setstate(std::ios::failbit); }
1013 setstate(std::ios::failbit);
1025 #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
virtual std::streamsize xsgetn(char_type *__s, std::streamsize __n)
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()
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 int open(const char hostname[], int port)
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())
virtual int attach(int sd)
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
void print_on_error(const char *msg) const
virtual std::streamsize xsgetn(char_type *__s, std::streamsize __n)
virtual std::streamsize xsputn(const char_type *__s, std::streamsize __n)
virtual std::streamsize xsputn(const char_type *__s, std::streamsize __n)
virtual int open(const char hostname[], int port)
socketserver(int port, int backlog=4)
int open(const char hostname[], int port)
static void remove_socket()
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...