ADDED ulex/netutil/testit.scm Index: ulex/netutil/testit.scm ================================================================== --- /dev/null +++ ulex/netutil/testit.scm @@ -0,0 +1,6 @@ + +(use ulex-netutil) +(use test) + +(test #f #t (not (not (member "127.0.0.1" (get-all-ips))))) + ADDED ulex/netutil/ulex-netutil.meta Index: ulex/netutil/ulex-netutil.meta ================================================================== --- /dev/null +++ ulex/netutil/ulex-netutil.meta @@ -0,0 +1,16 @@ +;; -*- scheme -*- +( +; Your egg's license: +(license "BSD") + +; Pick one from the list of categories (see below) for your egg and enter it +; here. +(category db) + +(needs foreign ) + +; A list of eggs required for TESTING ONLY. See the `Tests' section. +(test-depends test) + +(author "Brandon Barclay") +(synopsis "Get all IP addresses for all interfaces.")) ADDED ulex/netutil/ulex-netutil.release-info Index: ulex/netutil/ulex-netutil.release-info ================================================================== --- /dev/null +++ ulex/netutil/ulex-netutil.release-info @@ -0,0 +1,3 @@ +(repo fossil "http://www.kiatoa.com/cgi-bin/fossils/{egg-name}") +(uri zip "http://www.kiatoa.com/cgi-bin/fossils/{egg-name}/zip/{egg-name}.zip?uuid={egg-release}") +(release "0.1") ADDED ulex/netutil/ulex-netutil.scm Index: ulex/netutil/ulex-netutil.scm ================================================================== --- /dev/null +++ ulex/netutil/ulex-netutil.scm @@ -0,0 +1,134 @@ +;;; ulex: Distributed sqlite3 db +;;; +;; Copyright (C) 2018 Matt Welland +;; Redistribution and use in source and binary forms, with or without +;; modification, is permitted. +;; +;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +;; OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +;; USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +;; DAMAGE. + +;;====================================================================== +;; ABOUT: +;; See README in the distribution at https://www.kiatoa.com/fossils/ulex +;; NOTES: +;; provides all ipv4 addresses for all interfaces +;; +;;====================================================================== + +;; get IP addresses from ALL interfaces +(module ulex-netutil + (get-all-ips get-my-best-address get-all-ips-sorted) + +(import scheme chicken data-structures foreign ports regex-case posix) + + +;; #include +;; #include +;; #include +;; #include + +(foreign-declare "#include \"sys/types.h\"") +(foreign-declare "#include \"sys/socket.h\"") +(foreign-declare "#include \"ifaddrs.h\"") +(foreign-declare "#include \"arpa/inet.h\"") + +;; get IP addresses from ALL interfaces +(define get-all-ips + (foreign-safe-lambda* scheme-object () + " + +// from https://stackoverflow.com/questions/17909401/linux-c-get-default-interfaces-ip-address : + + + C_word lst = C_SCHEME_END_OF_LIST, len, str, *a; +// struct ifaddrs *ifa, *i; +// struct sockaddr *sa; + + struct ifaddrs * ifAddrStruct = NULL; + struct ifaddrs * ifa = NULL; + void * tmpAddrPtr = NULL; + + if ( getifaddrs(&ifAddrStruct) != 0) + C_return(C_SCHEME_FALSE); + +// for (i = ifa; i != NULL; i = i->ifa_next) { + for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family==AF_INET) { // Check it is + // a valid IPv4 address + tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + char addressBuffer[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); +// printf(\"%s IP Address %s\\n\", ifa->ifa_name, addressBuffer); + len = strlen(addressBuffer); + a = C_alloc(C_SIZEOF_PAIR + C_SIZEOF_STRING(len)); + str = C_string(&a, len, addressBuffer); + lst = C_a_pair(&a, str, lst); + } + +// else if (ifa->ifa_addr->sa_family==AF_INET6) { // Check it is +// // a valid IPv6 address +// tmpAddrPtr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; +// char addressBuffer[INET6_ADDRSTRLEN]; +// inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); +//// printf(\"%s IP Address %s\\n\", ifa->ifa_name, addressBuffer); +// len = strlen(addressBuffer); +// a = C_alloc(C_SIZEOF_PAIR + C_SIZEOF_STRING(len)); +// str = C_string(&a, len, addressBuffer); +// lst = C_a_pair(&a, str, lst); +// } + +// else { +// printf(\" not an IPv4 address\\n\"); +// } + + } + + freeifaddrs(ifa); + C_return(lst); + +")) + +;; Change this to bias for addresses with a reasonable broadcast value? +;; +(define (ip-pref-less? a b) + (let* ((rate (lambda (ipstr) + (regex-case ipstr + ( "^127\\." _ 0 ) + ( "^(10\\.0|192\\.168\\.)\\..*" _ 1 ) + ( else 2 ) )))) + (< (rate a) (rate b)))) + + +(define (get-my-best-address) + (let ((all-my-addresses (get-all-ips)) + ;;(all-my-addresses-old (vector->list (hostinfo-addresses (hostname->hostinfo (get-host-name))))) + ) + (cond + ((null? all-my-addresses) + (get-host-name)) ;; no interfaces? + ((eq? (length all-my-addresses) 1) + (car all-my-addresses)) ;; only one to choose from, just go with it + + (else + (car (sort all-my-addresses ip-pref-less?))) + ;; (else + ;; (ip->string (car (filter (lambda (x) ;; take any but 127. + ;; (not (eq? (u8vector-ref x 0) 127))) + ;; all-my-addresses)))) + + ))) + +(define (get-all-ips-sorted) + (sort (get-all-ips) ip-pref-less?)) + +) ADDED ulex/netutil/ulex-netutil.setup Index: ulex/netutil/ulex-netutil.setup ================================================================== --- /dev/null +++ ulex/netutil/ulex-netutil.setup @@ -0,0 +1,11 @@ +;; Copyright 2007-2018, Matthew Welland. +;; +;; This program is made available under the GNU GPL version 2.0 or +;; greater. See the accompanying file COPYING for details. +;; +;; This program is distributed WITHOUT ANY WARRANTY; without even the +;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +;; PURPOSE. + +;;;; ulex.setup +(standard-extension 'ulex-netutil "0.1") ADDED ulex/portlogger/portlogger.meta Index: ulex/portlogger/portlogger.meta ================================================================== --- /dev/null +++ ulex/portlogger/portlogger.meta @@ -0,0 +1,16 @@ +;; -*- scheme -*- +( +; Your egg's license: +(license "BSD") + +; Pick one from the list of categories (see below) for your egg and enter it +; here. +(category db) + +(needs foreign ) + +; A list of eggs required for TESTING ONLY. See the `Tests' section. +(test-depends test sqlite3 regex) + +(author "Matthew Welland") +(synopsis "thoughtfully optain tcp port.")) ADDED ulex/portlogger/portlogger.release-info Index: ulex/portlogger/portlogger.release-info ================================================================== --- /dev/null +++ ulex/portlogger/portlogger.release-info @@ -0,0 +1,3 @@ +(repo fossil "http://www.kiatoa.com/cgi-bin/fossils/{egg-name}") +(uri zip "http://www.kiatoa.com/cgi-bin/fossils/{egg-name}/zip/{egg-name}.zip?uuid={egg-release}") +(release "0.1") ADDED ulex/portlogger/portlogger.scm Index: ulex/portlogger/portlogger.scm ================================================================== --- /dev/null +++ ulex/portlogger/portlogger.scm @@ -0,0 +1,167 @@ +;;====================================================================== +;; P O R T L O G G E R - track ports used on the current machine +;;====================================================================== + +;; + +(module portlogger + (pl-open-run-close pl-find-port pl-release-port pl-open-db pl-get-prev-used-port pl-get-port-state pl-take-port) + (import scheme + posix + chicken + data-structures + ;ports + extras + ;files + ;mailbox + ;telemetry + regex + ;regex-case + + ) + (use (prefix sqlite3 sqlite3:)) + (use posix) + (use regex) + + (define (pl-open-db fname) + (let* ((avail #t) ;; for now - assume wait on journal not needed (tasks:wait-on-journal fname 5 remove: #t)) ;; wait up to about 10 seconds for the journal to go away + (exists (file-exists? fname)) + (db (if avail + (sqlite3:open-database fname) + (begin + (system (conc "rm -f " fname)) + (sqlite3:open-database fname)))) + (handler (sqlite3:make-busy-timeout 136000)) + (canwrite (file-write-access? fname))) + (sqlite3:set-busy-handler! db handler) + (sqlite3:execute db "PRAGMA synchronous = 0;") + (sqlite3:execute + db + "CREATE TABLE IF NOT EXISTS ports ( + port INTEGER PRIMARY KEY, + state TEXT DEFAULT 'not-used', + fail_count INTEGER DEFAULT 0, + update_time TIMESTAMP DEFAULT (strftime('%s','now')) );") + db)) + + (define (pl-open-run-close proc . params) + (let* ((fname (conc "/tmp/." (current-user-name) "-portlogger.db")) + (avail #t)) ;; (tasks:wait-on-journal fname 10))) ;; wait up to about 10 seconds for the journal to go away + ;; (handle-exceptions + ;; exn + ;; (begin + ;; ;; (release-dot-lock fname) + ;; (debug:print-error 0 *default-log-port* "pl-open-run-close failed. " proc " " params) + ;; (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn)) + ;; (debug:print 5 *default-log-port* "exn=" (condition->list exn)) + ;; (if (file-exists? fname)(delete-file fname)) ;; brutally get rid of it + ;; (print-call-chain (current-error-port))) + (let* (;; (lock (obtain-dot-lock fname 2 9 10)) + (db (pl-open-db fname)) + (res (apply proc db params))) + (sqlite3:finalize! db) + ;; (release-dot-lock fname) + res))) + ;; ) + + ;; (fold-row PROC INIT DATABASE SQL . PARAMETERS) + (define (pl-take-port db portnum) + (let* ((qry1 "INSERT INTO ports (port,state) VALUES (?,?);") + (qry2 "UPDATE ports SET state=?,update_time=strftime('%s','now') WHERE port=?;")) + (let* ((curr (pl-get-port-state db portnum)) + (res (case (string->symbol (or curr "n/a")) + ((released) (sqlite3:execute db qry2 "taken" portnum) 'taken) + ((not-tried n/a) (sqlite3:execute db qry1 portnum "taken") 'taken) + ((taken) 'already-taken) + ((failed) 'failed) + (else 'error)))) + ;; (print "res=" res) + res))) + + (define (pl-get-prev-used-port db) + ;; (handle-exceptions + ;; exn + ;; (with-output-to-port (current-error-port) + ;; (lambda () + ;; (print "EXCEPTION: portlogger database probably overloaded or unreadable. If you see this message again remove /tmp/.$USER-portlogger.db") + ;; (print " message: " ((condition-property-accessor 'exn 'message) exn)) + ;; (print "exn=" (condition->list exn)) + ;; (print-call-chain) ;; (current-error-port)) + ;; (print "Continuing anyway.") + ;; #f)) + (let ((res (sqlite3:fold-row + (lambda (var curr) + (or curr var curr)) + #f + db "SELECT port FROM ports WHERE state='released';"))) + (if res res #f))) + ;; ) + + (define (pl-find-port db acfg #!key (lowport 32768)) + ;;(slite3:with-transaction + ;; db + ;; (lambda () + (let loop ((numtries 0)) + (let* ((portnum (or (pl-get-prev-used-port db) + (+ lowport ;; top of registered ports is 49152 but let's use ports in the registered range + (random (- 64000 lowport)))))) + ;; (handle-exceptions + ;; exn + ;; (with-output-to-port (current-error-port) + ;; (lambda () + ;; (print "EXCEPTION: portlogger database probably overloaded or unreadable. If you see this message again remove /tmp/.$USER-portlogger.db") + ;; (print " message: " ((condition-property-accessor 'exn 'message) exn)) + ;; (print "exn=" (condition->list exn)) + ;; (print-call-chain) + ;; (print "Continuing anyway."))) + (pl-take-port db portnum) ;; always "take the port" + (if (pl-is-port-available portnum) + portnum + (begin + (pl-set-port db portnum "taken") + (loop (add1 numtries))))))) + + + ;; set port to "released", "failed" etc. + ;; + (define (pl-set-port db portnum value) + (sqlite3:execute db "UPDATE ports SET state=?,update_time=strftime('%s','now') WHERE port=?;") value portnum) + + ;; set port to "released", "failed" etc. + ;; + (define (pl-get-port-state db portnum) + (let ((res (sqlite3:fold-row ;; get the state of given port or "not-tried" + (lambda (var curr) ;; function on init/last current + (or curr var curr)) + #f ;; init + db "SELECT state FROM ports WHERE port=?;" + portnum))) ;; the parameter to the query + (if res res #f))) + + ;; (slite3:exec (slite3:sql db "UPDATE ports SET state=?,update_time=strftime('%s','now') WHERE port=?;") value portnum)) + + ;; release port + (define (pl-release-port db portnum) + (sqlite3:execute db "UPDATE ports SET state=?,update_time=strftime('%s','now') WHERE port=?;" "released" portnum) + (sqlite3:change-count db)) + + ;; set port to failed (attempted to take but got error) + ;; + (define (pl-set-failed db portnum) + (sqlite3:execute db "UPDATE ports SET state='failed',fail_count=fail_count+1,update_time=strftime('%s','now') WHERE port=?;" portnum) + (sqlite3:change-count db)) + + ;; pulled from mtut - TODO: remove from mtut, find a way *without* using netstat + ;; + (define (pl-is-port-available port-num) + (let-values (((inp oup pid) + (process "netstat" (list "-tulpn" )))) + (let loop ((inl (read-line inp))) + (if (not (eof-object? inl)) + (begin + (if (string-search (regexp (conc ":" port-num "\\s+")) inl) + #f + (loop (read-line inp)))) + #t)))) + + ) ;; end module ADDED ulex/portlogger/portlogger.setup Index: ulex/portlogger/portlogger.setup ================================================================== --- /dev/null +++ ulex/portlogger/portlogger.setup @@ -0,0 +1,11 @@ +;; Copyright 2007-2018, Matthew Welland. +;; +;; This program is made available under the GNU GPL version 2.0 or +;; greater. See the accompanying file COPYING for details. +;; +;; This program is distributed WITHOUT ANY WARRANTY; without even the +;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +;; PURPOSE. + +;;;; portlogger.setup +(standard-extension 'portlogger "0.1") ADDED ulex/portlogger/test.scm Index: ulex/portlogger/test.scm ================================================================== --- /dev/null +++ ulex/portlogger/test.scm @@ -0,0 +1,25 @@ +(use portlogger) +(use test) + +(test-begin "portlogger") +(use (prefix sqlite3 sqlite3:)) + +(define *port* #f) +(define *area* #f) +(test #f #f (begin + (pl-open-run-close + (lambda (db b) + (pl-get-prev-used-port db)) + *area*) + #f)) +(test #f #f (pl-open-run-close (lambda (db b)(pl-get-port-state db 1234567)) *area*)) +(test #f #f (number? (pl-open-run-close (lambda (db b)(pl-take-port db 123456)) *area*))) +(test #f #t (number? (let ((port (pl-open-run-close pl-find-port *area*))) + (set! *port* port) + port))) +(test #f 1 (pl-open-run-close pl-release-port *port*)) +(test #f "released" (pl-open-run-close + (lambda (db) + (sqlite3:first-result db "select state from ports where port=?" *port*)))) + +(test-end "portlogger") ADDED ulex/telemetry/telemetry-test-client.scm Index: ulex/telemetry/telemetry-test-client.scm ================================================================== --- /dev/null +++ ulex/telemetry/telemetry-test-client.scm @@ -0,0 +1,12 @@ + +(load "telemetry.scm") + +(import telemetry) + +(print 1) +(telemetry-open "localhost" 12346) +(print 2) +(telemetry-send "goo") +(print 3) +(telemetry-send "goo2") +(print 4) ADDED ulex/telemetry/telemetry-test-server.scm Index: ulex/telemetry/telemetry-test-server.scm ================================================================== --- /dev/null +++ ulex/telemetry/telemetry-test-server.scm @@ -0,0 +1,18 @@ + +(load "telemetry.scm") +(import telemetry) +(print "before") +(use mailbox) +(use mailbox-threads) +(use srfi-18) + +(set! handler-seq 0) +(define (handler msg) + (set! handler-seq (add1 handler-seq)) + (print "=============") + (print handler-seq msg)) + +(telemetry-server 12346 handler) + + +(print "after") ADDED ulex/telemetry/telemetry.meta Index: ulex/telemetry/telemetry.meta ================================================================== --- /dev/null +++ ulex/telemetry/telemetry.meta @@ -0,0 +1,21 @@ +;; -*- scheme -*- +( +; Your egg's license: +(license "BSD") + +; Pick one from the list of categories (see below) for your egg and enter it +; here. +(category db) + +; A list of eggs dbi depends on. If none, you can omit this declaration +; altogether. If you are making an egg for chicken 3 and you need to use +; procedures from the `files' unit, be sure to include the `files' egg in the +; `needs' section (chicken versions < 3.4.0 don't provide the `files' unit). +; `depends' is an alias to `needs'. +(needs udp mailbox-threads z3 base64 ) + +; A list of eggs required for TESTING ONLY. See the `Tests' section. +(test-depends test) + +(author "Brandon Barclay") +(synopsis "A telemetry send/receive system using udp.")) ADDED ulex/telemetry/telemetry.release-info Index: ulex/telemetry/telemetry.release-info ================================================================== --- /dev/null +++ ulex/telemetry/telemetry.release-info @@ -0,0 +1,3 @@ +(repo fossil "http://www.kiatoa.com/cgi-bin/fossils/{egg-name}") +(uri zip "http://www.kiatoa.com/cgi-bin/fossils/{egg-name}/zip/{egg-name}.zip?uuid={egg-release}") +(release "0.1") ADDED ulex/telemetry/telemetry.scm Index: ulex/telemetry/telemetry.scm ================================================================== --- /dev/null +++ ulex/telemetry/telemetry.scm @@ -0,0 +1,124 @@ + +(module telemetry + (telemetry-open telemetry-send telemetry-close telemetry-server + telemetry-show-debugs telemetry-hide-debugs ) + + (import chicken scheme data-structures + base64 srfi-18 + z3 udp posix extras ports mailbox mailbox-threads) + + (use udp) + (use base64) + (use z3) + (use mailbox-threads) + + (define *telemetry:telemetry-log-state* 'startup) + (define *telemetry:telemetry-log-socket* #f) + + (define *debug-print-flag* #f) + + (define (telemetry-show-debugs) + (set! *debug-print-flag* #t)) + + (define (telemetry-hide-debugs) + (set! *debug-print-flag* #f)) + + (define (debug-print . args) + (if *debug-print-flag* + (apply print "telemetry> " args))) + + (define (make-telemetry-server-thread port callback) + (let* ((thr + (make-thread + (lambda () + (let* ((s (udp-open-socket))) + (udp-bind! s #f port) + ;;(udp-connect! s "localhost" port) + (let loop ((seq 0)) + (debug-print "loop seq="seq) + (receive (n data from-host from-port) (udp-recvfrom s 640000) + (let* ((encapsulated-payload + (with-input-from-string + (z3:decode-buffer + (base64-decode data)) read)) + (callback-res `( (from-host . ,from-host) + (from-port . ,from-port) + (data-len . ,n) + ,@encapsulated-payload ))) + (callback callback-res)) + + ) + (loop (add1 seq))) + (udp-close-socket s)))))) + (thread-start! thr) + thr)) + + (define (telemetry-server port handler-callback) + (let* ((serv-thread (make-telemetry-server-thread port handler-callback))) + (print serv-thread) + (thread-join! serv-thread))) + + + (define (telemetry-open serverhost serverport) + (let* ((user (or (get-environment-variable "USER") "unknown")) + (host (or (get-environment-variable "HOST") "unknown"))) + (set! *telemetry:telemetry-log-state* + (handle-exceptions + exn + (begin + (debug-print "telemetry-open udp port failure") + 'broken) + (if (and serverhost serverport user host) + (let* ((s (udp-open-socket))) + ;;(udp-bind! s #f 0) + (udp-connect! s serverhost serverport) + (set! *telemetry:telemetry-log-socket* s) + 'open) + 'not-needed))))) + + + (define (telemetry-close) + (when (or (member *telemetry:telemetry-log-state* '(broken-or-no-server-preclose open)) *telemetry:telemetry-log-socket*) + (handle-exceptions + exn + (begin + (define *telemetry:telemetry-log-state* 'closed-fail) + (debug-print "telemetry-telemetry-log closure failure") + ) + (begin + (define *telemetry:telemetry-log-state* 'closed) + (udp-close-socket *telemetry:telemetry-log-socket*) + (set! *telemetry:telemetry-log-socket* #f))))) + + (define (telemetry-send payload) + (if (eq? 'open *telemetry:telemetry-log-state*) + (handle-exceptions + exn + (begin + (debug-print "telemetry-telemetry-log comms failure ; disabled (no server?)") + (define *telemetry:telemetry-log-state* 'broken-or-no-server-preclose) + (telemetry-close) + (define *telemetry:telemetry-log-state* 'broken-or-no-server) + (set! *telemetry:telemetry-log-socket* #f) + ) + (if (and *telemetry:telemetry-log-socket* payload) + (let* ((user (or (get-environment-variable "USER") "unknown")) + (host (or (get-environment-variable "HOST") "unknown")) + (encapsulated-payload + `( (user . ,user) + (host . ,host) + (pid . ,(current-process-id)) + (payload . ,payload) ) ) + (msg + (base64-encode + (z3:encode-buffer + (with-output-to-string (lambda () (pp encapsulated-payload))))))) + ;;(debug-print "pre-send") + (let ((res (udp-send *telemetry:telemetry-log-socket* msg))) + ;;(debug-print "post-send >"res"<") + res) + + )))) ) + + + ) ADDED ulex/telemetry/telemetry.setup Index: ulex/telemetry/telemetry.setup ================================================================== --- /dev/null +++ ulex/telemetry/telemetry.setup @@ -0,0 +1,11 @@ +;; Copyright 2007-2018, Matthew Welland. +;; +;; This program is made available under the GNU GPL version 2.0 or +;; greater. See the accompanying file COPYING for details. +;; +;; This program is distributed WITHOUT ANY WARRANTY; without even the +;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +;; PURPOSE. + +;;;; ulex.setup +(standard-extension 'telemetry "0.1") Index: ulex/tests/run.scm ================================================================== --- ulex/tests/run.scm +++ ulex/tests/run.scm @@ -43,11 +43,11 @@ ;;====================================================================== ;; Captainship ;;====================================================================== (define *udat1* (make-udat)) -(test #f #t (udat? (start-server-find-port *udat1*))) +(test #f #t (udat? (start-server-find-port *udat1* (+ 4242 (random 5000))))) (test-begin "captainship") (test #f #t (list? (get-all-captain-pkts *udat1*))) (test #f #t (udat? (let ((res (find-or-setup-captain *udat1*)))(print res) res))) (test-end "captainship") Index: ulex/ulex.scm ================================================================== --- ulex/ulex.scm +++ ulex/ulex.scm @@ -373,11 +373,11 @@ (car all-my-addresses)) ;; only one to choose from, just go with it (else (car (sort all-my-addresses ip-pref-less?))) ;; (else - ;; (ip->strin g(car (filter (lambda (x) ;; take any but 127. + ;; (ip->string (car (filter (lambda (x) ;; take any but 127. ;; (not (eq? (u8vector-ref x 0) 127))) ;; all-my-addresses)))) )))