Improved ENSURE-ADDRESS.
[iolib.git] / sockets / socket-methods.lisp
blobca3d902db646fc08736be178427be534c5bf18fd
1 ;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp -*-
3 ;; Copyright (C) 2006, 2007 Stelian Ionescu
4 ;;
5 ;; This code is free software; you can redistribute it and/or
6 ;; modify it under the terms of the version 2.1 of
7 ;; the GNU Lesser General Public License as published by
8 ;; the Free Software Foundation, as clarified by the
9 ;; preamble found here:
10 ;; http://opensource.franz.com/preamble.html
12 ;; This program is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU Lesser General
18 ;; Public License along with this library; if not, write to the
19 ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 ;; Boston, MA 02110-1301, USA
22 (in-package :net.sockets)
24 (defvar *socket-type-map*
25 '(((:ipv4 :stream :active :default) . socket-stream-internet-active)
26 ((:ipv6 :stream :active :default) . socket-stream-internet-active)
27 ((:ipv4 :stream :passive :default) . socket-stream-internet-passive)
28 ((:ipv6 :stream :passive :default) . socket-stream-internet-passive)
29 ((:local :stream :active :default) . socket-stream-local-active)
30 ((:local :stream :passive :default) . socket-stream-local-passive)
31 ((:local :datagram :active :default) . socket-datagram-local-active)
32 ((:ipv4 :datagram :active :default) . socket-datagram-internet-active)
33 ((:ipv6 :datagram :active :default) . socket-datagram-internet-active)))
35 (defun select-socket-type (family type connect protocol)
36 (or (cdr (assoc (list family type connect protocol) *socket-type-map*
37 :test #'equal))
38 (error "No socket class found !!")))
41 ;;;;;;;;;;;;;;;;;;;;;;;;;
42 ;; SHARED-INITIALIZE ;;
43 ;;;;;;;;;;;;;;;;;;;;;;;;;
45 (defun translate-make-socket-keywords-to-constants (family type protocol)
46 (let ((sf (ecase family
47 (:ipv4 et:af-inet)
48 (:ipv6 et:af-inet6)
49 (:local et:af-local)))
50 (st (ecase type
51 (:stream et:sock-stream)
52 (:datagram et:sock-dgram)))
53 (sp (cond
54 ((integerp protocol) protocol)
55 ((eql protocol :default) 0)
56 ((keywordp protocol)
57 (protocol-number
58 (get-protocol-by-name (string-downcase
59 (string protocol))))))))
60 (values sf st sp)))
62 (defmethod socket-fd ((socket socket))
63 (fd-of socket))
64 (defmethod (setf socket-fd) (fd (socket socket))
65 (setf (fd-of socket) fd))
67 (defmethod shared-initialize :after ((socket socket) slot-names
68 &key file-descriptor family
69 type (protocol :default))
70 (declare (ignore slot-names))
71 (when (socket-open-p socket)
72 (close socket))
73 (with-accessors ((fd fd-of)
74 (fam socket-family)
75 (proto socket-protocol)) socket
76 (setf fd (or file-descriptor
77 (multiple-value-bind (sf st sp)
78 (translate-make-socket-keywords-to-constants family type protocol)
79 (with-socket-error-filter
80 (et:socket sf st sp)))))
81 (setf fam family
82 proto protocol)))
84 (defmethod socket-type ((socket stream-socket))
85 :stream)
87 (defmethod socket-type ((socket datagram-socket))
88 :datagram)
91 ;;;;;;;;;;;;;;;;;;;;
92 ;; PRINT-OBJECT ;;
93 ;;;;;;;;;;;;;;;;;;;;
95 (defmethod print-object ((socket socket-stream-internet-active) stream)
96 (print-unreadable-object (socket stream :type nil :identity t)
97 (format stream "active internet stream socket" )
98 (if (socket-connected-p socket)
99 (multiple-value-bind (addr port) (remote-name socket)
100 (format stream " connected to ~A/~A"
101 (sockaddr->presentation addr) port))
102 (if (fd-of socket)
103 (format stream ", unconnected")
104 (format stream ", closed")))))
106 (defmethod print-object ((socket socket-stream-internet-passive) stream)
107 (print-unreadable-object (socket stream :type nil :identity t)
108 (format stream "passive internet stream socket" )
109 (if (socket-bound-p socket)
110 (multiple-value-bind (addr port) (local-name socket)
111 (format stream " ~A ~A/~A"
112 (if (socket-listening-p socket)
113 "waiting for connections @"
114 "bound to")
115 (sockaddr->presentation addr) port))
116 (if (fd-of socket)
117 (format stream ", unbound")
118 (format stream ", closed")))))
120 (defmethod print-object ((socket socket-stream-local-active) stream)
121 (print-unreadable-object (socket stream :type nil :identity t)
122 (format stream "active local stream socket" )
123 (if (socket-connected-p socket)
124 (format stream " connected")
125 (if (fd-of socket)
126 (format stream ", unconnected")
127 (format stream ", closed")))))
129 (defmethod print-object ((socket socket-stream-local-passive) stream)
130 (print-unreadable-object (socket stream :type nil :identity t)
131 (format stream "passive local stream socket" )
132 (if (socket-bound-p socket)
133 (format stream " ~A ~A"
134 (if (socket-listening-p socket)
135 "waiting for connections @"
136 "bound to")
137 (sockaddr->presentation (socket-address socket)))
138 (if (fd-of socket)
139 (format stream ", unbound")
140 (format stream ", closed")))))
142 (defmethod print-object ((socket socket-datagram-local-active) stream)
143 (print-unreadable-object (socket stream :type nil :identity t)
144 (format stream "local datagram socket" )
145 (if (socket-connected-p socket)
146 (format stream " connected")
147 (if (fd-of socket)
148 (format stream ", unconnected")
149 (format stream ", closed")))))
151 (defmethod print-object ((socket socket-datagram-internet-active) stream)
152 (print-unreadable-object (socket stream :type nil :identity t)
153 (format stream "internet datagram socket" )
154 (if (socket-connected-p socket)
155 (multiple-value-bind (addr port) (remote-name socket)
156 (format stream " connected to ~A/~A"
157 (sockaddr->presentation addr) port))
158 (if (fd-of socket)
159 (format stream ", unconnected")
160 (format stream ", closed")))))
163 ;;;;;;;;;;;;;
164 ;; CLOSE ;;
165 ;;;;;;;;;;;;;
167 (defmethod close :around ((socket socket) &key abort)
168 (declare (ignore abort))
169 (when (fd-of socket)
170 (with-socket-error-filter
171 (et:close (fd-of socket))))
172 (setf (fd-of socket) nil)
173 (call-next-method)
174 (values socket))
176 (defmethod close :around ((socket passive-socket) &key abort)
177 (declare (ignore abort))
178 (call-next-method)
179 (setf (slot-value socket 'bound) nil)
180 (setf (slot-value socket 'listening) nil)
181 (values socket))
183 (defmethod close ((socket socket) &key abort)
184 (declare (ignore socket abort)))
186 (defmethod socket-open-p ((socket socket))
187 (unless (fd-of socket)
188 (return-from socket-open-p nil))
189 (with-socket-error-filter
190 (handler-case
191 (with-foreign-object (ss 'et:sockaddr-storage)
192 (et:bzero ss et:size-of-sockaddr-storage)
193 (with-foreign-pointer (size et:size-of-socklen)
194 (setf (mem-ref size :socklen)
195 et:size-of-sockaddr-storage)
196 (et:getsockname (fd-of socket) ss size)
198 (et:ebadf ())
199 #+freebsd (et:econnreset ()))))
202 ;;;;;;;;;;;;;;;;;;;
203 ;; GETSOCKNAME ;;
204 ;;;;;;;;;;;;;;;;;;;
206 (defmethod local-name ((socket internet-socket))
207 (with-foreign-object (ss 'et:sockaddr-storage)
208 (et:bzero ss et:size-of-sockaddr-storage)
209 (with-foreign-pointer (size et:size-of-socklen)
210 (setf (mem-ref size :socklen)
211 et:size-of-sockaddr-storage)
212 (with-socket-error-filter
213 (et:getsockname (fd-of socket) ss size))
214 (return-from local-name
215 (sockaddr-storage->sockaddr ss)))))
217 (defmethod local-name ((socket local-socket))
218 (with-foreign-object (sun 'et:sockaddr-un)
219 (et:bzero sun et:size-of-sockaddr-un)
220 (with-foreign-pointer (size et:size-of-socklen)
221 (setf (mem-ref size :socklen)
222 et:size-of-sockaddr-storage)
223 (with-socket-error-filter
224 (et:getsockname (fd-of socket) sun size))
225 (return-from local-name
226 (sockaddr-un->sockaddr sun)))))
228 (defmethod socket-address ((socket socket))
229 (nth-value 0 (local-name socket)))
231 (defmethod socket-port ((socket internet-socket))
232 (nth-value 1 (local-name socket)))
235 ;;;;;;;;;;;;;;;;;;;
236 ;; GETPEERNAME ;;
237 ;;;;;;;;;;;;;;;;;;;
239 (defmethod remote-name ((socket internet-socket))
240 (with-foreign-object (ss 'et:sockaddr-storage)
241 (et:bzero ss et:size-of-sockaddr-storage)
242 (with-foreign-pointer (size et:size-of-socklen)
243 (setf (mem-ref size :socklen)
244 et:size-of-sockaddr-storage)
245 (with-socket-error-filter
246 (et:getpeername (fd-of socket) ss size))
247 (return-from remote-name
248 (sockaddr-storage->sockaddr ss)))))
250 (defmethod remote-name ((socket local-socket))
251 (with-foreign-object (sun 'et:sockaddr-un)
252 (et:bzero sun et:size-of-sockaddr-un)
253 (with-foreign-pointer (size et:size-of-socklen)
254 (setf (mem-ref size :socklen)
255 et:size-of-sockaddr-storage)
256 (with-socket-error-filter
257 (et:getpeername (fd-of socket) sun size))
258 (return-from remote-name
259 (sockaddr-un->sockaddr sun)))))
262 ;;;;;;;;;;;;
263 ;; BIND ;;
264 ;;;;;;;;;;;;
266 (defmethod bind-address :before ((socket internet-socket)
267 address &key (reuse-address t))
268 (declare (ignore address))
269 (when reuse-address
270 (set-socket-option socket :reuse-address :value t)))
272 (defun bind-ipv4-address (fd address port)
273 (with-foreign-object (sin 'et:sockaddr-in)
274 (make-sockaddr-in sin address port)
275 (with-socket-error-filter
276 (et:bind fd sin et:size-of-sockaddr-in))))
278 (defun bind-ipv6-address (fd address port)
279 (with-foreign-object (sin6 'et:sockaddr-in6)
280 (make-sockaddr-in6 sin6 address port)
281 (with-socket-error-filter
282 (et:bind fd sin6 et:size-of-sockaddr-in6))))
284 (defmethod bind-address ((socket internet-socket)
285 (address ipv4addr)
286 &key (port 0))
287 (if (eql (socket-family socket) :ipv6)
288 (bind-ipv6-address (fd-of socket)
289 (map-ipv4-vector-to-ipv6 (name address))
290 port)
291 (bind-ipv4-address (fd-of socket) (name address) port))
292 (values socket))
294 (defmethod bind-address ((socket internet-socket)
295 (address ipv6addr)
296 &key (port 0))
297 (bind-ipv6-address (fd-of socket) (name address) port)
298 (values socket))
300 (defmethod bind-address :before ((socket local-socket)
301 (address localaddr) &key)
302 (when (typep socket 'active-socket)
303 (error "You can't bind an active Unix socket.")))
305 (defmethod bind-address ((socket local-socket)
306 (address localaddr) &key)
307 (with-foreign-object (sun 'et:sockaddr-un)
308 (make-sockaddr-un sun (name address))
309 (with-socket-error-filter
310 (et:bind (fd-of socket) sun et:size-of-sockaddr-un)))
311 (values socket))
313 (defmethod bind-address :after ((socket socket)
314 (address sockaddr) &key)
315 (setf (slot-value socket 'bound) t))
318 ;;;;;;;;;;;;;;
319 ;; LISTEN ;;
320 ;;;;;;;;;;;;;;
322 (defmethod socket-listen ((socket passive-socket)
323 &key (backlog (min *default-backlog-size*
324 +max-backlog-size+)))
325 (unless backlog (setf backlog (min *default-backlog-size*
326 +max-backlog-size+)))
327 (check-type backlog unsigned-byte "a non-negative integer")
328 (with-socket-error-filter
329 (et:listen (fd-of socket) backlog))
330 (setf (slot-value socket 'listening) t)
331 (values socket))
333 (defmethod socket-listen ((socket active-socket)
334 &key backlog)
335 (declare (ignore backlog))
336 (error "You can't listen on active sockets."))
339 ;;;;;;;;;;;;;;
340 ;; ACCEPT ;;
341 ;;;;;;;;;;;;;;
343 (defmethod accept-connection ((socket active-socket)
344 &key wait)
345 (declare (ignore wait))
346 (error "You can't accept connections on active sockets."))
348 (defmethod accept-connection ((socket passive-socket)
349 &key (wait t))
350 (with-foreign-object (ss 'et:sockaddr-storage)
351 (et:bzero ss et:size-of-sockaddr-storage)
352 (with-foreign-pointer (size et:size-of-socklen)
353 (setf (mem-ref size :socklen)
354 et:size-of-sockaddr-storage)
355 (let (non-blocking-state
356 client-fd)
357 (with-socket-error-filter
358 (handler-case
359 (if wait
360 ;; do a "normal" accept
361 ;; Note: the socket may already be in non-blocking mode
362 (setf client-fd (et:accept (fd-of socket) ss size))
363 ;; set the socket to non-blocking mode before calling accept()
364 ;; if there's no new connection return NIL
365 (unwind-protect
366 (progn
367 ;; saving the current non-blocking state
368 (setf non-blocking-state (fd-non-blocking socket))
369 ;; switch the socket to non-blocking mode
370 (setf (fd-non-blocking socket) t)
371 (setf client-fd (et:accept (fd-of socket) ss size)))
372 ;; restoring the socket's non-blocking state
373 (setf (fd-non-blocking socket) non-blocking-state)))
374 ;; the socket is marked non-blocking and there's no new connection
375 (et:ewouldblock ()
376 (return-from accept-connection nil))))
378 (let ((client-socket
379 ;; create the client socket object
380 (make-instance (active-class socket)
381 :file-descriptor client-fd)))
382 (return-from accept-connection client-socket))))))
385 ;;;;;;;;;;;;;;;
386 ;; CONNECT ;;
387 ;;;;;;;;;;;;;;;
389 #+freebsd
390 (defmethod connect :before ((socket active-socket)
391 sockaddr &key)
392 (declare (ignore sockaddr))
393 (when *no-sigpipe*
394 (set-socket-option socket :no-sigpipe :value t)))
396 (defun ipv4-connect (fd address port)
397 (with-foreign-object (sin 'et:sockaddr-in)
398 (make-sockaddr-in sin address port)
399 (with-socket-error-filter
400 (et:connect fd sin et:size-of-sockaddr-in))))
402 (defun ipv6-connect (fd address port)
403 (with-foreign-object (sin6 'et:sockaddr-in6)
404 (make-sockaddr-in6 sin6 address port)
405 (with-socket-error-filter
406 (et:connect fd sin6 et:size-of-sockaddr-in6))))
408 (defmethod connect ((socket internet-socket)
409 (address ipv4addr) &key (port 0))
410 (if (eql (socket-family socket) :ipv6)
411 (ipv6-connect (fd-of socket)
412 (map-ipv4-vector-to-ipv6 (name address))
413 port)
414 (ipv4-connect (fd-of socket) (name address) port))
415 (values socket))
417 (defmethod connect ((socket internet-socket)
418 (address ipv6addr) &key (port 0))
419 (ipv6-connect (fd-of socket) (name address) port)
420 (values socket))
422 (defmethod connect ((socket local-socket)
423 (address localaddr) &key)
424 (with-foreign-object (sun 'et:sockaddr-un)
425 (make-sockaddr-un sun (name address))
426 (with-socket-error-filter
427 (et:connect (fd-of socket) sun et:size-of-sockaddr-un)))
428 (values socket))
430 (defmethod connect ((socket passive-socket)
431 address &key)
432 (declare (ignore address))
433 (error "You cannot connect passive sockets."))
435 (defmethod socket-connected-p ((socket socket))
436 (unless (fd-of socket)
437 (return-from socket-connected-p nil))
438 (with-socket-error-filter
439 (handler-case
440 (with-foreign-object (ss 'et:sockaddr-storage)
441 (et:bzero ss et:size-of-sockaddr-storage)
442 (with-foreign-pointer (size et:size-of-socklen)
443 (setf (mem-ref size :socklen)
444 et:size-of-sockaddr-storage)
445 (et:getpeername (fd-of socket) ss size)
447 (et:enotconn () nil))))
450 ;;;;;;;;;;;;;;;;
451 ;; SHUTDOWN ;;
452 ;;;;;;;;;;;;;;;;
454 (defmethod shutdown ((socket active-socket) direction)
455 (check-type direction (member :read :write :read-write)
456 "valid direction specifier")
457 (with-socket-error-filter
458 (et:shutdown (fd-of socket)
459 (ecase direction
460 (:read et:shut-rd)
461 (:write et:shut-wr)
462 (:read-write et:shut-rdwr))))
463 (values socket))
465 (defmethod shutdown ((socket passive-socket) direction)
466 (declare (ignore direction))
467 (error "You cannot shut down passive sockets."))
470 ;;;;;;;;;;;;
471 ;; SEND ;;
472 ;;;;;;;;;;;;
474 (defun %normalize-send-buffer (buff start end ef)
475 (setf (values start end) (%check-bounds buff start end))
476 (etypecase buff
477 (ub8-sarray (values buff start (- end start)))
478 (ub8-vector (values (coerce buff 'ub8-sarray)
479 start (- end start)))
480 (string (values (%to-octets buff ef start end)
481 0 (- end start)))))
483 (defmethod socket-send ((buffer array)
484 (socket active-socket) &key (start 0) end
485 remote-address remote-port end-of-record
486 dont-route dont-wait (no-signal *no-sigpipe*)
487 out-of-band #+linux more #+linux confirm)
488 (check-type start unsigned-byte
489 "a non-negative unsigned integer")
490 (check-type end (or unsigned-byte null)
491 "a non-negative unsigned integer or NIL")
492 (when (or remote-port remote-address)
493 (check-type remote-address sockaddr "a network address")
494 (check-type remote-port (unsigned-byte 16) "a valid IP port number"))
495 (let ((flags (logior (if end-of-record et:msg-eor 0)
496 (if dont-route et:msg-dontroute 0)
497 (if dont-wait et:msg-dontwait 0)
498 (if no-signal et:msg-nosignal 0)
499 (if out-of-band et:msg-oob 0)
500 #+linux (if more et:msg-more 0)
501 #+linux (if confirm et:msg-confirm 0))))
502 (when (and (ipv4-address-p remote-address)
503 (eql (socket-family socket) :ipv6))
504 (setf remote-address (map-ipv4-address->ipv6 remote-address)))
505 (multiple-value-bind (buff start-offset bufflen)
506 (%normalize-send-buffer buffer start end (external-format-of socket))
507 (with-foreign-object (ss 'et:sockaddr-storage)
508 (et:bzero ss et:size-of-sockaddr-storage)
509 (when remote-address
510 (sockaddr->sockaddr-storage ss remote-address remote-port))
511 (with-pointer-to-vector-data (buff-sap buff)
512 (incf-pointer buff-sap start-offset)
513 (with-socket-error-filter
514 (return-from socket-send
515 (et:sendto (fd-of socket)
516 buff-sap bufflen
517 flags
518 (if remote-address ss (null-pointer))
519 (if remote-address et:size-of-sockaddr-storage 0)))))))))
521 (defmethod socket-send (buffer (socket passive-socket) &key)
522 (declare (ignore buffer))
523 (error "You cannot send data on a passive socket."))
526 ;;;;;;;;;;;;
527 ;; RECV ;;
528 ;;;;;;;;;;;;
530 (defun %normalize-receive-buffer (buff start end)
531 (setf (values start end) (%check-bounds buff start end))
532 (etypecase buff
533 ((simple-array ub8 (*)) (values buff start (- end start)))))
535 (defmethod socket-receive ((buffer array)
536 (socket active-socket) &key (start 0) end
537 out-of-band peek wait-all
538 dont-wait (no-signal *no-sigpipe*))
539 (let ((flags (logior (if out-of-band et:msg-oob 0)
540 (if peek et:msg-peek 0)
541 (if wait-all et:msg-waitall 0)
542 (if dont-wait et:msg-dontwait 0)
543 (if no-signal et:msg-nosignal 0)))
544 bytes-received)
545 (multiple-value-bind (buff start-offset bufflen)
546 (%normalize-receive-buffer buffer start end)
547 (with-foreign-object (ss 'et:sockaddr-storage)
548 (et:bzero ss et:size-of-sockaddr-storage)
549 (with-foreign-pointer (size et:size-of-socklen)
550 (setf (mem-ref size :socklen)
551 et:size-of-sockaddr-storage)
552 (with-pointer-to-vector-data (buff-sap buff)
553 (incf-pointer buff-sap start-offset)
554 (with-socket-error-filter
555 (setf bytes-received
556 (et:recvfrom (fd-of socket)
557 buff-sap bufflen
558 flags
559 ss size)))))
561 (return-from socket-receive
562 ;; when socket is a datagram socket
563 ;; return the sender's address as 3rd value
564 (if (typep socket 'datagram-socket)
565 (multiple-value-bind (remote-address remote-port)
566 (sockaddr-storage->sockaddr ss)
567 (values buffer bytes-received remote-address remote-port))
568 (values buffer bytes-received)))))))
570 (defmethod socket-receive (buffer (socket passive-socket) &key)
571 (declare (ignore buffer))
572 (error "You cannot receive data from a passive socket."))
576 ;; Only for datagram sockets
579 (defmethod unconnect :before ((socket active-socket))
580 (unless (typep socket 'datagram-socket)
581 (error "You can only unconnect active datagram sockets.")))
583 (defmethod unconnect ((socket datagram-socket))
584 (with-socket-error-filter
585 (with-foreign-object (sin 'et:sockaddr-in)
586 (et:bzero sin et:size-of-sockaddr-in)
587 (setf (foreign-slot-value sin 'et:sockaddr-in 'et:addr) et:af-unspec)
588 (et:connect (fd-of socket) sin et:size-of-sockaddr-in))))