X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/78df1fb1d46d556bfc2698ca1802972b13613ba8..f9d1448f46d3d645e68fdd449758b50a1402d729:/src/gnutls.c diff --git a/src/gnutls.c b/src/gnutls.c index 99992e06cd..03f753fa8c 100644 --- a/src/gnutls.c +++ b/src/gnutls.c @@ -18,7 +18,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include "lisp.h" #include "process.h" @@ -31,15 +30,14 @@ along with GNU Emacs. If not, see . */ #include "w32.h" #endif -static int -emacs_gnutls_handle_error (gnutls_session_t, int err); +static bool emacs_gnutls_handle_error (gnutls_session_t, int); static Lisp_Object Qgnutls_dll; static Lisp_Object Qgnutls_code; static Lisp_Object Qgnutls_anon, Qgnutls_x509pki; static Lisp_Object Qgnutls_e_interrupted, Qgnutls_e_again, Qgnutls_e_invalid_session, Qgnutls_e_not_ready_for_handshake; -static int gnutls_global_initialized; +static bool gnutls_global_initialized; /* The following are for the property list of `gnutls-boot'. */ static Lisp_Object QCgnutls_bootprop_priority; @@ -142,13 +140,13 @@ DEF_GNUTLS_FN (int, gnutls_x509_crt_import, gnutls_x509_crt_fmt_t)); DEF_GNUTLS_FN (int, gnutls_x509_crt_init, (gnutls_x509_crt_t *)); -static int -init_gnutls_functions (Lisp_Object libraries) +static bool +init_gnutls_functions (void) { HMODULE library; int max_log_level = 1; - if (!(library = w32_delayed_load (libraries, Qgnutls_dll))) + if (!(library = w32_delayed_load (Qgnutls_dll))) { GNUTLS_LOG (1, max_log_level, "GnuTLS library not found"); return 0; @@ -200,8 +198,12 @@ init_gnutls_functions (Lisp_Object libraries) max_log_level = global_gnutls_log_level; - GNUTLS_LOG2 (1, max_log_level, "GnuTLS library loaded:", - SDATA (Fget (Qgnutls_dll, QCloaded_from))); + { + Lisp_Object name = CAR_SAFE (Fget (Qgnutls_dll, QCloaded_from)); + GNUTLS_LOG2 (1, max_log_level, "GnuTLS library loaded:", + STRINGP (name) ? (const char *) SDATA (name) : "unknown"); + } + return 1; } @@ -247,18 +249,27 @@ init_gnutls_functions (Lisp_Object libraries) #endif /* !WINDOWSNT */ +/* Function to log a simple message. */ static void gnutls_log_function (int level, const char* string) { message ("gnutls.c: [%d] %s", level, string); } +/* Function to log a message and a string. */ static void gnutls_log_function2 (int level, const char* string, const char* extra) { message ("gnutls.c: [%d] %s %s", level, string, extra); } +/* Function to log a message and an integer. */ +static void +gnutls_log_function2i (int level, const char* string, int extra) +{ + message ("gnutls.c: [%d] %s %d", level, string, extra); +} + static int emacs_gnutls_handshake (struct Lisp_Process *proc) { @@ -309,6 +320,7 @@ emacs_gnutls_handshake (struct Lisp_Process *proc) { ret = fn_gnutls_handshake (state); emacs_gnutls_handle_error (state, ret); + QUIT; } while (ret < 0 && fn_gnutls_error_is_fatal (ret) == 0); @@ -345,15 +357,11 @@ emacs_gnutls_write (struct Lisp_Process *proc, const char *buf, ptrdiff_t nbyte) ptrdiff_t bytes_written; gnutls_session_t state = proc->gnutls_state; - if (proc->gnutls_initstage != GNUTLS_STAGE_READY) { -#ifdef EWOULDBLOCK - errno = EWOULDBLOCK; -#endif -#ifdef EAGAIN - errno = EAGAIN; -#endif - return 0; - } + if (proc->gnutls_initstage != GNUTLS_STAGE_READY) + { + errno = EAGAIN; + return 0; + } bytes_written = 0; @@ -363,10 +371,17 @@ emacs_gnutls_write (struct Lisp_Process *proc, const char *buf, ptrdiff_t nbyte) if (rtnval < 0) { - if (rtnval == GNUTLS_E_AGAIN || rtnval == GNUTLS_E_INTERRUPTED) + if (rtnval == GNUTLS_E_INTERRUPTED) continue; else - break; + { + /* If we get GNUTLS_E_AGAIN, then set errno + appropriately so that send_process retries the + correct way instead of erroring out. */ + if (rtnval == GNUTLS_E_AGAIN) + errno = EAGAIN; + break; + } } buf += rtnval; @@ -384,10 +399,25 @@ emacs_gnutls_read (struct Lisp_Process *proc, char *buf, ptrdiff_t nbyte) ssize_t rtnval; gnutls_session_t state = proc->gnutls_state; + int log_level = proc->gnutls_log_level; + if (proc->gnutls_initstage != GNUTLS_STAGE_READY) { - emacs_gnutls_handshake (proc); - return -1; + /* If the handshake count is under the limit, try the handshake + again and increment the handshake count. This count is kept + per process (connection), not globally. */ + if (proc->gnutls_handshakes_tried < GNUTLS_EMACS_HANDSHAKES_LIMIT) + { + proc->gnutls_handshakes_tried++; + emacs_gnutls_handshake (proc); + GNUTLS_LOG2i (5, log_level, "Retried handshake", + proc->gnutls_handshakes_tried); + return -1; + } + + GNUTLS_LOG (2, log_level, "Giving up on handshake; resetting retries"); + proc->gnutls_handshakes_tried = 0; + return 0; } rtnval = fn_gnutls_record_recv (state, buf, nbyte); if (rtnval >= 0) @@ -395,7 +425,7 @@ emacs_gnutls_read (struct Lisp_Process *proc, char *buf, ptrdiff_t nbyte) else if (rtnval == GNUTLS_E_UNEXPECTED_PACKET_LENGTH) /* The peer closed the connection. */ return 0; - else if (emacs_gnutls_handle_error (state, rtnval) == 0) + else if (emacs_gnutls_handle_error (state, rtnval)) /* non-fatal error */ return -1; else { @@ -404,19 +434,19 @@ emacs_gnutls_read (struct Lisp_Process *proc, char *buf, ptrdiff_t nbyte) } } -/* report a GnuTLS error to the user. - Returns zero if the error code was successfully handled. */ -static int +/* 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; - int ret; + bool ret; const char *str; /* TODO: use a Lisp_Object generated by gnutls_make_error? */ if (err >= 0) - return 0; + return 1; max_log_level = global_gnutls_log_level; @@ -428,12 +458,12 @@ emacs_gnutls_handle_error (gnutls_session_t session, int err) if (fn_gnutls_error_is_fatal (err)) { - ret = err; + ret = 0; GNUTLS_LOG2 (0, max_log_level, "fatal error:", str); } else { - ret = 0; + ret = 1; GNUTLS_LOG2 (1, max_log_level, "non-fatal error:", str); /* TODO: EAGAIN AKA Qgnutls_e_again should be level 2. */ } @@ -613,7 +643,7 @@ DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0, else { Lisp_Object status; - status = init_gnutls_functions (Vdynamic_library_alist) ? Qt : Qnil; + status = init_gnutls_functions () ? Qt : Qnil; Vlibrary_cache = Fcons (Fcons (Qgnutls_dll, status), Vlibrary_cache); return status; } @@ -786,7 +816,7 @@ one trustfile (usually a CA bundle). */) XPROCESS (proc)->gnutls_state = NULL; XPROCESS (proc)->gnutls_x509_cred = NULL; XPROCESS (proc)->gnutls_anon_cred = NULL; - XPROCESS (proc)->gnutls_cred_type = type; + pset_gnutls_cred_type (XPROCESS (proc), type); GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY; GNUTLS_LOG (1, max_log_level, "allocating credentials"); @@ -827,9 +857,9 @@ one trustfile (usually a CA bundle). */) int file_format = GNUTLS_X509_FMT_PEM; Lisp_Object tail; - for (tail = trustfiles; !NILP (tail); tail = Fcdr (tail)) + for (tail = trustfiles; CONSP (tail); tail = XCDR (tail)) { - Lisp_Object trustfile = Fcar (tail); + Lisp_Object trustfile = XCAR (tail); if (STRINGP (trustfile)) { GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ", @@ -849,9 +879,9 @@ one trustfile (usually a CA bundle). */) } } - for (tail = crlfiles; !NILP (tail); tail = Fcdr (tail)) + for (tail = crlfiles; CONSP (tail); tail = XCDR (tail)) { - Lisp_Object crlfile = Fcar (tail); + Lisp_Object crlfile = XCAR (tail); if (STRINGP (crlfile)) { GNUTLS_LOG2 (1, max_log_level, "setting the CRL file: ", @@ -869,10 +899,10 @@ one trustfile (usually a CA bundle). */) } } - for (tail = keylist; !NILP (tail); tail = Fcdr (tail)) + for (tail = keylist; CONSP (tail); tail = XCDR (tail)) { - Lisp_Object keyfile = Fcar (Fcar (tail)); - Lisp_Object certfile = Fcar (Fcdr (tail)); + Lisp_Object keyfile = Fcar (XCAR (tail)); + Lisp_Object certfile = Fcar (Fcdr (XCAR (tail))); if (STRINGP (keyfile) && STRINGP (certfile)) { GNUTLS_LOG2 (1, max_log_level, "setting the client key file: ", @@ -1121,7 +1151,10 @@ syms_of_gnutls (void) defsubr (&Sgnutls_available_p); DEFVAR_INT ("gnutls-log-level", global_gnutls_log_level, - doc: /* Logging level used by the GnuTLS functions. */); + doc: /* Logging level used by the GnuTLS functions. +Set this larger than 0 to get debug output in the *Messages* buffer. +1 is for important messages, 2 is for debug data, and higher numbers +are as per the GnuTLS logging conventions. */); global_gnutls_log_level = 0; }