/* Report a GnuTLS error to the user. Return true if the error code was successfully handled. */ static bool emacs_gnutls_handle_error (gnutls_session_t session, int err) { int max_log_level = 0; bool ret; const char *str; /* TODO: use a Lisp_Object generated by gnutls_make_error? */ if (err >= 0) return 1; max_log_level = global_gnutls_log_level; /* TODO: use gnutls-error-fatalp and gnutls-error-string. */ str = fn_gnutls_strerror (err); if (!str) str = "unknown"; if (fn_gnutls_error_is_fatal (err)) { ret = 0; GNUTLS_LOG2 (0, max_log_level, "fatal error:", str); } else { ret = 1; switch (err) { case GNUTLS_E_AGAIN: GNUTLS_LOG2 (3, max_log_level, "retry:", str); default: GNUTLS_LOG2 (1, max_log_level, "non-fatal error:", str); } } if (err == GNUTLS_E_WARNING_ALERT_RECEIVED || err == GNUTLS_E_FATAL_ALERT_RECEIVED) { int alert = fn_gnutls_alert_get (session); int level = (err == GNUTLS_E_FATAL_ALERT_RECEIVED) ? 0 : 1; str = fn_gnutls_alert_get_name (alert); if (!str) str = "unknown"; GNUTLS_LOG2 (level, max_log_level, "Received alert: ", str); } return ret; }
/* report a GnuTLS error to the user. Returns zero if the error code was successfully handled. */ static int emacs_gnutls_handle_error (gnutls_session_t session, int err) { int max_log_level = 0; int ret; const char *str; /* TODO: use a Lisp_Object generated by gnutls_make_error? */ if (err >= 0) return 0; max_log_level = global_gnutls_log_level; /* TODO: use gnutls-error-fatalp and gnutls-error-string. */ str = fn_gnutls_strerror (err); if (!str) str = "unknown"; if (fn_gnutls_error_is_fatal (err)) { ret = err; GNUTLS_LOG2 (0, max_log_level, "fatal error:", str); } else { ret = 0; GNUTLS_LOG2 (1, max_log_level, "non-fatal error:", str); /* TODO: EAGAIN AKA Qgnutls_e_again should be level 2. */ } if (err == GNUTLS_E_WARNING_ALERT_RECEIVED || err == GNUTLS_E_FATAL_ALERT_RECEIVED) { int alert = fn_gnutls_alert_get (session); int level = (err == GNUTLS_E_FATAL_ALERT_RECEIVED) ? 0 : 1; str = fn_gnutls_alert_get_name (alert); if (!str) str = "unknown"; GNUTLS_LOG2 (level, max_log_level, "Received alert: ", str); } return ret; }
static int emacs_gnutls_handshake (struct Lisp_Process *proc) { gnutls_session_t state = proc->gnutls_state; int ret; if (proc->gnutls_initstage < GNUTLS_STAGE_HANDSHAKE_CANDO) return -1; if (proc->gnutls_initstage < GNUTLS_STAGE_TRANSPORT_POINTERS_SET) { #ifdef WINDOWSNT /* On W32 we cannot transfer socket handles between different runtime libraries, so we tell GnuTLS to use our special push/pull functions. */ fn_gnutls_transport_set_ptr2 (state, (gnutls_transport_ptr_t) proc, (gnutls_transport_ptr_t) proc); fn_gnutls_transport_set_push_function (state, &emacs_gnutls_push); fn_gnutls_transport_set_pull_function (state, &emacs_gnutls_pull); /* For non blocking sockets or other custom made pull/push functions the gnutls_transport_set_lowat must be called, with a zero low water mark value. (GnuTLS 2.10.4 documentation) (Note: this is probably not strictly necessary as the lowat value is only used when no custom pull/push functions are set.) */ /* According to GnuTLS NEWS file, lowat level has been set to zero by default in version 2.11.1, and the function gnutls_transport_set_lowat was removed from the library in version 2.99.0. */ if (!fn_gnutls_check_version ("2.11.1")) fn_gnutls_transport_set_lowat (state, 0); #else /* This is how GnuTLS takes sockets: as file descriptors passed in. For an Emacs process socket, infd and outfd are the same but we use this two-argument version for clarity. */ fn_gnutls_transport_set_ptr2 (state, (gnutls_transport_ptr_t) (long) proc->infd, (gnutls_transport_ptr_t) (long) proc->outfd); #endif proc->gnutls_initstage = GNUTLS_STAGE_TRANSPORT_POINTERS_SET; } do { ret = fn_gnutls_handshake (state); emacs_gnutls_handle_error (state, ret); } while (ret < 0 && fn_gnutls_error_is_fatal (ret) == 0); proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED; if (ret == GNUTLS_E_SUCCESS) { /* Here we're finally done. */ proc->gnutls_initstage = GNUTLS_STAGE_READY; } else { fn_gnutls_alert_send_appropriate (state, ret); } return ret; }