}
#endif
+/* VARARGS 1 */
+static void
+boot_error (struct Lisp_Process *p, const char *m, ...)
+{
+ va_list ap;
+ va_start (ap, m);
+ if (p->is_non_blocking_client)
+ pset_status (p, Qfailed);
+ else
+ verror (m, ap);
+}
+
+
DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0,
doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST.
Currently only client mode is supported. Return a success/failure
Lisp_Object verify_error;
Lisp_Object prime_bits;
Lisp_Object warnings;
+ struct Lisp_Process *p = XPROCESS (proc);
CHECK_PROCESS (proc);
CHECK_SYMBOL (type);
CHECK_LIST (proplist);
if (NILP (Fgnutls_available_p ()))
- error ("GnuTLS not available");
+ {
+ boot_error (p, "GnuTLS not available");
+ return Qnil;
+ }
if (!EQ (type, Qgnutls_x509pki) && !EQ (type, Qgnutls_anon))
- error ("Invalid GnuTLS credential type");
+ {
+ boot_error (p, "Invalid GnuTLS credential type");
+ return Qnil;
+ }
hostname = Fplist_get (proplist, QCgnutls_bootprop_hostname);
priority_string = Fplist_get (proplist, QCgnutls_bootprop_priority);
}
else if (NILP (Flistp (verify_error)))
{
- error ("gnutls-boot: invalid :verify_error parameter (not a list)");
+ boot_error (p, "gnutls-boot: invalid :verify_error parameter (not a list)");
+ return Qnil;
}
if (!STRINGP (hostname))
- error ("gnutls-boot: invalid :hostname parameter (not a string)");
+ {
+ boot_error (p, "gnutls-boot: invalid :hostname parameter (not a string)");
+ return Qnil;
+ }
c_hostname = SSDATA (hostname);
state = XPROCESS (proc)->gnutls_state;
else
{
emacs_gnutls_deinit (proc);
- error ("Invalid trustfile");
+ boot_error (p, "Invalid trustfile");
+ return Qnil;
}
}
else
{
emacs_gnutls_deinit (proc);
- error ("Invalid CRL file");
+ boot_error (p, "Invalid CRL file");
+ return Qnil;
}
}
else
{
emacs_gnutls_deinit (proc);
- error (STRINGP (keyfile) ? "Invalid client cert file"
- : "Invalid client key file");
+ boot_error (p, STRINGP (keyfile) ? "Invalid client cert file"
+ : "Invalid client key file");
+ return Qnil;
}
}
}
|| !NILP (Fmember (QCgnutls_bootprop_trustfiles, verify_error)))
{
emacs_gnutls_deinit (proc);
- error ("Certificate validation failed %s, verification code %x",
- c_hostname, peer_verification);
+ boot_error (p, "Certificate validation failed %s, verification code %x",
+ c_hostname, peer_verification);
+ return Qnil;
}
else
{
{
gnutls_x509_crt_deinit (gnutls_verify_cert);
emacs_gnutls_deinit (proc);
- error ("No x509 certificate was found\n");
+ boot_error (p, "No x509 certificate was found\n");
+ return Qnil;
}
/* We only check the first certificate in the given chain. */
{
gnutls_x509_crt_deinit (gnutls_verify_cert);
emacs_gnutls_deinit (proc);
- error ("The x509 certificate does not match \"%s\"", c_hostname);
+ boot_error (p, "The x509 certificate does not match \"%s\"", c_hostname);
+ return Qnil;
}
else
{
p->sentinel = NILP (val) ? Qinternal_default_process_sentinel : val;
}
static void
-pset_status (struct Lisp_Process *p, Lisp_Object val)
-{
- p->status = val;
-}
-static void
pset_tty_name (struct Lisp_Process *p, Lisp_Object val)
{
p->tty_name = val;
#ifdef HAVE_GNUTLS
if (!NILP (p->gnutls_async_parameters) && p->is_non_blocking_client) {
- Fgnutls_boot (proc, Fcar (p->gnutls_async_parameters),
- Fcdr (p->gnutls_async_parameters));
+ Lisp_Object params = p->gnutls_async_parameters, boot = Qnil;
+
p->gnutls_async_parameters = Qnil;
+ boot = Fgnutls_boot (proc, Fcar (params), Fcdr (params));
+ if (STRINGP (boot)) {
+ pset_status (p, Qfailed);
+ deactivate_process (proc);
+ }
}
#endif
+
}
#ifdef HAVE_GETADDRINFO_A
p->dns_requests = NULL;
#endif
+#ifdef HAVE_GNUTLS
+ p->gnutls_async_parameters = Qnil;
+#endif
unbind_to (count, Qnil);
}
#ifdef HAVE_GETADDRINFO_A
-static int
+static Lisp_Object
check_for_dns (Lisp_Object proc)
{
struct Lisp_Process *p = XPROCESS (proc);
Lisp_Object ip_addresses = Qnil;
int ret = 0;
- int connect = 0;
/* Sanity check. */
if (! p->dns_requests)
ret = gai_error (p->dns_requests[0]);
if (ret == EAI_INPROGRESS)
- return 0;
+ return Qt;
/* We got a response. */
if (ret == 0)
ip_addresses = Fnreverse (ip_addresses);
freeaddrinfo (p->dns_requests[0]->ar_result);
- connect = 1;
}
+ /* The DNS lookup failed. */
else
- pset_status (p, Qfailed);
+ {
+ pset_status (p, Qfailed);
+ deactivate_process (proc);
+ }
xfree ((void *)p->dns_requests[0]->ar_request);
xfree ((void *)p->dns_requests[0]->ar_name);
xfree (p->dns_requests);
p->dns_requests = NULL;
- if (connect)
- connect_network_socket (proc, ip_addresses);
-
- return 1;
+ return ip_addresses;
}
#endif /* HAVE_GETADDRINFO_A */
#ifdef HAVE_GETADDRINFO_A
if (!NILP (dns_processes))
{
- Lisp_Object dns_list = dns_processes, dns;
+ Lisp_Object dns_list = dns_processes, dns, ip_addresses,
+ answers = Qnil, answer, new = Qnil;
struct Lisp_Process *p;
+ /* This is programmed in a somewhat awkward fashion because
+ calling connect_network_socket might make us end up back
+ here again, and we would have a race condition with
+ segfaults. So first go through all pending requests and see
+ whether we got any answers. */
while (!NILP (dns_list))
{
dns = Fcar (dns_list);
dns_list = Fcdr (dns_list);
p = XPROCESS (dns);
- if (p && p->dns_requests &&
- (! wait_proc || p == wait_proc) &&
- check_for_dns (dns))
- dns_processes = Fdelq (dns, dns_processes);
+ if (p && p->dns_requests)
+ {
+ if (! wait_proc || p == wait_proc)
+ {
+ ip_addresses = check_for_dns (dns);
+ if (EQ (ip_addresses, Qt))
+ new = Fcons (dns, new);
+ else
+ answers = Fcons (Fcons (dns, ip_addresses), answers);
+ }
+ else
+ new = Fcons (dns, new);
+ }
+ }
+
+ /* Replace with the list of DNS requests still not responded
+ to. */
+ dns_processes = new;
+
+ /* Then continue the connection for the successful
+ requests. */
+ while (!NILP (answers))
+ {
+ answer = Fcar (answers);
+ answers = Fcdr (answers);
+ if (!NILP (Fcdr (answer)))
+ connect_network_socket (Fcar (answer), Fcdr (answer));
}
}
#endif /* HAVE_GETADDRINFO_A */
staticpro (&Vprocess_alist);
staticpro (&deleted_pid_list);
+ staticpro (&dns_processes);
#endif /* subprocesses */