From 1a43f24c5e848f07c94e291637ef30210c87fbe5 Mon Sep 17 00:00:00 2001 From: Rohan Prinja Date: Thu, 16 Jul 2015 13:06:25 +0530 Subject: [PATCH 2/5] guix/build/syscalls.scm: add wrapper accessors for netmask, addr and broadaddr --- guix/build/syscalls.scm | 108 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 5 deletions(-) diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm index d155f49..800a3a8 100644 --- a/guix/build/syscalls.scm +++ b/guix/build/syscalls.scm @@ -435,6 +435,16 @@ index START + LEN - 1" (define %struct-ifaddrs-type `(* * ,unsigned-int * * * *)) +;; Size of 'struct sockaddr' in bytes. +;; See also: bind (2). +(define %sizeof-struct-sockaddr + (+ 14 (sizeof unsigned-short))) + +(define (ifaddrs-pointer->bv ptr) + "Return a bytevector aliasing the memory pointed to by a +'struct ifaddrs' pointer, passed as a pointer object PTR." + (pointer->bytevector ptr (sizeof %struct-ifaddrs-type))) + ;; Initializer for 'struct ifaddrs'. (define %struct-ifaddrs-init (list %null-pointer @@ -445,6 +455,22 @@ index START + LEN - 1" %null-pointer %null-pointer)) +(define (next-ifaddr-ptr bv) + "Return a bytevector aliasing the memory pointed to by the +ifa_next field of a struct ifaddrs* pointer passed as a +bytevector BV." + (let* ((ptr-size (sizeof '*)) + (address (cond ((= ptr-size 4) (bytevector-u32-native-ref bv 0)) + ((= ptr-size 8) (bytevector-u64-native-ref bv 0))))) + (make-pointer address))) + +;; Return the bytevector aliasing the memory pointed to by +;; the ifa-next field in a 'struct ifaddrs' pointer passed in +;; as a bytevector. +(define next-ifaddr + (compose ifaddrs-pointer->bv + next-ifaddr-ptr)) + (define %getifaddrs (let* ((func-ptr (dynamic-func "getifaddrs" (dynamic-link))) (proc (pointer->procedure int func-ptr (list '*)))) @@ -468,25 +494,97 @@ index START + LEN - 1" (make-interface-address (pointer->string (make-pointer name-ptr)) flags (make-pointer addr) - netmask + (make-pointer netmask) (make-pointer broadaddr) (make-pointer data))))) +;; Is an interface the last in the intrusive linked list of struct ifaddrs? +;; Here, the only argument is a bytevector aliasing the memory pointed to by +;; a 'struct ifaddrs' pointer. +(define last-interface? + (compose null-pointer? next-ifaddr-ptr)) + +(define (pack-ifaddrs bv) + "Strip out the needless 4-byte padding after the +unsigned-int ifa-flags field" + (if (and (= 8 (sizeof '*)) + (= 4 (sizeof unsigned-int))) + (let* ((res (make-bytevector 52 0))) + (bytevector-copy! bv 0 res 0 20) + (bytevector-copy! bv 24 res 20 32) + res) + bv)) + (define (getifaddrs) "Return the list of network interfaces on the local system." (let ((ifaddrs (%getifaddrs))) (let loop ((curr ifaddrs) (res '())) (if (last-interface? curr) - (map make-ifaddrs (reverse res)) + (map (compose make-ifaddrs pack-ifaddrs) + (reverse res)) (loop (next-ifaddr curr) (cons curr res)))))) -;; Retrieve the ifa-name field from a 'struct ifaddrs' +;; Given a bytevector aliasing the memory pointed to by +;; a 'struct sockaddr' pointer, return a socket address. +(define-syntax-rule (bytevector->sockaddr bv) + (match (read-sockaddr-in bv 0) + ((family port address) + (if (member family (list AF_INET AF_INET6 AF_UNIX)) + (inet-ntop family address) + #f)))) + +;; Note: address fields in 'struct getifaddrs' are pointers to +;; 'struct sockaddr'. In 'interface-address-broadcast-addr' we are +;; implicitly typecasting this 'sockaddr' pointer to a +;; 'sockaddr_in' pointer. + +;; Note: getifaddrs returns multiple interfaces with the same +;; e.g. on my system I see multiple "eth0"s. The difference is +;; that for one of the eth0's, the family of the address +;; pointed to by the ifu.ifa-broadaddr field is 17, which is +;; not an AF_* constant. Hence the check for "(member family ...)". + +(define (extract-address-field iface field) + "Extract a field corresponding to an IPv4 address from a 'struct +sockaddr' from an record type." + (let* ((addr (field iface)) + (bv (pointer->bytevector addr %sizeof-struct-sockaddr))) + (bytevector->sockaddr bv))) + +;; Given an record IFACE, return its +;; address field as a sockaddr if it exists, otherwise return #f. +(define (interface-address-address iface) + (extract-address-field iface interface-address-addr)) + +;; Given an record IFACE, return its broadcast +;; address field as a sockaddr if it exists, otherwise return #f. +(define (interface-address-broadcast-addr iface) + (extract-address-field iface interface-address-broadaddr)) + +;; Given an record IFACE, return its netmask +;; address field as a sockaddr if it exists, otherwise return #f. +(define (interface-address-netmask-addr iface) + (extract-address-field iface interface-address-netmask)) + +;; Retrieve the ifa-next-ptr field from a 'struct ifaddrs' ;; pointer passed in as a bytevector BV. -(define-syntax-rule (ifaddr-name bv) +(define-syntax-rule (ifaddr-next-ptr bv) (match (read-ifaddrs bv 0) ((next name-ptr flags addr netmask broadaddr data) - (pointer->string (make-pointer name-ptr))))) + next))) + +;; Retrieve the bytes corresponding to the ifa-name field +;; from a 'struct ifaddrs' pointer passed in as a bytevector BV. +(define-syntax-rule (ifaddr-name-bytes bv) + (match (read-ifaddrs bv 0) + ((next name-ptr flags addr netmask broadaddr data) + name-ptr))) + +;; Retrieve the string pointed to by the ifa-name field +;; from a 'struct ifaddrs' pointer passed in as a bytevector BV. +(define-syntax-rule (ifaddr-name bv) + (pointer->string (make-pointer (ifaddr-name-bytes bv)))) ;; Retrieve the ifa-flags field from a 'struct ifaddrs' ;; pointer passed in as a bytevector BV. -- 1.9.1