1 (in-package :sb-bsd-sockets)
4 ((name :initarg :name :reader host-ent-name
5 :documentation "The name of the host")
6 ;; Deliberately not documented, since this isn't very useful,
7 ;; and the data isn't available when using getaddrinfo(). Unfortunately
9 (aliases :initarg :aliases :reader host-ent-aliases)
10 ;; presently always AF_INET. Not exported.
11 (address-type :initarg :type :reader host-ent-address-type)
12 (addresses :initarg :addresses :reader host-ent-addresses
13 :documentation "A list of addresses for this host."))
14 (:documentation "This class represents the results of an address lookup."))
16 (defgeneric host-ent-address (host-ent)
17 (:documentation "Returns some valid address for HOST-ENT."))
19 (defmethod host-ent-address ((host-ent host-ent))
20 (car (host-ent-addresses host-ent)))
22 #-sb-bsd-sockets-addrinfo
23 (defun make-host-ent (h &optional errno)
24 (when (sb-alien:null-alien h)
25 (name-service-error "gethostbyname" errno))
26 (let* ((length (sockint::hostent-length h))
27 (aliases (loop for i = 0 then (1+ i)
28 for al = (sb-alien:deref (sockint::hostent-aliases h) i)
32 (loop for i = 0 then (1+ i)
33 for ad = (sb-alien:deref (sockint::hostent-addresses h) i)
34 until (sb-alien:null-alien ad)
35 collect (ecase (sockint::hostent-type h)
37 ;; CLH: Work around x86-64 darwin bug here.
38 ;; The length is reported as 8, when it should be 4.
39 ;; FIXME: this is rumored to be fixed in 10.5
42 (assert (or (= length 4) (= length 8)))
43 (naturalize-unsigned-byte-8-array ad 4))
47 (naturalize-unsigned-byte-8-array ad length)))
50 (sb-alien:cast ad sb-alien:c-string))))))
51 (make-instance 'host-ent
52 :name (sockint::hostent-name h)
53 :type (sockint::hostent-type h)
55 :addresses addresses)))
57 (declaim (inline naturalize-unsigned-byte-8-array))
58 (defun naturalize-unsigned-byte-8-array (array length)
59 (let ((addr (make-array 4 :element-type '(unsigned-byte 8))))
61 (setf (elt addr i) (sb-alien:deref array i)))
66 #-sb-bsd-sockets-addrinfo
68 (sb-ext:defglobal **gethostby-lock**
69 (sb-thread:make-mutex :name "gethostby lock"))
71 (defun get-host-by-name (host-name)
72 "Returns a HOST-ENT instance for HOST-NAME or signals a NAME-SERVICE-ERROR.
73 HOST-NAME may also be an IP address in dotted quad notation or some other
74 weird stuff - see gethostbyname(3) for the details."
75 (sb-thread::with-system-mutex (**gethostby-lock** :allow-with-interrupts t)
76 (make-host-ent (sockint::gethostbyname host-name))))
78 (defun get-host-by-address (address)
79 "Returns a HOST-ENT instance for ADDRESS, which should be a vector of
80 (integer 0 255), or signals a NAME-SERVICE-ERROR. See gethostbyaddr(3)
82 (sb-thread::with-system-mutex (**gethostby-lock** :allow-with-interrupts t)
83 (sockint::with-in-addr packed-addr ()
84 (let ((addr-vector (coerce address 'vector)))
85 (loop for i from 0 below (length addr-vector)
86 do (setf (sb-alien:deref (sockint::in-addr-addr packed-addr) i)
88 (make-host-ent (sockint::gethostbyaddr packed-addr
90 sockint::af-inet)))))))
92 #+sb-bsd-sockets-addrinfo
93 (defconstant ni-max-host 1025) ;; Not inside PROGN because of #.
95 #+sb-bsd-sockets-addrinfo
97 (defun get-host-by-name (node)
98 "Returns a HOST-ENT instance for HOST-NAME or signals a NAME-SERVICE-ERROR.
99 HOST-NAME may also be an IP address in dotted quad notation or some other
100 weird stuff - see getaddrinfo(3) for the details."
101 (declare (optimize speed))
102 (sb-alien:with-alien ((info (* sockint::addrinfo)))
103 (let* ((err (sockint::getaddrinfo node nil nil (sb-alien:addr info)))
106 (let ((host-ent (make-instance 'host-ent
108 :type sockint::af-inet
111 (loop until (sb-alien::null-alien info)
112 ;; Only handle AF_INET currently.
114 (when (eq (sockint::addrinfo-family info) sockint::af-inet)
115 (let* ((sockaddr (sockint::addrinfo-addr info))
116 (address (sockint::sockaddr-in-addr sockaddr)))
117 ;; The same effective result can be multiple time
118 ;; in the list, with different socktypes. Only record
119 ;; each address once.
120 (setf (slot-value host-ent 'addresses)
121 (adjoin (naturalize-unsigned-byte-8-array address
123 (host-ent-addresses host-ent)
125 (setf info (sockint::addrinfo-next info)))
126 (sockint::freeaddrinfo to-free)
128 (addrinfo-error "getaddrinfo" err)))))
130 (defun get-host-by-address (address)
131 "Returns a HOST-ENT instance for ADDRESS, which should be a vector of
132 (integer 0 255), or signals a NAME-SERVICE-ERROR.
133 See gethostbyaddr(3) for details."
134 (declare (optimize speed)
136 (assert (= (length address) 4))
137 (sockint::with-sockaddr-in sockaddr ()
138 (sb-alien:with-alien ((host-buf (array char #.ni-max-host)))
139 #+darwin (setf (sockint::sockaddr-in-len sockaddr) 16)
140 (setf (sockint::sockaddr-in-family sockaddr) sockint::af-inet)
142 (setf (sb-alien:deref (sockint::sockaddr-in-addr sockaddr) i)
144 (let ((err (sockint::getnameinfo
146 (sb-alien:alien-size sockint::sockaddr-in :bytes)
147 (sb-alien:cast host-buf (* char)) ni-max-host
149 sockint::ni-namereqd)))
151 (make-instance 'host-ent
152 :name (sb-alien::c-string-to-string
153 (sb-alien:alien-sap host-buf)
154 (sb-impl::default-external-format)
156 :type sockint::af-inet
158 :addresses (list address))
159 (addrinfo-error "getnameinfo" err)))))))
163 (defvar *name-service-errno* 0
164 "The value of h_errno, after it's been fetched from Unix-land by calling
165 GET-NAME-SERVICE-ERRNO")
167 (defun name-service-error (where &optional errno)
168 ;; There was a dummy docstring here for the texinfo extractor, but I
169 ;; see no reason for this to be documented in the manual, and removed
171 (let ((*name-service-errno* (get-name-service-errno errno)))
172 ;; Comment next to NETDB_INTERNAL in netdb.h says "See errno.".
173 ;; This special case treatment hasn't actually been tested yet.
174 (if (and #-win32 (= *name-service-errno* sockint::NETDB-INTERNAL))
177 (condition-for-name-service-errno *name-service-errno*)))
178 (error condition :errno *name-service-errno* :syscall where)))))
180 (defun addrinfo-error (where error-code)
181 (let ((condition (condition-for-name-service-error-code error-code)))
182 (error condition :error-code error-code :syscall where)))
184 (define-condition name-service-error (error)
185 ((errno :initform nil :initarg :errno :reader name-service-error-errno)
186 (error-code :initform nil :initarg :error-code
187 :reader name-service-error-error-code)
188 (symbol :initform nil :initarg :symbol :reader name-service-error-symbol)
189 (syscall :initform "an unknown location" :initarg :syscall :reader name-service-error-syscall))
190 (:report (lambda (c s)
191 (let* ((errno (name-service-error-errno c))
192 (error-code (name-service-error-error-code c)))
193 (format s "Name service error in \"~A\": ~A (~A)"
194 (name-service-error-syscall c)
195 (or (name-service-error-symbol c)
198 (get-name-service-error-message errno error-code))))))
200 (defparameter *conditions-for-name-service-errno* nil)
201 ;; getaddrinfo and getnameinfo return an error code, rather than using
202 ;; h_errno. While on Linux there's no overlap between their possible
203 ;; values, this doesn't seem to be guaranteed on all systems.
204 (defparameter *conditions-for-name-service-error-code* nil)
206 ;; Define a special name-service-error for variour error cases, and associate
207 ;; them with the matching h_errno / error code.
208 (defmacro define-name-service-condition (errno-symbol error-code-symbol name)
210 (define-condition ,name (name-service-error)
211 ((errno-symbol :reader name-service-error-errno-symbol
212 :initform (quote ,errno-symbol))
213 (error-code-symbol :reader name-service-error-error-code-symbol
214 :initform (quote ,error-code-symbol))))
215 (push (cons ,errno-symbol (quote ,name))
216 *conditions-for-name-service-errno*)
217 #+sb-bsd-sockets-addrinfo
218 (push (cons ,error-code-symbol (quote ,name))
219 *conditions-for-name-service-error-code*)))
222 (define-name-service-condition
223 sockint::NETDB-INTERNAL
224 nil ;; Doesn't map directly to any getaddrinfo error code
225 netdb-internal-error)
227 (define-name-service-condition
228 sockint::NETDB-SUCCESS
229 nil ;; Doesn't map directly to any getaddrinfo error code
231 (define-name-service-condition
232 sockint::HOST-NOT-FOUND
234 host-not-found-error)
235 (define-name-service-condition
239 (define-name-service-condition
243 (define-name-service-condition
244 ;; Also defined as NO-DATA, with the same value
246 ;; getaddrinfo() as of RFC 3493 can no longer distinguish between
247 ;; host no found and address not found
251 (defun condition-for-name-service-errno (err)
252 (or (cdr (assoc err *conditions-for-name-service-errno* :test #'eql))
253 'name-service-error))
255 (defun condition-for-name-service-error-code (err)
256 (or (cdr (assoc err *conditions-for-name-service-error-code* :test #'eql))
257 'name-service-error))
259 (defun get-name-service-errno (&optional errno)
260 (setf *name-service-errno*
262 (sb-alien:alien-funcall
264 (sb-alien:extern-alien "get_h_errno" (function integer))
266 (sb-alien:extern-alien "WSAGetLastError" (function integer))))))
268 (defun get-name-service-error-message (errno error-code)
271 (sockint::h-strerror errno)
272 (sockint::gai-strerror error-code)))