sb-bsd-sockets: fix GET-HOST-BY-NAME and -ADDRESS on unthreaded builds
[sbcl.git] / contrib / sb-bsd-sockets / name-service.lisp
index 40c9cf5..0b731db 100644 (file)
@@ -1,16 +1,15 @@
 (in-package :sb-bsd-sockets)
 
 (defclass host-ent ()
-  ;; Unfortunately the docstring generator can't currently create.
-  ((name :initarg :name :accessor host-ent-name
+  ((name :initarg :name :reader host-ent-name
          :documentation "The name of the host")
    ;; Deliberately not documented, since this isn't very useful,
    ;; and the data isn't available when using getaddrinfo(). Unfortunately
    ;; it is exported.
-   (aliases :initarg :aliases :accessor host-ent-aliases)
+   (aliases :initarg :aliases :reader host-ent-aliases)
    ;; presently always AF_INET. Not exported.
-   (address-type :initarg :type :accessor host-ent-address-type)
-   (addresses :initarg :addresses :accessor host-ent-addresses
+   (address-type :initarg :type :reader host-ent-address-type)
+   (addresses :initarg :addresses :reader host-ent-addresses
               :documentation "A list of addresses for this host."))
   (:documentation "This class represents the results of an address lookup."))
 
@@ -21,7 +20,7 @@
   (car (host-ent-addresses host-ent)))
 
 (defun make-host-ent (h &optional errno)
-  (when (sb-grovel::foreign-nullp h)
+  (when (sb-alien:null-alien h)
     (name-service-error "gethostbyname" errno))
   (let* ((length (sockint::hostent-length h))
          (aliases (loop for i = 0 then (1+ i)
@@ -36,6 +35,7 @@
                           (#.sockint::af-inet
                            ;; CLH: Work around x86-64 darwin bug here.
                            ;; The length is reported as 8, when it should be 4.
+                           ;; FIXME: this is rumored to be fixed in 10.5
                            #+(and darwin x86-64)
                            (progn
                              (assert (or (= length 4) (= length 8)))
@@ -61,6 +61,9 @@
 
 ;;; Resolving
 
+#-sb-bsd-sockets-addrinfo
+(sb-ext:defglobal **gethostby-lock** (sb-thread:make-mutex :name "gethostby lock"))
+
 (defun get-host-by-name (host-name)
   "Returns a HOST-ENT instance for HOST-NAME or signals a NAME-SERVICE-ERROR.
 HOST-NAME may also be an IP address in dotted quad notation or some other
@@ -68,7 +71,8 @@ weird stuff - see gethostbyname(3) or getaddrinfo(3) for the details."
   #+sb-bsd-sockets-addrinfo
   (get-address-info host-name)
   #-sb-bsd-sockets-addrinfo
-  (make-host-ent (sockint::gethostbyname host-name)))
+  (sb-thread::with-system-mutex (**gethostby-lock** :allow-with-interrupts t)
+    (make-host-ent (sockint::gethostbyname host-name))))
 
 (defun get-host-by-address (address)
   "Returns a HOST-ENT instance for ADDRESS, which should be a vector of
@@ -77,22 +81,23 @@ weird stuff - see gethostbyname(3) or getaddrinfo(3) for the details."
   #+sb-bsd-sockets-addrinfo
   (get-name-info address)
   #-sb-bsd-sockets-addrinfo
-  (sockint::with-in-addr packed-addr ()
-    (let ((addr-vector (coerce address 'vector)))
-      (loop for i from 0 below (length addr-vector)
-            do (setf (sb-alien:deref (sockint::in-addr-addr packed-addr) i)
-                     (elt addr-vector i)))
-      (make-host-ent (sockint::gethostbyaddr packed-addr
-                                             4
-                                             sockint::af-inet)))))
+  (sb-thread::with-system-mutex (**gethostby-lock** :allow-with-interrupts t)
+    (sockint::with-in-addr packed-addr ()
+      (let ((addr-vector (coerce address 'vector)))
+        (loop for i from 0 below (length addr-vector)
+              do (setf (sb-alien:deref (sockint::in-addr-addr packed-addr) i)
+                       (elt addr-vector i)))
+        (make-host-ent (sockint::gethostbyaddr packed-addr
+                                               4
+                                               sockint::af-inet))))))
 
 ;;; Emulate the above two functions with getaddrinfo / getnameinfo
 
 #+sb-bsd-sockets-addrinfo
 (defun get-address-info (node)
-  (sb-alien:with-alien ((res (* (* sockint::addrinfo)) :local
-                             (sb-alien:make-alien (* sockint::addrinfo))))
-    (let ((err (sockint::getaddrinfo node nil nil res)))
+  (sb-alien:with-alien ((buf (sb-alien:array (* sockint::addrinfo) 1)))
+    (let* ((res (sb-alien:addr (sb-alien:deref buf 0)))
+           (err (sockint::getaddrinfo node nil nil res)))
       (if (zerop err)
           (let ((host-ent (make-instance 'host-ent
                                          :name node
@@ -109,12 +114,12 @@ weird stuff - see gethostbyname(3) or getaddrinfo(3) for the details."
                          ;; The same effective result can be multiple time
                          ;; in the list, with different socktypes. Only record
                          ;; each address once.
-                         (setf (host-ent-addresses host-ent)
+                         (setf (slot-value host-ent 'addresses)
                                (adjoin (naturalize-unsigned-byte-8-array address
                                                                          4)
                                        (host-ent-addresses host-ent)
                                        :test 'equalp)))))
-            (sockint::free-addrinfo (sb-alien:deref res))
+            (sockint::freeaddrinfo (sb-alien:deref res))
             host-ent)
           (addrinfo-error "getaddrinfo" err)))))
 
@@ -125,6 +130,7 @@ weird stuff - see gethostbyname(3) or getaddrinfo(3) for the details."
   (assert (= (length address) 4))
   (sockint::with-sockaddr-in sockaddr ()
     (sb-alien:with-alien ((host-buf (array char #.ni-max-host)))
+      #+darwin (setf (sockint::sockaddr-in-len sockaddr) 16)
       (setf (sockint::sockaddr-in-family sockaddr) sockint::af-inet)
       (dotimes (i 4)
         (setf (sb-alien:deref (sockint::sockaddr-in-addr sockaddr) i)
@@ -169,7 +175,7 @@ GET-NAME-SERVICE-ERRNO")
   (let ((condition (condition-for-name-service-error-code error-code)))
     (error condition :error-code error-code :syscall where)))
 
-(define-condition name-service-error (condition)
+(define-condition name-service-error (error)
   ((errno :initform nil :initarg :errno :reader name-service-error-errno)
    (error-code :initform nil :initarg :error-code
                :reader name-service-error-error-code)
@@ -229,8 +235,11 @@ GET-NAME-SERVICE-ERRNO")
     sockint::EAI-FAIL
     no-recovery-error)
 (define-name-service-condition
-    sockint::NO-ADDRESS  ;; Also defined as NO-DATA, with the same value
-    #-freebsd sockint::EAI-NODATA #+freebsd nil
+    ;; Also defined as NO-DATA, with the same value
+    sockint::NO-ADDRESS
+    ;; getaddrinfo() as of RFC 3493 can no longer distinguish between
+    ;; host no found and address not found
+    nil
     no-address-error)
 
 (defun condition-for-name-service-errno (err)