1 (in-package :sb-bsd-sockets)
4 getsockopt(socket, level, int optname, void *optval, socklen_t *optlen)
5 setsockopt(socket, level, int optname, void *optval, socklen_t optlen)
6 ^ SOL_SOCKET or a protocol number
8 In terms of providing a useful interface, we have to face up to the
9 fact that most of these take different data types - some are integers,
10 some are booleans, some are foreign struct instances, etc etc
12 (define-socket-option lisp-name doc level number mangle-arg size mangle-return)
14 macro-expands to two functions that define lisp-name and (setf ,lisp-name)
15 and calls the functions mangle-arg and mangle-return on outgoing and incoming
18 Parameters passed to the function thus defined (lisp-name)
19 are all passed directly into mangle-arg. mangle-arg should return an
20 alien pointer - this is passed unscathed to the foreign routine, so
21 wants to have type (* t). Note that even for options that have
22 integer arguments, this is still a pointer to said integer.
24 size is the size of the buffer that the return of mangle-arg points
25 to, and also of the buffer that we should allocate for getsockopt
28 mangle-return is called with an alien buffer and should turn it into
29 something that the caller will want.
31 Code for options that not every system has should be conditionalised:
33 (if (boundp 'sockint::IP_RECVIF)
34 (define-socket-option so-receive-interface nil (getprotobyname "ip")
35 sockint::IP_RECVIF ... ))
38 (defmacro define-socket-option
39 (lisp-name documentation
40 level number buffer-type mangle-arg mangle-return mangle-setf-buffer
41 &optional features info)
43 (if (numberp (eval level))
45 `(get-protocol-by-name ,(string-downcase (symbol-name level)))))
46 (supportedp (or (null features) (sb-int:featurep features))))
49 (defun ,lisp-name (socket)
50 ,@(when documentation (list (concatenate 'string documentation " " info)))
52 `(sb-alien:with-alien ((size sb-alien:int)
53 (buffer ,buffer-type))
54 (setf size (sb-alien:alien-size ,buffer-type :bytes))
55 (if (= -1 (sockint::getsockopt (socket-file-descriptor socket)
57 (sb-alien:addr buffer)
59 #-win32 (sb-alien:addr size)))
60 (socket-error "getsockopt")
61 (,mangle-return buffer size)))
62 `(error 'unsupported-operator
63 :format-control "Socket option ~S is not supported in this platform."
64 :format-arguments (list ',lisp-name))))
65 (defun (setf ,lisp-name) (new-val socket)
67 `(sb-alien:with-alien ((buffer ,buffer-type))
68 (setf buffer ,(if mangle-arg
69 `(,mangle-arg new-val)
71 (when (= -1 (sockint::setsockopt (socket-file-descriptor socket)
73 (,mangle-setf-buffer buffer)
74 ,(if (eql buffer-type 'sb-alien:c-string)
76 `(sb-alien:alien-size ,buffer-type :bytes))))
77 (socket-error "setsockopt")))
78 `(error 'unsupported-operator
79 :format-control "Socket option ~S is not supported on this platform."
80 :format-arguments (list ',lisp-name)))))))
82 ;;; sockopts that have integer arguments
84 (defun foreign-int-to-integer (buffer size)
85 (assert (= size (sb-alien:alien-size sb-alien:int :bytes)))
88 (defmacro define-socket-option-int (name level number &optional features (info ""))
89 `(define-socket-option ,name nil ,level ,number
90 sb-alien:int nil foreign-int-to-integer sb-alien:addr ,features ,info))
92 (define-socket-option-int
93 sockopt-receive-low-water sockint::sol-socket sockint::so-rcvlowat)
94 (define-socket-option-int
95 sockopt-send-low-water sockint::sol-socket sockint::so-sndlowat)
96 (define-socket-option-int
97 sockopt-type sockint::sol-socket sockint::so-type)
98 (define-socket-option-int
99 sockopt-send-buffer sockint::sol-socket sockint::so-sndbuf)
100 (define-socket-option-int
101 sockopt-receive-buffer sockint::sol-socket sockint::so-rcvbuf)
102 (define-socket-option-int
103 sockopt-priority sockint::sol-socket sockint::so-priority :linux
104 "Available only on Linux.")
106 (define-socket-option-int
107 sockopt-tcp-keepcnt :tcp sockint::tcp-keepcnt :linux "Available only on Linux.")
108 (define-socket-option-int
109 sockopt-tcp-keepidle :tcp sockint::tcp-keepidle :linux "Available only on Linux.")
110 (define-socket-option-int
111 sockopt-tcp-keepintvl :tcp sockint::tcp-keepintvl :linux "Available only on Linux.")
113 ;;; boolean options are integers really
115 (defun foreign-int-to-bool (x size)
116 (if (zerop (foreign-int-to-integer x size))
120 (defun bool-to-foreign-int (val)
123 (defmacro define-socket-option-bool (name level c-name &optional features (info ""))
124 `(define-socket-option ,name
125 ,(format nil "~@<Return the value of the ~A socket option for SOCKET. ~
126 This can also be updated with SETF.~:@>"
127 (symbol-name c-name))
129 sb-alien:int bool-to-foreign-int foreign-int-to-bool sb-alien:addr
132 (define-socket-option-bool
133 sockopt-reuse-address sockint::sol-socket sockint::so-reuseaddr)
134 (define-socket-option-bool
135 sockopt-keep-alive sockint::sol-socket sockint::so-keepalive)
136 (define-socket-option-bool
137 sockopt-oob-inline sockint::sol-socket sockint::so-oobinline)
138 (define-socket-option-bool
139 sockopt-bsd-compatible sockint::sol-socket sockint::so-bsdcompat :linux
140 "Available only on Linux.")
141 (define-socket-option-bool
142 sockopt-pass-credentials sockint::sol-socket sockint::so-passcred :linux
143 "Available only on Linux.")
144 (define-socket-option-bool
145 sockopt-debug sockint::sol-socket sockint::so-debug)
146 (define-socket-option-bool
147 sockopt-dont-route sockint::sol-socket sockint::so-dontroute)
148 (define-socket-option-bool
149 sockopt-broadcast sockint::sol-socket sockint::so-broadcast)
151 (define-socket-option-bool sockopt-tcp-nodelay :tcp sockint::tcp-nodelay)
153 (defun identity-1 (x &rest args)
154 (declare (ignore args))
157 (define-socket-option sockopt-bind-to-device nil sockint::sol-socket
158 sockint::so-bindtodevice sb-alien:c-string identity identity-1 identity
159 :linux "Available only on Linux")
161 ;;; other kinds of socket option
163 ;;; so_peercred takes a ucre structure
164 ;;; so_linger struct linger {
165 ; int l_onoff; /* linger active */
166 ; int l_linger; /* how many seconds to linger for */
171 (sockopt-reuse-address 2)
173 (defun echo-server ()
174 (let ((s (make-inet-socket :stream (get-protocol-by-name "tcp"))))
175 (setf (sockopt-reuse-address s) t)
176 (setf (sockopt-bind-to-device s) "lo")
177 (socket-bind s (make-inet-address "127.0.0.1") 3459)
180 (let* ((s1 (socket-accept s))
181 (stream (socket-make-stream s1 :input t :output t :buffering :none)))
182 (let ((line (read-line stream)))
183 (format t "got one ~A ~%" line)
184 (format stream "~A~%" line))