You should not have to use the @file{gnutls.el} functions directly.
But you can test them with @code{open-gnutls-stream}.
-@defun open-gnutls-stream name buffer host service
+@defun open-gnutls-stream name buffer host service &optional nowait
This function creates a buffer connected to a specific @var{host} and
@var{service} (port number or service name). The parameters and their
syntax are the same as those given to @code{open-network-stream}
Manual}). The connection process is called @var{name} (made unique if
necessary). This function returns the connection process.
+If called with @var{nowait}, the process is returned immediately
+(before connecting to the server).
+
@lisp
;; open a HTTPS connection
(open-gnutls-stream "tls" "tls-buffer" "yourserver.com" "https")
(integer :tag "Number of bits" 512))
:group 'gnutls)
-(defun open-gnutls-stream (name buffer host service)
+(defun open-gnutls-stream (name buffer host service &optional nowait)
"Open a SSL/TLS connection for a service to a host.
Returns a subprocess-object to represent the connection.
Input and output work as for subprocesses; `delete-process' closes it.
Third arg is name of the host to connect to, or its IP address.
Fourth arg SERVICE is name of the service desired, or an integer
specifying a port number to connect to.
+Fifth arg NOWAIT (which is optional) means that the socket should
+be opened asynchronously.
Usage example:
documentation for the specific parameters you can use to open a
GnuTLS connection, including specifying the credential type,
trust and key files, and priority string."
- (gnutls-negotiate :process (open-network-stream name buffer host service)
- :type 'gnutls-x509pki
- :hostname host))
+ (let ((process (open-network-stream name buffer host service
+ :nowait nowait)))
+ (if nowait
+ (progn
+ (gnutls-mark-process process t)
+ (set-process-sentinel process 'gnutls-async-sentinel)
+ process)
+ (gnutls-negotiate :process (open-network-stream name buffer host service)
+ :type 'gnutls-x509pki
+ :hostname host))))
+
+(defun gnutls-async-sentinel (process change)
+ (message "change: %S %s" change (car (process-contact process)))
+ (when (string-match "open" change)
+ (gnutls-negotiate :process process
+ :type 'gnutls-x509pki
+ :hostname (car (process-contact process)))
+ (gnutls-mark-process process nil)))
(define-error 'gnutls-error "GnuTLS error")
(with-current-buffer buffer
(let* ((start (point-max))
(stream
- (funcall (if (gnutls-available-p)
- 'open-gnutls-stream
- 'open-tls-stream)
- name buffer host service))
+ (if (gnutls-available-p)
+ (open-gnutls-stream name buffer host service
+ (plist-get parameters :nowait))
+ (open-tls-stream name buffer host service)))
(eoc (plist-get parameters :end-of-command)))
;; Check certificate validity etc.
(when (and (gnutls-available-p) stream)
(pcase (process-status connection)
(`connect
;; Asynchronous connection
- (set-process-sentinel connection 'url-http-async-sentinel))
+ (if (not (process-sentinel connection))
+ (set-process-sentinel connection 'url-http-async-sentinel)
+ ;; If we already have a sentinel on this process (for
+ ;; instance on TLS connections), then chain them
+ ;; together.
+ (let ((old (process-sentinel connection)))
+ (set-process-sentinel
+ connection
+ `(lambda (proc why)
+ (funcall ',old proc why)
+ (url-http-async-sentinel proc why))))))
(`failed
;; Asynchronous connection failed
(error "Could not create connection to %s:%d" host port))
return Qt;
}
+DEFUN ("gnutls-mark-process", Fgnutls_mark_process, Sgnutls_mark_process, 2, 2, 0,
+ doc: /* Mark this process as being a pre-init GnuTLS process. */)
+ (Lisp_Object proc, Lisp_Object state)
+{
+ CHECK_PROCESS (proc);
+
+ XPROCESS (proc)->gnutls_wait_p = !NILP (state);
+ return Qnil;
+}
+
DEFUN ("gnutls-get-initstage", Fgnutls_get_initstage, Sgnutls_get_initstage, 1, 1, 0,
doc: /* Return the GnuTLS init stage of process PROC.
See also `gnutls-boot'. */)
make_number (GNUTLS_E_APPLICATION_ERROR_MIN));
defsubr (&Sgnutls_get_initstage);
+ defsubr (&Sgnutls_mark_process);
defsubr (&Sgnutls_errorp);
defsubr (&Sgnutls_error_fatalp);
defsubr (&Sgnutls_error_string);
if (p->outfd < 0)
error ("Output file descriptor of %s is closed", SDATA (p->name));
+#ifdef HAVE_GNUTLS
+ if (p->gnutls_wait_p)
+ return;
+#endif
+
coding = proc_encode_coding_system[p->outfd];
Vlast_coding_system_used = CODING_ID_NAME (coding->id);
int gnutls_log_level;
int gnutls_handshakes_tried;
bool_bf gnutls_p : 1;
+ bool_bf gnutls_wait_p : 1;
#endif
};