(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 values network protocol number associated with the string NAME,
-using getprotobyname(2) (or getprotobyname_r if SB-THREAD is enabled) which
-typically looks in NIS or /etc/protocols; the protocol's canonical name, and a
-list of protocol aliases"
-
- ;;Brownie Points. Hopefully there's one person out there using
- ;;RSPF sockets and SBCL who will appreciate the extra info
+ "Given a protocol name, return the protocol number, the protocol name, and
+a list of protocol aliases"
+ ;; 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))))))
- #+sb-thread
+ 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))
+ (max-buffer 10000)
+ (result-buf nil)
+ (buffer nil)
+ #-solaris
+ (result nil))
(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))))))))
- #-sb-thread
- (let ((ent (sockint::getprotobyname name)))
- (if (sb-alien::null-alien ent)
- (error 'unknown-protocol :name name))
- (protoent-to-values ent))))
+ (unwind-protect
+ (progn
+ (setf result-buf (sb-alien:make-alien sockint::protoent)
+ buffer (sb-alien:make-alien sb-alien:char buffer-length))
+ #-solaris
+ (setf result (sb-alien:make-alien (* sockint::protoent)))
+ (when (or (sb-alien:null-alien result-buf)
+ (sb-alien:null-alien buffer)
+ (sb-alien:null-alien result))
+ (error "Could not allocate foreign memory."))
+ (let ((res (sockint::getprotobyname-r
+ name result-buf buffer buffer-length #-solaris result)))
+ (cond ((eql res 0)
+ #-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)))
+ (t
+ (let ((errno (sb-unix::get-errno)))
+ (cond ((eql errno sockint::erange)
+ (incf buffer-length 1024)
+ (when (> buffer-length max-buffer)
+ (error "Exceeded max-buffer of ~d" max-buffer)))
+ (t
+ (error "Unexpected errno ~d" errno))))))))
+ (when result-buf
+ (sb-alien:free-alien result-buf))
+ (when buffer
+ (sb-alien:free-alien buffer))
+ #-solaris
+ (when result
+ (sb-alien:free-alien result)))))
+ #-(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