diff options
| author | Lars Ingebrigtsen | 2016-02-01 00:27:07 +0100 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2016-02-01 00:27:07 +0100 |
| commit | 4ff81f8fac1270a829bb2725911bf6b614711257 (patch) | |
| tree | 5c3a640b436037a3d2f6a4e8bb569c01cc9a3599 /src | |
| parent | 9972329387b7f1e1a9b1c8713a1d5bbdd032de12 (diff) | |
| download | emacs-4ff81f8fac1270a829bb2725911bf6b614711257.tar.gz emacs-4ff81f8fac1270a829bb2725911bf6b614711257.zip | |
Further TLS async work
* gnutls.c (boot_error): New function to either signal an
error or return an error code.
(Fgnutls_boot): Don't signal errors when running asynchronously.
* process.h (pset_status): Move here from process.c to be
able to use from gnutls.c.
* process.c (connect_network_socket): Do the TLS boot here
when running asynchronously.
(wait_reading_process_output): Rework the dns_processes
handling for more safety.
Diffstat (limited to 'src')
| -rw-r--r-- | src/gnutls.c | 54 | ||||
| -rw-r--r-- | src/process.c | 75 | ||||
| -rw-r--r-- | src/process.h | 6 |
3 files changed, 102 insertions, 33 deletions
diff --git a/src/gnutls.c b/src/gnutls.c index 06459fb3ccd..a0b6e0df68b 100644 --- a/src/gnutls.c +++ b/src/gnutls.c | |||
| @@ -1167,6 +1167,19 @@ emacs_gnutls_global_deinit (void) | |||
| 1167 | } | 1167 | } |
| 1168 | #endif | 1168 | #endif |
| 1169 | 1169 | ||
| 1170 | /* VARARGS 1 */ | ||
| 1171 | static void | ||
| 1172 | boot_error (struct Lisp_Process *p, const char *m, ...) | ||
| 1173 | { | ||
| 1174 | va_list ap; | ||
| 1175 | va_start (ap, m); | ||
| 1176 | if (p->is_non_blocking_client) | ||
| 1177 | pset_status (p, Qfailed); | ||
| 1178 | else | ||
| 1179 | verror (m, ap); | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | |||
| 1170 | DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0, | 1183 | DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0, |
| 1171 | doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST. | 1184 | doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST. |
| 1172 | Currently only client mode is supported. Return a success/failure | 1185 | Currently only client mode is supported. Return a success/failure |
| @@ -1246,16 +1259,23 @@ one trustfile (usually a CA bundle). */) | |||
| 1246 | Lisp_Object verify_error; | 1259 | Lisp_Object verify_error; |
| 1247 | Lisp_Object prime_bits; | 1260 | Lisp_Object prime_bits; |
| 1248 | Lisp_Object warnings; | 1261 | Lisp_Object warnings; |
| 1262 | struct Lisp_Process *p = XPROCESS (proc); | ||
| 1249 | 1263 | ||
| 1250 | CHECK_PROCESS (proc); | 1264 | CHECK_PROCESS (proc); |
| 1251 | CHECK_SYMBOL (type); | 1265 | CHECK_SYMBOL (type); |
| 1252 | CHECK_LIST (proplist); | 1266 | CHECK_LIST (proplist); |
| 1253 | 1267 | ||
| 1254 | if (NILP (Fgnutls_available_p ())) | 1268 | if (NILP (Fgnutls_available_p ())) |
| 1255 | error ("GnuTLS not available"); | 1269 | { |
| 1270 | boot_error (p, "GnuTLS not available"); | ||
| 1271 | return Qnil; | ||
| 1272 | } | ||
| 1256 | 1273 | ||
| 1257 | if (!EQ (type, Qgnutls_x509pki) && !EQ (type, Qgnutls_anon)) | 1274 | if (!EQ (type, Qgnutls_x509pki) && !EQ (type, Qgnutls_anon)) |
| 1258 | error ("Invalid GnuTLS credential type"); | 1275 | { |
| 1276 | boot_error (p, "Invalid GnuTLS credential type"); | ||
| 1277 | return Qnil; | ||
| 1278 | } | ||
| 1259 | 1279 | ||
| 1260 | hostname = Fplist_get (proplist, QCgnutls_bootprop_hostname); | 1280 | hostname = Fplist_get (proplist, QCgnutls_bootprop_hostname); |
| 1261 | priority_string = Fplist_get (proplist, QCgnutls_bootprop_priority); | 1281 | priority_string = Fplist_get (proplist, QCgnutls_bootprop_priority); |
| @@ -1272,11 +1292,15 @@ one trustfile (usually a CA bundle). */) | |||
| 1272 | } | 1292 | } |
| 1273 | else if (NILP (Flistp (verify_error))) | 1293 | else if (NILP (Flistp (verify_error))) |
| 1274 | { | 1294 | { |
| 1275 | error ("gnutls-boot: invalid :verify_error parameter (not a list)"); | 1295 | boot_error (p, "gnutls-boot: invalid :verify_error parameter (not a list)"); |
| 1296 | return Qnil; | ||
| 1276 | } | 1297 | } |
| 1277 | 1298 | ||
| 1278 | if (!STRINGP (hostname)) | 1299 | if (!STRINGP (hostname)) |
| 1279 | error ("gnutls-boot: invalid :hostname parameter (not a string)"); | 1300 | { |
| 1301 | boot_error (p, "gnutls-boot: invalid :hostname parameter (not a string)"); | ||
| 1302 | return Qnil; | ||
| 1303 | } | ||
| 1280 | c_hostname = SSDATA (hostname); | 1304 | c_hostname = SSDATA (hostname); |
| 1281 | 1305 | ||
| 1282 | state = XPROCESS (proc)->gnutls_state; | 1306 | state = XPROCESS (proc)->gnutls_state; |
| @@ -1384,7 +1408,8 @@ one trustfile (usually a CA bundle). */) | |||
| 1384 | else | 1408 | else |
| 1385 | { | 1409 | { |
| 1386 | emacs_gnutls_deinit (proc); | 1410 | emacs_gnutls_deinit (proc); |
| 1387 | error ("Invalid trustfile"); | 1411 | boot_error (p, "Invalid trustfile"); |
| 1412 | return Qnil; | ||
| 1388 | } | 1413 | } |
| 1389 | } | 1414 | } |
| 1390 | 1415 | ||
| @@ -1408,7 +1433,8 @@ one trustfile (usually a CA bundle). */) | |||
| 1408 | else | 1433 | else |
| 1409 | { | 1434 | { |
| 1410 | emacs_gnutls_deinit (proc); | 1435 | emacs_gnutls_deinit (proc); |
| 1411 | error ("Invalid CRL file"); | 1436 | boot_error (p, "Invalid CRL file"); |
| 1437 | return Qnil; | ||
| 1412 | } | 1438 | } |
| 1413 | } | 1439 | } |
| 1414 | 1440 | ||
| @@ -1437,8 +1463,9 @@ one trustfile (usually a CA bundle). */) | |||
| 1437 | else | 1463 | else |
| 1438 | { | 1464 | { |
| 1439 | emacs_gnutls_deinit (proc); | 1465 | emacs_gnutls_deinit (proc); |
| 1440 | error (STRINGP (keyfile) ? "Invalid client cert file" | 1466 | boot_error (p, STRINGP (keyfile) ? "Invalid client cert file" |
| 1441 | : "Invalid client key file"); | 1467 | : "Invalid client key file"); |
| 1468 | return Qnil; | ||
| 1442 | } | 1469 | } |
| 1443 | } | 1470 | } |
| 1444 | } | 1471 | } |
| @@ -1528,8 +1555,9 @@ one trustfile (usually a CA bundle). */) | |||
| 1528 | || !NILP (Fmember (QCgnutls_bootprop_trustfiles, verify_error))) | 1555 | || !NILP (Fmember (QCgnutls_bootprop_trustfiles, verify_error))) |
| 1529 | { | 1556 | { |
| 1530 | emacs_gnutls_deinit (proc); | 1557 | emacs_gnutls_deinit (proc); |
| 1531 | error ("Certificate validation failed %s, verification code %x", | 1558 | boot_error (p, "Certificate validation failed %s, verification code %x", |
| 1532 | c_hostname, peer_verification); | 1559 | c_hostname, peer_verification); |
| 1560 | return Qnil; | ||
| 1533 | } | 1561 | } |
| 1534 | else | 1562 | else |
| 1535 | { | 1563 | { |
| @@ -1558,7 +1586,8 @@ one trustfile (usually a CA bundle). */) | |||
| 1558 | { | 1586 | { |
| 1559 | gnutls_x509_crt_deinit (gnutls_verify_cert); | 1587 | gnutls_x509_crt_deinit (gnutls_verify_cert); |
| 1560 | emacs_gnutls_deinit (proc); | 1588 | emacs_gnutls_deinit (proc); |
| 1561 | error ("No x509 certificate was found\n"); | 1589 | boot_error (p, "No x509 certificate was found\n"); |
| 1590 | return Qnil; | ||
| 1562 | } | 1591 | } |
| 1563 | 1592 | ||
| 1564 | /* We only check the first certificate in the given chain. */ | 1593 | /* We only check the first certificate in the given chain. */ |
| @@ -1586,7 +1615,8 @@ one trustfile (usually a CA bundle). */) | |||
| 1586 | { | 1615 | { |
| 1587 | gnutls_x509_crt_deinit (gnutls_verify_cert); | 1616 | gnutls_x509_crt_deinit (gnutls_verify_cert); |
| 1588 | emacs_gnutls_deinit (proc); | 1617 | emacs_gnutls_deinit (proc); |
| 1589 | error ("The x509 certificate does not match \"%s\"", c_hostname); | 1618 | boot_error (p, "The x509 certificate does not match \"%s\"", c_hostname); |
| 1619 | return Qnil; | ||
| 1590 | } | 1620 | } |
| 1591 | else | 1621 | else |
| 1592 | { | 1622 | { |
diff --git a/src/process.c b/src/process.c index 55264058340..afb98256ba5 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -385,11 +385,6 @@ pset_sentinel (struct Lisp_Process *p, Lisp_Object val) | |||
| 385 | p->sentinel = NILP (val) ? Qinternal_default_process_sentinel : val; | 385 | p->sentinel = NILP (val) ? Qinternal_default_process_sentinel : val; |
| 386 | } | 386 | } |
| 387 | static void | 387 | static void |
| 388 | pset_status (struct Lisp_Process *p, Lisp_Object val) | ||
| 389 | { | ||
| 390 | p->status = val; | ||
| 391 | } | ||
| 392 | static void | ||
| 393 | pset_tty_name (struct Lisp_Process *p, Lisp_Object val) | 388 | pset_tty_name (struct Lisp_Process *p, Lisp_Object val) |
| 394 | { | 389 | { |
| 395 | p->tty_name = val; | 390 | p->tty_name = val; |
| @@ -3309,11 +3304,17 @@ void connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses) | |||
| 3309 | 3304 | ||
| 3310 | #ifdef HAVE_GNUTLS | 3305 | #ifdef HAVE_GNUTLS |
| 3311 | if (!NILP (p->gnutls_async_parameters) && p->is_non_blocking_client) { | 3306 | if (!NILP (p->gnutls_async_parameters) && p->is_non_blocking_client) { |
| 3312 | Fgnutls_boot (proc, Fcar (p->gnutls_async_parameters), | 3307 | Lisp_Object params = p->gnutls_async_parameters, boot = Qnil; |
| 3313 | Fcdr (p->gnutls_async_parameters)); | 3308 | |
| 3314 | p->gnutls_async_parameters = Qnil; | 3309 | p->gnutls_async_parameters = Qnil; |
| 3310 | boot = Fgnutls_boot (proc, Fcar (params), Fcdr (params)); | ||
| 3311 | if (STRINGP (boot)) { | ||
| 3312 | pset_status (p, Qfailed); | ||
| 3313 | deactivate_process (proc); | ||
| 3314 | } | ||
| 3315 | } | 3315 | } |
| 3316 | #endif | 3316 | #endif |
| 3317 | |||
| 3317 | } | 3318 | } |
| 3318 | 3319 | ||
| 3319 | 3320 | ||
| @@ -3798,6 +3799,9 @@ usage: (make-network-process &rest ARGS) */) | |||
| 3798 | #ifdef HAVE_GETADDRINFO_A | 3799 | #ifdef HAVE_GETADDRINFO_A |
| 3799 | p->dns_requests = NULL; | 3800 | p->dns_requests = NULL; |
| 3800 | #endif | 3801 | #endif |
| 3802 | #ifdef HAVE_GNUTLS | ||
| 3803 | p->gnutls_async_parameters = Qnil; | ||
| 3804 | #endif | ||
| 3801 | 3805 | ||
| 3802 | unbind_to (count, Qnil); | 3806 | unbind_to (count, Qnil); |
| 3803 | 3807 | ||
| @@ -4545,13 +4549,12 @@ server_accept_connection (Lisp_Object server, int channel) | |||
| 4545 | } | 4549 | } |
| 4546 | 4550 | ||
| 4547 | #ifdef HAVE_GETADDRINFO_A | 4551 | #ifdef HAVE_GETADDRINFO_A |
| 4548 | static int | 4552 | static Lisp_Object |
| 4549 | check_for_dns (Lisp_Object proc) | 4553 | check_for_dns (Lisp_Object proc) |
| 4550 | { | 4554 | { |
| 4551 | struct Lisp_Process *p = XPROCESS (proc); | 4555 | struct Lisp_Process *p = XPROCESS (proc); |
| 4552 | Lisp_Object ip_addresses = Qnil; | 4556 | Lisp_Object ip_addresses = Qnil; |
| 4553 | int ret = 0; | 4557 | int ret = 0; |
| 4554 | int connect = 0; | ||
| 4555 | 4558 | ||
| 4556 | /* Sanity check. */ | 4559 | /* Sanity check. */ |
| 4557 | if (! p->dns_requests) | 4560 | if (! p->dns_requests) |
| @@ -4559,7 +4562,7 @@ check_for_dns (Lisp_Object proc) | |||
| 4559 | 4562 | ||
| 4560 | ret = gai_error (p->dns_requests[0]); | 4563 | ret = gai_error (p->dns_requests[0]); |
| 4561 | if (ret == EAI_INPROGRESS) | 4564 | if (ret == EAI_INPROGRESS) |
| 4562 | return 0; | 4565 | return Qt; |
| 4563 | 4566 | ||
| 4564 | /* We got a response. */ | 4567 | /* We got a response. */ |
| 4565 | if (ret == 0) | 4568 | if (ret == 0) |
| @@ -4575,10 +4578,13 @@ check_for_dns (Lisp_Object proc) | |||
| 4575 | 4578 | ||
| 4576 | ip_addresses = Fnreverse (ip_addresses); | 4579 | ip_addresses = Fnreverse (ip_addresses); |
| 4577 | freeaddrinfo (p->dns_requests[0]->ar_result); | 4580 | freeaddrinfo (p->dns_requests[0]->ar_result); |
| 4578 | connect = 1; | ||
| 4579 | } | 4581 | } |
| 4582 | /* The DNS lookup failed. */ | ||
| 4580 | else | 4583 | else |
| 4581 | pset_status (p, Qfailed); | 4584 | { |
| 4585 | pset_status (p, Qfailed); | ||
| 4586 | deactivate_process (proc); | ||
| 4587 | } | ||
| 4582 | 4588 | ||
| 4583 | xfree ((void *)p->dns_requests[0]->ar_request); | 4589 | xfree ((void *)p->dns_requests[0]->ar_request); |
| 4584 | xfree ((void *)p->dns_requests[0]->ar_name); | 4590 | xfree ((void *)p->dns_requests[0]->ar_name); |
| @@ -4587,10 +4593,7 @@ check_for_dns (Lisp_Object proc) | |||
| 4587 | xfree (p->dns_requests); | 4593 | xfree (p->dns_requests); |
| 4588 | p->dns_requests = NULL; | 4594 | p->dns_requests = NULL; |
| 4589 | 4595 | ||
| 4590 | if (connect) | 4596 | return ip_addresses; |
| 4591 | connect_network_socket (proc, ip_addresses); | ||
| 4592 | |||
| 4593 | return 1; | ||
| 4594 | } | 4597 | } |
| 4595 | #endif /* HAVE_GETADDRINFO_A */ | 4598 | #endif /* HAVE_GETADDRINFO_A */ |
| 4596 | 4599 | ||
| @@ -4722,18 +4725,47 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 4722 | #ifdef HAVE_GETADDRINFO_A | 4725 | #ifdef HAVE_GETADDRINFO_A |
| 4723 | if (!NILP (dns_processes)) | 4726 | if (!NILP (dns_processes)) |
| 4724 | { | 4727 | { |
| 4725 | Lisp_Object dns_list = dns_processes, dns; | 4728 | Lisp_Object dns_list = dns_processes, dns, ip_addresses, |
| 4729 | answers = Qnil, answer, new = Qnil; | ||
| 4726 | struct Lisp_Process *p; | 4730 | struct Lisp_Process *p; |
| 4727 | 4731 | ||
| 4732 | /* This is programmed in a somewhat awkward fashion because | ||
| 4733 | calling connect_network_socket might make us end up back | ||
| 4734 | here again, and we would have a race condition with | ||
| 4735 | segfaults. So first go through all pending requests and see | ||
| 4736 | whether we got any answers. */ | ||
| 4728 | while (!NILP (dns_list)) | 4737 | while (!NILP (dns_list)) |
| 4729 | { | 4738 | { |
| 4730 | dns = Fcar (dns_list); | 4739 | dns = Fcar (dns_list); |
| 4731 | dns_list = Fcdr (dns_list); | 4740 | dns_list = Fcdr (dns_list); |
| 4732 | p = XPROCESS (dns); | 4741 | p = XPROCESS (dns); |
| 4733 | if (p && p->dns_requests && | 4742 | if (p && p->dns_requests) |
| 4734 | (! wait_proc || p == wait_proc) && | 4743 | { |
| 4735 | check_for_dns (dns)) | 4744 | if (! wait_proc || p == wait_proc) |
| 4736 | dns_processes = Fdelq (dns, dns_processes); | 4745 | { |
| 4746 | ip_addresses = check_for_dns (dns); | ||
| 4747 | if (EQ (ip_addresses, Qt)) | ||
| 4748 | new = Fcons (dns, new); | ||
| 4749 | else | ||
| 4750 | answers = Fcons (Fcons (dns, ip_addresses), answers); | ||
| 4751 | } | ||
| 4752 | else | ||
| 4753 | new = Fcons (dns, new); | ||
| 4754 | } | ||
| 4755 | } | ||
| 4756 | |||
| 4757 | /* Replace with the list of DNS requests still not responded | ||
| 4758 | to. */ | ||
| 4759 | dns_processes = new; | ||
| 4760 | |||
| 4761 | /* Then continue the connection for the successful | ||
| 4762 | requests. */ | ||
| 4763 | while (!NILP (answers)) | ||
| 4764 | { | ||
| 4765 | answer = Fcar (answers); | ||
| 4766 | answers = Fcdr (answers); | ||
| 4767 | if (!NILP (Fcdr (answer))) | ||
| 4768 | connect_network_socket (Fcar (answer), Fcdr (answer)); | ||
| 4737 | } | 4769 | } |
| 4738 | } | 4770 | } |
| 4739 | #endif /* HAVE_GETADDRINFO_A */ | 4771 | #endif /* HAVE_GETADDRINFO_A */ |
| @@ -7685,6 +7717,7 @@ syms_of_process (void) | |||
| 7685 | 7717 | ||
| 7686 | staticpro (&Vprocess_alist); | 7718 | staticpro (&Vprocess_alist); |
| 7687 | staticpro (&deleted_pid_list); | 7719 | staticpro (&deleted_pid_list); |
| 7720 | staticpro (&dns_processes); | ||
| 7688 | 7721 | ||
| 7689 | #endif /* subprocesses */ | 7722 | #endif /* subprocesses */ |
| 7690 | 7723 | ||
diff --git a/src/process.h b/src/process.h index eb34f5f0411..95c64fa73b7 100644 --- a/src/process.h +++ b/src/process.h | |||
| @@ -210,6 +210,12 @@ pset_childp (struct Lisp_Process *p, Lisp_Object val) | |||
| 210 | p->childp = val; | 210 | p->childp = val; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | INLINE void | ||
| 214 | pset_status (struct Lisp_Process *p, Lisp_Object val) | ||
| 215 | { | ||
| 216 | p->status = val; | ||
| 217 | } | ||
| 218 | |||
| 213 | #ifdef HAVE_GNUTLS | 219 | #ifdef HAVE_GNUTLS |
| 214 | INLINE void | 220 | INLINE void |
| 215 | pset_gnutls_cred_type (struct Lisp_Process *p, Lisp_Object val) | 221 | pset_gnutls_cred_type (struct Lisp_Process *p, Lisp_Object val) |