Fix NET.TRIVIAL-SOCKETS.ASD
[iolib/alendvai.git] / net.sockets / common.lisp
blob2fa9e9ad6ce68bf9f781c84ea73e34130fc0fde5
1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Indent-tabs-mode: NIL -*-
2 ;;;
3 ;;; common.lisp --- Various helpers for bsd-sockets.
4 ;;;
5 ;;; Copyright (C) 2006-2008, Stelian Ionescu <sionescu@common-lisp.net>
6 ;;;
7 ;;; This code is free software; you can redistribute it and/or
8 ;;; modify it under the terms of the version 2.1 of
9 ;;; the GNU Lesser General Public License as published by
10 ;;; the Free Software Foundation, as clarified by the
11 ;;; preamble found here:
12 ;;; http://opensource.franz.com/preamble.html
13 ;;;
14 ;;; This program is distributed in the hope that it will be useful,
15 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;;; GNU General Public License for more details.
18 ;;;
19 ;;; You should have received a copy of the GNU Lesser General
20 ;;; Public License along with this library; if not, write to the
21 ;;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 ;;; Boston, MA 02110-1301, USA
24 (in-package :net.sockets)
26 ;;;; Types
28 (deftype ipv4-array () '(ub8-sarray 4))
29 (deftype ipv6-array () '(ub16-sarray 8))
31 ;;;; Byte-swap functions
33 (defun htons (short)
34 #+little-endian
35 (logior (ash (logand (the ub16 short) #x00FF) 8)
36 (ash (logand (the ub16 short) #xFF00) -8))
37 #+big-endian short)
39 (defun ntohs (short)
40 (htons short))
42 (defun htonl (long)
43 #+little-endian
44 (logior (ash (logand (the ub32 long) #x000000FF) 24)
45 (ash (logand (the ub32 long) #x0000FF00) 8)
46 (ash (logand (the ub32 long) #x00FF0000) -8)
47 (ash (logand (the ub32 long) #xFF000000) -24))
48 #+big-endian long)
50 (defun ntohl (long)
51 (htonl long))
53 ;;;; Conversion between address formats
55 (defun copy-simple-array-ub16-to-alien-vector (lisp-vec alien-vec)
56 (declare (type ipv6-array lisp-vec))
57 (dotimes (i 8)
58 (setf (mem-aref alien-vec :uint16 i)
59 (htons (aref lisp-vec i)))))
61 (defun map-ipv4-vector-to-ipv6 (addr)
62 (declare (type ipv4-array addr))
63 (let ((ipv6addr (make-array 8 :element-type 'ub16
64 :initial-element 0)))
65 ;; setting the IPv4 marker
66 (setf (aref ipv6addr 5) #xFFFF)
67 ;; setting the first two bytes
68 (setf (aref ipv6addr 6) (+ (ash (aref addr 0) 8)
69 (aref addr 1)))
70 ;; setting the last two bytes
71 (setf (aref ipv6addr 7) (+ (ash (aref addr 2) 8)
72 (aref addr 3)))
73 (values ipv6addr)))
75 (defun map-ipv6-vector-to-ipv4 (addr)
76 (declare (type ipv6-array addr))
77 (let ((ipv4addr (make-array 4 :element-type 'ub8
78 :initial-element 0)))
79 (setf (aref ipv4addr 0) (ldb (byte 8 8) (aref addr 6)))
80 (setf (aref ipv4addr 1) (ldb (byte 8 0) (aref addr 6)))
81 (setf (aref ipv4addr 2) (ldb (byte 8 8) (aref addr 7)))
82 (setf (aref ipv4addr 3) (ldb (byte 8 0) (aref addr 7)))
83 (values ipv4addr)))
85 ;;; From CLOCC's PORT library.
86 (defun vector-to-integer (vector)
87 "Convert a vector to a 32-bit unsigned integer."
88 (coercef vector 'ipv4-array)
89 (+ (ash (aref vector 0) 24)
90 (ash (aref vector 1) 16)
91 (ash (aref vector 2) 8)
92 (aref vector 3)))
94 (defun integer-to-vector (ipaddr)
95 "Convert a 32-bit unsigned integer to a vector."
96 (check-type ipaddr ub32 "an '(unsigned-byte 32)")
97 (let ((vector (make-array 4 :element-type 'ub8)))
98 (setf (aref vector 0) (ldb (byte 8 24) ipaddr)
99 (aref vector 1) (ldb (byte 8 16) ipaddr)
100 (aref vector 2) (ldb (byte 8 8) ipaddr)
101 (aref vector 3) (ldb (byte 8 0) ipaddr))
102 vector))
104 (defun in6-addr-to-ipv6-array (in6-addr)
105 (let ((vector (make-array 8 :element-type 'ub16)))
106 (dotimes (i 8)
107 (setf (aref vector i)
108 (ntohs (mem-aref in6-addr :uint16 i))))
109 vector))
111 ;;;; Constructors for SOCKADDR_* structs
113 (defun make-sockaddr-in (sin ub8-vector &optional (portno 0))
114 (declare (type ipv4-array ub8-vector) (type ub16 portno))
115 (bzero sin size-of-sockaddr-in)
116 (with-foreign-slots ((family addr port) sin sockaddr-in)
117 (setf family af-inet)
118 (setf addr (htonl (vector-to-integer ub8-vector)))
119 (setf port (htons portno)))
120 (values sin))
122 (defmacro with-sockaddr-in ((var address &optional (port 0)) &body body)
123 `(with-foreign-object (,var 'sockaddr-in)
124 (make-sockaddr-in ,var ,address ,port)
125 ,@body))
127 (defun make-sockaddr-in6 (sin6 ub16-vector &optional (portno 0))
128 (declare (type ipv6-array ub16-vector) (type ub16 portno))
129 (bzero sin6 size-of-sockaddr-in6)
130 (with-foreign-slots ((family addr port) sin6 sockaddr-in6)
131 (setf family af-inet6)
132 (copy-simple-array-ub16-to-alien-vector ub16-vector addr)
133 (setf port (htons portno)))
134 (values sin6))
136 (defmacro with-sockaddr-in6 ((var address &optional port) &body body)
137 `(with-foreign-object (,var 'sockaddr-in6)
138 (make-sockaddr-in6 ,var ,address ,port)
139 ,@body))
141 (defun make-sockaddr-un (sun string)
142 (declare (type string string))
143 (bzero sun size-of-sockaddr-un)
144 (with-foreign-slots ((family path) sun sockaddr-un)
145 (setf family af-local)
146 (with-foreign-string (c-string string)
147 (loop :for off :below (1- unix-path-max)
148 :do (setf (mem-aref path :uint8 off)
149 (mem-aref c-string :uint8 off)))))
150 (values sun))
152 (defmacro with-sockaddr-un ((var address) &body body)
153 `(with-foreign-object (,var 'sockaddr-un)
154 (make-sockaddr-un ,var ,address)
155 ,@body))
157 (defmacro with-sockaddr-storage ((var) &body body)
158 `(with-foreign-object (,var 'sockaddr-storage)
159 (bzero ,var size-of-sockaddr-storage)
160 ,@body))
162 ;;;; Conversion functions for SOCKADDR_* structs
164 (defun sockaddr-in->sockaddr (sin)
165 (with-foreign-slots ((addr port) sin sockaddr-in)
166 (values (make-instance 'ipv4-address
167 :name (integer-to-vector (ntohl addr)))
168 (ntohs port))))
170 (defun sockaddr-in6->sockaddr (sin6)
171 (with-foreign-slots ((addr port) sin6 sockaddr-in6)
172 (values (make-instance 'ipv6-address
173 :name (in6-addr-to-ipv6-array addr))
174 (ntohs port))))
176 (defun sockaddr-un->sockaddr (sun)
177 (with-foreign-slots ((path) sun sockaddr-un)
178 (let ((name (make-string (1- unix-path-max)))
179 (abstract nil))
180 (cond ((zerop (mem-aref path :uint8 0))
181 ;; abstract address
182 (setf abstract t)
183 (loop :for sindex :from 0 :below (1- unix-path-max)
184 :for pindex :from 1 :below unix-path-max
185 :do (setf (schar name sindex)
186 (code-char (mem-aref path :uint8 pindex)))))
188 ;; address is in the filesystem
189 (setf name (foreign-string-to-lisp path))))
190 (make-instance 'local-address
191 :name name
192 :abstract abstract))))
194 (defun sockaddr-storage->sockaddr (ss)
195 (with-foreign-slots ((family) ss sockaddr-storage)
196 (ecase family
197 (#.af-inet (sockaddr-in->sockaddr ss))
198 (#.af-inet6 (sockaddr-in6->sockaddr ss))
199 (#.af-local (sockaddr-un->sockaddr ss)))))
201 (defun sockaddr->sockaddr-storage (ss sockaddr &optional (port 0))
202 (etypecase sockaddr
203 (ipv4-address (make-sockaddr-in ss (address-name sockaddr) port))
204 (ipv6-address (make-sockaddr-in6 ss (address-name sockaddr) port))
205 (local-address (make-sockaddr-un ss (address-name sockaddr)))))
207 ;;;; Misc
209 (defmacro check-bounds (sequence start end)
210 (with-gensyms (length)
211 `(let ((,length (length ,sequence)))
212 (check-type ,start unsigned-byte "a non-negative integer")
213 (check-type ,end (or unsigned-byte null) "a non-negative integer or NIL")
214 (unless ,end
215 (setq ,end ,length))
216 (unless (<= ,start ,end ,length)
217 (error "Wrong sequence bounds. start: ~S end: ~S" ,start ,end)))))
219 (defun %to-octets (buff ef start end)
220 (babel:string-to-octets buff :start start :end end
221 :encoding (babel:external-format-encoding ef)))
223 (defun parse-number-or-nil (value &optional (type :any) (radix 10))
224 (check-type value (or string unsigned-byte) "a string or an unsigned-byte")
225 (let ((parsed
226 (if (stringp value)
227 (ignore-errors (parse-integer value :radix radix
228 :junk-allowed nil))
229 value)))
230 (and parsed
231 ;; if it's a number and its type is ok return it
232 (typep parsed (ecase type
233 (:any t) (:ub8 'ub8)
234 (:ub16 'ub16) (:ub32 'ub32)))
235 (values parsed))))
237 (defun ensure-string-or-unsigned-byte (thing &optional (type :any) (radix 10))
238 (or (and (symbolp thing) (string-downcase thing))
239 (parse-number-or-nil thing type radix)
240 thing))
242 (defun lisp->c-bool (val)
243 (if val 1 0))
245 (defmacro with-socklen ((var value) &body body)
246 `(with-foreign-object (,var 'socklen)
247 (setf (mem-ref ,var 'socklen) ,value)
248 ,@body))
250 (defun memq (value list)
251 (member value list :test #'eq))
253 (defmacro multiple-value-case (values &body body)
254 (setf values (ensure-list values))
255 (assert values () "Must provide at least one value to test")
256 (labels ((%do-var (var val)
257 (cond
258 ((and (symbolp var) (string= var "_"))
260 ((consp var)
261 `(memq ,val ',var))
263 `(eq ,val ',var))))
264 (%do-clause (c)
265 (destructuring-bind ((&rest vals) &rest code) c
266 `((and ,@(mapcar #'%do-var vals values)) ,@code)))
267 (%do-last-clause (c)
268 (when c
269 (destructuring-bind (test &rest code) c
270 (if (member test '(otherwise t))
271 `((t ,@code))
272 `(,(%do-clause c)))))))
273 `(cond ,@(append (mapcar #'%do-clause (butlast body))
274 (%do-last-clause (lastcar body))))))
276 ;;; Reader macros
278 (defun make-ht-from-list (list stream test)
279 (flet ((err () (error 'reader-error :stream stream))
280 (separatorp (s) (string= s ","))
281 (middlep (s) (string= s "=>")))
282 (let* ((series (scan 'list list))
283 (slen (collect-length series))
284 (separators (choose (mask (scan-range :from 3 :by 4)) series)))
285 (unless (collect-and (map-fn 'boolean #'separatorp separators)) (err))
286 (multiple-value-bind (keys middles values) (chunk 3 4 series)
287 (unless (or (zerop slen) (= slen (1- (* 4 (collect-length values))))) (err))
288 (unless (collect-and (map-fn 'boolean #'middlep middles)) (err))
289 (collect-hash keys values :test test :size (collect-length keys))))))
291 (defun read-literal-ht (stream &optional c n)
292 (declare (ignore c n))
293 (let ((*readtable* (copy-readtable))
294 (c (read-char stream))
295 (test 'eql))
296 (set-syntax-from-char #\} #\))
297 (set-syntax-from-char #\{ #\))
298 (set-syntax-from-char #\, #\$)
299 (flet ((err () (error 'reader-error :stream stream)))
300 (case c
301 (#\{ t)
302 (#\: (let ((l (read-delimited-list #\{ stream)))
303 (unless (= 1 (length l)) (err))
304 (setf test (car l))))
305 (t (err))))
306 (make-ht-from-list (read-delimited-list #\} stream)
307 stream test)))
309 (set-dispatch-macro-character #\# #\h 'read-literal-ht)