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 #include <gnutls/openpgp.h>
51 setg(NULL, NULL, NULL);
58 struct sockaddr_in sa;
62 setg(NULL, NULL, NULL);
65 hp = gethostbyname(hostname);
71 memset(&sa, 0,
sizeof(sa));
72 memcpy((
char *)&sa.sin_addr, hp->h_addr, hp->h_length);
73 sa.sin_family = hp->h_addrtype;
74 sa.sin_port = htons(port);
86 (
char *)(&on),
sizeof(on)) < 0)
95 (
const struct sockaddr *)&sa,
sizeof(sa)) < 0)
118 ssize_t bw, n = pptr() - pbase();
130 mfem::out <<
"Error in send(): " << strerror(errno) << std::endl;
153 mfem::out <<
"Error in recv(): " << strerror(errno) << std::endl;
156 setg(NULL, NULL, NULL);
157 return traits_type::eof();
160 return traits_type::to_int_type(*
ibuf);
167 return traits_type::eof();
169 if (traits_type::eq_int_type(c, traits_type::eof()))
171 return traits_type::not_eof(c);
173 *pptr() = traits_type::to_char_type(c);
182 const std::streamsize bn = egptr() - gptr();
185 traits_type::copy(__s, gptr(), __n);
189 traits_type::copy(__s, gptr(), bn);
190 setg(NULL, NULL, NULL);
191 std::streamsize remain = __n - bn;
192 char_type *end = __s + __n;
202 mfem::out <<
"Error in recv(): " << strerror(errno) << std::endl;
205 return (__n - remain);
216 if (pptr() + __n <= epptr())
218 traits_type::copy(pptr(), __s, __n);
227 std::streamsize remain = __n;
228 const char_type *end = __s + __n;
239 mfem::out <<
"Error in send(): " << strerror(errno) << std::endl;
241 return (__n - remain);
247 traits_type::copy(pptr(), end - remain, remain);
256 listen_socket = socket(PF_INET, SOCK_STREAM, 0);
257 if (listen_socket < 0)
262 if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR,
263 (
char *)(&on),
sizeof(on)) < 0)
265 closesocket(listen_socket);
269 struct sockaddr_in sa;
270 memset(&sa, 0,
sizeof(sa));
271 sa.sin_family = AF_INET;
272 sa.sin_port = htons(port);
273 sa.sin_addr.s_addr = INADDR_ANY;
274 if (bind(listen_socket, (
const struct sockaddr *)&sa,
sizeof(sa)))
276 closesocket(listen_socket);
281 if (listen(listen_socket, backlog) < 0)
283 closesocket(listen_socket);
295 int err = closesocket(listen_socket);
302 return good() ?
::accept(listen_socket, NULL, NULL) : -1;
311 int socketd =
::accept(listen_socket, NULL, NULL);
321 #ifdef MFEM_USE_GNUTLS
323 static void mfem_gnutls_log_func(
int level,
const char *str)
325 mfem::out <<
"GnuTLS <" << level <<
"> " << str << std::flush;
336 gnutls_global_set_log_function(mfem_gnutls_log_func);
357 #if GNUTLS_VERSION_NUMBER >= 0x021200
359 gnutls_sec_param_to_pk_bits(
360 GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LEGACY);
362 unsigned bits = 1024;
364 mfem::out <<
"Generating DH params (" << bits <<
" bits) ..."
378 static int mfem_gnutls_verify_callback(gnutls_session_t session)
381 #if GNUTLS_VERSION_NUMBER >= 0x030104
382 const char *hostname = (
const char *) gnutls_session_get_ptr(session);
383 int ret = gnutls_certificate_verify_peers3(session, hostname, &status);
386 mfem::out <<
"Error in gnutls_certificate_verify_peers3:"
387 << gnutls_strerror(ret) << std::endl;
388 return GNUTLS_E_CERTIFICATE_ERROR;
393 gnutls_certificate_type_t type = gnutls_certificate_type_get(session);
394 ret = gnutls_certificate_verification_status_print(status, type, &out, 0);
397 mfem::out <<
"Error in gnutls_certificate_verification_status_print:"
398 << gnutls_strerror(ret) << std::endl;
399 return GNUTLS_E_CERTIFICATE_ERROR;
402 gnutls_free(out.data);
404 #else // --> GNUTLS_VERSION_NUMBER < 0x030104
405 int ret = gnutls_certificate_verify_peers2(session, &status);
408 mfem::out <<
"Error in gnutls_certificate_verify_peers2:"
409 << gnutls_strerror(ret) << std::endl;
410 return GNUTLS_E_CERTIFICATE_ERROR;
414 "The certificate is NOT trusted." :
415 "The certificate is trusted.") << std::endl;
419 return status ? GNUTLS_E_CERTIFICATE_ERROR : 0;
424 const char *privkey_file,
const char *trustedkeys_file,
unsigned int flags)
428 my_flags = status.good() ? flags : 0;
434 gnutls_certificate_allocate_credentials(&
my_cred));
435 status.print_on_error(
"gnutls_certificate_allocate_credentials");
437 if (!status.good()) {
my_cred = NULL; }
441 gnutls_certificate_set_openpgp_key_file(
442 my_cred, pubkey_file, privkey_file, GNUTLS_OPENPGP_FMT_RAW));
443 status.print_on_error(
"gnutls_certificate_set_openpgp_key_file");
459 gnutls_certificate_set_openpgp_keyring_file(
460 my_cred, trustedkeys_file, GNUTLS_OPENPGP_FMT_RAW));
461 status.print_on_error(
"gnutls_certificate_set_openpgp_keyring_file");
464 #if GNUTLS_VERSION_NUMBER >= 0x021000
467 gnutls_certificate_set_verify_function(
468 my_cred, mfem_gnutls_verify_callback);
472 if (status.good() && (flags & GNUTLS_SERVER))
478 gnutls_certificate_set_dh_params(
my_cred, dh_params);
485 #ifdef MFEM_USE_GNUTLS_DEBUG
486 mfem::out <<
"[GnuTLS_socketbuf::handshake]" << std::endl;
493 err = gnutls_handshake(session);
494 status.set_result(err);
498 mfem::out <<
"handshake successful, TLS version is "
499 << gnutls_protocol_get_name(
500 gnutls_protocol_get_version(session)) << std::endl;
505 while (err == GNUTLS_E_INTERRUPTED || err == GNUTLS_E_AGAIN);
507 status.print_on_error(
"gnutls_handshake");
511 #if (defined(MSG_NOSIGNAL) && !defined(_WIN32) && !defined(__APPLE__))
512 #define MFEM_USE_GNUTLS_PUSH_FUNCTION
514 static ssize_t mfem_gnutls_push_function(
515 gnutls_transport_ptr_t fd_ptr,
const void *data,
size_t datasize)
517 return send((
int)(
long)fd_ptr, data, datasize, MSG_NOSIGNAL);
523 #ifdef MFEM_USE_GNUTLS_DEBUG
524 mfem::out <<
"[GnuTLS_socketbuf::start_session]" << std::endl;
533 #if GNUTLS_VERSION_NUMBER >= 0x030102
539 status.print_on_error(
"gnutls_init");
545 const char *priorities;
547 if (gnutls_check_version(
"2.12.0") != NULL)
550 priorities =
"NONE:+VERS-TLS1.2:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:"
551 "+COMP-ALL:+KX-ALL:+CTYPE-OPENPGP:+CURVE-ALL";
556 priorities =
"NORMAL:-CTYPE-X.509";
560 gnutls_priority_set_direct(session, priorities, &err_ptr));
561 status.print_on_error(
"gnutls_priority_set_direct");
564 mfem::out <<
"Error ptr = \"" << err_ptr <<
'"' << std::endl;
572 gnutls_credentials_set(
573 session, GNUTLS_CRD_CERTIFICATE,
my_cred));
574 status.print_on_error(
"gnutls_credentials_set");
579 const char *hostname = NULL;
580 gnutls_session_set_ptr(session, (
void*)hostname);
584 gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE);
586 #if GNUTLS_VERSION_NUMBER >= 0x030100
587 gnutls_handshake_set_timeout(
588 session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
594 #if GNUTLS_VERSION_NUMBER >= 0x030109
597 gnutls_transport_set_ptr(session,
604 #if GNUTLS_VERSION_NUMBER < 0x021000
607 status.set_result(mfem_gnutls_verify_callback(session));
615 err = gnutls_bye(session, GNUTLS_SHUT_WR);
617 while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED);
622 #ifdef MFEM_USE_GNUTLS_PUSH_FUNCTION
625 gnutls_transport_set_push_function(session, mfem_gnutls_push_function);
639 #ifdef MFEM_USE_GNUTLS_DEBUG
640 mfem::out <<
"[GnuTLS_socketbuf::end_session]" << std::endl;
646 if (
is_open() && status.good())
649 #ifdef MFEM_USE_GNUTLS_DEBUG
650 mfem::out <<
"[GnuTLS_socketbuf::end_session: gnutls_bye]" << std::endl;
656 err = gnutls_bye(session, GNUTLS_SHUT_WR);
657 status.set_result(err);
659 while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED);
660 status.print_on_error(
"gnutls_bye");
663 gnutls_deinit(session);
669 #ifdef MFEM_USE_GNUTLS_DEBUG
670 mfem::out <<
"[GnuTLS_socketbuf::attach]" << std::endl;
684 #ifdef MFEM_USE_GNUTLS_DEBUG
685 mfem::out <<
"[GnuTLS_socketbuf::open]" << std::endl;
689 if (err) {
return err; }
693 return status.good() ? 0 : -100;
698 #ifdef MFEM_USE_GNUTLS_DEBUG
699 mfem::out <<
"[GnuTLS_socketbuf::close]" << std::endl;
706 return status.good() ? err : -100;
711 ssize_t bw, n = pptr() - pbase();
712 #ifdef MFEM_USE_GNUTLS_DEBUG
713 mfem::out <<
"[GnuTLS_socketbuf::sync n=" << n <<
']' << std::endl;
718 bw = gnutls_record_send(session, pptr() - n, n);
719 if (bw == GNUTLS_E_INTERRUPTED || bw == GNUTLS_E_AGAIN) {
continue; }
722 status.set_result((
int)bw);
724 status.print_on_error(
"gnutls_record_send");
738 #ifdef MFEM_USE_GNUTLS_DEBUG
739 mfem::out <<
"[GnuTLS_socketbuf::underflow ...]" << std::endl;
746 br = gnutls_record_recv(session,
ibuf,
buflen);
747 if (br == GNUTLS_E_REHANDSHAKE)
752 while (br == GNUTLS_E_INTERRUPTED || br == GNUTLS_E_AGAIN);
753 #ifdef MFEM_USE_GNUTLS_DEBUG
754 mfem::out <<
"[GnuTLS_socketbuf::underflow br=" << br <<
']' << std::endl;
761 status.set_result((
int)br);
763 status.print_on_error(
"gnutls_record_recv");
766 setg(NULL, NULL, NULL);
767 return traits_type::eof();
770 return traits_type::to_int_type(*
ibuf);
775 #ifdef MFEM_USE_GNUTLS_DEBUG
776 mfem::out <<
"[GnuTLS_socketbuf::xsgetn __n=" << __n <<
']' << std::endl;
780 const std::streamsize bn = egptr() - gptr();
783 traits_type::copy(__s, gptr(), __n);
787 traits_type::copy(__s, gptr(), bn);
788 setg(NULL, NULL, NULL);
789 std::streamsize remain = __n - bn;
790 char_type *end = __s + __n;
796 br = gnutls_record_recv(session, end - remain, remain);
797 if (br == GNUTLS_E_REHANDSHAKE)
802 while (br == GNUTLS_E_INTERRUPTED || br == GNUTLS_E_AGAIN);
807 status.set_result((
int)br);
809 status.print_on_error(
"gnutls_record_recv");
812 return (__n - remain);
822 #ifdef MFEM_USE_GNUTLS_DEBUG
823 mfem::out <<
"[GnuTLS_socketbuf::xsputn __n=" << __n <<
']' << std::endl;
827 if (pptr() + __n <= epptr())
829 traits_type::copy(pptr(), __s, __n);
838 std::streamsize remain = __n;
839 const char_type *end = __s + __n;
842 bw = gnutls_record_send(session, end - remain, remain);
843 if (bw == GNUTLS_E_INTERRUPTED || bw == GNUTLS_E_AGAIN) {
continue; }
844 #ifdef MFEM_USE_GNUTLS_DEBUG
845 mfem::out <<
"[GnuTLS_socketbuf::xsputn bw=" << bw <<
']' << std::endl;
849 status.set_result((
int)bw);
851 status.print_on_error(
"gnutls_record_send");
853 return (__n - remain);
859 traits_type::copy(pptr(), end - remain, remain);
877 std::string home_dir(getenv(
"HOME"));
878 std::string client_dir = home_dir +
"/.config/glvis/client/";
879 std::string pubkey = client_dir +
"pubring.gpg";
880 std::string privkey = client_dir +
"secring.gpg";
881 std::string trustedkeys = client_dir +
"trusted-servers.gpg";
883 *
state, pubkey.c_str(), privkey.c_str(), trustedkeys.c_str(),
887 mfem::out <<
" public key = " << pubkey <<
'\n'
888 <<
" private key = " << privkey <<
'\n'
889 <<
" trusted keys = " << trustedkeys << std::endl;
890 mfem::out <<
"Error setting GLVis client parameters.\n"
891 "Use the following GLVis script to create your GLVis keys:\n"
892 " bash glvis-keygen.sh [\"Your Name\"] [\"Your Email\"]"
917 std::iostream::rdbuf(
buf__);
921 : std::iostream(0), glvis_client(false)
927 #endif // MFEM_USE_GNUTLS
934 #ifdef MFEM_USE_GNUTLS
937 mfem_error(
"The secure option in class mfem::socketstream can only\n"
938 "be used when GnuTLS support is enabled.");
944 std::iostream::rdbuf(
buf__);
950 #ifdef MFEM_USE_GNUTLS
952 else { setstate(std::ios::failbit); }
974 setstate(std::ios::failbit);
986 #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.
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 mfem_error(const char *msg)
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...