From ehuelsmann at common-lisp.net Wed Oct 18 06:56:34 2006 From: ehuelsmann at common-lisp.net (ehuelsmann at common-lisp.net) Date: Wed, 18 Oct 2006 02:56:34 -0400 (EDT) Subject: [usocket-cvs] r119 - in usocket/trunk: . backend doc notes Message-ID: <20061018065634.232D869002@common-lisp.net> Author: ehuelsmann Date: Wed Oct 18 02:56:33 2006 New Revision: 119 Added: usocket/trunk/backend/scl.lisp usocket/trunk/notes/accept-apis.txt Modified: usocket/trunk/condition.lisp usocket/trunk/doc/design.txt usocket/trunk/usocket.asd usocket/trunk/usocket.lisp Log: Add Scieneer support. Donated by Douglas Crosher . Added: usocket/trunk/backend/scl.lisp ============================================================================== --- (empty file) +++ usocket/trunk/backend/scl.lisp Wed Oct 18 02:56:33 2006 @@ -0,0 +1,101 @@ +;;;; $Id: scl.lisp$ +;;;; $URL: svn://common-lisp.net/project/usocket/svn/usocket/trunk/backend/scl.lisp $ + +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(defparameter +scl-error-map+ + (append +unix-errno-condition-map+ + +unix-errno-error-map+)) + +(defun scl-map-socket-error (err &key condition socket) + (let ((usock-err (cdr (assoc err +scl-error-map+ :test #'member)))) + (cond (usock-err + (if (subtypep usock-err 'error) + (error usock-err :socket socket) + (signal usock-err :socket socket))) + (t + (error 'unknown-error + :socket socket + :real-error condition))))) + +(defun handle-condition (condition &optional (socket nil)) + "Dispatch correct usocket condition." + (etypecase condition + (ext::socket-error + (format t "erron: ~D~%" (ext::socket-errno condition)) + (scl-map-socket-error (ext::socket-errno condition) + :socket socket + :condition condition)) + (error + (error 'unknown-error + :real-condition condition + :socket socket)))) + +(defun socket-connect (host port) + (let* ((socket + (with-mapped-conditions (nil) + (ext:connect-to-inet-socket (host-to-hbo host) port :kind :stream))) + (stream (sys:make-fd-stream socket :input t :output t + :element-type 'character + :buffering :full))) + ;;###FIXME the above line probably needs an :external-format + (make-socket :socket socket :stream stream))) + +(defmethod socket-close ((usocket usocket)) + "Close socket." + (with-mapped-conditions (usocket) + (ext:close-socket (socket usocket)))) + +(defmethod get-local-name ((usocket usocket)) + (multiple-value-bind (address port) + (with-mapped-conditions (usocket) + (ext:get-socket-host-and-port (socket usocket))) + (values (hbo-to-vector-quad address) port))) + +(defmethod get-peer-name ((usocket usocket)) + (multiple-value-bind (address port) + (with-mapped-conditions (usocket) + (ext:get-peer-host-and-port (socket usocket))) + (values (hbo-to-vector-quad address) port))) + +(defmethod get-local-address ((usocket usocket)) + (nth-value 0 (get-local-name usocket))) + +(defmethod get-peer-address ((usocket usocket)) + (nth-value 0 (get-peer-name usocket))) + +(defmethod get-local-port ((usocket usocket)) + (nth-value 1 (get-local-name usocket))) + +(defmethod get-peer-port ((usocket usocket)) + (nth-value 1 (get-peer-name usocket))) + + +(defun get-host-by-address (address) + (multiple-value-bind (host errno) + (ext:lookup-host-entry (host-byte-order address)) + (cond (host + (ext:host-entry-name host)) + (t + (let ((condition (cdr (assoc errno +unix-ns-error-map+)))) + (cond (condition + (error condition :host-or-ip address)) + (t + (error 'ns-unknown-error :host-or-ip address + :real-error errno)))))))) + +(defun get-hosts-by-name (name) + (multiple-value-bind (host errno) + (ext:lookup-host-entry name) + (cond (host + (mapcar #'hbo-to-vector-quad + (ext:host-entry-addr-list host))) + (t + (let ((condition (cdr (assoc errno +unix-ns-error-map+)))) + (cond (condition + (error condition :host-or-ip name)) + (t + (error 'ns-unknown-error :host-or-ip name + :real-error errno)))))))) Modified: usocket/trunk/condition.lisp ============================================================================== --- usocket/trunk/condition.lisp (original) +++ usocket/trunk/condition.lisp Wed Oct 18 02:56:33 2006 @@ -102,8 +102,8 @@ ;; isn't really an error: there's just no data to return. ;; with lisp, we just return NIL (indicating no data) instead of ;; raising an exception... - (ns-host-not-found - ns-no-recovery) + (ns-host-not-found-error + ns-no-recovery-error) (ns-error)) (define-condition ns-unknown-error (ns-error) Modified: usocket/trunk/doc/design.txt ============================================================================== --- usocket/trunk/doc/design.txt (original) +++ usocket/trunk/doc/design.txt Wed Oct 18 02:56:33 2006 @@ -13,7 +13,7 @@ * Motivation * Design goal * Functional requirements - + * Comments on the functional requirements @@ -83,6 +83,33 @@ - OpenMCL +The lifetime of a socket can be described with these steps: + + 1. Socket creation (socket() function) + 2. Socket initializaiton (setsockopt(), bind() and listen()/connect() funcs) + 3. Socket use (accept() / recv[from], send[to]) + 4. Socket termination (shutdown()) + 5. Socket destruction (close()) + +While for most applications steps 1-3 can be condensed into 1 (which most +implementations do), if the library wants to be extensible into other +domains than IP, a means should be provided to do socket initialization +without knowing what parameters to accept beforehand: other protocols +require parameters for setsockopt we will not know about in advance. + +There are several possibilities to address this issue: + + a. Force the 3 steps apart [hard to get done with the current status + for some implementations, as they are currently integrated in the + public interface]. + b. Find a mechanism to pass options which we want setsockopt to + be called with. Problem: what to do with implementations which + don't support setting of all options *before* the bind() call? + Does it matter that some options may be set after the bind() + call? What if they're not set before connect() [buffer size changes + have to be set before connect()]? + c. ... ? + Comments on the design above ============================ Added: usocket/trunk/notes/accept-apis.txt ============================================================================== --- (empty file) +++ usocket/trunk/notes/accept-apis.txt Wed Oct 18 02:56:33 2006 @@ -0,0 +1,173 @@ + + -*- text -*- + +Part of 'Step 3': Server/passive tcp socket interfaces supplied by +the different implementations in order to provide the same externally. + + +ABCL +==== + + - ext:make-server-socket port + - ext:socket-accept socket + - ext:socket-close socket + +Allegro +======= + + - socket:make-socket :type :stream :connect :passive + :local-port :reuse-address t :backlog + :local-host + - socket:accept-connection sock &key wait + - close + + +clisp +===== + + - socket:socket-server &optional port &key interface backlog + - socket:socket-server-close sock + - socket:socket-server-host sock + - socket:socket-server-port sock + - socket:socket-accept sock &key element-type external-format buffered timeout + - socket:socket-options sock &rest options + +... and ofcourse, there's the raw-sockets + +CMUCL +===== + + - ext:create-inet-listener port &optional kind + &key reuseaddress backlog interface + - ext:accept-tcp-connection socket + + +LispWorks +========= + + - comm::get-fd-from-socket (socket-os-fd lispworks-socket) + - comm::create-tcp-socket-for-service port + (may use comm::*use_so_reuseaddr* for that socket option) + misses the ability to specify an interface to bind to. + - comm::socket-close + + +OpenMCL +======= + + - openmcl-socket:accept-connection + - openmcl-socket:make-socket :local-host :local-port port + :reuse-address t :type :stream :connect :passive + :backlog + - close + + +SBCL +==== + + - make-instance 'inet-socket + - sb-bsd-sockets:sockopt-* + - sb-bsd-sockets:socket-bind + - sb-bsd-sockets:socket-listen + - sb-bsd-sockets:socket-accept + + +;; +;; +;; The above APIs are good enough to implement a simple +;; accept interface, but doesn't give access to specifying +;; socket options before the socket is bound to the interface +;; ==> This may only actually be required for SO_REUSEADDRESS?!??? +;; +;; The other option would be to use lots of FFI - where needed - +;; and use the (mostly internal) glue routines from the implementations + + +ABCL +==== + + With ABCL - lacking a good sockets API - it's still possible to implement + whatever we need to get good access... + + +Allegro +======= + + Hmm. The accept function in this implementation does not allow limiting + connections to a given host/ip, but it does allow to create sockets + with mostly the right options. + + Is that enough reason to do this entirely in ffi?! + + Also, doing this in FFI would require to reverse engineer the creation + of socket streams. Maybe Franz tech support could help there though. + + Need to investigate the IPC_* symbols an the sockets package: + there are lots of functions which look like they should be useable. + + +clisp +===== + + This implementation allows access to the full sockets as described + in http://clisp.cons.org/impnotes/rawsock.html. + + +CMUCL +===== + + Provides (in unix package): + + - unix-accept + - unix-bind + - unix-listen + - unix-socket + + Provides (in extentions): + + - inet-sockaddr + - get-socket-option + - set-socket-option + - create-inet-listener port &key host reuse-address backlog + + +LispWorks +========= + + The implementation provides a lot of undocumented functions the library + could tap into: + + - comm::socket + - comm::bind + - comm::accept + - comm::getsockopt + - comm::setsockopt + - comm::initialize-sockaddr_in (helper) + - comm::streams-from-fd (helper) + + +OpenMCL +======= + + - make-socket provides all options which we'll need to set, + it doesn't however provide access to [gs]etsockopt... + + +SBCL +==== + + provides (in sb-bsd-sockets): + socket-bind + socket-accept + sokcet-listen + + provides (in sb-bsd-sockets-internal [sockint]): + getsockopt + setsockopt + + SO-* constants + TCP-* constant(s) + AF-* constants (and, since AF-* == IF-*, we don't need others) + + + Modified: usocket/trunk/usocket.asd ============================================================================== --- usocket/trunk/usocket.asd (original) +++ usocket/trunk/usocket.asd Wed Oct 18 02:56:33 2006 @@ -28,6 +28,8 @@ :depends-on ("condition")) #+cmu (:file "cmucl" :pathname "backend/cmucl" :depends-on ("condition")) + #+scl (:file "scl" :pathname "backend/scl" + :depends-on ("condition")) #+sbcl (:file "sbcl" :pathname "backend/sbcl" :depends-on ("condition")) #+lispworks (:file "lispworks" :pathname "backend/lispworks" Modified: usocket/trunk/usocket.lisp ============================================================================== --- usocket/trunk/usocket.lisp (original) +++ usocket/trunk/usocket.lisp Wed Oct 18 02:56:33 2006 @@ -164,8 +164,8 @@ (string (let ((ip (ignore-errors (dotted-quad-to-vector-quad host)))) (if (and ip (= 4 (length ip))) - ip - (host-to-hbo (get-host-by-name host))))) + (host-byte-order ip) + (host-to-hbo (get-host-by-name host))))) ((vector t 4) (host-byte-order host)) (integer host)))) @@ -186,9 +186,19 @@ ;; (setf (documentation 'socket-connect 'function) - "Connect to `host' on `port'. `host' is assumed to be a string of + "Connect to `host' on `port'. `host' is assumed to be a string or an IP address represented in vector notation, such as #(192 168 1 1). `port' is assumed to be an integer. Returns a usocket object.") +;; Documentation for the function +;; +;; (defun SOCKET-LISTEN (host port &key local-ip local-port +;; reuseaddress backlog) ..) + + +;; Documentation for the function +;; +;; (defun SOCKET-ACCEPT (socket &key element-type external-format +;; buffered timeout) ..) From ehuelsmann at common-lisp.net Wed Oct 18 07:03:56 2006 From: ehuelsmann at common-lisp.net (ehuelsmann at common-lisp.net) Date: Wed, 18 Oct 2006 03:03:56 -0400 (EDT) Subject: [usocket-cvs] r120 - public_html Message-ID: <20061018070356.4A8DD70247@common-lisp.net> Author: ehuelsmann Date: Wed Oct 18 03:03:55 2006 New Revision: 120 Modified: public_html/index.shtml Log: Note added Scieneer support. Modified: public_html/index.shtml ============================================================================== --- public_html/index.shtml (original) +++ public_html/index.shtml Wed Oct 18 03:03:55 2006 @@ -35,6 +35,7 @@
  • Allegro
  • LispWorks
  • OpenMCL
  • +
  • Scieneer
  • Community

    @@ -104,6 +105,7 @@ Allegro LispWorks OpenMCL + Scieneer @@ -121,6 +123,7 @@ DONE DONE DONE + DONE @@ -132,6 +135,7 @@ DONE DONE DONE + DONE Implement active socket support. @@ -142,6 +146,7 @@ DONE DONE DONE + DONE Implement remapping of implementation defined errors. @@ -152,6 +157,7 @@ DONE DONE DONE + DONE Implementation test-suite status @@ -162,6 +168,7 @@ PASS PASS PASS + PASS Add functions to retrieve socket properties:
    @@ -175,6 +182,7 @@ DONE DONE DONE + DONE Implement it. @@ -185,6 +193,7 @@ DONE DONE DONE + DONE Implementation test-suite status @@ -195,6 +204,7 @@ PASS PASS PASS + PASS Add support for passive (connection-accepting/server) @@ -207,6 +217,7 @@ TODO TODO TODO + TODO Implement api calls get- and setsockopt. @@ -217,6 +228,7 @@ TODO TODO TODO + TODO Implement more uncommon api calls @@ -230,6 +242,7 @@ TODO TODO TODO + TODO shutdown @@ -240,6 +253,7 @@ TODO TODO TODO + TODO Implement udp socket support. @@ -252,6 +266,7 @@ TODO TODO TODO + TODO From ehuelsmann at common-lisp.net Wed Oct 18 16:46:43 2006 From: ehuelsmann at common-lisp.net (ehuelsmann at common-lisp.net) Date: Wed, 18 Oct 2006 12:46:43 -0400 (EDT) Subject: [usocket-cvs] r121 - in usocket/trunk: doc notes Message-ID: <20061018164643.2337A39006@common-lisp.net> Author: ehuelsmann Date: Wed Oct 18 12:46:42 2006 New Revision: 121 Removed: usocket/trunk/notes/accept-apis.txt Modified: usocket/trunk/doc/design.txt Log: Remove cruft accidentally added in r119. This wasn't part of the contribution. Modified: usocket/trunk/doc/design.txt ============================================================================== --- usocket/trunk/doc/design.txt (original) +++ usocket/trunk/doc/design.txt Wed Oct 18 12:46:42 2006 @@ -13,7 +13,7 @@ * Motivation * Design goal * Functional requirements - * Comments on the functional requirements + @@ -83,33 +83,6 @@ - OpenMCL -The lifetime of a socket can be described with these steps: - - 1. Socket creation (socket() function) - 2. Socket initializaiton (setsockopt(), bind() and listen()/connect() funcs) - 3. Socket use (accept() / recv[from], send[to]) - 4. Socket termination (shutdown()) - 5. Socket destruction (close()) - -While for most applications steps 1-3 can be condensed into 1 (which most -implementations do), if the library wants to be extensible into other -domains than IP, a means should be provided to do socket initialization -without knowing what parameters to accept beforehand: other protocols -require parameters for setsockopt we will not know about in advance. - -There are several possibilities to address this issue: - - a. Force the 3 steps apart [hard to get done with the current status - for some implementations, as they are currently integrated in the - public interface]. - b. Find a mechanism to pass options which we want setsockopt to - be called with. Problem: what to do with implementations which - don't support setting of all options *before* the bind() call? - Does it matter that some options may be set after the bind() - call? What if they're not set before connect() [buffer size changes - have to be set before connect()]? - c. ... ? - Comments on the design above ============================ From ehuelsmann at common-lisp.net Sun Oct 22 08:42:01 2006 From: ehuelsmann at common-lisp.net (ehuelsmann at common-lisp.net) Date: Sun, 22 Oct 2006 04:42:01 -0400 (EDT) Subject: [usocket-cvs] r122 - usocket/trunk/doc Message-ID: <20061022084201.2DC1F69002@common-lisp.net> Author: ehuelsmann Date: Sun Oct 22 04:42:00 2006 New Revision: 122 Modified: usocket/trunk/doc/design.txt Log: Some design comments sent to the mailing list. Modified: usocket/trunk/doc/design.txt ============================================================================== --- usocket/trunk/doc/design.txt (original) +++ usocket/trunk/doc/design.txt Sun Oct 22 04:42:00 2006 @@ -13,7 +13,7 @@ * Motivation * Design goal * Functional requirements - + * Class structure @@ -119,3 +119,18 @@ int *__h_errno_location(void) points to thread local h_errno on threaded glibc2 systems. + +Class structure +=============== + + usocket + | + +- datagram-usocket + +- stream-usocket + \- stream-server-usocket + +The usocket class will have methods to query local properties, such +as: + + - get-local-name: to query to which interface the socket is bound + - From ehuelsmann at common-lisp.net Wed Oct 25 19:28:17 2006 From: ehuelsmann at common-lisp.net (ehuelsmann at common-lisp.net) Date: Wed, 25 Oct 2006 15:28:17 -0400 (EDT) Subject: [usocket-cvs] r123 - in usocket/trunk: . backend Message-ID: <20061025192817.67C501900C@common-lisp.net> Author: ehuelsmann Date: Wed Oct 25 15:28:16 2006 New Revision: 123 Modified: usocket/trunk/backend/allegro.lisp usocket/trunk/backend/armedbear.lisp usocket/trunk/backend/clisp.lisp usocket/trunk/backend/cmucl.lisp usocket/trunk/backend/lispworks.lisp usocket/trunk/backend/openmcl.lisp usocket/trunk/backend/sbcl.lisp usocket/trunk/backend/scl.lisp usocket/trunk/usocket.lisp Log: Prepare for server-side sockets support. Note: The new socket classes are not used (yet). Modified: usocket/trunk/backend/allegro.lisp ============================================================================== --- usocket/trunk/backend/allegro.lisp (original) +++ usocket/trunk/backend/allegro.lisp Wed Oct 25 15:28:16 2006 @@ -42,7 +42,7 @@ (with-mapped-conditions (socket) (socket:make-socket :remote-host (host-to-hostname host) :remote-port port))) - (make-socket :socket socket :stream socket))) + (make-stream-socket :socket socket :stream socket))) (defmethod socket-close ((usocket usocket)) "Close socket." Modified: usocket/trunk/backend/armedbear.lisp ============================================================================== --- usocket/trunk/backend/armedbear.lisp (original) +++ usocket/trunk/backend/armedbear.lisp Wed Oct 25 15:28:16 2006 @@ -16,8 +16,8 @@ (with-mapped-conditions (usock) (let ((sock (ext:make-socket (host-to-hostname host) port))) (setf usock - (make-socket :socket sock - :stream (ext:get-socket-stream sock))))))) + (make-stream-socket :socket sock + :stream (ext:get-socket-stream sock))))))) (defmethod socket-close ((usocket usocket)) (with-mapped-conditions (usocket) Modified: usocket/trunk/backend/clisp.lisp ============================================================================== --- usocket/trunk/backend/clisp.lisp (original) +++ usocket/trunk/backend/clisp.lisp Wed Oct 25 15:28:16 2006 @@ -46,8 +46,8 @@ (socket:socket-connect port hostname :element-type 'character :buffered t))) - (make-socket :socket socket - :stream socket))) ;; the socket is a stream too + (make-stream-socket :socket socket + :stream socket))) ;; the socket is a stream too ;; :host host ;; :port port)) Modified: usocket/trunk/backend/cmucl.lisp ============================================================================== --- usocket/trunk/backend/cmucl.lisp (original) +++ usocket/trunk/backend/cmucl.lisp Wed Oct 25 15:28:16 2006 @@ -63,8 +63,8 @@ :element-type 'character :buffering :full)) ;;###FIXME the above line probably needs an :external-format - (usocket (make-socket :socket socket - :stream stream))) + (usocket (make-stream-socket :socket socket + :stream stream))) usocket) (let ((err (unix:unix-errno))) (when err (cmucl-map-socket-error err)))))) Modified: usocket/trunk/backend/lispworks.lisp ============================================================================== --- usocket/trunk/backend/lispworks.lisp (original) +++ usocket/trunk/backend/lispworks.lisp Wed Oct 25 15:28:16 2006 @@ -54,8 +54,8 @@ (with-mapped-conditions () (comm:open-tcp-stream hostname port))) (if stream - (make-socket :socket (comm:socket-stream-socket stream) - :stream stream) + (make-stream-socket :socket (comm:socket-stream-socket stream) + :stream stream) (error 'unknown-error)))) ;; :host host ;; :port port)) Modified: usocket/trunk/backend/openmcl.lisp ============================================================================== --- usocket/trunk/backend/openmcl.lisp (original) +++ usocket/trunk/backend/openmcl.lisp Wed Oct 25 15:28:16 2006 @@ -46,7 +46,7 @@ (host-to-hostname host) :remote-port port))) (openmcl-socket:socket-connect mcl-sock) - (make-socket :stream mcl-sock :socket mcl-sock)))) + (make-stream-socket :stream mcl-sock :socket mcl-sock)))) (defmethod socket-close ((usocket usocket)) (with-mapped-conditions (usocket) Modified: usocket/trunk/backend/sbcl.lisp ============================================================================== --- usocket/trunk/backend/sbcl.lisp (original) +++ usocket/trunk/backend/sbcl.lisp Wed Oct 25 15:28:16 2006 @@ -68,7 +68,7 @@ :buffering :full :element-type 'character)) ;;###FIXME: The above line probably needs an :external-format - (usocket (make-instance 'usocket :stream stream :socket socket)) + (usocket (make-stream-socket :stream stream :socket socket)) (ip (host-to-vector-quad host))) (with-mapped-conditions (usocket) (sb-bsd-sockets:socket-connect socket ip port)) Modified: usocket/trunk/backend/scl.lisp ============================================================================== --- usocket/trunk/backend/scl.lisp (original) +++ usocket/trunk/backend/scl.lisp Wed Oct 25 15:28:16 2006 @@ -41,7 +41,7 @@ :element-type 'character :buffering :full))) ;;###FIXME the above line probably needs an :external-format - (make-socket :socket socket :stream stream))) + (make-stream-socket :socket socket :stream stream))) (defmethod socket-close ((usocket usocket)) "Close socket." Modified: usocket/trunk/usocket.lisp ============================================================================== --- usocket/trunk/usocket.lisp (original) +++ usocket/trunk/usocket.lisp Wed Oct 25 15:28:16 2006 @@ -11,19 +11,46 @@ ((socket :initarg :socket :accessor socket - :documentation "Implementation specific socket object instance.") - (stream + :documentation "Implementation specific socket object instance.")) + (:documentation +"The main socket class.")) + +(defclass stream-usocket (usocket) + ((stream :initarg :stream :accessor socket-stream - :documentation "Implementation specific socket stream instance."))) + :documentation "Stream instance associated with the socket. -(defun make-socket (&key socket stream) +Iff an external-format was passed to `socket-connect' or `socket-listen' +the stream is a flexi-stream. Otherwise the stream is implementation +specific.")) + (:documentation "")) + +(defclass stream-server-usocket (usocket) + () + (:documentation "")) + +;;Not in use yet: +;;(defclass datagram-usocket (usocket) +;; () +;; (:documentation "")) + +(defun make-socket (&key socket) + "Create a usocket socket type from implementation specific socket." + (make-stream-socket :socket socket)) + +(defun make-stream-socket (&key socket stream) "Create a usocket socket type from implementation specific socket and stream objects." - (make-instance 'usocket + (make-instance 'stream-usocket :socket socket :stream stream)) +(defun make-stream-server-socket (socket) + "Create a usocket-server socket type from an implementation-specific socket +object." + (make-instance 'stream-server-usocket :socket socket)) + (defun open-stream (peer-host peer-port &key (local-host :any) (local-port 0)