summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gnutls.c71
-rw-r--r--src/gnutls.h1
-rw-r--r--src/process.c131
3 files changed, 119 insertions, 84 deletions
diff --git a/src/gnutls.c b/src/gnutls.c
index 948a0c56f14..6573c87cf78 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -397,11 +397,42 @@ gnutls_log_function2i (int level, const char *string, int extra)
message ("gnutls.c: [%d] %s %d", level, string, extra);
}
+int
+gnutls_try_handshake (struct Lisp_Process *proc)
+{
+ gnutls_session_t state = proc->gnutls_state;
+ int ret;
+
+ do
+ {
+ ret = gnutls_handshake (state);
+ emacs_gnutls_handle_error (state, ret);
+ QUIT;
+ }
+ while (ret < 0 && gnutls_error_is_fatal (ret) == 0 &&
+ ! proc->is_non_blocking_client);
+
+ proc->gnutls_initstage = GNUTLS_STAGE_HANDSHAKE_TRIED;
+
+ if (proc->is_non_blocking_client)
+ proc->gnutls_p = 1;
+
+ if (ret == GNUTLS_E_SUCCESS)
+ {
+ /* Here we're finally done. */
+ proc->gnutls_initstage = GNUTLS_STAGE_READY;
+ }
+ else
+ {
+ //check_memory_full (gnutls_alert_send_appropriate (state, ret));
+ }
+ 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;
@@ -443,26 +474,7 @@ emacs_gnutls_handshake (struct Lisp_Process *proc)
proc->gnutls_initstage = GNUTLS_STAGE_TRANSPORT_POINTERS_SET;
}
- do
- {
- ret = gnutls_handshake (state);
- emacs_gnutls_handle_error (state, ret);
- QUIT;
- }
- while (ret < 0 && 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
- {
- check_memory_full (gnutls_alert_send_appropriate (state, ret));
- }
- return ret;
+ return gnutls_try_handshake (proc);
}
ptrdiff_t
@@ -531,23 +543,8 @@ emacs_gnutls_read (struct Lisp_Process *proc, char *buf, ptrdiff_t nbyte)
int log_level = proc->gnutls_log_level;
if (proc->gnutls_initstage != GNUTLS_STAGE_READY)
- {
- /* 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;
- }
+ return -1;
- GNUTLS_LOG (2, log_level, "Giving up on handshake; resetting retries");
- proc->gnutls_handshakes_tried = 0;
- return 0;
- }
rtnval = gnutls_record_recv (state, buf, nbyte);
if (rtnval >= 0)
return rtnval;
diff --git a/src/gnutls.h b/src/gnutls.h
index 8e879c168bd..cb521350b9d 100644
--- a/src/gnutls.h
+++ b/src/gnutls.h
@@ -84,6 +84,7 @@ extern void emacs_gnutls_transport_set_errno (gnutls_session_t state, int err);
#endif
extern Lisp_Object emacs_gnutls_deinit (Lisp_Object);
extern Lisp_Object emacs_gnutls_global_init (void);
+extern int gnutls_try_handshake (struct Lisp_Process *p);
#endif
diff --git a/src/process.c b/src/process.c
index 9a3bcaed389..ec31ea87c7b 100644
--- a/src/process.c
+++ b/src/process.c
@@ -281,9 +281,7 @@ static int max_input_desc;
/* Indexed by descriptor, gives the process (if any) for that descriptor. */
static Lisp_Object chan_process[FD_SETSIZE];
-#ifdef HAVE_GETADDRINFO_A
static void wait_for_socket_fds (Lisp_Object process, char *name);
-#endif
/* Alist of elements (NAME . PROCESS). */
static Lisp_Object Vprocess_alist;
@@ -3038,7 +3036,45 @@ void set_network_socket_coding_system (Lisp_Object proc)
= !(!NILP (tem) || NILP (p->buffer) || !inherit_process_coding_system);
}
-void connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
+#ifdef HAVE_GNUTLS
+void
+finish_after_tls_connection (Lisp_Object proc)
+{
+ struct Lisp_Process *p = XPROCESS (proc);
+ Lisp_Object contact = p->childp;
+ Lisp_Object result = Qt;
+
+ if (!NILP (Ffboundp (Qnsm_verify_connection)))
+ result = call3 (Qnsm_verify_connection,
+ proc,
+ Fplist_get (contact, QChost),
+ Fplist_get (contact, QCservice));
+
+ if (NILP (result))
+ {
+ pset_status (p, list2 (Qfailed,
+ build_string ("The Network Security Manager stopped the connections")));
+ deactivate_process (proc);
+ }
+ else
+ {
+ /* If we cleared the connection wait mask before we did
+ the TLS setup, then we have to say that the process
+ is finally "open" here. */
+ if (! FD_ISSET (p->outfd, &connect_wait_mask))
+ {
+ pset_status (p, Qrun);
+ /* Execute the sentinel here. If we had relied on
+ status_notify to do it later, it will read input
+ from the process before calling the sentinel. */
+ exec_sentinel (proc, build_string ("open\n"));
+ }
+ }
+}
+#endif
+
+void
+connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
{
ptrdiff_t count = SPECPDL_INDEX ();
ptrdiff_t count1;
@@ -3359,8 +3395,10 @@ void connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
boot = Fgnutls_boot (proc, XCAR (params), XCDR (params));
p->gnutls_boot_parameters = Qnil;
- if (NILP (boot) || STRINGP (boot) ||
- p->gnutls_initstage != GNUTLS_STAGE_READY)
+ if (p->gnutls_initstage == GNUTLS_STAGE_READY)
+ /* Run sentinels, etc. */
+ finish_after_tls_connection (proc);
+ else if (p->gnutls_initstage != GNUTLS_STAGE_HANDSHAKE_TRIED)
{
deactivate_process (proc);
if (NILP (boot))
@@ -3369,37 +3407,6 @@ void connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses)
else
pset_status (p, list2 (Qfailed, boot));
}
- else
- {
- Lisp_Object result = Qt;
-
- if (!NILP (Ffboundp (Qnsm_verify_connection)))
- result = call3 (Qnsm_verify_connection,
- proc,
- Fplist_get (contact, QChost),
- Fplist_get (contact, QCservice));
-
- if (NILP (result))
- {
- pset_status (p, list2 (Qfailed,
- build_string ("The Network Security Manager stopped the connections")));
- deactivate_process (proc);
- }
- else
- {
- /* If we cleared the connection wait mask before we did
- the TLS setup, then we have to say that the process
- is finally "open" here. */
- if (! FD_ISSET (p->outfd, &connect_wait_mask))
- {
- pset_status (p, Qrun);
- /* Execute the sentinel here. If we had relied on
- status_notify to do it later, it will read input
- from the process before calling the sentinel. */
- exec_sentinel (proc, build_string ("open\n"));
- }
- }
- }
}
#endif
@@ -4747,8 +4754,8 @@ static void
wait_for_tls_negotiation (Lisp_Object process)
{
#ifdef HAVE_GNUTLS
- while (EQ (XPROCESS (process)->status, Qconnect) &&
- !NILP (XPROCESS (process)->gnutls_boot_parameters))
+ while (XPROCESS (process)->gnutls_p &&
+ XPROCESS (process)->gnutls_initstage != GNUTLS_STAGE_READY)
{
printf("Waiting for TLS...\n");
wait_reading_process_output (0, 20 * 1000 * 1000, 0, 0, Qnil, NULL, 0);
@@ -4881,7 +4888,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
break;
-#ifdef HAVE_GETADDRINFO_A
+#if defined (HAVE_GETADDRINFO_A) || defined (HAVE_GNUTLS)
{
Lisp_Object ip_addresses;
Lisp_Object process_list_head, aproc;
@@ -4891,17 +4898,41 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
{
p = XPROCESS (aproc);
- if (p->dns_requests &&
- (! wait_proc || p == wait_proc))
+ if (! wait_proc || p == wait_proc)
{
- ip_addresses = check_for_dns (aproc);
- if (!NILP (ip_addresses) &&
- !EQ (ip_addresses, Qt))
- connect_network_socket (aproc, ip_addresses);
+#ifdef HAVE_GETADDRINFO_A
+ /* Check for pending DNS requests. */
+ if (p->dns_requests)
+ {
+ ip_addresses = check_for_dns (aproc);
+ if (!NILP (ip_addresses) &&
+ !EQ (ip_addresses, Qt))
+ connect_network_socket (aproc, ip_addresses);
+ }
+#endif
+#ifdef HAVE_GNUTLS
+ /* Continue TLS negotiation. */
+ if (p->gnutls_initstage == GNUTLS_STAGE_HANDSHAKE_TRIED &&
+ p->is_non_blocking_client)
+ {
+ gnutls_try_handshake (p);
+ p->gnutls_handshakes_tried++;
+
+ if (p->gnutls_initstage == GNUTLS_STAGE_READY)
+ finish_after_tls_connection (aproc);
+ else if (p->gnutls_handshakes_tried >
+ GNUTLS_EMACS_HANDSHAKES_LIMIT)
+ {
+ deactivate_process (proc);
+ pset_status (p, list2 (Qfailed,
+ build_string ("TLS negotiation failed")));
+ }
+ }
+#endif
}
}
}
-#endif /* HAVE_GETADDRINFO_A */
+#endif /* GETADDRINFO_A or GNUTLS */
/* Compute time from now till when time limit is up. */
/* Exit if already run out. */
@@ -5522,7 +5553,13 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
}
else
{
- if (NILP (p->gnutls_boot_parameters))
+#ifdef HAVE_GNUTLS
+ /* If we have an incompletely set up TLS connection,
+ then defer the sentinel signalling until
+ later. */
+ if (NILP (p->gnutls_boot_parameters) &&
+ !p->gnutls_p)
+#endif
{
pset_status (p, Qrun);
/* Execute the sentinel here. If we had relied on