X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=contrib%2Fsb-bsd-sockets%2Fsockopt.lisp;h=7fa1ff7417b60bd3922671575345781cc8eecc04;hb=78fa16bf55be44cc16845be84d98023e83fb14bc;hp=04bf3bb831047a2978163b54fe5a1247a216d273;hpb=d4c7ab04ed10729a2cfa3321f4382d8a218ad958;p=sbcl.git diff --git a/contrib/sb-bsd-sockets/sockopt.lisp b/contrib/sb-bsd-sockets/sockopt.lisp index 04bf3bb..7fa1ff7 100644 --- a/contrib/sb-bsd-sockets/sockopt.lisp +++ b/contrib/sb-bsd-sockets/sockopt.lisp @@ -1,16 +1,5 @@ (in-package :sb-bsd-sockets) -#|| -

Socket Options

- -

A subset of socket options are supported, using a fairly -general framework which should make it simple to add more as required -- see sockopt.lisp for details. The name mapping from C is fairly -straightforward: SO_RCVLOWAT becomes -sockopt-receive-low-water and (setf -sockopt-receive-low-water). -||# - #| getsockopt(socket, level, int optname, void *optval, socklen_t *optlen) setsockopt(socket, level, int optname, void *optval, socklen_t optlen) @@ -20,7 +9,7 @@ In terms of providing a useful interface, we have to face up to the fact that most of these take different data types - some are integers, some are booleans, some are foreign struct instances, etc etc - (define-socket-option lisp-name level number mangle-arg size mangle-return) + (define-socket-option lisp-name doc level number mangle-arg size mangle-return) macro-expands to two functions that define lisp-name and (setf ,lisp-name) and calls the functions mangle-arg and mangle-return on outgoing and incoming @@ -42,51 +31,62 @@ something that the caller will want. Code for options that not every system has should be conditionalised: (if (boundp 'sockint::IP_RECVIF) - (define-socket-option so-receive-interface (getprotobyname "ip") + (define-socket-option so-receive-interface nil (getprotobyname "ip") sockint::IP_RECVIF ... )) - - |# (defmacro define-socket-option - (lisp-name level number buffer-type mangle-arg mangle-return mangle-setf-buffer) + (lisp-name documentation + level number buffer-type mangle-arg mangle-return mangle-setf-buffer + &optional features info) (let ((find-level (if (numberp (eval level)) level - `(get-protocol-by-name ,(string-downcase (symbol-name level)))))) + `(get-protocol-by-name ,(string-downcase (symbol-name level))))) + (supportedp (or (null features) (featurep features)))) `(progn (export ',lisp-name) - (defun ,lisp-name (socket &aux (fd (socket-file-descriptor socket))) - (sb-alien:with-alien ((size sb-alien:integer) - (buffer ,buffer-type)) - (setf size (sb-alien:alien-size ,buffer-type :bytes)) - (if (= -1 (sockint::getsockopt fd ,find-level ,number - (sb-alien:addr buffer) - (sb-alien:addr size))) - (socket-error "getsockopt") - (,mangle-return buffer size)))) - (defun (setf ,lisp-name) (new-val socket - &aux (fd (socket-file-descriptor socket))) - (sb-alien:with-alien ((buffer ,buffer-type)) - (setf buffer ,(if mangle-arg - `(,mangle-arg new-val) - `new-val)) - (when (= -1 (sockint::setsockopt fd ,find-level ,number - (,mangle-setf-buffer buffer) - ,(if (eql buffer-type 'sb-alien:c-string) - `(length new-val) - `(sb-alien:alien-size ,buffer-type :bytes)))) - (socket-error "setsockopt"))))))) + (defun ,lisp-name (socket) + ,@(when documentation (list (concatenate 'string documentation " " info))) + ,(if supportedp + `(sb-alien:with-alien ((size sb-alien:int) + (buffer ,buffer-type)) + (setf size (sb-alien:alien-size ,buffer-type :bytes)) + (if (= -1 (sockint::getsockopt (socket-file-descriptor socket) + ,find-level ,number + (sb-alien:addr buffer) + (sb-alien:addr size))) + (socket-error "getsockopt") + (,mangle-return buffer size))) + `(error 'unsupported-operator + :format-control "Socket option ~S is not supported in this platform." + :format-arguments (list ',lisp-name)))) + (defun (setf ,lisp-name) (new-val socket) + ,(if supportedp + `(sb-alien:with-alien ((buffer ,buffer-type)) + (setf buffer ,(if mangle-arg + `(,mangle-arg new-val) + `new-val)) + (when (= -1 (sockint::setsockopt (socket-file-descriptor socket) + ,find-level ,number + (,mangle-setf-buffer buffer) + ,(if (eql buffer-type 'sb-alien:c-string) + `(length new-val) + `(sb-alien:alien-size ,buffer-type :bytes)))) + (socket-error "setsockopt"))) + `(error 'unsupported-operator + :format-control "Socket option ~S is not supported on this platform." + :format-arguments (list ',lisp-name))))))) ;;; sockopts that have integer arguments (defun foreign-int-to-integer (buffer size) - (assert (= size (sb-alien:alien-size sb-alien:integer :bytes))) + (assert (= size (sb-alien:alien-size sb-alien:int :bytes))) buffer) -(defmacro define-socket-option-int (name level number) - `(define-socket-option ,name ,level ,number - sb-alien:integer nil foreign-int-to-integer sb-alien:addr)) +(defmacro define-socket-option-int (name level number &optional features (info "")) + `(define-socket-option ,name nil ,level ,number + sb-alien:int nil foreign-int-to-integer sb-alien:addr ,features ,info)) (define-socket-option-int sockopt-receive-low-water sockint::sol-socket sockint::so-rcvlowat) @@ -98,8 +98,9 @@ Code for options that not every system has should be conditionalised: sockopt-send-buffer sockint::sol-socket sockint::so-sndbuf) (define-socket-option-int sockopt-receive-buffer sockint::sol-socket sockint::so-rcvbuf) -#+linux(define-socket-option-int - sockopt-priority sockint::sol-socket sockint::so-priority) +(define-socket-option-int + sockopt-priority sockint::sol-socket sockint::so-priority :linux + "Available only on Linux.") ;;; boolean options are integers really @@ -111,9 +112,14 @@ Code for options that not every system has should be conditionalised: (defun bool-to-foreign-int (val) (if val 1 0)) -(defmacro define-socket-option-bool (name level number) - `(define-socket-option ,name ,level ,number - sb-alien:integer bool-to-foreign-int foreign-int-to-bool sb-alien:addr)) +(defmacro define-socket-option-bool (name level c-name &optional features (info "")) + `(define-socket-option ,name + ,(format nil "~@" + (symbol-name c-name)) + ,level ,c-name + sb-alien:int bool-to-foreign-int foreign-int-to-bool sb-alien:addr + ,features ,info)) (define-socket-option-bool sockopt-reuse-address sockint::sol-socket sockint::so-reuseaddr) @@ -121,10 +127,12 @@ Code for options that not every system has should be conditionalised: sockopt-keep-alive sockint::sol-socket sockint::so-keepalive) (define-socket-option-bool sockopt-oob-inline sockint::sol-socket sockint::so-oobinline) -#+linux(define-socket-option-bool - sockopt-bsd-compatible sockint::sol-socket sockint::so-bsdcompat) -#+linux(define-socket-option-bool - sockopt-pass-credentials sockint::sol-socket sockint::so-passcred) +(define-socket-option-bool + sockopt-bsd-compatible sockint::sol-socket sockint::so-bsdcompat :linux + "Available only on Linux.") +(define-socket-option-bool + sockopt-pass-credentials sockint::sol-socket sockint::so-passcred :linux + "Available only on Linux.") (define-socket-option-bool sockopt-debug sockint::sol-socket sockint::so-debug) (define-socket-option-bool @@ -138,8 +146,9 @@ Code for options that not every system has should be conditionalised: (declare (ignore args)) x) -#+linux(define-socket-option sockopt-bind-to-device sockint::sol-socket - sockint::so-bindtodevice sb-alien:c-string identity identity-1 identity) +(define-socket-option sockopt-bind-to-device nil sockint::sol-socket + sockint::so-bindtodevice sb-alien:c-string identity identity-1 identity + :linux "Available only on Linux") ;;; other kinds of socket option