diff options
| author | Mathieu Othacehe <othacehe@gnu.org> | 2020-11-22 15:12:17 +0100 |
|---|---|---|
| committer | Mathieu Othacehe <othacehe@gnu.org> | 2020-11-29 15:08:26 +0100 |
| commit | 375cc7dea20da7117c9459e4a4d15144095e015b (patch) | |
| tree | dc8f9c08d48912f94e379fcb37e3f37844cafdfd | |
| parent | 8518a3692cbb9cd96d69c03e9de9ad6fdcfebbee (diff) | |
Add Avahi support.
* guix/avahi.scm: New file.
* Makefile.am (MODULES): Add it.
* configure.ac: Add Guile-Avahi dependency.
* doc/guix.texi (Requirements): Document it.
* gnu/packages/package-management.scm (guix)[native-inputs]: Add
"guile-avahi",
[propagated-inputs]: ditto.
* guix/self.scm (specification->package): Add guile-avahi.
(compiled-guix): Ditto.
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | configure.ac | 6 | ||||
| -rw-r--r-- | doc/guix.texi | 1 | ||||
| -rw-r--r-- | gnu/packages/package-management.scm | 5 | ||||
| -rw-r--r-- | guix/avahi.scm | 167 | ||||
| -rw-r--r-- | guix/self.scm | 9 |
6 files changed, 186 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am index d63f2ae4b7b..7049da95946 100644 --- a/Makefile.am +++ b/Makefile.am | |||
| @@ -73,6 +73,7 @@ include gnu/local.mk | |||
| 73 | include po/doc/local.mk | 73 | include po/doc/local.mk |
| 74 | 74 | ||
| 75 | MODULES = \ | 75 | MODULES = \ |
| 76 | guix/avahi.scm \ | ||
| 76 | guix/base16.scm \ | 77 | guix/base16.scm \ |
| 77 | guix/base32.scm \ | 78 | guix/base32.scm \ |
| 78 | guix/base64.scm \ | 79 | guix/base64.scm \ |
diff --git a/configure.ac b/configure.ac index 6e718afdd1c..307e8b361f9 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -161,6 +161,12 @@ if test "x$have_guile_lzlib" != "xyes"; then | |||
| 161 | AC_MSG_ERROR([Guile-lzlib is missing; please install it.]) | 161 | AC_MSG_ERROR([Guile-lzlib is missing; please install it.]) |
| 162 | fi | 162 | fi |
| 163 | 163 | ||
| 164 | dnl Check for Guile-Avahi. | ||
| 165 | GUILE_MODULE_AVAILABLE([have_guile_avahi], [(avahi)]) | ||
| 166 | if test "x$have_guile_avahi" != "xyes"; then | ||
| 167 | AC_MSG_ERROR([Guile-Avahi is missing; please install it.]) | ||
| 168 | fi | ||
| 169 | |||
| 164 | dnl Guile-newt is used by the graphical installer. | 170 | dnl Guile-newt is used by the graphical installer. |
| 165 | GUILE_MODULE_AVAILABLE([have_guile_newt], [(newt)]) | 171 | GUILE_MODULE_AVAILABLE([have_guile_newt], [(newt)]) |
| 166 | 172 | ||
diff --git a/doc/guix.texi b/doc/guix.texi index 07da51f131f..baf6e69039a 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -829,6 +829,7 @@ Guile,, gnutls-guile, GnuTLS-Guile}); | |||
| 829 | or later; | 829 | or later; |
| 830 | @item @uref{https://notabug.org/guile-zlib/guile-zlib, Guile-zlib}; | 830 | @item @uref{https://notabug.org/guile-zlib/guile-zlib, Guile-zlib}; |
| 831 | @item @uref{https://notabug.org/guile-lzlib/guile-lzlib, Guile-lzlib}; | 831 | @item @uref{https://notabug.org/guile-lzlib/guile-lzlib, Guile-lzlib}; |
| 832 | @item @uref{https://www.nongnu.org/guile-avahi/, Guile-Avahi}; | ||
| 832 | @item | 833 | @item |
| 833 | @c FIXME: Specify a version number once a release has been made. | 834 | @c FIXME: Specify a version number once a release has been made. |
| 834 | @uref{https://gitlab.com/guile-git/guile-git, Guile-Git}, version 0.3.0 | 835 | @uref{https://gitlab.com/guile-git/guile-git, Guile-Git}, version 0.3.0 |
diff --git a/gnu/packages/package-management.scm b/gnu/packages/package-management.scm index 7a93a790075..8ee2f2d1d46 100644 --- a/gnu/packages/package-management.scm +++ b/gnu/packages/package-management.scm | |||
| @@ -294,6 +294,7 @@ $(prefix)/etc/init.d\n"))) | |||
| 294 | (guile ,@(if (%current-target-system) | 294 | (guile ,@(if (%current-target-system) |
| 295 | '((assoc-ref native-inputs "guile")) | 295 | '((assoc-ref native-inputs "guile")) |
| 296 | '((assoc-ref inputs "guile")))) | 296 | '((assoc-ref inputs "guile")))) |
| 297 | (avahi (assoc-ref inputs "guile-avahi")) | ||
| 297 | (gcrypt (assoc-ref inputs "guile-gcrypt")) | 298 | (gcrypt (assoc-ref inputs "guile-gcrypt")) |
| 298 | (json (assoc-ref inputs "guile-json")) | 299 | (json (assoc-ref inputs "guile-json")) |
| 299 | (sqlite (assoc-ref inputs "guile-sqlite3")) | 300 | (sqlite (assoc-ref inputs "guile-sqlite3")) |
| @@ -305,7 +306,7 @@ $(prefix)/etc/init.d\n"))) | |||
| 305 | (ssh (assoc-ref inputs "guile-ssh")) | 306 | (ssh (assoc-ref inputs "guile-ssh")) |
| 306 | (gnutls (assoc-ref inputs "gnutls")) | 307 | (gnutls (assoc-ref inputs "gnutls")) |
| 307 | (locales (assoc-ref inputs "glibc-utf8-locales")) | 308 | (locales (assoc-ref inputs "glibc-utf8-locales")) |
| 308 | (deps (list gcrypt json sqlite gnutls | 309 | (deps (list avahi gcrypt json sqlite gnutls |
| 309 | git bs ssh zlib lzlib)) | 310 | git bs ssh zlib lzlib)) |
| 310 | (effective | 311 | (effective |
| 311 | (read-line | 312 | (read-line |
| @@ -349,6 +350,7 @@ $(prefix)/etc/init.d\n"))) | |||
| 349 | ;; cross-compilation. | 350 | ;; cross-compilation. |
| 350 | ("guile" ,guile-3.0-latest) ;for faster builds | 351 | ("guile" ,guile-3.0-latest) ;for faster builds |
| 351 | ("gnutls" ,gnutls) | 352 | ("gnutls" ,gnutls) |
| 353 | ("guile-avahi" ,guile-avahi) | ||
| 352 | ("guile-gcrypt" ,guile-gcrypt) | 354 | ("guile-gcrypt" ,guile-gcrypt) |
| 353 | ("guile-json" ,guile-json-4) | 355 | ("guile-json" ,guile-json-4) |
| 354 | ("guile-sqlite3" ,guile-sqlite3) | 356 | ("guile-sqlite3" ,guile-sqlite3) |
| @@ -399,6 +401,7 @@ $(prefix)/etc/init.d\n"))) | |||
| 399 | ("glibc-utf8-locales" ,glibc-utf8-locales))) | 401 | ("glibc-utf8-locales" ,glibc-utf8-locales))) |
| 400 | (propagated-inputs | 402 | (propagated-inputs |
| 401 | `(("gnutls" ,(if (%current-target-system) gnutls-3.6.14 gnutls)) | 403 | `(("gnutls" ,(if (%current-target-system) gnutls-3.6.14 gnutls)) |
| 404 | ("guile-avahi" ,guile-avahi) | ||
| 402 | ("guile-gcrypt" ,guile-gcrypt) | 405 | ("guile-gcrypt" ,guile-gcrypt) |
| 403 | ("guile-json" ,guile-json-4) | 406 | ("guile-json" ,guile-json-4) |
| 404 | ("guile-sqlite3" ,guile-sqlite3) | 407 | ("guile-sqlite3" ,guile-sqlite3) |
diff --git a/guix/avahi.scm b/guix/avahi.scm new file mode 100644 index 00000000000..8a82fd3beb0 --- /dev/null +++ b/guix/avahi.scm | |||
| @@ -0,0 +1,167 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2020 Mathieu Othacehe <othacehe@gnu.org> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (guix avahi) | ||
| 20 | #:use-module (guix records) | ||
| 21 | #:use-module (guix build syscalls) | ||
| 22 | #:use-module (avahi) | ||
| 23 | #:use-module (avahi client) | ||
| 24 | #:use-module (avahi client lookup) | ||
| 25 | #:use-module (avahi client publish) | ||
| 26 | #:use-module (srfi srfi-9) | ||
| 27 | #:use-module (ice-9 threads) | ||
| 28 | #:export (avahi-service | ||
| 29 | avahi-service? | ||
| 30 | avahi-service-name | ||
| 31 | avahi-service-type | ||
| 32 | avahi-service-interface | ||
| 33 | avahi-service-local-address | ||
| 34 | avahi-service-address | ||
| 35 | avahi-service-port | ||
| 36 | avahi-service-txt | ||
| 37 | |||
| 38 | avahi-publish-service-thread | ||
| 39 | avahi-browse-service-thread)) | ||
| 40 | |||
| 41 | (define-record-type* <avahi-service> | ||
| 42 | avahi-service make-avahi-service | ||
| 43 | avahi-service? | ||
| 44 | (name avahi-service-name) | ||
| 45 | (type avahi-service-type) | ||
| 46 | (interface avahi-service-interface) | ||
| 47 | (local-address avahi-service-local-address) | ||
| 48 | (address avahi-service-address) | ||
| 49 | (port avahi-service-port) | ||
| 50 | (txt avahi-service-txt)) | ||
| 51 | |||
| 52 | (define* (avahi-publish-service-thread name | ||
| 53 | #:key | ||
| 54 | type port | ||
| 55 | (stop-loop? (const #f)) | ||
| 56 | (timeout 100) | ||
| 57 | (txt '())) | ||
| 58 | "Publish the service TYPE using Avahi, for the given PORT, on all interfaces | ||
| 59 | and for all protocols. Also, advertise the given TXT record list. | ||
| 60 | |||
| 61 | This procedure starts a new thread running the Avahi event loop. It exits | ||
| 62 | when STOP-LOOP? procedure returns true." | ||
| 63 | (define client-callback | ||
| 64 | (lambda (client state) | ||
| 65 | (when (eq? state client-state/s-running) | ||
| 66 | (let ((group (make-entry-group client (const #t)))) | ||
| 67 | (apply | ||
| 68 | add-entry-group-service! group interface/unspecified | ||
| 69 | protocol/unspecified '() | ||
| 70 | name type #f #f port txt) | ||
| 71 | (commit-entry-group group))))) | ||
| 72 | |||
| 73 | (call-with-new-thread | ||
| 74 | (lambda () | ||
| 75 | (let* ((poll (make-simple-poll)) | ||
| 76 | (client (make-client (simple-poll poll) | ||
| 77 | (list | ||
| 78 | client-flag/ignore-user-config) | ||
| 79 | client-callback))) | ||
| 80 | (while (not (stop-loop?)) | ||
| 81 | (iterate-simple-poll poll timeout)))))) | ||
| 82 | |||
| 83 | (define (interface->ip-address interface) | ||
| 84 | "Return the local IP address of the given INTERFACE." | ||
| 85 | (let* ((socket (socket AF_INET SOCK_STREAM 0)) | ||
| 86 | (address (network-interface-address socket interface)) | ||
| 87 | (ip (inet-ntop (sockaddr:fam address) | ||
| 88 | (sockaddr:addr address)))) | ||
| 89 | (close-port socket) | ||
| 90 | ip)) | ||
| 91 | |||
| 92 | (define* (avahi-browse-service-thread proc | ||
| 93 | #:key | ||
| 94 | types | ||
| 95 | (family AF_INET) | ||
| 96 | (stop-loop? (const #f)) | ||
| 97 | (timeout 100)) | ||
| 98 | "Browse services which type is part of the TYPES list, using Avahi. The | ||
| 99 | search is restricted to services with the given FAMILY. Each time a service | ||
| 100 | is found or removed, PROC is called and passed as argument the corresponding | ||
| 101 | AVAHI-SERVICE record. If a service is available on multiple network | ||
| 102 | interfaces, it will only be reported on the first interface found. | ||
| 103 | |||
| 104 | This procedure starts a new thread running the Avahi event loop. It exits | ||
| 105 | when STOP-LOOP? procedure returns true." | ||
| 106 | (define %known-hosts | ||
| 107 | ;; Set of Avahi discovered hosts. | ||
| 108 | (make-hash-table)) | ||
| 109 | |||
| 110 | (define (service-resolver-callback resolver interface protocol event | ||
| 111 | service-name service-type domain | ||
| 112 | host-name address-type address port | ||
| 113 | txt flags) | ||
| 114 | ;; Handle service resolution events. | ||
| 115 | (cond ((eq? event resolver-event/found) | ||
| 116 | ;; Add the service if the host is unknown. This means that if a | ||
| 117 | ;; service is available on multiple network interfaces for a single | ||
| 118 | ;; host, only the first interface found will be considered. | ||
| 119 | (unless (hash-ref %known-hosts service-name) | ||
| 120 | (let* ((address (inet-ntop family address)) | ||
| 121 | (local-address (interface->ip-address interface)) | ||
| 122 | (service* (avahi-service | ||
| 123 | (name service-name) | ||
| 124 | (type service-type) | ||
| 125 | (interface interface) | ||
| 126 | (local-address local-address) | ||
| 127 | (address address) | ||
| 128 | (port port) | ||
| 129 | (txt txt)))) | ||
| 130 | (hash-set! %known-hosts service-name service*) | ||
| 131 | (proc 'new-service service*))))) | ||
| 132 | (free-service-resolver! resolver)) | ||
| 133 | |||
| 134 | (define (service-browser-callback browser interface protocol event | ||
| 135 | service-name service-type | ||
| 136 | domain flags) | ||
| 137 | (cond | ||
| 138 | ((eq? event browser-event/new) | ||
| 139 | (make-service-resolver (service-browser-client browser) | ||
| 140 | interface protocol | ||
| 141 | service-name service-type domain | ||
| 142 | protocol/unspecified '() | ||
| 143 | service-resolver-callback)) | ||
| 144 | ((eq? event browser-event/remove) | ||
| 145 | (let ((service (hash-ref %known-hosts service-name))) | ||
| 146 | (when service | ||
| 147 | (proc 'remove-service service) | ||
| 148 | (hash-remove! %known-hosts service-name)))))) | ||
| 149 | |||
| 150 | (define client-callback | ||
| 151 | (lambda (client state) | ||
| 152 | (if (eq? state client-state/s-running) | ||
| 153 | (for-each (lambda (type) | ||
| 154 | (make-service-browser client | ||
| 155 | interface/unspecified | ||
| 156 | protocol/inet | ||
| 157 | type #f '() | ||
| 158 | service-browser-callback)) | ||
| 159 | types)))) | ||
| 160 | |||
| 161 | (let* ((poll (make-simple-poll)) | ||
| 162 | (client (make-client (simple-poll poll) | ||
| 163 | '() ;; no flags | ||
| 164 | client-callback))) | ||
| 165 | (and (client? client) | ||
| 166 | (while (not (stop-loop?)) | ||
| 167 | (iterate-simple-poll poll timeout))))) | ||
diff --git a/guix/self.scm b/guix/self.scm index 026dcd9c1a7..257c8eefde6 100644 --- a/guix/self.scm +++ b/guix/self.scm | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | (module-ref (resolve-interface module) variable)))) | 50 | (module-ref (resolve-interface module) variable)))) |
| 51 | (match-lambda | 51 | (match-lambda |
| 52 | ("guile" (ref '(gnu packages guile) 'guile-3.0/libgc-7)) | 52 | ("guile" (ref '(gnu packages guile) 'guile-3.0/libgc-7)) |
| 53 | ("guile-avahi" (ref '(gnu packages guile) 'guile-avahi)) | ||
| 53 | ("guile-json" (ref '(gnu packages guile) 'guile-json-4)) | 54 | ("guile-json" (ref '(gnu packages guile) 'guile-json-4)) |
| 54 | ("guile-ssh" (ref '(gnu packages ssh) 'guile-ssh)) | 55 | ("guile-ssh" (ref '(gnu packages ssh) 'guile-ssh)) |
| 55 | ("guile-git" (ref '(gnu packages guile) 'guile-git)) | 56 | ("guile-git" (ref '(gnu packages guile) 'guile-git)) |
| @@ -784,6 +785,9 @@ Info manual." | |||
| 784 | (xz (specification->package "xz")) | 785 | (xz (specification->package "xz")) |
| 785 | (guix (specification->package "guix"))) | 786 | (guix (specification->package "guix"))) |
| 786 | "Return a file-like object that contains a compiled Guix." | 787 | "Return a file-like object that contains a compiled Guix." |
| 788 | (define guile-avahi | ||
| 789 | (specification->package "guile-avahi")) | ||
| 790 | |||
| 787 | (define guile-json | 791 | (define guile-json |
| 788 | (specification->package "guile-json")) | 792 | (specification->package "guile-json")) |
| 789 | 793 | ||
| @@ -812,8 +816,9 @@ Info manual." | |||
| 812 | (match (append-map (lambda (package) | 816 | (match (append-map (lambda (package) |
| 813 | (cons (list "x" package) | 817 | (cons (list "x" package) |
| 814 | (package-transitive-propagated-inputs package))) | 818 | (package-transitive-propagated-inputs package))) |
| 815 | (list guile-gcrypt gnutls guile-git guile-json | 819 | (list guile-gcrypt gnutls guile-git guile-avahi |
| 816 | guile-ssh guile-sqlite3 guile-zlib guile-lzlib)) | 820 | guile-json guile-ssh guile-sqlite3 guile-zlib |
| 821 | guile-lzlib)) | ||
| 817 | (((labels packages _ ...) ...) | 822 | (((labels packages _ ...) ...) |
| 818 | packages))) | 823 | packages))) |
| 819 | 824 | ||
