On Wed, 2014-09-17 at 10:08 +0200, Hans Hübner wrote:
> I'm going to come up with a more complete IPv6 update to > sb-bsd-sockets in the next few days and try to get it merged into > SBCL. In the meantime, I extended the patch you mentioned to the attached form. Should I polish it, get it reviewed by other SBCL developers and commit it or would you prefer to write IPv6 support yourself, maybe using the patch as a starting point? (I'm not asking sarcastically since you may have a very different implementation in mind) Kind regards, Jan
From 2f0da13e0388f5254f855e42f025a8a688380fa0 Mon Sep 17 00:00:00 2001 From: Jan Moringen <jmori...@techfak.uni-bielefeld.de> Date: Fri, 18 Apr 2014 19:53:50 +0200 Subject: [PATCH 1/4] Separate inet and inet4 in contrib/sb-bsd-sockets --- contrib/sb-bsd-sockets/inet.lisp | 110 +---------------------------- contrib/sb-bsd-sockets/inet4.lisp | 111 ++++++++++++++++++++++++++++++ contrib/sb-bsd-sockets/sb-bsd-sockets.asd | 5 +- 3 files changed, 115 insertions(+), 111 deletions(-) create mode 100644 contrib/sb-bsd-sockets/inet4.lisp diff --git a/contrib/sb-bsd-sockets/inet.lisp b/contrib/sb-bsd-sockets/inet.lisp index 42f207e..608c96e 100644 --- a/contrib/sb-bsd-sockets/inet.lisp +++ b/contrib/sb-bsd-sockets/inet.lisp @@ -1,61 +1,6 @@ (in-package :sb-bsd-sockets) -;;; Our class and constructor - -(eval-when (:compile-toplevel :load-toplevel :execute) - (defclass inet-socket (socket) - ((family :initform sockint::AF-INET)) - (:documentation "Class representing TCP and UDP sockets. - -Examples: - - (make-instance 'inet-socket :type :stream :protocol :tcp) - - (make-instance 'inet-socket :type :datagram :protocol :udp) -"))) - -;;; XXX should we *...* this? -(defparameter inet-address-any (vector 0 0 0 0)) - -(defmethod socket-namestring ((socket inet-socket)) - (ignore-errors - (multiple-value-bind (addr port) (socket-name socket) - (format nil "~{~A~^.~}:~A" (coerce addr 'list) port)))) - -(defmethod socket-peerstring ((socket inet-socket)) - (ignore-errors - (multiple-value-bind (addr port) (socket-peername socket) - (format nil "~{~A~^.~}:~A" (coerce addr 'list) port)))) - -;;; binding a socket to an address and port. Doubt that anyone's -;;; actually using this much, to be honest. - -(defun make-inet-address (dotted-quads) - "Return a vector of octets given a string DOTTED-QUADS in the format -\"127.0.0.1\". Signals an error if the string is malformed." - (declare (type string dotted-quads)) - (labels ((oops () - (error "~S is not a string designating an IP address." - dotted-quads)) - (check (x) - (if (typep x '(unsigned-byte 8)) - x - (oops)))) - (let* ((s1 (position #\. dotted-quads)) - (s2 (if s1 (position #\. dotted-quads :start (1+ s1)) (oops))) - (s3 (if s2 (position #\. dotted-quads :start (1+ s2)) (oops))) - (u0 (parse-integer dotted-quads :end s1)) - (u1 (parse-integer dotted-quads :start (1+ s1) :end s2)) - (u2 (parse-integer dotted-quads :start (1+ s2) :end s3))) - (multiple-value-bind (u3 end) (parse-integer dotted-quads :start (1+ s3) :junk-allowed t) - (unless (= end (length dotted-quads)) - (oops)) - (let ((vector (make-array 4 :element-type '(unsigned-byte 8)))) - (setf (aref vector 0) (check u0) - (aref vector 1) (check u1) - (aref vector 2) (check u2) - (aref vector 3) (check u3)) - vector))))) +;;; (define-condition unknown-protocol () ((name :initarg :name @@ -147,56 +92,3 @@ a list of protocol aliases" (get-it)) :error (error 'unknown-protocol :name name)))) - -;;; our protocol provides make-sockaddr-for, size-of-sockaddr, -;;; bits-of-sockaddr - -(defmethod make-sockaddr-for ((socket inet-socket) &optional sockaddr &rest address) - (let ((host (first address)) - (port (second address)) - (sockaddr (or sockaddr (sockint::allocate-sockaddr-in)))) - (when (and host port) - (let ((in-port (sockint::sockaddr-in-port sockaddr)) - (in-addr (sockint::sockaddr-in-addr sockaddr))) - (declare (fixnum port)) - ;; port and host are represented in C as "network-endian" unsigned - ;; integers of various lengths. This is stupid. The value of the - ;; integer doesn't matter (and will change depending on your - ;; machine's endianness); what the bind(2) call is interested in - ;; is the pattern of bytes within that integer. - - ;; We have no truck with such dreadful type punning. Octets to - ;; octets, dust to dust. - (setf (sockint::sockaddr-in-family sockaddr) sockint::af-inet) - (setf (sb-alien:deref in-port 0) (ldb (byte 8 8) port)) - (setf (sb-alien:deref in-port 1) (ldb (byte 8 0) port)) - - (setf (sb-alien:deref in-addr 0) (elt host 0)) - (setf (sb-alien:deref in-addr 1) (elt host 1)) - (setf (sb-alien:deref in-addr 2) (elt host 2)) - (setf (sb-alien:deref in-addr 3) (elt host 3)))) - sockaddr)) - -(defmethod free-sockaddr-for ((socket inet-socket) sockaddr) - (sockint::free-sockaddr-in sockaddr)) - -(defmethod size-of-sockaddr ((socket inet-socket)) - sockint::size-of-sockaddr-in) - -(defmethod bits-of-sockaddr ((socket inet-socket) sockaddr) - "Returns address and port of SOCKADDR as multiple values" - (declare (type (sb-alien:alien - (* (sb-alien:struct sb-bsd-sockets-internal::sockaddr-in))) - sockaddr)) - (let ((vector (make-array 4 :element-type '(unsigned-byte 8)))) - (loop for i below 4 - do (setf (aref vector i) - (sb-alien:deref (sockint::sockaddr-in-addr sockaddr) i))) - (values - vector - (+ (* 256 (sb-alien:deref (sockint::sockaddr-in-port sockaddr) 0)) - (sb-alien:deref (sockint::sockaddr-in-port sockaddr) 1))))) - -(defun make-inet-socket (type protocol) - "Make an INET socket. Deprecated in favour of make-instance" - (make-instance 'inet-socket :type type :protocol protocol)) diff --git a/contrib/sb-bsd-sockets/inet4.lisp b/contrib/sb-bsd-sockets/inet4.lisp new file mode 100644 index 0000000..635f02e --- /dev/null +++ b/contrib/sb-bsd-sockets/inet4.lisp @@ -0,0 +1,111 @@ +(in-package :sb-bsd-sockets) + +;;; Our class and constructor + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defclass inet-socket (socket) + ((family :initform sockint::AF-INET)) + (:documentation "Class representing TCP and UDP over IPv4 sockets. + +Examples: + + (make-instance 'inet-socket :type :stream :protocol :tcp) + + (make-instance 'inet-socket :type :datagram :protocol :udp) +"))) + +;;; XXX should we *...* this? +(defparameter inet-address-any (vector 0 0 0 0)) + +(defmethod socket-namestring ((socket inet-socket)) + (ignore-errors + (multiple-value-bind (addr port) (socket-name socket) + (format nil "~{~A~^.~}:~A" (coerce addr 'list) port)))) + +(defmethod socket-peerstring ((socket inet-socket)) + (ignore-errors + (multiple-value-bind (addr port) (socket-peername socket) + (format nil "~{~A~^.~}:~A" (coerce addr 'list) port)))) + +;;; binding a socket to an address and port. Doubt that anyone's +;;; actually using this much, to be honest. + +(defun make-inet-address (dotted-quads) + "Return a vector of octets given a string DOTTED-QUADS in the format +\"127.0.0.1\". Signals an error if the string is malformed." + (declare (type string dotted-quads)) + (labels ((oops () + (error "~S is not a string designating an IP address." + dotted-quads)) + (check (x) + (if (typep x '(unsigned-byte 8)) + x + (oops)))) + (let* ((s1 (position #\. dotted-quads)) + (s2 (if s1 (position #\. dotted-quads :start (1+ s1)) (oops))) + (s3 (if s2 (position #\. dotted-quads :start (1+ s2)) (oops))) + (u0 (parse-integer dotted-quads :end s1)) + (u1 (parse-integer dotted-quads :start (1+ s1) :end s2)) + (u2 (parse-integer dotted-quads :start (1+ s2) :end s3))) + (multiple-value-bind (u3 end) (parse-integer dotted-quads :start (1+ s3) :junk-allowed t) + (unless (= end (length dotted-quads)) + (oops)) + (let ((vector (make-array 4 :element-type '(unsigned-byte 8)))) + (setf (aref vector 0) (check u0) + (aref vector 1) (check u1) + (aref vector 2) (check u2) + (aref vector 3) (check u3)) + vector))))) + +;;; our protocol provides make-sockaddr-for, size-of-sockaddr, +;;; bits-of-sockaddr + +(defmethod make-sockaddr-for ((socket inet-socket) &optional sockaddr &rest address) + (let ((host (first address)) + (port (second address)) + (sockaddr (or sockaddr (sockint::allocate-sockaddr-in)))) + (when (and host port) + (let ((in-port (sockint::sockaddr-in-port sockaddr)) + (in-addr (sockint::sockaddr-in-addr sockaddr))) + (declare (fixnum port)) + ;; port and host are represented in C as "network-endian" unsigned + ;; integers of various lengths. This is stupid. The value of the + ;; integer doesn't matter (and will change depending on your + ;; machine's endianness); what the bind(2) call is interested in + ;; is the pattern of bytes within that integer. + + ;; We have no truck with such dreadful type punning. Octets to + ;; octets, dust to dust. + (setf (sockint::sockaddr-in-family sockaddr) sockint::af-inet) + (setf (sb-alien:deref in-port 0) (ldb (byte 8 8) port)) + (setf (sb-alien:deref in-port 1) (ldb (byte 8 0) port)) + + (setf (sb-alien:deref in-addr 0) (elt host 0)) + (setf (sb-alien:deref in-addr 1) (elt host 1)) + (setf (sb-alien:deref in-addr 2) (elt host 2)) + (setf (sb-alien:deref in-addr 3) (elt host 3)))) + sockaddr)) + +(defmethod free-sockaddr-for ((socket inet-socket) sockaddr) + (sockint::free-sockaddr-in sockaddr)) + +(defmethod size-of-sockaddr ((socket inet-socket)) + sockint::size-of-sockaddr-in) + +(defmethod bits-of-sockaddr ((socket inet-socket) sockaddr) + "Returns address and port of SOCKADDR as multiple values" + (declare (type (sb-alien:alien + (* (sb-alien:struct sb-bsd-sockets-internal::sockaddr-in))) + sockaddr)) + (let ((vector (make-array 4 :element-type '(unsigned-byte 8)))) + (loop for i below 4 + do (setf (aref vector i) + (sb-alien:deref (sockint::sockaddr-in-addr sockaddr) i))) + (values + vector + (+ (* 256 (sb-alien:deref (sockint::sockaddr-in-port sockaddr) 0)) + (sb-alien:deref (sockint::sockaddr-in-port sockaddr) 1))))) + +(defun make-inet-socket (type protocol) + "Make an INET socket. Deprecated in favour of make-instance" + (make-instance 'inet-socket :type type :protocol protocol)) diff --git a/contrib/sb-bsd-sockets/sb-bsd-sockets.asd b/contrib/sb-bsd-sockets/sb-bsd-sockets.asd index cc5af7d..b29ab9c 100644 --- a/contrib/sb-bsd-sockets/sb-bsd-sockets.asd +++ b/contrib/sb-bsd-sockets/sb-bsd-sockets.asd @@ -17,8 +17,9 @@ :depends-on ("win32-constants") :if-feature :win32) (:file "sockets" :depends-on ("constants" "win32-sockets")) (:file "sockopt" :depends-on ("sockets")) - (:file "inet" :depends-on ("sockets" "split")) - (:file "local" :depends-on ("sockets" "split")) + (:file "inet" :depends-on ("sockets")) + (:file "inet4" :depends-on ("sockets")) + (:file "local" :depends-on ("sockets")) (:file "name-service" :depends-on ("sockets")) (:file "misc" :depends-on ("sockets")) (:static-file "NEWS") -- 2.1.0
From 9f80730931eb57427f9881efe4ac1cb3946499e1 Mon Sep 17 00:00:00 2001 From: Jan Moringen <jmori...@techfak.uni-bielefeld.de> Date: Sun, 3 Mar 2013 20:14:47 +0100 Subject: [PATCH 2/4] Initial addition of inet6.lisp --- contrib/sb-bsd-sockets/constants.lisp | 14 +++++ contrib/sb-bsd-sockets/defpackage.lisp | 2 +- contrib/sb-bsd-sockets/inet4.lisp | 14 +++-- contrib/sb-bsd-sockets/inet6.lisp | 100 ++++++++++++++++++++++++++++++ contrib/sb-bsd-sockets/sb-bsd-sockets.asd | 1 + contrib/sb-bsd-sockets/sockets.lisp | 10 +-- 6 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 contrib/sb-bsd-sockets/inet6.lisp diff --git a/contrib/sb-bsd-sockets/constants.lisp b/contrib/sb-bsd-sockets/constants.lisp index de0e2e8..6cd4155 100644 --- a/contrib/sb-bsd-sockets/constants.lisp +++ b/contrib/sb-bsd-sockets/constants.lisp @@ -171,6 +171,20 @@ ;; of the old sb-grovel scheme. ((array (unsigned 8)) port "u_int16_t" "sin_port") ((array (unsigned 8)) addr "struct in_addr" "sin_addr"))) + (:structure in6-addr ("struct in6_addr" + ((array (unsigned 8)) addr "unsigned char" "s6_addr[16]"))) + (:structure sockaddr-in6 ("struct sockaddr_in6" + #+darwin ((unsigned 8) len "__uint8_t" "sin_len") + (integer family "sa_family_t" "sin6_family") + ;; These two could be in-port-t and + ;; in-addr-t, but then we'd throw away the + ;; convenience (and byte-order agnosticism) + ;; of the old sb-grovel scheme. + ((array (unsigned 8)) port "u_int16_t" "sin6_port") + ((array (unsigned 8)) flowinfo "u_int32_t" "sin6_flowinfo") + + ((array (unsigned 8)) addr "struct in_addr6" "sin6_addr") + ((array (unsigned 8)) scope-id "u_int32_t" "sin6_scope_id"))) (:structure sockaddr-un ("struct sockaddr_un" (integer family "sa_family_t" "sun_family") (c-string path "char" "sun_path"))) diff --git a/contrib/sb-bsd-sockets/defpackage.lisp b/contrib/sb-bsd-sockets/defpackage.lisp index a690fbb..956c851 100644 --- a/contrib/sb-bsd-sockets/defpackage.lisp +++ b/contrib/sb-bsd-sockets/defpackage.lisp @@ -5,7 +5,7 @@ (:use "COMMON-LISP" "SB-ALIEN" "SB-EXT")) (defpackage "SB-BSD-SOCKETS" - (:export socket local-socket local-abstract-socket inet-socket + (:export socket local-socket local-abstract-socket inet-socket inet6-socket make-inet-socket socket-bind socket-accept socket-connect socket-send socket-receive diff --git a/contrib/sb-bsd-sockets/inet4.lisp b/contrib/sb-bsd-sockets/inet4.lisp index 635f02e..655821a 100644 --- a/contrib/sb-bsd-sockets/inet4.lisp +++ b/contrib/sb-bsd-sockets/inet4.lisp @@ -17,15 +17,21 @@ Examples: ;;; XXX should we *...* this? (defparameter inet-address-any (vector 0 0 0 0)) +(defun address-numbers/v4 (address) + (coerce address 'list)) + +(defun endpoint-string/v4 (address port) + (format nil "~{~A~^.~}:~A" (address-numbers/v4 address) port)) + (defmethod socket-namestring ((socket inet-socket)) (ignore-errors - (multiple-value-bind (addr port) (socket-name socket) - (format nil "~{~A~^.~}:~A" (coerce addr 'list) port)))) + (multiple-value-bind (address port) (socket-name socket) + (endpoint-string/v4 address port)))) (defmethod socket-peerstring ((socket inet-socket)) (ignore-errors - (multiple-value-bind (addr port) (socket-peername socket) - (format nil "~{~A~^.~}:~A" (coerce addr 'list) port)))) + (multiple-value-bind (address port) (socket-peername socket) + (endpoint-string/v4 address port)))) ;;; binding a socket to an address and port. Doubt that anyone's ;;; actually using this much, to be honest. diff --git a/contrib/sb-bsd-sockets/inet6.lisp b/contrib/sb-bsd-sockets/inet6.lisp new file mode 100644 index 0000000..b3808e6 --- /dev/null +++ b/contrib/sb-bsd-sockets/inet6.lisp @@ -0,0 +1,100 @@ +(in-package :sb-bsd-sockets) + +;;; Socket class and constructor + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defclass inet6-socket (socket) + ((family :initform sockint::AF-INET6)) + (:documentation "Class representing TCP and UDP over IPv6 sockets. + +Examples: + + (make-instance 'inet-socket6 :type :stream :protocol :tcp) + + (make-instance 'inet-socket6 :type :datagram :protocol :udp) +"))) + +(defparameter *inet6-address-any* (vector 0 0 0 0)) + +(defun address-numbers/v6 (address) + (loop for i from 0 below 8 by 2 + collect (let ((number (+ (* 256 (aref address i)) + (aref address (1+ i))))) + (unless (zerop number) number)))) + +(defun endpoint-string/v6 (address port) + (format nil "~{~@[~(~X~)~]~^:~}:~A" + (address-numbers/v6 address) port)) + +(defmethod socket-namestring ((socket inet6-socket)) + (ignore-errors + (multiple-value-bind (address port) (socket-name socket) + (endpoint-string/v6 address port)))) + +(defmethod socket-peerstring ((socket inet6-socket)) + (ignore-errors + (multiple-value-bind (address port) (socket-peername socket) + (endpoint-string/v6 address port)))) + +;; Binding a socket to an address and port. Doubt that anyone's +;; actually using this much, to be honest. +(defun make-inet6-address (colon-separated-integers) + "Return a vector of octets given a TODO. Signals an error if the string is malformed." + (declare (type string colon-separated-integers)) + (let ((address (make-array 16 :element-type '(unsigned-byte 8))) + (i 0)) + (dolist (component (split colon-separated-integers 8 '(#\:))) + (multiple-value-bind (high low) + (floor (parse-integer component :radix 16) 256) + (check-type high (unsigned-byte 8) #+maybe octet) + (check-type low (unsigned-byte 8) #+maybe octet) + (setf (aref address i) high + (aref address (1+ i)) low) + (incf i 2))) + address)) + +;;; our protocol provides make-sockaddr-for, size-of-sockaddr, +;;; bits-of-sockaddr + +(defmethod make-sockaddr-for ((socket inet6-socket) &optional sockaddr + &rest address) + (let ((host (first address)) + (port (second address)) + (sockaddr (or sockaddr (sockint::allocate-sockaddr-in6)))) + (when (and host port) + (setf host (coerce host '(simple-array (unsigned-byte 8) (16)))) + ;; port and host are represented in C as "network-endian" unsigned + ;; integers of various lengths. This is stupid. The value of the + ;; integer doesn't matter (and will change depending on your + ;; machine's endianness); what the bind(2) call is interested in + ;; is the pattern of bytes within that integer. + + ;; We have no truck with such dreadful type punning. Octets to + ;; octets, dust to dust. + + (setf (sockint::sockaddr-in6-family sockaddr) sockint::af-inet6) + (setf (sb-alien:deref (sockint::sockaddr-in6-port sockaddr) 0) (ldb (byte 8 8) port)) + (setf (sb-alien:deref (sockint::sockaddr-in6-port sockaddr) 1) (ldb (byte 8 0) port)) + (dotimes (i 4) + (setf (sb-alien:deref (sockint::sockaddr-in6-flowinfo sockaddr) i) 0)) + + (dotimes (i 16) + (setf (sb-alien:deref (sockint::sockaddr-in6-addr sockaddr) i) (elt host i))) + (dotimes (i 4) + (setf (sb-alien:deref (sockint::sockaddr-in6-scope-id sockaddr) i) 0))) + sockaddr)) + +(defmethod free-sockaddr-for ((socket inet6-socket) sockaddr) + (sockint::free-sockaddr-in6 sockaddr)) + +(defmethod size-of-sockaddr ((socket inet6-socket)) + sockint::size-of-sockaddr-in6) + +(defmethod bits-of-sockaddr ((socket inet6-socket) sockaddr) + "Returns address and port of SOCKADDR as multiple values" + (values + (coerce (loop for i from 0 below 16 + collect (sb-alien:deref (sockint::sockaddr-in6-addr sockaddr) i)) + '(vector (unsigned-byte 8) 16)) + (+ (* 256 (sb-alien:deref (sockint::sockaddr-in6-port sockaddr) 0)) + (sb-alien:deref (sockint::sockaddr-in6-port sockaddr) 1)))) diff --git a/contrib/sb-bsd-sockets/sb-bsd-sockets.asd b/contrib/sb-bsd-sockets/sb-bsd-sockets.asd index b29ab9c..1948848 100644 --- a/contrib/sb-bsd-sockets/sb-bsd-sockets.asd +++ b/contrib/sb-bsd-sockets/sb-bsd-sockets.asd @@ -19,6 +19,7 @@ (:file "sockopt" :depends-on ("sockets")) (:file "inet" :depends-on ("sockets")) (:file "inet4" :depends-on ("sockets")) + (:file "inet6" :depends-on ("sockets" "split")) (:file "local" :depends-on ("sockets")) (:file "name-service" :depends-on ("sockets")) (:file "misc" :depends-on ("sockets")) diff --git a/contrib/sb-bsd-sockets/sockets.lisp b/contrib/sb-bsd-sockets/sockets.lisp index ed863ae..aea084c 100644 --- a/contrib/sb-bsd-sockets/sockets.lisp +++ b/contrib/sb-bsd-sockets/sockets.lisp @@ -137,11 +137,11 @@ values")) (defmethod socket-connect ((socket socket) &rest peer) (with-sockaddr-for (socket sockaddr peer) - (if (= (sockint::connect (socket-file-descriptor socket) - sockaddr - (size-of-sockaddr socket)) - -1) - (socket-error "connect")))) + (when (= (sockint::connect (socket-file-descriptor socket) + sockaddr + (size-of-sockaddr socket)) + -1) + (socket-error "connect")))) (defgeneric socket-peername (socket) (:documentation "Return the socket's peer; depending on the address -- 2.1.0
From 3965cdd98aed322ec7bade381c8f293a7a66c80e Mon Sep 17 00:00:00 2001 From: Jan Moringen <jmori...@techfak.uni-bielefeld.de> Date: Fri, 18 Apr 2014 20:59:55 +0200 Subject: [PATCH 3/4] Cosmetic changes in sb-bsd-sockets --- contrib/sb-bsd-sockets/defpackage.lisp | 4 ++-- contrib/sb-bsd-sockets/sockets.lisp | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/contrib/sb-bsd-sockets/defpackage.lisp b/contrib/sb-bsd-sockets/defpackage.lisp index 956c851..38cd8a4 100644 --- a/contrib/sb-bsd-sockets/defpackage.lisp +++ b/contrib/sb-bsd-sockets/defpackage.lisp @@ -6,7 +6,7 @@ (defpackage "SB-BSD-SOCKETS" (:export socket local-socket local-abstract-socket inet-socket inet6-socket - make-inet-socket + make-inet-socket ; deprecated socket-bind socket-accept socket-connect socket-send socket-receive socket-name socket-peername socket-listen @@ -56,7 +56,7 @@ arguments to fit Lisp style more closely.")) ;;; thread-safe on OS X, but they probably can't be any worse than ;;; gethostbyname and gethostbyaddr. ;;; -;;; CLH: getaddrinfo seems to be broken is broken on x86-64/darwin +;;; CLH: getaddrinfo seems to be broken on x86-64/darwin #-(or win32 (and x86-64 darwin)) (let ((addr (sb-alien::find-dynamic-foreign-symbol-address "getaddrinfo"))) (when addr diff --git a/contrib/sb-bsd-sockets/sockets.lisp b/contrib/sb-bsd-sockets/sockets.lisp index aea084c..128031c 100644 --- a/contrib/sb-bsd-sockets/sockets.lisp +++ b/contrib/sb-bsd-sockets/sockets.lisp @@ -15,7 +15,7 @@ (defclass socket () ((file-descriptor :initarg :descriptor :reader socket-file-descriptor) - (family :initform (error "No socket family") + (family :initform (error "No socket family") ; subclasses supply initforms :reader socket-family) (protocol :initarg :protocol :reader socket-protocol @@ -29,7 +29,9 @@ protocol. Other values are used as-is.") #+win32 (non-blocking-p :type (member t nil) :initform nil) (stream)) - (:documentation "Common base class of all sockets, not meant to be + (:default-initargs + :type (sb-int:missing-arg)) + (:documentation "Common superclass of all sockets, not meant to be directly instantiated."))) (defmethod print-object ((object socket) stream) @@ -64,7 +66,7 @@ directly instantiated."))) ((:datagram) sockint::sock-dgram) ((:stream) sockint::sock-stream)) proto-num)))) - (if (= fd -1) (socket-error "socket")) + (when (= fd -1) (socket-error "socket")) (setf (slot-value socket 'file-descriptor) fd (slot-value socket 'protocol) proto-num (slot-value socket 'type) type) @@ -525,7 +527,7 @@ request an input stream and get an output stream in response\)." #+sbcl (defun socket-error (where) - ;; FIXME: Our Texinfo documentation extracter need at least his to spit + ;; FIXME: Our Texinfo documentation extracter need at least this to spit ;; out the signature. Real documentation would be better... "" (let* ((errno (socket-errno)) -- 2.1.0
From b2322bc28039e7fbf0a141a80609c94db0f900ed Mon Sep 17 00:00:00 2001 From: Jan Moringen <jmori...@techfak.uni-bielefeld.de> Date: Fri, 18 Apr 2014 21:18:11 +0200 Subject: [PATCH 4/4] Moved protocol into contrib/sb-bsd-sockets/protocol.lisp --- contrib/sb-bsd-sockets/misc.lisp | 6 -- contrib/sb-bsd-sockets/name-service.lisp | 3 - contrib/sb-bsd-sockets/protocol.lisp | 132 ++++++++++++++++++++++++++++++ contrib/sb-bsd-sockets/sb-bsd-sockets.asd | 33 ++++---- contrib/sb-bsd-sockets/sockets.lisp | 112 ------------------------- 5 files changed, 151 insertions(+), 135 deletions(-) create mode 100644 contrib/sb-bsd-sockets/protocol.lisp diff --git a/contrib/sb-bsd-sockets/misc.lisp b/contrib/sb-bsd-sockets/misc.lisp index e38a613..66152ff 100644 --- a/contrib/sb-bsd-sockets/misc.lisp +++ b/contrib/sb-bsd-sockets/misc.lisp @@ -9,9 +9,6 @@ ;;; XXX bad (sizeof (int) ==4 ) assumptions -(defgeneric non-blocking-mode (socket) - (:documentation "Is SOCKET in non-blocking mode?")) - #-win32 (defmethod non-blocking-mode ((socket socket)) (let ((fd (socket-file-descriptor socket))) @@ -25,9 +22,6 @@ (defmethod non-blocking-mode ((socket socket)) (slot-value socket 'non-blocking-p)) -(defgeneric (setf non-blocking-mode) (non-blocking-p socket) - (:documentation "Put SOCKET in non-blocking mode - or not, according to NON-BLOCKING-P")) - #-win32 (defmethod (setf non-blocking-mode) (non-blocking-p (socket socket)) (declare (optimize (speed 3))) diff --git a/contrib/sb-bsd-sockets/name-service.lisp b/contrib/sb-bsd-sockets/name-service.lisp index ba7d2f2..f1d708a 100644 --- a/contrib/sb-bsd-sockets/name-service.lisp +++ b/contrib/sb-bsd-sockets/name-service.lisp @@ -13,9 +13,6 @@ :documentation "A list of addresses for this host.")) (:documentation "This class represents the results of an address lookup.")) -(defgeneric host-ent-address (host-ent) - (:documentation "Returns some valid address for HOST-ENT.")) - (defmethod host-ent-address ((host-ent host-ent)) (car (host-ent-addresses host-ent))) diff --git a/contrib/sb-bsd-sockets/protocol.lisp b/contrib/sb-bsd-sockets/protocol.lisp new file mode 100644 index 0000000..a6642bd --- /dev/null +++ b/contrib/sb-bsd-sockets/protocol.lisp @@ -0,0 +1,132 @@ +(cl:in-package #:sb-bsd-sockets) + +;;; Addresses + +(defgeneric make-sockaddr-for (socket &optional sockaddr &rest address) + (:documentation "Return a Socket Address object suitable for use with SOCKET. +When SOCKADDR is passed, it is used instead of a new object.")) + +(defgeneric free-sockaddr-for (socket sockaddr) + (:documentation "Deallocate a Socket Address object that was created +for SOCKET.")) + +(defgeneric bits-of-sockaddr (socket sockaddr) + (:documentation "Return as multiple values protocol-dependent bits +of parameter SOCKADDR, e.g. the host/port if SOCKET is an inet +socket.")) + +(defgeneric size-of-sockaddr (socket) + (:documentation "Return the size of a sockaddr object for SOCKET.")) + +;;; Sockets + +(defgeneric socket-name (socket) + (:documentation "Return the address (as vector of bytes) and port + that the socket is bound to, as multiple values.")) + +(defgeneric socket-peername (socket) + (:documentation "Return the socket's peer; depending on the address + family this may return multiple values")) + +(defgeneric socket-namestring (socket) + (:method ((socket t)) + nil) + (:documentation "TODO")) + +(defgeneric socket-peerstring (socket) + (:method ((socket t)) + nil) + (:documentation "TODO")) + +(defgeneric socket-open-p (socket) + (:documentation "Return true if SOCKET is open; otherwise, return false.") + (:method ((socket t)) (error 'type-error + :datum socket :expected-type 'socket))) + +(defgeneric socket-close (socket &key abort) + (:documentation + "Close SOCKET, unless it was already closed. + +If SOCKET-MAKE-STREAM has been called, calls CLOSE using ABORT on that +stream. Otherwise closes the socket file descriptor using +close(2).")) + +(defgeneric socket-bind (socket &rest address) + (:documentation "Bind SOCKET to ADDRESS, which may vary according to +socket family. For the INET family, pass ADDRESS and PORT as two +arguments; for FILE address family sockets, pass the filename string. +See also bind(2)")) + +(defgeneric socket-accept (socket) + (:documentation "Perform the accept(2) call, returning a +newly-created connected socket and the peer address as multiple +values")) + +(defgeneric socket-connect (socket &rest address) + (:documentation "Perform the connect(2) call to connect SOCKET to a + remote PEER. No useful return value.")) + +(defgeneric socket-receive (socket buffer length + &key + oob peek waitall dontwait element-type) + (:documentation + "Read LENGTH octets from SOCKET into BUFFER (or a freshly-consed +buffer if NIL), using recvfrom(2). If LENGTH is NIL, the length of +BUFFER is used, so at least one of these two arguments must be +non-NIL. If BUFFER is supplied, it had better be of an element type +one octet wide. Returns the buffer, its length, and the address of the +peer that sent it, as multiple values. On datagram sockets, sets +MSG_TRUNC so that the actual packet length is returned even if the +buffer was too small.")) + +(defgeneric socket-send (socket buffer length + &key + address + external-format + oob eor dontroute dontwait nosignal + #+linux confirm #+linux more) + (:documentation + "Send LENGTH octets from BUFFER into SOCKET, using sendto(2). If +BUFFER is a string, it will converted to octets according to +EXTERNAL-FORMAT. If LENGTH is NIL, the length of the octet buffer is +used. The format of ADDRESS depends on the socket type (for example +for INET domain sockets it would be a list of an IP address and a +port). If no socket address is provided, send(2) will be called +instead. Returns the number of octets written.")) + +(defgeneric socket-listen (socket backlog) + (:documentation "Mark SOCKET as willing to accept incoming +connections. BACKLOG defines the maximum length that the queue of +pending connections may grow to before new connection attempts are +refused. See also listen(2)")) + +(defgeneric socket-shutdown (socket &key direction) + (:documentation + "Indicate that no communication in DIRECTION will be performed on SOCKET. + +DIRECTION has to be one of :INPUT, :OUTPUT or :IO. + +After a shutdown, no input and/or output of the indicated DIRECTION +can be performed on SOCKET.")) + +(defgeneric socket-make-stream (socket &key input output + element-type external-format + buffering + timeout) + (:documentation "Find or create a STREAM that can be used for IO on +SOCKET \(which must be connected\). Specify whether the stream is for +INPUT, OUTPUT, or both \(it is an error to specify neither\). +ELEMENT-TYPE and EXTERNAL-FORMAT are as per OPEN. TIMEOUT specifies a +read timeout for the stream.")) + +(defgeneric non-blocking-mode (socket) + (:documentation "Is SOCKET in non-blocking mode?")) + +(defgeneric (setf non-blocking-mode) (non-blocking-p socket) + (:documentation "Put SOCKET in non-blocking mode - or not, according +to NON-BLOCKING-P")) + +;;; Name service + +(defgeneric host-ent-address (host-ent) + (:documentation "Returns some valid address for HOST-ENT.")) diff --git a/contrib/sb-bsd-sockets/sb-bsd-sockets.asd b/contrib/sb-bsd-sockets/sb-bsd-sockets.asd index 1948848..f950a58 100644 --- a/contrib/sb-bsd-sockets/sb-bsd-sockets.asd +++ b/contrib/sb-bsd-sockets/sb-bsd-sockets.asd @@ -1,6 +1,6 @@ ;;; -*- Lisp -*- -(defsystem sb-bsd-sockets +(defsystem :sb-bsd-sockets :version "0.58" :defsystem-depends-on (sb-grovel) #+sb-building-contrib :pathname @@ -9,19 +9,24 @@ ((:file "defpackage") (:file "split" :depends-on ("defpackage")) (:file "win32-lib" :if-feature :win32) - (:sb-grovel-constants-file "constants" :package :sockint - :depends-on ("defpackage") :if-feature (:not :win32)) - (:sb-grovel-constants-file "win32-constants" :package - :sockint :depends-on ("defpackage" "win32-lib") :if-feature :win32) - (:file "win32-sockets" - :depends-on ("win32-constants") :if-feature :win32) - (:file "sockets" :depends-on ("constants" "win32-sockets")) + (:sb-grovel-constants-file "constants" + :package :sockint + :depends-on ("defpackage") + :if-feature (:not :win32)) + (:sb-grovel-constants-file "win32-constants" + :package :sockint + :depends-on ("defpackage" "win32-lib") + :if-feature :win32) + (:file "protocol" :depends-on ("defpackage")) + (:file "win32-sockets" :depends-on ("protocol" "win32-constants") + :if-feature :win32) + (:file "sockets" :depends-on ("protocol" "constants" "win32-sockets")) (:file "sockopt" :depends-on ("sockets")) - (:file "inet" :depends-on ("sockets")) - (:file "inet4" :depends-on ("sockets")) - (:file "inet6" :depends-on ("sockets" "split")) - (:file "local" :depends-on ("sockets")) - (:file "name-service" :depends-on ("sockets")) + (:file "inet" :depends-on ("protocol" "sockets")) + (:file "inet4" :depends-on ("protocol" "sockets")) + (:file "inet6" :depends-on ("protocol" "sockets" "split")) + (:file "local" :depends-on ("protocol" "sockets")) + (:file "name-service" :depends-on ("protocol" "sockets")) (:file "misc" :depends-on ("sockets")) (:static-file "NEWS") ;; (:static-file "INSTALL") @@ -31,7 +36,7 @@ :perform (load-op :after (o c) (provide 'sb-bsd-sockets)) :perform (test-op (o c) (test-system 'sb-bsd-sockets/tests))) -(defsystem sb-bsd-sockets/tests +(defsystem :sb-bsd-sockets/tests :depends-on (sb-rt sb-bsd-sockets #-win32 sb-posix) :components ((:file "tests")) :perform (test-op (o c) diff --git a/contrib/sb-bsd-sockets/sockets.lisp b/contrib/sb-bsd-sockets/sockets.lisp index 128031c..b2c8390 100644 --- a/contrib/sb-bsd-sockets/sockets.lisp +++ b/contrib/sb-bsd-sockets/sockets.lisp @@ -5,7 +5,6 @@ (eval-when (:load-toplevel :compile-toplevel :execute) - ;;; Winsock is different w.r.t errno (defun socket-errno () "Get socket error code, usually from errno, but see #+win32." @@ -41,16 +40,6 @@ directly instantiated."))) (socket-peerstring object) (slot-value object 'file-descriptor)))) -(defgeneric socket-namestring (socket)) - -(defmethod socket-namestring (socket) - nil) - -(defgeneric socket-peerstring (socket)) - -(defmethod socket-peerstring (socket) - nil) - (defmethod shared-initialize :after ((socket socket) slot-names &key protocol type &allow-other-keys) @@ -75,14 +64,6 @@ directly instantiated."))) -(defgeneric make-sockaddr-for (socket &optional sockaddr &rest address) - (:documentation "Return a Socket Address object suitable for use with SOCKET. -When SOCKADDR is passed, it is used instead of a new object.")) - -(defgeneric free-sockaddr-for (socket sockaddr) - (:documentation "Deallocate a Socket Address object that was -created for SOCKET.")) - (defmacro with-sockaddr-for ((socket sockaddr &optional sockaddr-args) &body body) `(let ((,sockaddr (apply #'make-sockaddr-for ,socket nil ,sockaddr-args))) (unwind-protect (progn ,@body) @@ -92,12 +73,6 @@ created for SOCKET.")) ;; sockaddr_something as second arg, we pass the elements of one as ;; multiple arguments. -(defgeneric socket-bind (socket &rest address) - (:documentation "Bind SOCKET to ADDRESS, which may vary according to -socket family. For the INET family, pass ADDRESS and PORT as two -arguments; for FILE address family sockets, pass the filename string. -See also bind(2)")) - (defmethod socket-bind ((socket socket) &rest address) (with-sockaddr-for (socket sockaddr address) @@ -108,10 +83,6 @@ See also bind(2)")) (socket-error "bind")))) -(defgeneric socket-accept (socket) - (:documentation "Perform the accept(2) call, returning a -newly-created connected socket and the peer address as multiple -values")) (defmethod socket-accept ((socket socket)) (with-sockaddr-for (socket sockaddr) @@ -133,10 +104,6 @@ values")) :dont-save t)) (multiple-value-list (bits-of-sockaddr socket sockaddr)))))))) -(defgeneric socket-connect (socket &rest address) - (:documentation "Perform the connect(2) call to connect SOCKET to a - remote PEER. No useful return value.")) - (defmethod socket-connect ((socket socket) &rest peer) (with-sockaddr-for (socket sockaddr peer) (when (= (sockint::connect (socket-file-descriptor socket) @@ -145,10 +112,6 @@ values")) -1) (socket-error "connect")))) -(defgeneric socket-peername (socket) - (:documentation "Return the socket's peer; depending on the address - family this may return multiple values")) - (defmethod socket-peername ((socket socket)) (with-sockaddr-for (socket sockaddr) (when (= (sockint::getpeername (socket-file-descriptor socket) @@ -158,10 +121,6 @@ values")) (socket-error "getpeername")) (bits-of-sockaddr socket sockaddr))) -(defgeneric socket-name (socket) - (:documentation "Return the address (as vector of bytes) and port - that the socket is bound to, as multiple values.")) - (defmethod socket-name ((socket socket)) (with-sockaddr-for (socket sockaddr) (when (= (sockint::getsockname (socket-file-descriptor socket) @@ -178,19 +137,6 @@ values")) ;;; allows us to read from an unconnected socket into a buffer, and ;;; to learn who the sender of the packet was -(defgeneric socket-receive (socket buffer length - &key - oob peek waitall dontwait element-type) - (:documentation - "Read LENGTH octets from SOCKET into BUFFER (or a freshly-consed -buffer if NIL), using recvfrom(2). If LENGTH is NIL, the length of -BUFFER is used, so at least one of these two arguments must be -non-NIL. If BUFFER is supplied, it had better be of an element type -one octet wide. Returns the buffer, its length, and the address of the -peer that sent it, as multiple values. On datagram sockets, sets -MSG_TRUNC so that the actual packet length is returned even if the -buffer was too small.")) - (defmethod socket-receive ((socket socket) buffer length &key oob peek waitall dontwait @@ -248,20 +194,6 @@ buffer was too small.")) (let ((,name (sb-sys:vector-sap ,vector))) ,@body))) -(defgeneric socket-send (socket buffer length - &key - address - external-format - oob eor dontroute dontwait nosignal - #+linux confirm #+linux more) - (:documentation - "Send LENGTH octets from BUFFER into SOCKET, using sendto(2). If BUFFER -is a string, it will converted to octets according to EXTERNAL-FORMAT. If -LENGTH is NIL, the length of the octet buffer is used. The format of ADDRESS -depends on the socket type (for example for INET domain sockets it would -be a list of an IP address and a port). If no socket address is provided, -send(2) will be called instead. Returns the number of octets written.")) - (defmethod socket-send ((socket socket) buffer length &key address @@ -313,33 +245,16 @@ send(2) will be called instead. Returns the number of octets written.")) (socket-error "sendto")) (t len)))) -(defgeneric socket-listen (socket backlog) - (:documentation "Mark SOCKET as willing to accept incoming connections. BACKLOG -defines the maximum length that the queue of pending connections may -grow to before new connection attempts are refused. See also listen(2)")) - (defmethod socket-listen ((socket socket) backlog) (let ((r (sockint::listen (socket-file-descriptor socket) backlog))) (if (= r -1) (socket-error "listen")))) -(defgeneric socket-open-p (socket) - (:documentation "Return true if SOCKET is open; otherwise, return false.") - (:method ((socket t)) (error 'type-error - :datum socket :expected-type 'socket))) - (defmethod socket-open-p ((socket socket)) (if (slot-boundp socket 'stream) (open-stream-p (slot-value socket 'stream)) (/= -1 (socket-file-descriptor socket)))) -(defgeneric socket-close (socket &key abort) - (:documentation - "Close SOCKET, unless it was already closed. - -If SOCKET-MAKE-STREAM has been called, calls CLOSE using ABORT on that stream. -Otherwise closes the socket file descriptor using close(2).")) - (defmethod socket-close ((socket socket) &key abort) ;; the close(2) manual page has all kinds of warning about not ;; checking the return value of close, on the grounds that an @@ -378,15 +293,6 @@ Otherwise closes the socket file descriptor using close(2).")) (declare (ignore r)) (drop-it)))))))) -(defgeneric socket-shutdown (socket &key direction) - (:documentation - "Indicate that no communication in DIRECTION will be performed on SOCKET. - -DIRECTION has to be one of :INPUT, :OUTPUT or :IO. - -After a shutdown, no input and/or output of the indicated DIRECTION -can be performed on SOCKET.")) - (defmethod socket-shutdown ((socket socket) &key direction) (let* ((fd (socket-file-descriptor socket)) (how (ecase direction @@ -396,16 +302,6 @@ can be performed on SOCKET.")) (when (minusp (sockint::shutdown fd how)) (socket-error "shutdown")))) -(defgeneric socket-make-stream (socket &key input output - element-type external-format - buffering - timeout) - (:documentation "Find or create a STREAM that can be used for IO on -SOCKET \(which must be connected\). Specify whether the stream is for -INPUT, OUTPUT, or both \(it is an error to specify neither\). ELEMENT-TYPE -and EXTERNAL-FORMAT are as per OPEN. TIMEOUT specifies a read timeout -for the stream.")) - (defmethod socket-make-stream ((socket socket) &key input output (element-type 'character) @@ -533,11 +429,3 @@ request an input stream and get an output stream in response\)." (let* ((errno (socket-errno)) (condition (condition-for-errno errno))) (error condition :errno errno :syscall where))) - - -(defgeneric bits-of-sockaddr (socket sockaddr) - (:documentation "Return protocol-dependent bits of parameter -SOCKADDR, e.g. the Host/Port if SOCKET is an inet socket.")) - -(defgeneric size-of-sockaddr (socket) - (:documentation "Return the size of a sockaddr object for SOCKET.")) -- 2.1.0
_______________________________________________ Usocket-devel mailing list Usocket-devel@common-lisp.net http://mailman.common-lisp.net/cgi-bin/mailman/listinfo/usocket-devel