(:integer EOPNOTSUPP "EOPNOTSUPP")
(:integer EPERM "EPERM")
(:integer EPROTONOSUPPORT "EPROTONOSUPPORT")
+ (:integer ERANGE "ERANGE")
(:integer ESOCKTNOSUPPORT "ESOCKTNOSUPPORT")
(:integer ENETUNREACH "ENETUNREACH")
(:integer ENOTCONN "ENOTCONN")
(integer proto "int" "p_proto")))
(:function getprotobyname ("getprotobyname" (* protoent)
(name c-string)))
+
+;; getprotobyname_r is a thread-safe reentrant version of getprotobyname
+ #+os-provides-getprotoby-r
+ (:function getprotobyname-r ("getprotobyname_r" int
+ (name c-string)
+ (result_buf (* protoent))
+ (buffer (* char))
+ (buffer-len size-t)
+ #-solaris
+ (result (* (* protoent)))))
+
+
(:function getprotobynumber ("getprotobynumber" (* protoent)
(proto int)))
+ ;;ditto, save for the getprotobynumber part
+ #+os-provides-getprotoby-r
+ (:function getprotobynumber-r ("getprotobynumber_r" int
+ (proto int)
+ (result_buf (* protoent))
+ (buffer (* char))
+ (buffer-len size-t)
+ #-solaris
+ (result (* (* protoent)))))
+
(:integer inaddr-any "INADDR_ANY")
(:structure in-addr ("struct in_addr"
((array (unsigned 8)) addr "u_int32_t" "s_addr")))
(format s "Protocol not found: ~a" (prin1-to-string
(unknown-protocol-name c))))))
+#+(and sb-thread (not os-provides-getprotoby-r))
+;; Since getprotobyname is not thread-safe, we need a lock.
+(sb-ext:defglobal **getprotoby-lock** (sb-thread:make-mutex :name "getprotoby lock"))
+
;;; getprotobyname only works in the internet domain, which is why this
;;; is here
(defun get-protocol-by-name (name) ;exported
- "Returns the network protocol number associated with the string NAME,
-using getprotobyname(2) which typically looks in NIS or /etc/protocols"
- ;; for extra brownie points, could return canonical protocol name
- ;; and aliases as extra values
- (let ((ent (sockint::getprotobyname name)))
- (if (sb-alien::null-alien ent)
- (error 'unknown-protocol :name name))
- (sockint::protoent-proto ent)))
+
+ ;; Brownie Points. Hopefully there's one person out there using
+ ;; RSPF sockets and SBCL who will appreciate the extra info
+ (labels ((protoent-to-values (protoent)
+ (values
+ (sockint::protoent-proto protoent)
+ (sockint::protoent-name protoent)
+ (let ((index 0))
+ (loop
+ for alias = (sb-alien:deref (sockint::protoent-aliases protoent) index)
+ while (not (sb-alien:null-alien alias))
+ do (incf index)
+ collect (sb-alien::c-string-to-string (sb-alien:alien-sap alias)
+ (sb-impl::default-external-format)
+ 'character))))))
+ #+(and sb-thread os-provides-getprotoby-r)
+ (let ((buffer-length 1024)
+ (max-buffer 10000))
+ (declare (type fixnum buffer-length)
+ (type fixnum max-buffer))
+ (loop
+ (sb-alien:with-alien ((result-buf (* sockint::protoent)
+ (sb-alien:make-alien sockint::protoent))
+ (buffer (* char )
+ (sb-alien:make-alien sb-alien:char buffer-length))
+ #-solaris
+ (result (* (* sockint::protoent))
+ (sb-alien:make-alien (* sockint::protoent))))
+
+ (let ((res (sockint::getprotobyname-r name
+ result-buf
+ buffer
+ buffer-length
+ #-solaris
+ result)))
+ (if (eql res 0)
+ (progn
+ #-solaris
+ (when (sb-alien::null-alien (sb-alien:deref result 0))
+ (error 'unknown-protocol :name name))
+ (return-from get-protocol-by-name
+ (protoent-to-values result-buf)))
+ (let ((errno (sb-unix::get-errno)))
+ (if (eql errno sockint::erange)
+ (progn
+ (incf buffer-length 1024)
+ (if (> buffer-length max-buffer)
+ (error "Exceeded max-buffer of ~d" max-buffer)))
+ (error "Unexpected errno ~d" errno))))))))
+ #-(and sb-thread os-provides-getprotoby-r)
+ (tagbody
+ (flet ((get-it ()
+ (let ((ent (sockint::getprotobyname name)))
+ (if (sb-alien::null-alien ent)
+ (go :error)
+ (return-from get-protocol-by-name (protoent-to-values ent))))))
+ #+sb-thread
+ (sb-thread::with-system-mutex (**getprotoby-lock**)
+ (get-it))
+ #-sb-thread
+ (get-it))
+ :error
+ (error 'unknown-protocol :name name))))
;;; our protocol provides make-sockaddr-for, size-of-sockaddr,
;;; bits-of-sockaddr