From 0898ca10c0109274d24f91453036c065f9f5c056 Mon Sep 17 00:00:00 2001 From: Juanma Barranquero Date: Wed, 4 May 2011 16:03:16 +0200 Subject: [PATCH] Implement dynamic loading of GnuTLS on Windows. * lisp/term/w32-win.el (dynamic-library-alist): Add `gnutls'. * nt/INSTALL: Clarify GnuTLS support. * src/callproc.c, src/emacs.c: Include lisp.h before src/w32.h, not after. * src/gnutls.c (Qgnutls_dll): Define. (DEF_GNUTLS_FN, LOAD_GNUTLS_FN): New macros. (gnutls_*): Declare function pointers. (init_gnutls_functions): New function to initialize function pointers. (emacs_gnutls_handshake, Fgnutls_error_string, Fgnutls_deinit) (emacs_gnutls_global_init, Fgnutls_bye): Use function pointers. (emacs_gnutls_record_check_pending, emacs_gnutls_transport_set_errno): Wrappers for gnutls_record_check_pending and gnutls_transport_set_errno. (emacs_gnutls_write, emacs_gnutls_read) (emacs_gnutls_handle_error, Fgnutls_error_fatalp) (Fgnutls_available_p): New function. (Fgnutls_boot): Call Fgnutls_available_p. Use function pointers. (syms_of_gnutls) : Initialize and staticpro it. (syms_of_gnutls) : defsubr it. * src/gnutls.h (GNUTLS_EMACS_ERROR_NOT_LOADED): New macro. (emacs_gnutls_write, emacs_gnutls_read): Mark as extern. (emacs_gnutls_record_check_pending, emacs_gnutls_transport_set_errno): Declare. * src/w32.c (QCloaded_from, Vlibrary_cache): Define. (w32_delayed_load): Move from image.c. When loading a library, record its filename in the :loaded-from property of the library id. (globals_of_w32) : Initialize and staticpro them. (emacs_gnutls_pull, emacs_gnutls_push): Call emacs_gnutls_* functions. * src/image.c: Include w32.h. (Vimage_type_cache): Delete. (syms_of_image) : Don't initialize and staticpro it. (CACHE_IMAGE_TYPE, Finit_image_library): Use Vlibrary_cache instead. (w32_delayed_load): Move to w32.c. * src/process.c: Include lisp.h before src/w32.h, not after. (wait_reading_process_output): Call emacs_gnutls_record_check_pending instead of gnutls_record_check_pending. * src/w32.h (VlibraryCache, QCloaded_from, w32_delayed_load): Declare. --- lisp/ChangeLog | 4 + lisp/term/w32-win.el | 15 +- nt/ChangeLog | 4 + nt/INSTALL | 15 +- src/ChangeLog | 45 ++++++ src/callproc.c | 3 +- src/emacs.c | 3 +- src/gnutls.c | 322 ++++++++++++++++++++++++++++++++++++------- src/gnutls.h | 8 +- src/image.c | 41 +----- src/process.c | 7 +- src/w32.c | 62 ++++++++- src/w32.h | 3 + 13 files changed, 420 insertions(+), 112 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 3d7b2c3383..4f6ebe8827 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,7 @@ +2011-05-04 Juanma Barranquero + + * term/w32-win.el (dynamic-library-alist): Add `gnutls'. + 2011-05-04 Glenn Morris * calendar/diary-lib.el (diary-fancy-date-pattern): Turn it into a diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el index f1385a9645..e4bf031d42 100644 --- a/lisp/term/w32-win.el +++ b/lisp/term/w32-win.el @@ -202,13 +202,14 @@ See the documentation of `create-fontset-from-fontset-spec' for the format.") '(png "libpng12d.dll" "libpng12.dll" "libpng3.dll" "libpng.dll" ;; these are libpng 1.2.8 from GTK+ "libpng13d.dll" "libpng13.dll")) - '(jpeg "jpeg62.dll" "libjpeg.dll" "jpeg-62.dll" "jpeg.dll") - '(tiff "libtiff3.dll" "libtiff.dll") - '(gif "giflib4.dll" "libungif4.dll" "libungif.dll") - '(svg "librsvg-2-2.dll") - '(gdk-pixbuf "libgdk_pixbuf-2.0-0.dll") - '(glib "libglib-2.0-0.dll") - '(gobject "libgobject-2.0-0.dll"))) + '(jpeg "jpeg62.dll" "libjpeg.dll" "jpeg-62.dll" "jpeg.dll") + '(tiff "libtiff3.dll" "libtiff.dll") + '(gif "giflib4.dll" "libungif4.dll" "libungif.dll") + '(svg "librsvg-2-2.dll") + '(gdk-pixbuf "libgdk_pixbuf-2.0-0.dll") + '(glib "libglib-2.0-0.dll") + '(gobject "libgobject-2.0-0.dll") + '(gnutls "libgnutls-26.dll"))) ;;; multi-tty support (defvar w32-initialized nil diff --git a/nt/ChangeLog b/nt/ChangeLog index 660140f66c..83080273f5 100644 --- a/nt/ChangeLog +++ b/nt/ChangeLog @@ -1,3 +1,7 @@ +2011-05-04 Juanma Barranquero + + * INSTALL: Clarify GnuTLS support. + 2011-04-30 Eli Zaretskii * config.nt (HAVE_LONG_LONG_INT, HAVE_UNSIGNED_LONG_LONG_INT): diff --git a/nt/INSTALL b/nt/INSTALL index dc57cd20b8..2a1a9aaab1 100644 --- a/nt/INSTALL +++ b/nt/INSTALL @@ -325,12 +325,17 @@ * Optional GnuTLS support - You can build Emacs with GnuTLS support. Put the gnutls/gnutls.h header in - the include path and link to the appropriate libraries (gnutls.dll and - gcrypt.dll) with the --lib option. + If configure.bat finds the gnutls/gnutls.h file in the include path, + Emacs is built with GnuTLS support by default; to avoid that you can + pass the argument --without-gnutls. - You can get pre-built binaries and an installer at - http://josefsson.org/gnutls4win/. + In order to support GnuTLS at runtime, a GnuTLS-enabled Emacs must + be able to find the relevant DLLs during startup; failure to do so + is not an error, but GnuTLS won't be available to the running + session. + + You can get pre-built binaries (including any required DLL and the + gnutls.h file) and an installer at http://josefsson.org/gnutls4win/. * Experimental SVG support diff --git a/src/ChangeLog b/src/ChangeLog index bc6b89f145..9e1705339d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,48 @@ +2011-05-04 Juanma Barranquero + + Implement dynamic loading of GnuTLS on Windows. + + * gnutls.h (GNUTLS_EMACS_ERROR_NOT_LOADED): New macro. + (emacs_gnutls_write, emacs_gnutls_read): Mark as extern. + (emacs_gnutls_record_check_pending, emacs_gnutls_transport_set_errno): + Declare. + + * gnutls.c (Qgnutls_dll): Define. + (DEF_GNUTLS_FN, LOAD_GNUTLS_FN): New macros. + (gnutls_*): Declare function pointers. + (init_gnutls_functions): New function to initialize function pointers. + (emacs_gnutls_handshake, Fgnutls_error_string, Fgnutls_deinit) + (emacs_gnutls_global_init, Fgnutls_bye): Use function pointers. + (emacs_gnutls_record_check_pending, emacs_gnutls_transport_set_errno): + Wrappers for gnutls_record_check_pending and gnutls_transport_set_errno. + (emacs_gnutls_write, emacs_gnutls_read) + (emacs_gnutls_handle_error, Fgnutls_error_fatalp) + (Fgnutls_available_p): New function. + (Fgnutls_boot): Call Fgnutls_available_p. Use function pointers. + (syms_of_gnutls) : Initialize and staticpro it. + (syms_of_gnutls) : defsubr it. + + * image.c: Include w32.h. + (Vimage_type_cache): Delete. + (syms_of_image) : Don't initialize and staticpro it. + (CACHE_IMAGE_TYPE, Finit_image_library): Use Vlibrary_cache instead. + (w32_delayed_load): Move to w32.c. + + * w32.h (VlibraryCache, QCloaded_from, w32_delayed_load): Declare. + + * w32.c (QCloaded_from, Vlibrary_cache): Define. + (w32_delayed_load): Move from image.c. When loading a library, record + its filename in the :loaded-from property of the library id. + (globals_of_w32) : + Initialize and staticpro them. + (emacs_gnutls_pull, emacs_gnutls_push): Call emacs_gnutls_* functions. + + * process.c: Include lisp.h before w32.h, not after. + (wait_reading_process_output): Call emacs_gnutls_record_check_pending + instead of gnutls_record_check_pending. + + * callproc.c, emacs.c: Include lisp.h before w32.h, not after. + 2011-05-04 Teodor Zlatanov * gnutls.c (Fgnutls_boot): Support :keylist and :crlfiles options diff --git a/src/callproc.c b/src/callproc.c index 4a29e95b35..1d3d8764ff 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -29,6 +29,8 @@ along with GNU Emacs. If not, see . */ #include #include +#include "lisp.h" + #ifdef WINDOWSNT #define NOMINMAX #include @@ -41,7 +43,6 @@ along with GNU Emacs. If not, see . */ #include #endif /* MSDOS */ -#include "lisp.h" #include "commands.h" #include "buffer.h" #include "character.h" diff --git a/src/emacs.c b/src/emacs.c index 0a132e156a..8c4490b0a5 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -29,6 +29,8 @@ along with GNU Emacs. If not, see . */ #include #include +#include "lisp.h" + #ifdef WINDOWSNT #include #include /* just for w32.h */ @@ -41,7 +43,6 @@ along with GNU Emacs. If not, see . */ #include #endif -#include "lisp.h" #include "commands.h" #include "intervals.h" #include "buffer.h" diff --git a/src/gnutls.c b/src/gnutls.c index fd970910d2..7e821ccd41 100644 --- a/src/gnutls.c +++ b/src/gnutls.c @@ -34,6 +34,7 @@ along with GNU Emacs. If not, see . */ static int emacs_gnutls_handle_error (gnutls_session_t, int err); +static Lisp_Object Qgnutls_dll; static Lisp_Object Qgnutls_log_level; static Lisp_Object Qgnutls_code; static Lisp_Object Qgnutls_anon, Qgnutls_x509pki; @@ -56,6 +57,181 @@ static Lisp_Object Qgnutls_bootprop_verify_hostname_error; /* Callback keys for `gnutls-boot'. Unused currently. */ static Lisp_Object Qgnutls_bootprop_callbacks_verify; +static void gnutls_log_function (int, const char *); +static void gnutls_log_function2 (int, const char*, const char*); + + +#ifdef WINDOWSNT + +/* Macro for defining functions that will be loaded from the GnuTLS DLL. */ +#define DEF_GNUTLS_FN(rettype,func,args) rettype (FAR CDECL *fn_##func)args + +/* Macro for loading GnuTLS functions from the library. */ +#define LOAD_GNUTLS_FN(lib,func) { \ + fn_##func = (void *) GetProcAddress (lib, #func); \ + if (!fn_##func) return 0; \ + } + +DEF_GNUTLS_FN (gnutls_alert_description_t, gnutls_alert_get, + (gnutls_session_t)); +DEF_GNUTLS_FN (const char *, gnutls_alert_get_name, + (gnutls_alert_description_t)); +DEF_GNUTLS_FN (int, gnutls_alert_send_appropriate, (gnutls_session_t, int)); +DEF_GNUTLS_FN (int, gnutls_anon_allocate_client_credentials, + (gnutls_anon_client_credentials_t *)); +DEF_GNUTLS_FN (void, gnutls_anon_free_client_credentials, + (gnutls_anon_client_credentials_t)); +DEF_GNUTLS_FN (int, gnutls_bye, (gnutls_session_t, gnutls_close_request_t)); +DEF_GNUTLS_FN (int, gnutls_certificate_allocate_credentials, + (gnutls_certificate_credentials_t *)); +DEF_GNUTLS_FN (void, gnutls_certificate_free_credentials, + (gnutls_certificate_credentials_t)); +DEF_GNUTLS_FN (const gnutls_datum_t *, gnutls_certificate_get_peers, + (gnutls_session_t, unsigned int *)); +DEF_GNUTLS_FN (void, gnutls_certificate_set_verify_flags, + (gnutls_certificate_credentials_t, unsigned int)); +DEF_GNUTLS_FN (int, gnutls_certificate_set_x509_crl_file, + (gnutls_certificate_credentials_t, const char *, + gnutls_x509_crt_fmt_t)); +DEF_GNUTLS_FN (int, gnutls_certificate_set_x509_key_file, + (gnutls_certificate_credentials_t, const char *, const char *, + gnutls_x509_crt_fmt_t)); +DEF_GNUTLS_FN (int, gnutls_certificate_set_x509_trust_file, + (gnutls_certificate_credentials_t, const char *, + gnutls_x509_crt_fmt_t)); +DEF_GNUTLS_FN (gnutls_certificate_type_t, gnutls_certificate_type_get, + (gnutls_session_t)); +DEF_GNUTLS_FN (int, gnutls_certificate_verify_peers2, + (gnutls_session_t, unsigned int *)); +DEF_GNUTLS_FN (int, gnutls_credentials_set, + (gnutls_session_t, gnutls_credentials_type_t, void *)); +DEF_GNUTLS_FN (void, gnutls_deinit, (gnutls_session_t)); +DEF_GNUTLS_FN (int, gnutls_error_is_fatal, (int)); +DEF_GNUTLS_FN (int, gnutls_global_init, (void)); +DEF_GNUTLS_FN (void, gnutls_global_set_log_function, (gnutls_log_func)); +DEF_GNUTLS_FN (void, gnutls_global_set_log_level, (int)); +DEF_GNUTLS_FN (int, gnutls_handshake, (gnutls_session_t)); +DEF_GNUTLS_FN (int, gnutls_init, (gnutls_session_t *, gnutls_connection_end_t)); +DEF_GNUTLS_FN (int, gnutls_priority_set_direct, + (gnutls_session_t, const char *, const char **)); +DEF_GNUTLS_FN (size_t, gnutls_record_check_pending, (gnutls_session_t)); +DEF_GNUTLS_FN (ssize_t, gnutls_record_recv, (gnutls_session_t, void *, size_t)); +DEF_GNUTLS_FN (ssize_t, gnutls_record_send, + (gnutls_session_t, const void *, size_t)); +DEF_GNUTLS_FN (const char *, gnutls_strerror, (int)); +DEF_GNUTLS_FN (void, gnutls_transport_set_errno, (gnutls_session_t, int)); +DEF_GNUTLS_FN (void, gnutls_transport_set_lowat, (gnutls_session_t, int)); +DEF_GNUTLS_FN (void, gnutls_transport_set_ptr2, + (gnutls_session_t, gnutls_transport_ptr_t, + gnutls_transport_ptr_t)); +DEF_GNUTLS_FN (void, gnutls_transport_set_pull_function, + (gnutls_session_t, gnutls_pull_func)); +DEF_GNUTLS_FN (void, gnutls_transport_set_push_function, + (gnutls_session_t, gnutls_push_func)); +DEF_GNUTLS_FN (int, gnutls_x509_crt_check_hostname, + (gnutls_x509_crt_t, const char *)); +DEF_GNUTLS_FN (void, gnutls_x509_crt_deinit, (gnutls_x509_crt_t)); +DEF_GNUTLS_FN (int, gnutls_x509_crt_import, + (gnutls_x509_crt_t, const gnutls_datum_t *, + 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) +{ + HMODULE library; + + if (!(library = w32_delayed_load (libraries, Qgnutls_dll))) + { + GNUTLS_LOG (1, 1, "GnuTLS library not found"); + return 0; + } + + LOAD_GNUTLS_FN (library, gnutls_alert_get); + LOAD_GNUTLS_FN (library, gnutls_alert_get_name); + LOAD_GNUTLS_FN (library, gnutls_alert_send_appropriate); + LOAD_GNUTLS_FN (library, gnutls_anon_allocate_client_credentials); + LOAD_GNUTLS_FN (library, gnutls_anon_free_client_credentials); + LOAD_GNUTLS_FN (library, gnutls_bye); + LOAD_GNUTLS_FN (library, gnutls_certificate_allocate_credentials); + LOAD_GNUTLS_FN (library, gnutls_certificate_free_credentials); + LOAD_GNUTLS_FN (library, gnutls_certificate_get_peers); + LOAD_GNUTLS_FN (library, gnutls_certificate_set_verify_flags); + LOAD_GNUTLS_FN (library, gnutls_certificate_set_x509_crl_file); + LOAD_GNUTLS_FN (library, gnutls_certificate_set_x509_key_file); + LOAD_GNUTLS_FN (library, gnutls_certificate_set_x509_trust_file); + LOAD_GNUTLS_FN (library, gnutls_certificate_type_get); + LOAD_GNUTLS_FN (library, gnutls_certificate_verify_peers2); + LOAD_GNUTLS_FN (library, gnutls_credentials_set); + LOAD_GNUTLS_FN (library, gnutls_deinit); + LOAD_GNUTLS_FN (library, gnutls_error_is_fatal); + LOAD_GNUTLS_FN (library, gnutls_global_init); + LOAD_GNUTLS_FN (library, gnutls_global_set_log_function); + LOAD_GNUTLS_FN (library, gnutls_global_set_log_level); + LOAD_GNUTLS_FN (library, gnutls_handshake); + LOAD_GNUTLS_FN (library, gnutls_init); + LOAD_GNUTLS_FN (library, gnutls_priority_set_direct); + LOAD_GNUTLS_FN (library, gnutls_record_check_pending); + LOAD_GNUTLS_FN (library, gnutls_record_recv); + LOAD_GNUTLS_FN (library, gnutls_record_send); + LOAD_GNUTLS_FN (library, gnutls_strerror); + LOAD_GNUTLS_FN (library, gnutls_transport_set_errno); + LOAD_GNUTLS_FN (library, gnutls_transport_set_lowat); + LOAD_GNUTLS_FN (library, gnutls_transport_set_ptr2); + LOAD_GNUTLS_FN (library, gnutls_transport_set_pull_function); + LOAD_GNUTLS_FN (library, gnutls_transport_set_push_function); + LOAD_GNUTLS_FN (library, gnutls_x509_crt_check_hostname); + LOAD_GNUTLS_FN (library, gnutls_x509_crt_deinit); + LOAD_GNUTLS_FN (library, gnutls_x509_crt_import); + LOAD_GNUTLS_FN (library, gnutls_x509_crt_init); + + GNUTLS_LOG2 (1, 1, "GnuTLS library loaded:", + SDATA (Fget (Qgnutls_dll, QCloaded_from))); + return 1; +} + +#else /* !WINDOWSNT */ + +#define fn_gnutls_alert_get gnutls_alert_get +#define fn_gnutls_alert_get_name gnutls_alert_get_name +#define fn_gnutls_alert_send_appropriate gnutls_alert_send_appropriate +#define fn_gnutls_anon_allocate_client_credentials gnutls_anon_allocate_client_credentials +#define fn_gnutls_anon_free_client_credentials gnutls_anon_free_client_credentials +#define fn_gnutls_bye gnutls_bye +#define fn_gnutls_certificate_allocate_credentials gnutls_certificate_allocate_credentials +#define fn_gnutls_certificate_free_credentials gnutls_certificate_free_credentials +#define fn_gnutls_certificate_get_peers gnutls_certificate_get_peers +#define fn_gnutls_certificate_set_verify_flags gnutls_certificate_set_verify_flags +#define fn_gnutls_certificate_set_x509_crl_file gnutls_certificate_set_x509_crl_file +#define fn_gnutls_certificate_set_x509_trust_file gnutls_certificate_set_x509_trust_file +#define fn_gnutls_certificate_type_get gnutls_certificate_type_get +#define fn_gnutls_certificate_verify_peers2 gnutls_certificate_verify_peers2 +#define fn_gnutls_credentials_set gnutls_credentials_set +#define fn_gnutls_deinit gnutls_deinit +#define fn_gnutls_error_is_fatal gnutls_error_is_fatal +#define fn_gnutls_global_init gnutls_global_init +#define fn_gnutls_global_set_log_function gnutls_global_set_log_function +#define fn_gnutls_global_set_log_level gnutls_global_set_log_level +#define fn_gnutls_handshake gnutls_handshake +#define fn_gnutls_init gnutls_init +#define fn_gnutls_priority_set_direct gnutls_priority_set_direct +#define fn_gnutls_record_check_pending gnutls_record_check_pending +#define fn_gnutls_record_recv gnutls_record_recv +#define fn_gnutls_record_send gnutls_record_send +#define fn_gnutls_strerror gnutls_strerror +#define fn_gnutls_transport_set_errno gnutls_transport_set_errno +#define fn_gnutls_transport_set_lowat gnutls_transport_set_lowat +#define fn_gnutls_transport_set_ptr2 gnutls_transport_set_ptr2 +#define fn_gnutls_transport_set_pull_function gnutls_transport_set_pull_function +#define fn_gnutls_transport_set_push_function gnutls_transport_set_push_function +#define fn_gnutls_x509_crt_check_hostname gnutls_x509_crt_check_hostname +#define fn_gnutls_x509_crt_deinit gnutls_x509_crt_deinit +#define fn_gnutls_x509_crt_import gnutls_x509_crt_import +#define fn_gnutls_x509_crt_init gnutls_x509_crt_init + +#endif /* !WINDOWSNT */ + + static void gnutls_log_function (int level, const char* string) { @@ -83,11 +259,11 @@ emacs_gnutls_handshake (struct Lisp_Process *proc) /* On W32 we cannot transfer socket handles between different runtime libraries, so we tell GnuTLS to use our special push/pull functions. */ - gnutls_transport_set_ptr2 (state, - (gnutls_transport_ptr_t) proc, - (gnutls_transport_ptr_t) proc); - gnutls_transport_set_push_function (state, &emacs_gnutls_push); - gnutls_transport_set_pull_function (state, &emacs_gnutls_pull); + 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 @@ -96,14 +272,14 @@ emacs_gnutls_handshake (struct Lisp_Process *proc) (Note: this is probably not strictly necessary as the lowat value is only used when no custom pull/push functions are set.) */ - gnutls_transport_set_lowat (state, 0); + 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. */ - gnutls_transport_set_ptr2 (state, - (gnutls_transport_ptr_t) (long) proc->infd, - (gnutls_transport_ptr_t) (long) proc->outfd); + 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; @@ -111,10 +287,10 @@ emacs_gnutls_handshake (struct Lisp_Process *proc) do { - ret = gnutls_handshake (state); + ret = fn_gnutls_handshake (state); emacs_gnutls_handle_error (state, ret); } - while (ret < 0 && gnutls_error_is_fatal (ret) == 0); + while (ret < 0 && fn_gnutls_error_is_fatal (ret) == 0); proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED; @@ -125,11 +301,23 @@ emacs_gnutls_handshake (struct Lisp_Process *proc) } else { - gnutls_alert_send_appropriate (state, ret); + fn_gnutls_alert_send_appropriate (state, ret); } return ret; } +int +emacs_gnutls_record_check_pending (gnutls_session_t state) +{ + return fn_gnutls_record_check_pending (state); +} + +void +emacs_gnutls_transport_set_errno (gnutls_session_t state, int err) +{ + fn_gnutls_transport_set_errno (state, err); +} + EMACS_INT emacs_gnutls_write (int fildes, struct Lisp_Process *proc, const char *buf, EMACS_INT nbyte) @@ -152,7 +340,7 @@ emacs_gnutls_write (int fildes, struct Lisp_Process *proc, const char *buf, while (nbyte > 0) { - rtnval = gnutls_write (state, buf, nbyte); + rtnval = fn_gnutls_record_send (state, buf, nbyte); if (rtnval < 0) { @@ -183,7 +371,7 @@ emacs_gnutls_read (int fildes, struct Lisp_Process *proc, char *buf, emacs_gnutls_handshake (proc); return -1; } - rtnval = gnutls_read (state, buf, nbyte); + rtnval = fn_gnutls_record_recv (state, buf, nbyte); if (rtnval >= 0) return rtnval; else if (emacs_gnutls_handle_error (state, rtnval) == 0) @@ -215,11 +403,11 @@ emacs_gnutls_handle_error (gnutls_session_t session, int err) /* TODO: use gnutls-error-fatalp and gnutls-error-string. */ - str = gnutls_strerror (err); + str = fn_gnutls_strerror (err); if (!str) str = "unknown"; - if (gnutls_error_is_fatal (err)) + if (fn_gnutls_error_is_fatal (err)) { ret = err; GNUTLS_LOG2 (0, max_log_level, "fatal error:", str); @@ -234,9 +422,9 @@ emacs_gnutls_handle_error (gnutls_session_t session, int err) if (err == GNUTLS_E_WARNING_ALERT_RECEIVED || err == GNUTLS_E_FATAL_ALERT_RECEIVED) { - int alert = gnutls_alert_get (session); + int alert = fn_gnutls_alert_get (session); int level = (err == GNUTLS_E_FATAL_ALERT_RECEIVED) ? 0 : 1; - str = gnutls_alert_get_name (alert); + str = fn_gnutls_alert_get_name (alert); if (!str) str = "unknown"; @@ -314,7 +502,7 @@ usage: (gnutls-error-fatalp ERROR) */) if (!NUMBERP (err)) error ("Not an error symbol or code"); - if (0 == gnutls_error_is_fatal (XINT (err))) + if (0 == fn_gnutls_error_is_fatal (XINT (err))) return Qnil; return Qt; @@ -346,7 +534,7 @@ usage: (gnutls-error-string ERROR) */) if (!NUMBERP (err)) return build_string ("Not an error symbol or code"); - return build_string (gnutls_strerror (XINT (err))); + return build_string (fn_gnutls_strerror (XINT (err))); } DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0, @@ -361,13 +549,34 @@ See also `gnutls-init'. */) if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT) { - gnutls_deinit (state); + fn_gnutls_deinit (state); GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1; } return Qt; } +DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0, + doc: /* Return t if GnuTLS is available in this instance of Emacs. */) + (void) +{ +#ifdef WINDOWSNT + Lisp_Object found = Fassq (Qgnutls_dll, Vlibrary_cache); + if (CONSP (found)) + return XCDR (found); + else + { + Lisp_Object status; + status = init_gnutls_functions (Vdynamic_library_alist) ? Qt : Qnil; + Vlibrary_cache = Fcons (Fcons (Qgnutls_dll, status), Vlibrary_cache); + return status; + } +#else + return Qt; +#endif +} + + /* Initializes global GnuTLS state to defaults. Call `gnutls-global-deinit' when GnuTLS usage is no longer needed. Returns zero on success. */ @@ -377,8 +586,7 @@ emacs_gnutls_global_init (void) int ret = GNUTLS_E_SUCCESS; if (!gnutls_global_initialized) - ret = gnutls_global_init (); - + ret = fn_gnutls_global_init (); gnutls_global_initialized = 1; return gnutls_make_error (ret); @@ -488,6 +696,12 @@ one trustfile (usually a CA bundle). */) CHECK_SYMBOL (type); CHECK_LIST (proplist); + if (NILP (Fgnutls_available_p ())) + { + error ("GnuTLS not available"); + return gnutls_make_error (GNUTLS_EMACS_ERROR_NOT_LOADED); + } + hostname = Fplist_get (proplist, Qgnutls_bootprop_hostname); priority_string = Fplist_get (proplist, Qgnutls_bootprop_priority); trustfiles = Fplist_get (proplist, Qgnutls_bootprop_trustfiles); @@ -509,8 +723,8 @@ one trustfile (usually a CA bundle). */) if (NUMBERP (loglevel)) { - gnutls_global_set_log_function (gnutls_log_function); - gnutls_global_set_log_level (XINT (loglevel)); + fn_gnutls_global_set_log_function (gnutls_log_function); + fn_gnutls_global_set_log_level (XINT (loglevel)); max_log_level = XINT (loglevel); XPROCESS (proc)->gnutls_log_level = max_log_level; } @@ -529,13 +743,13 @@ one trustfile (usually a CA bundle). */) { GNUTLS_LOG (2, max_log_level, "deallocating x509 credentials"); x509_cred = XPROCESS (proc)->gnutls_x509_cred; - gnutls_certificate_free_credentials (x509_cred); + fn_gnutls_certificate_free_credentials (x509_cred); } else if (EQ (type, Qgnutls_anon)) { GNUTLS_LOG (2, max_log_level, "deallocating anon credentials"); anon_cred = XPROCESS (proc)->gnutls_anon_cred; - gnutls_anon_free_client_credentials (anon_cred); + fn_gnutls_anon_free_client_credentials (anon_cred); } else { @@ -558,7 +772,7 @@ one trustfile (usually a CA bundle). */) { GNUTLS_LOG (2, max_log_level, "allocating x509 credentials"); x509_cred = XPROCESS (proc)->gnutls_x509_cred; - if (gnutls_certificate_allocate_credentials (&x509_cred) < 0) + if (fn_gnutls_certificate_allocate_credentials (&x509_cred) < 0) memory_full (); if (NUMBERP (verify_flags)) @@ -576,13 +790,13 @@ one trustfile (usually a CA bundle). */) /* The default is already GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT. */ GNUTLS_LOG (2, max_log_level, "ignoring invalid verify-flags"); } - gnutls_certificate_set_verify_flags (x509_cred, gnutls_verify_flags); + fn_gnutls_certificate_set_verify_flags (x509_cred, gnutls_verify_flags); } else if (EQ (type, Qgnutls_anon)) { GNUTLS_LOG (2, max_log_level, "allocating anon credentials"); anon_cred = XPROCESS (proc)->gnutls_anon_cred; - if (gnutls_anon_allocate_client_credentials (&anon_cred) < 0) + if (fn_gnutls_anon_allocate_client_credentials (&anon_cred) < 0) memory_full (); } else @@ -605,7 +819,7 @@ one trustfile (usually a CA bundle). */) { GNUTLS_LOG2 (1, max_log_level, "setting the trustfile: ", SSDATA (trustfile)); - ret = gnutls_certificate_set_x509_trust_file + ret = fn_gnutls_certificate_set_x509_trust_file (x509_cred, SSDATA (trustfile), file_format); @@ -627,7 +841,7 @@ one trustfile (usually a CA bundle). */) { GNUTLS_LOG2 (1, max_log_level, "setting the CRL file: ", SSDATA (crlfile)); - ret = gnutls_certificate_set_x509_crl_file + ret = fn_gnutls_certificate_set_x509_crl_file (x509_cred, SSDATA (crlfile), file_format); @@ -652,7 +866,7 @@ one trustfile (usually a CA bundle). */) SSDATA (keyfile)); GNUTLS_LOG2 (1, max_log_level, "setting the client cert file: ", SSDATA (certfile)); - ret = gnutls_certificate_set_x509_key_file + ret = fn_gnutls_certificate_set_x509_key_file (x509_cred, SSDATA (certfile), SSDATA (keyfile), @@ -685,7 +899,7 @@ one trustfile (usually a CA bundle). */) GNUTLS_LOG (1, max_log_level, "gnutls_init"); - ret = gnutls_init (&state, GNUTLS_CLIENT); + ret = fn_gnutls_init (&state, GNUTLS_CLIENT); if (ret < GNUTLS_E_SUCCESS) return gnutls_make_error (ret); @@ -708,9 +922,9 @@ one trustfile (usually a CA bundle). */) GNUTLS_LOG (1, max_log_level, "setting the priority string"); - ret = gnutls_priority_set_direct (state, - priority_string_ptr, - NULL); + ret = fn_gnutls_priority_set_direct (state, + priority_string_ptr, + NULL); if (ret < GNUTLS_E_SUCCESS) return gnutls_make_error (ret); @@ -719,11 +933,11 @@ one trustfile (usually a CA bundle). */) if (EQ (type, Qgnutls_x509pki)) { - ret = gnutls_cred_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred); + ret = fn_gnutls_credentials_set (state, GNUTLS_CRD_CERTIFICATE, x509_cred); } else if (EQ (type, Qgnutls_anon)) { - ret = gnutls_cred_set (state, GNUTLS_CRD_ANON, anon_cred); + ret = fn_gnutls_credentials_set (state, GNUTLS_CRD_ANON, anon_cred); } else { @@ -751,7 +965,7 @@ one trustfile (usually a CA bundle). */) check of the certificate's hostname with gnutls_x509_crt_check_hostname() against :hostname. */ - ret = gnutls_certificate_verify_peers2 (state, &peer_verification); + ret = fn_gnutls_certificate_verify_peers2 (state, &peer_verification); if (ret < GNUTLS_E_SUCCESS) return gnutls_make_error (ret); @@ -802,15 +1016,15 @@ one trustfile (usually a CA bundle). */) /* Up to here the process is the same for X.509 certificates and OpenPGP keys. From now on X.509 certificates are assumed. This can be easily extended to work with openpgp keys as well. */ - if (gnutls_certificate_type_get (state) == GNUTLS_CRT_X509) + if (fn_gnutls_certificate_type_get (state) == GNUTLS_CRT_X509) { - ret = gnutls_x509_crt_init (&gnutls_verify_cert); + ret = fn_gnutls_x509_crt_init (&gnutls_verify_cert); if (ret < GNUTLS_E_SUCCESS) return gnutls_make_error (ret); gnutls_verify_cert_list = - gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size); + fn_gnutls_certificate_get_peers (state, &gnutls_verify_cert_list_size); if (NULL == gnutls_verify_cert_list) { @@ -818,17 +1032,17 @@ one trustfile (usually a CA bundle). */) } /* We only check the first certificate in the given chain. */ - ret = gnutls_x509_crt_import (gnutls_verify_cert, - &gnutls_verify_cert_list[0], - GNUTLS_X509_FMT_DER); + ret = fn_gnutls_x509_crt_import (gnutls_verify_cert, + &gnutls_verify_cert_list[0], + GNUTLS_X509_FMT_DER); if (ret < GNUTLS_E_SUCCESS) { - gnutls_x509_crt_deinit (gnutls_verify_cert); + fn_gnutls_x509_crt_deinit (gnutls_verify_cert); return gnutls_make_error (ret); } - if (!gnutls_x509_crt_check_hostname (gnutls_verify_cert, c_hostname)) + if (!fn_gnutls_x509_crt_check_hostname (gnutls_verify_cert, c_hostname)) { if (NILP (verify_hostname_error)) { @@ -837,13 +1051,13 @@ one trustfile (usually a CA bundle). */) } else { - gnutls_x509_crt_deinit (gnutls_verify_cert); + fn_gnutls_x509_crt_deinit (gnutls_verify_cert); error ("The x509 certificate does not match \"%s\"", c_hostname); } } - gnutls_x509_crt_deinit (gnutls_verify_cert); + fn_gnutls_x509_crt_deinit (gnutls_verify_cert); } return gnutls_make_error (ret); @@ -872,8 +1086,8 @@ This function may also return `gnutls-e-again', or state = XPROCESS (proc)->gnutls_state; - ret = gnutls_bye (state, - NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR); + ret = fn_gnutls_bye (state, + NILP (cont) ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR); return gnutls_make_error (ret); } @@ -883,6 +1097,9 @@ syms_of_gnutls (void) { gnutls_global_initialized = 0; + Qgnutls_dll = intern_c_string ("gnutls"); + staticpro (&Qgnutls_dll); + Qgnutls_log_level = intern_c_string ("gnutls-log-level"); staticpro (&Qgnutls_log_level); @@ -956,6 +1173,7 @@ syms_of_gnutls (void) defsubr (&Sgnutls_boot); defsubr (&Sgnutls_deinit); defsubr (&Sgnutls_bye); + defsubr (&Sgnutls_available_p); } #endif /* HAVE_GNUTLS */ diff --git a/src/gnutls.h b/src/gnutls.h index 6c2e4c6952..afe6337fac 100644 --- a/src/gnutls.h +++ b/src/gnutls.h @@ -42,6 +42,7 @@ typedef enum GNUTLS_STAGE_READY, } gnutls_initstage_t; +#define GNUTLS_EMACS_ERROR_NOT_LOADED GNUTLS_E_APPLICATION_ERROR_MIN + 1 #define GNUTLS_EMACS_ERROR_INVALID_TYPE GNUTLS_E_APPLICATION_ERROR_MIN #define GNUTLS_INITSTAGE(proc) (XPROCESS (proc)->gnutls_initstage) @@ -52,13 +53,16 @@ typedef enum #define GNUTLS_LOG2(level, max, string, extra) if (level <= max) { gnutls_log_function2 (level, "(Emacs) " string, extra); } -EMACS_INT +extern EMACS_INT emacs_gnutls_write (int fildes, struct Lisp_Process *proc, const char *buf, EMACS_INT nbyte); -EMACS_INT +extern EMACS_INT emacs_gnutls_read (int fildes, struct Lisp_Process *proc, char *buf, EMACS_INT nbyte); +extern int emacs_gnutls_record_check_pending (gnutls_session_t state); +extern void emacs_gnutls_transport_set_errno (gnutls_session_t state, int err); + extern void syms_of_gnutls (void); #endif diff --git a/src/image.c b/src/image.c index 6feeb75afd..2377b41735 100644 --- a/src/image.c +++ b/src/image.c @@ -67,6 +67,7 @@ typedef struct x_bitmap_record Bitmap_Record; #ifdef HAVE_NTGUI +#include "w32.h" #include "w32term.h" /* W32_TODO : Color tables on W32. */ @@ -556,10 +557,6 @@ x_create_bitmap_mask (struct frame *f, int id) static struct image_type *image_types; -/* Cache for delayed-loading image types. */ - -static Lisp_Object Vimage_type_cache; - /* The symbol `xbm' which is used as the type symbol for XBM images. */ static Lisp_Object Qxbm; @@ -589,7 +586,7 @@ static int x_build_heuristic_mask (struct frame *, struct image *, Lisp_Object); #define CACHE_IMAGE_TYPE(type, status) \ - do { Vimage_type_cache = Fcons (Fcons (type, status), Vimage_type_cache); } while (0) + do { Vlibrary_cache = Fcons (Fcons (type, status), Vlibrary_cache); } while (0) #define ADD_IMAGE_TYPE(type) \ do { Vimage_types = Fcons (type, Vimage_types); } while (0) @@ -1900,34 +1897,6 @@ mark_image_cache (struct image_cache *c) if (!fn_##func) return 0; \ } -/* Load a DLL implementing an image type. - The argument LIBRARIES is usually the variable - `dynamic-library-alist', which associates a symbol, identifying - an external DLL library, to a list of possible filenames. - The function returns NULL if no library could be loaded for - the given symbol, or if the library was previously loaded; - else the handle of the DLL. */ -static HMODULE -w32_delayed_load (Lisp_Object libraries, Lisp_Object type) -{ - HMODULE library = NULL; - - if (CONSP (libraries) && NILP (Fassq (type, Vimage_type_cache))) - { - Lisp_Object dlls = Fassq (type, libraries); - - if (CONSP (dlls)) - for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls)) - { - CHECK_STRING_CAR (dlls); - if (library = LoadLibrary (SDATA (XCAR (dlls)))) - break; - } - } - - return library; -} - #endif /* HAVE_NTGUI */ static int x_create_x_image_and_pixmap (struct frame *, int, int, int, @@ -5452,7 +5421,6 @@ init_png_functions (Lisp_Object libraries) { HMODULE library; - /* Try loading libpng under probable names. */ if (!(library = w32_delayed_load (libraries, Qpng))) return 0; @@ -8634,7 +8602,7 @@ of `dynamic-library-alist', which see). */) Lisp_Object tested; /* Don't try to reload the library. */ - tested = Fassq (type, Vimage_type_cache); + tested = Fassq (type, Vlibrary_cache); if (CONSP (tested)) return XCDR (tested); @@ -8714,9 +8682,6 @@ as a ratio to the frame height and width. If the value is non-numeric, there is no explicit limit on the size of images. */); Vmax_image_size = make_float (MAX_IMAGE_SIZE); - Vimage_type_cache = Qnil; - staticpro (&Vimage_type_cache); - Qpbm = intern_c_string ("pbm"); staticpro (&Qpbm); ADD_IMAGE_TYPE (Qpbm); diff --git a/src/process.c b/src/process.c index 5370307830..454f7d8a9a 100644 --- a/src/process.c +++ b/src/process.c @@ -33,6 +33,8 @@ along with GNU Emacs. If not, see . */ #include #include +#include "lisp.h" + /* Only MS-DOS does not define `subprocesses'. */ #ifdef subprocesses @@ -77,7 +79,6 @@ along with GNU Emacs. If not, see . */ #endif /* subprocesses */ -#include "lisp.h" #include "systime.h" #include "systty.h" @@ -4537,10 +4538,10 @@ wait_reading_process_output (int time_limit, int microsecs, int read_kbd, some data in the TCP buffers so that select works, but with custom pull/push functions we need to check if some data is available in the buffers manually. */ - if (nfds == 0 && + if (nfds == 0 && wait_proc && wait_proc->gnutls_p /* Check for valid process. */ /* Do we have pending data? */ - && gnutls_record_check_pending (wait_proc->gnutls_state) > 0) + && emacs_gnutls_record_check_pending (wait_proc->gnutls_state) > 0) { nfds = 1; /* Set to Available. */ diff --git a/src/w32.c b/src/w32.c index 230ccc8de1..d81fdf3305 100644 --- a/src/w32.c +++ b/src/w32.c @@ -150,6 +150,8 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX { typedef HRESULT (WINAPI * ShGetFolderPath_fn) (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *); +Lisp_Object QCloaded_from; + void globals_of_w32 (void); static DWORD get_rid (PSID); @@ -5712,6 +5714,54 @@ sys_localtime (const time_t *t) return localtime (t); } + + +/* Delayed loading of libraries. */ + +Lisp_Object Vlibrary_cache; + +/* The argument LIBRARIES is an alist that associates a symbol + LIBRARY_ID, identifying an external DLL library known to Emacs, to + a list of filenames under which the library is usually found. In + most cases, the argument passed as LIBRARIES is the variable + `dynamic-library-alist', which is initialized to a list of common + library names. If the function loads the library successfully, it + returns the handle of the DLL, and records the filename in the + property :loaded-from of LIBRARY_ID; it returns NULL if the library + could not be found, or when it was already loaded (because the + handle is not recorded anywhere, and so is lost after use). It + would be trivial to save the handle too in :loaded-from, but + currently there's no use case for it. */ +HMODULE +w32_delayed_load (Lisp_Object libraries, Lisp_Object library_id) +{ + HMODULE library_dll = NULL; + + CHECK_SYMBOL (library_id); + + if (CONSP (libraries) && NILP (Fassq (library_id, Vlibrary_cache))) + { + Lisp_Object found = Qnil; + Lisp_Object dlls = Fassq (library_id, libraries); + + if (CONSP (dlls)) + for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls)) + { + CHECK_STRING_CAR (dlls); + if (library_dll = LoadLibrary (SDATA (XCAR (dlls)))) + { + found = XCAR (dlls); + break; + } + } + + Fput (library_id, QCloaded_from, found); + } + + return library_dll; +} + + static void check_windows_init_file (void) { @@ -5910,6 +5960,12 @@ globals_of_w32 (void) get_process_times_fn = (GetProcessTimes_Proc) GetProcAddress (kernel32, "GetProcessTimes"); + QCloaded_from = intern_c_string (":loaded-from"); + staticpro (&QCloaded_from); + + Vlibrary_cache = Qnil; + staticpro (&Vlibrary_cache); + g_b_init_is_windows_9x = 0; g_b_init_open_process_token = 0; g_b_init_get_token_information = 0; @@ -6178,7 +6234,7 @@ emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz) err = errno; /* Other errors are just passed on. */ } - gnutls_transport_set_errno (process->gnutls_state, err); + emacs_gnutls_transport_set_errno (process->gnutls_state, err); return -1; } @@ -6197,8 +6253,8 @@ emacs_gnutls_push (gnutls_transport_ptr_t p, const void* buf, size_t sz) /* Negative bytes written means we got an error in errno. Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */ - gnutls_transport_set_errno (process->gnutls_state, - errno == EWOULDBLOCK ? EAGAIN : errno); + emacs_gnutls_transport_set_errno (process->gnutls_state, + errno == EWOULDBLOCK ? EAGAIN : errno); return -1; } diff --git a/src/w32.h b/src/w32.h index 4086c4190e..f1915125c9 100644 --- a/src/w32.h +++ b/src/w32.h @@ -143,6 +143,9 @@ extern void syms_of_fontset (void); extern int _sys_read_ahead (int fd); extern int _sys_wait_accept (int fd); +extern Lisp_Object Vlibrary_cache, QCloaded_from; +extern HMODULE w32_delayed_load (Lisp_Object, Lisp_Object); + #ifdef HAVE_GNUTLS #include -- 2.20.1