Forgot to dereference a pointer when returning a socket option.
[iolib.git] / sockets / common.lisp
blob2fa4b8ce7a2629e32ccf64a04aa001493999e08b
1 ;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp -*-
3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4 ; Copyright (C) 2006 by Stelian Ionescu ;
5 ; ;
6 ; This program is free software; you can redistribute it and/or modify ;
7 ; it under the terms of the GNU General Public License as published by ;
8 ; the Free Software Foundation; either version 2 of the License, or ;
9 ; (at your option) any later version. ;
10 ; ;
11 ; This program is distributed in the hope that it will be useful, ;
12 ; but WITHOUT ANY WARRANTY; without even the implied warranty of ;
13 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;
14 ; GNU General Public License for more details. ;
15 ; ;
16 ; You should have received a copy of the GNU General Public License ;
17 ; along with this program; if not, write to the ;
18 ; Free Software Foundation, Inc., ;
19 ; 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ;
20 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
22 ;; (declaim (optimize (speed 3) (safety 1) (space 1) (debug 1)))
23 (declaim (optimize (speed 0) (safety 2) (space 0) (debug 2)))
25 (in-package :net.sockets)
27 (deftype ub8 () `(unsigned-byte 8))
28 (deftype ub16 () `(unsigned-byte 16))
29 (deftype ub32 () `(unsigned-byte 32))
30 (deftype sb8 () `(signed-byte 8))
31 (deftype sb16 () `(signed-byte 16))
32 (deftype sb32 () `(signed-byte 32))
34 (defun parse-number-or-nil (value &optional (type :any) (radix 10))
35 (check-type value (or string unsigned-byte))
36 (let ((parsed
37 (if (stringp value)
38 (ignore-errors (parse-integer value :radix radix
39 :junk-allowed nil))
40 value)))
41 (if parsed
42 ;; if it's a number and its type is ok return it
43 (and (ecase type
44 (:any t)
45 (:ub8 (typep parsed 'ub8))
46 (:ub16 (typep parsed 'ub16))
47 (:ub32 (typep parsed 'ub32)))
48 parsed)
49 ;; otherwise nil
50 nil)))
52 (defun c->lisp-bool (val)
53 (if (zerop val) nil t))
55 (defun lisp->c-bool (val)
56 (if val 1 0))
58 (defun addrerr-value (keyword)
59 (foreign-enum-value 'et:addrinfo-errors keyword))
61 (defun unixerr-value (keyword)
62 (foreign-enum-value 'et:errno-values keyword))
64 (defun xor (x1 x2)
65 (not (eql (not x1) (not x2))))
67 ;;;
68 ;;; Byte-swap functions
69 ;;;
71 (defun htons (short)
72 (check-type short ub16 "a 16-bit unsigned number")
73 #+little-endian
74 (logior (ash (logand (the ub16 short) #x00FF) 8)
75 (ash (logand (the ub16 short) #xFF00) -8))
76 #+big-endian short)
78 (defun ntohs (short)
79 (htons short))
81 (defun htonl (long)
82 (check-type long ub32 "a 32-bit unsigned number")
83 #+little-endian
84 (logior (ash (logand (the ub32 long) #x000000FF) 24)
85 (ash (logand (the ub32 long) #x0000FF00) 8)
86 (ash (logand (the ub32 long) #x00FF0000) -8)
87 (ash (logand (the ub32 long) #xFF000000) -24))
88 #+big-endian long)
90 (defun ntohl (long)
91 (htonl long))
93 (defun copy-simple-array-ub16-to-alien-vector (lisp-vec alien-vec)
94 (declare (type (simple-array ub16 (8)) lisp-vec))
95 (dotimes (i 8)
96 (setf (mem-aref alien-vec :uint16 i)
97 (htons (aref lisp-vec i)))))
99 (defun map-ipv4-vector-to-ipv6 (addr)
100 (declare (type (simple-array ub8 (*)) addr))
101 (let ((ipv6addr (make-array 8 :element-type 'ub16
102 :initial-element 0)))
103 ;; setting the IPv4 marker
104 (setf (aref ipv6addr 5) #xFFFF)
105 ;; setting the first two bytes
106 (setf (aref ipv6addr 6) (+ (ash (aref addr 0) 8)
107 (aref addr 1)))
108 ;; setting the last two bytes
109 (setf (aref ipv6addr 7) (+ (ash (aref addr 2) 8)
110 (aref addr 3)))
112 ipv6addr))
114 ;; From CLOCC's PORT library
115 (defun vector-to-ipaddr (vector)
116 (coerce vector '(simple-array ub8 (4)))
117 (+ (ash (aref vector 0) 24)
118 (ash (aref vector 1) 16)
119 (ash (aref vector 2) 8)
120 (aref vector 3)))
122 (defun make-sockaddr-in (sin ub8-vector &optional (port 0))
123 (et:memset sin 0 #.(foreign-type-size 'et:sockaddr-in))
124 (let ((tmp port))
125 (with-foreign-slots ((et:family et:address et:port) sin et:sockaddr-in)
126 (setf et:family et:af-inet)
127 (setf et:address (htonl (vector-to-ipaddr ub8-vector)))
128 (setf et:port (htons tmp))))
129 sin)
131 (defun make-sockaddr-in6 (sin6 ub16-vector &optional (port 0))
132 (et:memset sin6 0 #.(foreign-type-size 'et:sockaddr-in6))
133 (let ((tmp port))
134 (with-foreign-slots ((et:family et:address et:port) sin6 et:sockaddr-in6)
135 (setf et:family et:af-inet6)
136 (copy-simple-array-ub16-to-alien-vector ub16-vector et:address)
137 (setf et:port (htons tmp))))
138 sin6)
140 (defun make-sockaddr-un (sun string)
141 (check-type string string)
142 (et:memset sun 0 (foreign-type-size 'et:sockaddr-un))
143 (with-foreign-slots ((et:family et:path) sun et:sockaddr-un)
144 (setf et:family et:af-local)
145 (with-foreign-string (c-string string)
146 (loop
147 :for off :below (1- et:unix-path-max)
148 :do (setf (mem-aref et:path :uint8 off)
149 (mem-aref c-string :uint8 off)))))
150 sun)
152 (defun make-vector-u8-4-from-in-addr (in-addr)
153 (check-type in-addr ub32)
154 (let ((vector (make-array 4 :element-type 'ub8)))
155 (setf in-addr (ntohl in-addr))
156 (setf (aref vector 0) (ldb (byte 8 24) in-addr))
157 (setf (aref vector 1) (ldb (byte 8 16) in-addr))
158 (setf (aref vector 2) (ldb (byte 8 8) in-addr))
159 (setf (aref vector 3) (ldb (byte 8 0) in-addr))
160 vector))
162 (defun make-vector-u16-8-from-in6-addr (in6-addr)
163 (let ((newvector (make-array 8 :element-type 'ub16)))
164 (dotimes (i 8)
165 (setf (aref newvector i)
166 (ntohs (mem-aref in6-addr :uint16 i))))
167 newvector))
169 (defun sockaddr-in->sockaddr (sin)
170 (with-foreign-slots ((et:address et:port) sin et:sockaddr-in)
171 (values (make-instance 'ipv4addr
172 :name (make-vector-u8-4-from-in-addr et:address))
173 (ntohs et:port))))
175 (defun sockaddr-in6->sockaddr (sin6)
176 (with-foreign-slots ((et:address et:port) sin6 et:sockaddr-in6)
177 (values (make-instance 'ipv6addr
178 :name (make-vector-u16-8-from-in6-addr et:address))
179 (ntohs et:port))))
181 (defun sockaddr-un->sockaddr (sun)
182 (with-foreign-slots ((et:path) sun et:sockaddr-un)
183 (let ((name (make-string (1- et:unix-path-max)))
184 (abstract nil))
185 (if (zerop (mem-aref et:path :uint8 0))
186 ;; abstract address
187 (progn
188 (setf abstract t)
189 (loop
190 :for sindex :from 0 :below (1- et:unix-path-max)
191 :for pindex :from 1 :below et:unix-path-max
192 :do (setf (schar name sindex)
193 (code-char (mem-aref et:path :uint8 pindex)))))
194 ;; address is in the filesystem
195 (setf name (foreign-string-to-lisp et:path)))
196 (make-instance 'localaddr
197 :name name
198 :abstract abstract))))
200 (defun sockaddr-storage->sockaddr (ss)
201 (with-foreign-slots ((et:family) ss et:sockaddr-storage)
202 (ecase et:family
203 (#.et:af-inet
204 (sockaddr-in->sockaddr ss))
205 (#.et:af-inet6
206 (sockaddr-in6->sockaddr ss))
207 (#.et:af-local
208 (sockaddr-un->sockaddr ss)))))
210 (defun sockaddr->sockaddr-storage (ss sockaddr &optional (port 0))
211 (etypecase sockaddr
212 (ipv4addr
213 (make-sockaddr-in ss (name sockaddr) port))
214 (ipv6addr
215 (make-sockaddr-in6 ss (name sockaddr) port))
216 (localaddr
217 (make-sockaddr-un ss (name sockaddr)))))