New function: ENSURE-EXTERNAL-FORMAT, added slot EXTERNAL-FORMAT to passive sockets.
[iolib.git] / sockets / socket-methods.lisp
blob6fe1aec90c6a0aa9397717122a2f4f205c63ee38
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 (setf external-format-of) (external-format (socket passive-socket))
85 (setf (slot-value socket 'external-format)
86 (ensure-external-format external-format)))
88 (defmethod shared-initialize :after ((socket passive-socket) slot-names
89 &key external-format)
90 (declare (ignore slot-names))
91 (setf (external-format-of socket) external-format))
93 (defmethod socket-type ((socket stream-socket))
94 :stream)
96 (defmethod socket-type ((socket datagram-socket))
97 :datagram)
100 ;;;;;;;;;;;;;;;;;;;;
101 ;; PRINT-OBJECT ;;
102 ;;;;;;;;;;;;;;;;;;;;
104 (defun sock-fam (socket)
105 (ecase (socket-family socket)
106 (:ipv4 "IPv4")
107 (:ipv6 "IPv6")))
109 (defmethod print-object ((socket socket-stream-internet-active) stream)
110 (print-unreadable-object (socket stream :type nil :identity t)
111 (format stream "active ~A stream socket" (sock-fam socket))
112 (if (socket-connected-p socket)
113 (multiple-value-bind (addr port) (remote-name socket)
114 (format stream " connected to ~A/~A"
115 (sockaddr->presentation addr) port))
116 (if (fd-of socket)
117 (format stream ", unconnected")
118 (format stream ", closed")))))
120 (defmethod print-object ((socket socket-stream-internet-passive) stream)
121 (print-unreadable-object (socket stream :type nil :identity t)
122 (format stream "passive ~A stream socket" (sock-fam socket))
123 (if (socket-bound-p socket)
124 (multiple-value-bind (addr port) (local-name socket)
125 (format stream " ~A ~A/~A"
126 (if (socket-listening-p socket)
127 "waiting for connections @"
128 "bound to")
129 (sockaddr->presentation addr) port))
130 (if (fd-of socket)
131 (format stream ", unbound")
132 (format stream ", closed")))))
134 (defmethod print-object ((socket socket-stream-local-active) stream)
135 (print-unreadable-object (socket stream :type nil :identity t)
136 (format stream "active local stream socket")
137 (if (socket-connected-p socket)
138 (format stream " connected")
139 (if (fd-of socket)
140 (format stream ", unconnected")
141 (format stream ", closed")))))
143 (defmethod print-object ((socket socket-stream-local-passive) stream)
144 (print-unreadable-object (socket stream :type nil :identity t)
145 (format stream "passive local stream socket")
146 (if (socket-bound-p socket)
147 (format stream " ~A ~A"
148 (if (socket-listening-p socket)
149 "waiting for connections @"
150 "bound to")
151 (sockaddr->presentation (socket-address socket)))
152 (if (fd-of socket)
153 (format stream ", unbound")
154 (format stream ", closed")))))
156 (defmethod print-object ((socket socket-datagram-local-active) stream)
157 (print-unreadable-object (socket stream :type nil :identity t)
158 (format stream "local datagram socket")
159 (if (socket-connected-p socket)
160 (format stream " connected")
161 (if (fd-of socket)
162 (format stream ", unconnected")
163 (format stream ", closed")))))
165 (defmethod print-object ((socket socket-datagram-internet-active) stream)
166 (print-unreadable-object (socket stream :type nil :identity t)
167 (format stream "~A datagram socket" (sock-fam socket))
168 (if (socket-connected-p socket)
169 (multiple-value-bind (addr port) (remote-name socket)
170 (format stream " connected to ~A/~A"
171 (sockaddr->presentation addr) port))
172 (if (fd-of socket)
173 (format stream ", unconnected")
174 (format stream ", closed")))))
177 ;;;;;;;;;;;;;
178 ;; CLOSE ;;
179 ;;;;;;;;;;;;;
181 (defmethod close :around ((socket socket) &key abort)
182 (declare (ignore abort))
183 (call-next-method)
184 (when (fd-of socket)
185 (with-socket-error-filter
186 (et:close (fd-of socket))))
187 (setf (fd-of socket) nil
188 (slot-value socket 'bound) nil)
189 (values socket))
191 (defmethod close :around ((socket passive-socket) &key abort)
192 (declare (ignore abort))
193 (call-next-method)
194 (setf (slot-value socket 'listening) nil)
195 (values socket))
197 (defmethod close ((socket socket) &key abort)
198 (declare (ignore socket abort)))
200 (defmethod socket-open-p ((socket socket))
201 (unless (fd-of socket)
202 (return-from socket-open-p nil))
203 (with-socket-error-filter
204 (handler-case
205 (with-foreign-object (ss 'et:sockaddr-storage)
206 (et:bzero ss et:size-of-sockaddr-storage)
207 (with-foreign-pointer (size et:size-of-socklen)
208 (setf (mem-ref size 'et:socklen)
209 et:size-of-sockaddr-storage)
210 (et:getsockname (fd-of socket) ss size)
212 (et:ebadf ())
213 #+freebsd (et:econnreset ()))))
216 ;;;;;;;;;;;;;;;;;;;
217 ;; GETSOCKNAME ;;
218 ;;;;;;;;;;;;;;;;;;;
220 (defmethod local-name ((socket internet-socket))
221 (with-foreign-object (ss 'et:sockaddr-storage)
222 (et:bzero ss et:size-of-sockaddr-storage)
223 (with-foreign-pointer (size et:size-of-socklen)
224 (setf (mem-ref size 'et:socklen)
225 et:size-of-sockaddr-storage)
226 (with-socket-error-filter
227 (et:getsockname (fd-of socket) ss size))
228 (return-from local-name
229 (sockaddr-storage->sockaddr ss)))))
231 (defmethod local-name ((socket local-socket))
232 (with-foreign-object (sun 'et:sockaddr-un)
233 (et:bzero sun et:size-of-sockaddr-un)
234 (with-foreign-pointer (size et:size-of-socklen)
235 (setf (mem-ref size 'et:socklen)
236 et:size-of-sockaddr-storage)
237 (with-socket-error-filter
238 (et:getsockname (fd-of socket) sun size))
239 (return-from local-name
240 (sockaddr-un->sockaddr sun)))))
242 (defmethod socket-address ((socket socket))
243 (nth-value 0 (local-name socket)))
245 (defmethod socket-port ((socket internet-socket))
246 (nth-value 1 (local-name socket)))
249 ;;;;;;;;;;;;;;;;;;;
250 ;; GETPEERNAME ;;
251 ;;;;;;;;;;;;;;;;;;;
253 (defmethod remote-name ((socket internet-socket))
254 (with-foreign-object (ss 'et:sockaddr-storage)
255 (et:bzero ss et:size-of-sockaddr-storage)
256 (with-foreign-pointer (size et:size-of-socklen)
257 (setf (mem-ref size 'et:socklen)
258 et:size-of-sockaddr-storage)
259 (with-socket-error-filter
260 (et:getpeername (fd-of socket) ss size))
261 (return-from remote-name
262 (sockaddr-storage->sockaddr ss)))))
264 (defmethod remote-name ((socket local-socket))
265 (with-foreign-object (sun 'et:sockaddr-un)
266 (et:bzero sun et:size-of-sockaddr-un)
267 (with-foreign-pointer (size et:size-of-socklen)
268 (setf (mem-ref size 'et:socklen)
269 et:size-of-sockaddr-storage)
270 (with-socket-error-filter
271 (et:getpeername (fd-of socket) sun size))
272 (return-from remote-name
273 (sockaddr-un->sockaddr sun)))))
276 ;;;;;;;;;;;;
277 ;; BIND ;;
278 ;;;;;;;;;;;;
280 (defmethod bind-address :before ((socket internet-socket)
281 address &key (reuse-address t))
282 (declare (ignore address))
283 (when reuse-address
284 (set-socket-option socket :reuse-address :value t)))
286 (defun bind-ipv4-address (fd address port)
287 (with-foreign-object (sin 'et:sockaddr-in)
288 (make-sockaddr-in sin address port)
289 (with-socket-error-filter
290 (et:bind fd sin et:size-of-sockaddr-in))))
292 (defun bind-ipv6-address (fd address port)
293 (with-foreign-object (sin6 'et:sockaddr-in6)
294 (make-sockaddr-in6 sin6 address port)
295 (with-socket-error-filter
296 (et:bind fd sin6 et:size-of-sockaddr-in6))))
298 (defmethod bind-address ((socket internet-socket)
299 (address ipv4addr)
300 &key (port 0))
301 (if (eql (socket-family socket) :ipv6)
302 (bind-ipv6-address (fd-of socket)
303 (map-ipv4-vector-to-ipv6 (name address))
304 port)
305 (bind-ipv4-address (fd-of socket) (name address) port))
306 (values socket))
308 (defmethod bind-address ((socket internet-socket)
309 (address ipv6addr)
310 &key (port 0))
311 (bind-ipv6-address (fd-of socket) (name address) port)
312 (values socket))
314 (defmethod bind-address :before ((socket local-socket)
315 (address localaddr) &key)
316 (when (typep socket 'active-socket)
317 (error "You can't bind an active Unix socket.")))
319 (defmethod bind-address ((socket local-socket)
320 (address localaddr) &key)
321 (with-foreign-object (sun 'et:sockaddr-un)
322 (make-sockaddr-un sun (name address))
323 (with-socket-error-filter
324 (et:bind (fd-of socket) sun et:size-of-sockaddr-un)))
325 (values socket))
327 (defmethod bind-address :after ((socket socket)
328 (address sockaddr) &key)
329 (setf (slot-value socket 'bound) t))
332 ;;;;;;;;;;;;;;
333 ;; LISTEN ;;
334 ;;;;;;;;;;;;;;
336 (defmethod socket-listen ((socket passive-socket)
337 &key backlog)
338 (unless backlog (setf backlog (min *default-backlog-size*
339 +max-backlog-size+)))
340 (check-type backlog unsigned-byte "a non-negative integer")
341 (with-socket-error-filter
342 (et:listen (fd-of socket) backlog))
343 (setf (slot-value socket 'listening) t)
344 (values socket))
346 (defmethod socket-listen ((socket active-socket)
347 &key backlog)
348 (declare (ignore backlog))
349 (error "You can't listen on active sockets."))
352 ;;;;;;;;;;;;;;
353 ;; ACCEPT ;;
354 ;;;;;;;;;;;;;;
356 (defmethod accept-connection ((socket active-socket)
357 &key wait)
358 (declare (ignore wait))
359 (error "You can't accept connections on active sockets."))
361 (defmethod accept-connection ((socket passive-socket)
362 &key (wait t))
363 (with-foreign-object (ss 'et:sockaddr-storage)
364 (et:bzero ss et:size-of-sockaddr-storage)
365 (with-foreign-pointer (size et:size-of-socklen)
366 (setf (mem-ref size 'et:socklen)
367 et:size-of-sockaddr-storage)
368 (let (non-blocking-state
369 client-fd)
370 (with-socket-error-filter
371 (handler-case
372 (if wait
373 ;; do a "normal" accept
374 ;; Note: the socket may already be in non-blocking mode
375 (setf client-fd (et:accept (fd-of socket) ss size))
376 ;; set the socket to non-blocking mode before calling accept()
377 ;; if there's no new connection return NIL
378 (unwind-protect
379 (progn
380 ;; saving the current non-blocking state
381 (setf non-blocking-state (fd-non-blocking socket))
382 ;; switch the socket to non-blocking mode
383 (setf (fd-non-blocking socket) t)
384 (setf client-fd (et:accept (fd-of socket) ss size)))
385 ;; restoring the socket's non-blocking state
386 (setf (fd-non-blocking socket) non-blocking-state)))
387 ;; the socket is marked non-blocking and there's no new connection
388 (et:ewouldblock ()
389 (return-from accept-connection nil))))
391 (let ((client-socket
392 ;; create the client socket object
393 (make-instance (active-class socket)
394 :file-descriptor client-fd)))
395 (return-from accept-connection client-socket))))))
398 ;;;;;;;;;;;;;;;
399 ;; CONNECT ;;
400 ;;;;;;;;;;;;;;;
402 #+freebsd
403 (defmethod connect :before ((socket active-socket)
404 sockaddr &key)
405 (declare (ignore sockaddr))
406 (when *no-sigpipe*
407 (set-socket-option socket :no-sigpipe :value t)))
409 (defun ipv4-connect (fd address port)
410 (with-foreign-object (sin 'et:sockaddr-in)
411 (make-sockaddr-in sin address port)
412 (with-socket-error-filter
413 (et:connect fd sin et:size-of-sockaddr-in))))
415 (defun ipv6-connect (fd address port)
416 (with-foreign-object (sin6 'et:sockaddr-in6)
417 (make-sockaddr-in6 sin6 address port)
418 (with-socket-error-filter
419 (et:connect fd sin6 et:size-of-sockaddr-in6))))
421 (defmethod connect ((socket internet-socket)
422 (address ipv4addr) &key (port 0))
423 (if (eql (socket-family socket) :ipv6)
424 (ipv6-connect (fd-of socket)
425 (map-ipv4-vector-to-ipv6 (name address))
426 port)
427 (ipv4-connect (fd-of socket) (name address) port))
428 (values socket))
430 (defmethod connect ((socket internet-socket)
431 (address ipv6addr) &key (port 0))
432 (ipv6-connect (fd-of socket) (name address) port)
433 (values socket))
435 (defmethod connect ((socket local-socket)
436 (address localaddr) &key)
437 (with-foreign-object (sun 'et:sockaddr-un)
438 (make-sockaddr-un sun (name address))
439 (with-socket-error-filter
440 (et:connect (fd-of socket) sun et:size-of-sockaddr-un)))
441 (values socket))
443 (defmethod connect ((socket passive-socket)
444 address &key)
445 (declare (ignore address))
446 (error "You cannot connect passive sockets."))
448 (defmethod socket-connected-p ((socket socket))
449 (unless (fd-of socket)
450 (return-from socket-connected-p nil))
451 (with-socket-error-filter
452 (handler-case
453 (with-foreign-object (ss 'et:sockaddr-storage)
454 (et:bzero ss et:size-of-sockaddr-storage)
455 (with-foreign-pointer (size et:size-of-socklen)
456 (setf (mem-ref size 'et:socklen)
457 et:size-of-sockaddr-storage)
458 (et:getpeername (fd-of socket) ss size)
460 (et:enotconn () nil))))
463 ;;;;;;;;;;;;;;;;
464 ;; SHUTDOWN ;;
465 ;;;;;;;;;;;;;;;;
467 (defmethod shutdown ((socket active-socket) direction)
468 (check-type direction (member :read :write :read-write)
469 "valid direction specifier")
470 (with-socket-error-filter
471 (et:shutdown (fd-of socket)
472 (ecase direction
473 (:read et:shut-rd)
474 (:write et:shut-wr)
475 (:read-write et:shut-rdwr))))
476 (values socket))
478 (defmethod shutdown ((socket passive-socket) direction)
479 (declare (ignore direction))
480 (error "You cannot shut down passive sockets."))
483 ;;;;;;;;;;;;
484 ;; SEND ;;
485 ;;;;;;;;;;;;
487 (defun %normalize-send-buffer (buff start end ef)
488 (setf (values start end) (%check-bounds buff start end))
489 (etypecase buff
490 (ub8-sarray (values buff start (- end start)))
491 (ub8-vector (values (coerce buff 'ub8-sarray)
492 start (- end start)))
493 (string (values (%to-octets buff ef start end)
494 0 (- end start)))))
496 (defmethod socket-send ((buffer array)
497 (socket active-socket) &key (start 0) end
498 remote-address remote-port end-of-record
499 dont-route dont-wait (no-signal *no-sigpipe*)
500 out-of-band #+linux more #+linux confirm)
501 (check-type start unsigned-byte
502 "a non-negative unsigned integer")
503 (check-type end (or unsigned-byte null)
504 "a non-negative unsigned integer or NIL")
505 (when (or remote-port remote-address)
506 (check-type remote-address sockaddr "a network address")
507 (check-type remote-port (unsigned-byte 16) "a valid IP port number"))
508 (let ((flags (logior (if end-of-record et:msg-eor 0)
509 (if dont-route et:msg-dontroute 0)
510 (if dont-wait et:msg-dontwait 0)
511 (if no-signal et:msg-nosignal 0)
512 (if out-of-band et:msg-oob 0)
513 #+linux (if more et:msg-more 0)
514 #+linux (if confirm et:msg-confirm 0))))
515 (when (and (ipv4-address-p remote-address)
516 (eql (socket-family socket) :ipv6))
517 (setf remote-address (map-ipv4-address->ipv6 remote-address)))
518 (multiple-value-bind (buff start-offset bufflen)
519 (%normalize-send-buffer buffer start end (external-format-of socket))
520 (with-foreign-object (ss 'et:sockaddr-storage)
521 (et:bzero ss et:size-of-sockaddr-storage)
522 (when remote-address
523 (sockaddr->sockaddr-storage ss remote-address remote-port))
524 (with-pointer-to-vector-data (buff-sap buff)
525 (incf-pointer buff-sap start-offset)
526 (with-socket-error-filter
527 (return-from socket-send
528 (et:sendto (fd-of socket)
529 buff-sap bufflen
530 flags
531 (if remote-address ss (null-pointer))
532 (if remote-address et:size-of-sockaddr-storage 0)))))))))
534 (defmethod socket-send (buffer (socket passive-socket) &key)
535 (declare (ignore buffer))
536 (error "You cannot send data on a passive socket."))
539 ;;;;;;;;;;;;
540 ;; RECV ;;
541 ;;;;;;;;;;;;
543 (defun %normalize-receive-buffer (buff start end)
544 (setf (values start end) (%check-bounds buff start end))
545 (etypecase buff
546 ((simple-array ub8 (*)) (values buff start (- end start)))))
548 (defmethod socket-receive ((buffer array)
549 (socket active-socket) &key (start 0) end
550 out-of-band peek wait-all
551 dont-wait (no-signal *no-sigpipe*))
552 (let ((flags (logior (if out-of-band et:msg-oob 0)
553 (if peek et:msg-peek 0)
554 (if wait-all et:msg-waitall 0)
555 (if dont-wait et:msg-dontwait 0)
556 (if no-signal et:msg-nosignal 0)))
557 bytes-received)
558 (multiple-value-bind (buff start-offset bufflen)
559 (%normalize-receive-buffer buffer start end)
560 (with-foreign-object (ss 'et:sockaddr-storage)
561 (et:bzero ss et:size-of-sockaddr-storage)
562 (with-foreign-pointer (size et:size-of-socklen)
563 (setf (mem-ref size 'et:socklen)
564 et:size-of-sockaddr-storage)
565 (with-pointer-to-vector-data (buff-sap buff)
566 (incf-pointer buff-sap start-offset)
567 (with-socket-error-filter
568 (setf bytes-received
569 (et:recvfrom (fd-of socket)
570 buff-sap bufflen
571 flags
572 ss size)))))
574 (return-from socket-receive
575 ;; when socket is a datagram socket
576 ;; return the sender's address as 3rd value
577 (if (typep socket 'datagram-socket)
578 (multiple-value-bind (remote-address remote-port)
579 (sockaddr-storage->sockaddr ss)
580 (values buffer bytes-received remote-address remote-port))
581 (values buffer bytes-received)))))))
583 (defmethod socket-receive (buffer (socket passive-socket) &key)
584 (declare (ignore buffer))
585 (error "You cannot receive data from a passive socket."))
589 ;; Only for datagram sockets
592 (defmethod unconnect :before ((socket active-socket))
593 (unless (typep socket 'datagram-socket)
594 (error "You can only unconnect active datagram sockets.")))
596 (defmethod unconnect ((socket datagram-socket))
597 (with-socket-error-filter
598 (with-foreign-object (sin 'et:sockaddr-in)
599 (et:bzero sin et:size-of-sockaddr-in)
600 (setf (foreign-slot-value sin 'et:sockaddr-in 'et:addr) et:af-unspec)
601 (et:connect (fd-of socket) sin et:size-of-sockaddr-in))))