From ctian at common-lisp.net Fri Apr 1 08:05:39 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 04:05:39 -0400 Subject: [usocket-cvs] r628 - usocket/branches/0.5.x Message-ID: Author: ctian Date: Fri Apr 1 04:05:38 2011 New Revision: 628 Log: Update ChangeLog Modified: usocket/branches/0.5.x/CHANGES Modified: usocket/branches/0.5.x/CHANGES ============================================================================== --- usocket/branches/0.5.x/CHANGES (original) +++ usocket/branches/0.5.x/CHANGES Fri Apr 1 04:05:38 2011 @@ -8,6 +8,9 @@ 0.5.1: +* New feature: [CLISP] add UDP (Datagram) support based on FFI, no RAWSOCK needed. +* Enhancement: SOCKET-SERVER return a second value (socket) when calling in new-thread mode. +* Enhancement: [CLISP] Full support of DNS helper functions (GET-HOST-BY-NAME, ...) added. * Bugfix: Fixed wrong macro expansions of {IP|PORT}-{FROM|TO}-OCTET-BUFFER functions! * Bugfix: SOCKET-CONNECT didn't set CONNECTED-P for datagram usockets on most backends. * Bugfix: [SBCL] Fixes for "SBCL/Win32: finalizer problem, etc", by Anton Kovalenko @@ -15,12 +18,9 @@ * Bugfix: [SBCL] SOCKET-CONNECT's TIMEOUT argument now works as a "connection timeout". * Bugfix: [CMUCL] Fixed SOCKET-SEND on unconnected usockets under Unicode version of CMUCL. * Bugfix: [LispWorks] Better network error type detection on LispWorks. -* Bugfix: [CLISP] Fixed UDP (Datagram) support (RAWSOCK version), confirmed by CL-NET-SNMP. -* Enhancement: SOCKET-SERVER return a second value (socket) when calling in new-thread mode. -* Enhancement: [CLISP] Full support of DNS helper functions (GET-HOST-BY-NAME, ...) added. +* Bugfix: [CLISP] Fixed and confirmed UDP (Datagram) support (RAWSOCK version). [TODO] -* New feature: CLISP support UDP without RAWSOCK (using FFI interface) * New feature: CLISP support some advanced TCP features which CLISP's SOCKET interface not provide * New feature: Macintosh Common Lisp (MCL) support Datagram sockets (UDP) From ctian at common-lisp.net Fri Apr 1 08:45:48 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 04:45:48 -0400 Subject: [usocket-cvs] r629 - usocket/branches/0.5.x/backend Message-ID: Author: ctian Date: Fri Apr 1 04:45:48 2011 New Revision: 629 Log: [CLISP] SOCKET-RECEIVE (RAWSOCK version) returns reduced buffer when calling with a NIL buffer argument. Modified: usocket/branches/0.5.x/backend/clisp.lisp Modified: usocket/branches/0.5.x/backend/clisp.lisp ============================================================================== --- usocket/branches/0.5.x/backend/clisp.lisp (original) +++ usocket/branches/0.5.x/backend/clisp.lisp Fri Apr 1 04:45:48 2011 @@ -237,15 +237,19 @@ (sockaddr (rawsock:make-sockaddr :inet)) (real-length (or length +max-datagram-packet-size+)) (real-buffer (or buffer - (make-array real-length :element-type '(unsigned-byte 8)))) - (rv (rawsock:recvfrom sock real-buffer sockaddr + (make-array real-length + :element-type '(unsigned-byte 8))))) + (let ((rv (rawsock:recvfrom sock real-buffer sockaddr :start 0 :end real-length)) - (host 0) (port 0)) - (unless (connected-p socket) - (let ((data (rawsock:sockaddr-data sockaddr))) - (setq host (ip-from-octet-buffer data :start 4) - port (port-from-octet-buffer data :start 2)))) - (values real-buffer rv host port))) + (host 0) (port 0)) + (unless (connected-p socket) + (let ((data (rawsock:sockaddr-data sockaddr))) + (setq host (ip-from-octet-buffer data :start 4) + port (port-from-octet-buffer data :start 2)))) + (values (if buffer real-buffer (subseq real-buffer 0 rv)) + rv + host + port)))) (defmethod socket-send ((socket datagram-usocket) buffer length &key host port) "Returns the number of octets sent." From ctian at common-lisp.net Fri Apr 1 10:33:17 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 06:33:17 -0400 Subject: [usocket-cvs] r630 - usocket/branches/0.5.x/backend Message-ID: Author: ctian Date: Fri Apr 1 06:33:17 2011 New Revision: 630 Log: [CLISP] rewrite error handling facility. Modified: usocket/branches/0.5.x/backend/clisp.lisp Modified: usocket/branches/0.5.x/backend/clisp.lisp ============================================================================== --- usocket/branches/0.5.x/backend/clisp.lisp (original) +++ usocket/branches/0.5.x/backend/clisp.lisp Fri Apr 1 06:33:17 2011 @@ -44,35 +44,74 @@ (mapcar #'host-to-vector-quad (posix:hostent-addr-list hostent))))) -#+win32 -(defun remap-maybe-for-win32 (z) - (mapcar #'(lambda (x) - (cons (mapcar #'(lambda (y) - (+ 10000 y)) - (car x)) - (cdr x))) - z)) - +;; Format: ((UNIX Windows) . CONDITION) (defparameter +clisp-error-map+ - #+win32 - (append (remap-maybe-for-win32 +unix-errno-condition-map+) - (remap-maybe-for-win32 +unix-errno-error-map+)) #-win32 - (append +unix-errno-condition-map+ - +unix-errno-error-map+)) + `((:EADDRINUSE . address-in-use-error) + (:EADDRNOTAVAIL . address-not-available-error) + (:EBADF . bad-file-descriptor-error) + (:ECONNREFUSED . connection-refused-error) + (:ECONNRESET . connection-reset-error) + (:ECONNABORTED . connection-aborted-error) + (:EINVAL . invalid-argument-error) + (:ENOBUFS . no-buffers-error) + (:ENOMEM . out-of-memory-error) + (:ENOTSUP . operation-not-supported-error) + (:EPERM . operation-not-permitted-error) + (:EPROTONOSUPPORT . protocol-not-supported-error) + (:ESOCKTNOSUPPORT . socket-type-not-supported-error) + (:ENETUNREACH . network-unreachable-error) + (:ENETDOWN . network-down-error) + (:ENETRESET . network-reset-error) + (:ESHUTDOWN . already-shutdown-error) + (:ETIMEDOUT . timeout-error) + (:EHOSTDOWN . host-down-error) + (:EHOSTUNREACH . host-unreachable-error)) + #+win32 + `((:WSAEADDRINUSE . address-in-use-error) + (:WSAEADDRNOTAVAIL . address-not-available-error) + (:WSAEBADF . bad-file-descriptor-error) + (:WSAECONNREFUSED . connection-refused-error) + (:WSAECONNRESET . connection-reset-error) + (:WSAECONNABORTED . connection-aborted-error) + (:WSAEINVAL . invalid-argument-error) + (:WSAENOBUFS . no-buffers-error) + (:WSAENOMEM . out-of-memory-error) + (:WSAENOTSUP . operation-not-supported-error) + (:WSAEPERM . operation-not-permitted-error) + (:WSAEPROTONOSUPPORT . protocol-not-supported-error) + (:WSAESOCKTNOSUPPORT . socket-type-not-supported-error) + (:WSAENETUNREACH . network-unreachable-error) + (:WSAENETDOWN . network-down-error) + (:WSAENETRESET . network-reset-error) + (:WSAESHUTDOWN . already-shutdown-error) + (:WSAETIMEDOUT . timeout-error) + (:WSAEHOSTDOWN . host-down-error) + (:WSAEHOSTUNREACH . host-unreachable-error))) (defun handle-condition (condition &optional (socket nil)) "Dispatch correct usocket condition." - (typecase condition - (system::simple-os-error - (let ((usock-err - (cdr (assoc (car (simple-condition-format-arguments condition)) - +clisp-error-map+ :test #'member)))) - (when usock-err ;; don't claim the error if we don't know - ;; it's actually a socket error ... - (if (subtypep usock-err 'error) - (error usock-err :socket socket) - (signal usock-err :socket socket))))))) + (let (error-keyword error-string) + (typecase condition + (system::simple-os-error + (let ((errno (car (simple-condition-format-arguments condition)))) + (setq error-keyword (os:errno errno) + error-string (os:strerror errno)))) + (simple-error + (let ((keyword + (car (simple-condition-format-arguments condition)))) + (setq error-keyword keyword + error-string (os:strerror keyword)))) + (error (error 'unknown-error :real-error condition)) + (condition (signal 'unknown-condition :real-condition condition))) + (when error-keyword + (let ((usocket-error + (cdr (assoc error-keyword +clisp-error-map+ :test #'eq)))) + (if usocket-error + (if (subtypep usocket-error 'error) + (error usocket-error :socket socket) + (signal usocket-error :socket socket)) + (error "Unknown OS error: ~A (~A)" error-string error-keyword)))))) (defun socket-connect (host port &key (protocol :stream) (element-type 'character) timeout deadline (nodelay t nodelay-specified) @@ -505,14 +544,19 @@ (rsock_addr (when remote-host (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in) remote-host (or remote-port local-port))))) + (unless (plusp sock) + (error "SOCKET-CREATE-DATAGRAM ERROR (socket): ~A" (os:errno))) (unwind-protect - (progn - (%bind sock (ffi:cast (ffi:foreign-value lsock_addr) 'sockaddr) - *length-of-sockaddr_in*) + (let ((rv (%bind sock (ffi:cast (ffi:foreign-value lsock_addr) 'sockaddr) + *length-of-sockaddr_in*))) + (unless (zerop rv) + (error "SOCKET-CREATE-DATAGRAM ERROR (bind): ~A" (os:errno))) (when rsock_addr - (%connect sock - (ffi:cast (ffi:foreign-value rsock_addr) 'sockaddr) - *length-of-sockaddr_in*))) + (let ((rv (%connect sock + (ffi:cast (ffi:foreign-value rsock_addr) 'sockaddr) + *length-of-sockaddr_in*))) + (unless (zerop rv) + (error "SOCKET-CREATE-DATAGRAM ERROR (connect): ~A" (os:errno)))))) (ffi:foreign-free lsock_addr) (when remote-host (ffi:foreign-free rsock_addr))) @@ -549,6 +593,8 @@ 0 ; flags (ffi:cast (ffi:foreign-value remote-address) 'sockaddr) (ffi:foreign-value remote-address-length)) + (when (minusp n) + (error "SOCKET-RECEIVE ERROR: ~A" (os:errno))) (setq nbytes n) (when (= address-length *length-of-sockaddr_in*) (let ((data (sockaddr-sa_data address))) @@ -561,8 +607,7 @@ (end-2 (min n +max-datagram-packet-size+))) (replace buffer return-buffer :end1 end-1 :end2 end-2)) (setq buffer (subseq return-buffer 0 (min n +max-datagram-packet-size+)))))) - ((zerop n)) ; do nothing - (t))) ; TODO: handle error here. + ((zerop n)))) (ffi:foreign-free remote-address) (ffi:foreign-free remote-address-length)) (values buffer nbytes host port))) @@ -583,23 +628,25 @@ (ffi:allocate-deep 'ffi:uint8 (subseq buffer 0 length) :count length :read-only t) ;; then we allocate the whole buffer directly, that should be faster. (ffi:allocate-deep 'ffi:uint8 buffer :count (length buffer) :read-only t)))) - nbytes) + (real-length (min length +max-datagram-packet-size+)) + (nbytes 0)) (unwind-protect (let ((n (if remote-address (%sendto (socket usocket) (ffi:foreign-address send-buffer) - (min length +max-datagram-packet-size+) 0 + real-length + 0 ; flags (ffi:cast (ffi:foreign-value remote-address) 'sockaddr) *length-of-sockaddr_in*) (%send (socket usocket) - ;; (ffi:cast (ffi:foreign-value send-buffer) 'ffi:c-pointer) (ffi:foreign-address send-buffer) - (min length +max-datagram-packet-size+) 0)))) + real-length + 0)))) (cond ((plusp n) (setq nbytes n)) ((zerop n) (setq nbytes n)) - (t))) ; TODO: error handling + (t (error "SOCKET-SEND ERROR: ~A" (os:errno))))) (ffi:foreign-free send-buffer) (when remote-address (ffi:foreign-free remote-address)) @@ -621,7 +668,7 @@ (let ((data (sockaddr-sa_data return-address))) (setq host (ip-from-octet-buffer data :start 2) port (port-from-octet-buffer data))) - (error "get-socket-name error"))) ; TODO: convert this + (error "GET-SOCKET-NAME ERROR: ~A" (os:errno)))) (ffi:foreign-free address) (ffi:foreign-free address-length)) (values (hbo-to-vector-quad host) port))) From ctian at common-lisp.net Fri Apr 1 10:51:57 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 06:51:57 -0400 Subject: [usocket-cvs] r631 - usocket/branches/0.5.x/backend Message-ID: Author: ctian Date: Fri Apr 1 06:51:57 2011 New Revision: 631 Log: [CLISP, LW] Use IP_PROTO_UCP when doing socket() system call. Modified: usocket/branches/0.5.x/backend/clisp.lisp usocket/branches/0.5.x/backend/lispworks.lisp Modified: usocket/branches/0.5.x/backend/clisp.lisp ============================================================================== --- usocket/branches/0.5.x/backend/clisp.lisp (original) +++ usocket/branches/0.5.x/backend/clisp.lisp Fri Apr 1 06:51:57 2011 @@ -520,6 +520,8 @@ ;; socket constants (defconstant +socket-af-inet+ 2) (defconstant +socket-sock-dgram+ 2) + (defconstant +socket-ip-proto-udp+ 17) + (defconstant +sockopt-so-rcvtimeo+ #-linux #x1006 #+linux 20 "Socket receive timeout") (defvar *length-of-sockaddr_in* (ffi:sizeof 'sockaddr_in)) @@ -538,7 +540,7 @@ &key (local-host *wildcard-host*) remote-host remote-port) - (let ((sock (%socket +socket-af-inet+ +socket-sock-dgram+ 0)) + (let ((sock (%socket +socket-af-inet+ +socket-sock-dgram+ +socket-ip-proto-udp+)) (lsock_addr (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in) local-host local-port)) (rsock_addr (when remote-host Modified: usocket/branches/0.5.x/backend/lispworks.lisp ============================================================================== --- usocket/branches/0.5.x/backend/lispworks.lisp (original) +++ usocket/branches/0.5.x/backend/lispworks.lisp Fri Apr 1 06:51:57 2011 @@ -81,6 +81,8 @@ (defconstant *socket_sock_dgram* 2 "Connectionless, unreliable datagrams of fixed maximum length.") +(defconstant *socket_ip_proto_udp* 17) + (defconstant *sockopt_so_rcvtimeo* #-linux #x1006 #+linux 20 @@ -186,7 +188,7 @@ "Open a unconnected UDP socket. For binding on address ANY(*), just not set LOCAL-ADDRESS (NIL), for binding on random free unused port, set LOCAL-PORT to 0." - (let ((socket-fd (comm::socket comm::*socket_af_inet* *socket_sock_dgram* comm::*socket_pf_unspec*))) + (let ((socket-fd (comm::socket comm::*socket_af_inet* *socket_sock_dgram* *socket_ip_proto_udp*))) (if socket-fd (progn (when read-timeout (set-socket-receive-timeout socket-fd read-timeout)) From ctian at common-lisp.net Fri Apr 1 11:54:03 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 07:54:03 -0400 Subject: [usocket-cvs] r632 - usocket/branches/0.5.x/backend Message-ID: Author: ctian Date: Fri Apr 1 07:54:02 2011 New Revision: 632 Log: [CLISP] Serious FFI fixes for Linux, confirmed by CL-NET-SNMP. Modified: usocket/branches/0.5.x/backend/clisp.lisp Modified: usocket/branches/0.5.x/backend/clisp.lisp ============================================================================== --- usocket/branches/0.5.x/backend/clisp.lisp (original) +++ usocket/branches/0.5.x/backend/clisp.lisp Fri Apr 1 07:54:02 2011 @@ -342,23 +342,22 @@ #+(and ffi (not rawsock)) (progn ;; C primitive types - (ffi:def-c-type size_t) - (ffi:def-c-type in_addr_t ffi:uint32) - (ffi:def-c-type in_port_t ffi:uint16) - (ffi:def-c-type sa_family_t ffi:uint8) - (ffi:def-c-type socklen_t ffi:uint32) + (ffi:def-c-type socklen_t ffi:uint32) ;; C structures (ffi:def-c-struct sockaddr - (sa_len ffi:uint8) - (sa_family sa_family_t) + #+macos (sa_len ffi:uint8) + (sa_family #-macos ffi:ushort + #+macos ffi:uint8) (sa_data (ffi:c-array ffi:char 14))) (ffi:def-c-struct sockaddr_in - (sin_len ffi:uint8) - (sin_family sa_family_t) - (sin_port in_port_t) - (sin_addr in_addr_t) ; should be struct in_addr + #+macos (sin_len ffi:uint8) + (sin_family #-macos ffi:short + #+macos ffi:uint8) + (sin_port #-macos ffi:ushort + #+macos ffi:uint16) + (sin_addr ffi:uint32) (sin_zero (ffi:c-array ffi:char 8))) (ffi:def-c-struct timeval @@ -524,14 +523,15 @@ (defconstant +sockopt-so-rcvtimeo+ #-linux #x1006 #+linux 20 "Socket receive timeout") - (defvar *length-of-sockaddr_in* (ffi:sizeof 'sockaddr_in)) + (defparameter *length-of-sockaddr_in* (ffi:sizeof 'sockaddr_in)) (declaim (inline fill-sockaddr_in)) (defun fill-sockaddr_in (sockaddr host port) (let ((hbo (host-to-hbo host))) (ffi:with-c-place (place sockaddr) - (setf (ffi:slot place 'sin_len) *length-of-sockaddr_in* - (ffi:slot place 'sin_family) +socket-af-inet+ + #+macos + (setf (ffi:slot place 'sin_len) *length-of-sockaddr_in*) + (setf (ffi:slot place 'sin_family) +socket-af-inet+ (ffi:slot place 'sin_port) (%htons port) (ffi:slot place 'sin_addr) (%htonl hbo))) sockaddr)) From ctian at common-lisp.net Fri Apr 1 12:06:28 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 08:06:28 -0400 Subject: [usocket-cvs] r633 - usocket/branches/0.5.x Message-ID: Author: ctian Date: Fri Apr 1 08:06:23 2011 New Revision: 633 Log: Update ChangeLog, prepare for 0.5.1 release Modified: usocket/branches/0.5.x/CHANGES usocket/branches/0.5.x/README usocket/branches/0.5.x/usocket-test.asd usocket/branches/0.5.x/usocket.asd Modified: usocket/branches/0.5.x/CHANGES ============================================================================== --- usocket/branches/0.5.x/CHANGES (original) +++ usocket/branches/0.5.x/CHANGES Fri Apr 1 08:06:23 2011 @@ -8,16 +8,17 @@ 0.5.1: -* New feature: [CLISP] add UDP (Datagram) support based on FFI, no RAWSOCK needed. +* New feature: [CLISP] UDP (Datagram) support based on FFI (Win/Mac/Linux), no RAWSOCK needed. * Enhancement: SOCKET-SERVER return a second value (socket) when calling in new-thread mode. * Enhancement: [CLISP] Full support of DNS helper functions (GET-HOST-BY-NAME, ...) added. -* Bugfix: Fixed wrong macro expansions of {IP|PORT}-{FROM|TO}-OCTET-BUFFER functions! +* Enhancement: [CLISP] Better network error type detection based on OS error code. +* Enhancement: [LispWorks] Better network error type detection based on OS error code. +* Bugfix: Fixed wrong macro expansions of {IP|PORT}-{FROM|TO}-OCTET-BUFFER functions (since 0.4.0) * Bugfix: SOCKET-CONNECT didn't set CONNECTED-P for datagram usockets on most backends. * Bugfix: [SBCL] Fixes for "SBCL/Win32: finalizer problem, etc", by Anton Kovalenko * Bugfix: [SBCL] Fixed SOCKET-SERVER (UDP) on SBCL due to a issue in SOCKET-CONNECT when HOST is NIL. * Bugfix: [SBCL] SOCKET-CONNECT's TIMEOUT argument now works as a "connection timeout". * Bugfix: [CMUCL] Fixed SOCKET-SEND on unconnected usockets under Unicode version of CMUCL. -* Bugfix: [LispWorks] Better network error type detection on LispWorks. * Bugfix: [CLISP] Fixed and confirmed UDP (Datagram) support (RAWSOCK version). [TODO] Modified: usocket/branches/0.5.x/README ============================================================================== --- usocket/branches/0.5.x/README (original) +++ usocket/branches/0.5.x/README Fri Apr 1 08:06:23 2011 @@ -1,6 +1,5 @@ - -*- text -*- - -$Id$ +;;;; -*- Mode: Text -*- +;;;; $Id$ Content ======= @@ -164,14 +163,3 @@ reuse the FFI code on all platforms (including Windows). This benefit currently outweighs the additional requirement. (hey, it's *Embeddable* Common Lisp, so, you probably wanted to embed it all along, right?) - -- LispWorks has a bug(?) in wait-for-input-streams which make it - unsuited for waiting for input on stream socket servers, making it - necessary to resort to different means. With the absence of notice-fd - on Windows, that currenty leaves Windows unsupported. - -- SBCL can't use select() on Windows because it would mean porting - the FD_* macros and the select structures which I'm not sure - is the right way yet (if I need to write custom Win32 code anyway...) - The alternative is to use WSAEventSelect() and friends (which don't - have a limited number of sockets). Modified: usocket/branches/0.5.x/usocket-test.asd ============================================================================== --- usocket/branches/0.5.x/usocket-test.asd (original) +++ usocket/branches/0.5.x/usocket-test.asd Fri Apr 1 08:06:23 2011 @@ -15,7 +15,8 @@ (defsystem usocket-test :name "usocket test" :author "Erik Enge" - :version "0.1.0" + :maintainer "Chun Tian (binghe)" + :version "0.2.0" :licence "MIT" :description "Tests for usocket" :depends-on (:usocket Modified: usocket/branches/0.5.x/usocket.asd ============================================================================== --- usocket/branches/0.5.x/usocket.asd (original) +++ usocket/branches/0.5.x/usocket.asd Fri Apr 1 08:06:23 2011 @@ -14,6 +14,7 @@ (defsystem usocket :name "usocket" :author "Erik Enge & Erik Huelsmann" + :maintainer "Chun Tian (binghe)" :version "0.5.1" :licence "MIT" :description "Universal socket library for Common Lisp" From ctian at common-lisp.net Fri Apr 1 12:41:51 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 08:41:51 -0400 Subject: [usocket-cvs] r634 - usocket/branches/0.5.x/backend Message-ID: Author: ctian Date: Fri Apr 1 08:41:51 2011 New Revision: 634 Log: [CCL] Clozure CL doesn't understand VALUES declaration ... Modified: usocket/branches/0.5.x/backend/openmcl.lisp Modified: usocket/branches/0.5.x/backend/openmcl.lisp ============================================================================== --- usocket/branches/0.5.x/backend/openmcl.lisp (original) +++ usocket/branches/0.5.x/backend/openmcl.lisp Fri Apr 1 08:41:51 2011 @@ -157,10 +157,6 @@ (ccl::send-for-usocket (socket usocket) buffer length)))) (defmethod socket-receive ((usocket datagram-usocket) buffer length &key) - (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer - (integer 0) ; size - (unsigned-byte 32) ; host - (unsigned-byte 16))) ; port (with-mapped-conditions (usocket) (openmcl-socket:receive-from (socket usocket) length :buffer buffer))) From ctian at common-lisp.net Fri Apr 1 16:52:19 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 12:52:19 -0400 Subject: [usocket-cvs] r635 - in usocket/trunk: . backend test Message-ID: Author: ctian Date: Fri Apr 1 12:52:18 2011 New Revision: 635 Log: Merge all changes from branch 0.5.x (r616-r634) before tagging the 0.5.1 Modified: usocket/trunk/CHANGES usocket/trunk/README usocket/trunk/backend/abcl.lisp usocket/trunk/backend/allegro.lisp usocket/trunk/backend/clisp.lisp usocket/trunk/backend/cmucl.lisp usocket/trunk/backend/lispworks.lisp usocket/trunk/backend/sbcl.lisp usocket/trunk/backend/scl.lisp usocket/trunk/test/test-usocket.lisp usocket/trunk/usocket-test.asd usocket/trunk/usocket.lisp Modified: usocket/trunk/CHANGES ============================================================================== --- usocket/trunk/CHANGES (original) +++ usocket/trunk/CHANGES Fri Apr 1 12:52:18 2011 @@ -8,20 +8,21 @@ 0.5.1: -* Bugfix: Fixed wrong macro expansions of {IP|PORT}-{FROM|TO}-OCTET-BUFFER functions! +* New feature: [CLISP] UDP (Datagram) support based on FFI (Win/Mac/Linux), no RAWSOCK needed. +* Enhancement: SOCKET-SERVER return a second value (socket) when calling in new-thread mode. +* Enhancement: [CLISP] Full support of DNS helper functions (GET-HOST-BY-NAME, ...) added. +* Enhancement: [CLISP] Better network error type detection based on OS error code. +* Enhancement: [LispWorks] Better network error type detection based on OS error code. +* Bugfix: Fixed wrong macro expansions of {IP|PORT}-{FROM|TO}-OCTET-BUFFER functions (since 0.4.0) * Bugfix: SOCKET-CONNECT didn't set CONNECTED-P for datagram usockets on most backends. * Bugfix: [SBCL] Fixes for "SBCL/Win32: finalizer problem, etc", by Anton Kovalenko * Bugfix: [SBCL] Fixed SOCKET-SERVER (UDP) on SBCL due to a issue in SOCKET-CONNECT when HOST is NIL. * Bugfix: [SBCL] SOCKET-CONNECT's TIMEOUT argument now works as a "connection timeout". * Bugfix: [CMUCL] Fixed SOCKET-SEND on unconnected usockets under Unicode version of CMUCL. -* Bugfix: [LispWorks] Better network error type detection on LispWorks. -* Bugfix: [CLISP] Fixed UDP (Datagram) support (RAWSOCK version), confirmed by CL-NET-SNMP. -* Enhancement: SOCKET-SERVER return a second value (socket) when calling in new-thread mode. -* Enhancement: [CLISP] Full support of DNS helper functions (GET-HOST-BY-NAME, ...) added. +* Bugfix: [CLISP] Fixed and confirmed UDP (Datagram) support (RAWSOCK version). [TODO] -* New feature: CLISP support UDP without RAWSOCK (using FFI interface) * New feature: CLISP support some advanced TCP features which CLISP's SOCKET interface not provide * New feature: Macintosh Common Lisp (MCL) support Datagram sockets (UDP) Modified: usocket/trunk/README ============================================================================== --- usocket/trunk/README (original) +++ usocket/trunk/README Fri Apr 1 12:52:18 2011 @@ -1,6 +1,5 @@ - -*- text -*- - -$Id$ +;;;; -*- Mode: Text -*- +;;;; $Id$ Content ======= @@ -164,14 +163,3 @@ reuse the FFI code on all platforms (including Windows). This benefit currently outweighs the additional requirement. (hey, it's *Embeddable* Common Lisp, so, you probably wanted to embed it all along, right?) - -- LispWorks has a bug(?) in wait-for-input-streams which make it - unsuited for waiting for input on stream socket servers, making it - necessary to resort to different means. With the absence of notice-fd - on Windows, that currenty leaves Windows unsupported. - -- SBCL can't use select() on Windows because it would mean porting - the FD_* macros and the select structures which I'm not sure - is the right way yet (if I need to write custom Win32 code anyway...) - The alternative is to use WSAEventSelect() and friends (which don't - have a limited number of sockets). Modified: usocket/trunk/backend/abcl.lisp ============================================================================== --- usocket/trunk/backend/abcl.lisp (original) +++ usocket/trunk/backend/abcl.lisp Fri Apr 1 12:52:18 2011 @@ -343,6 +343,10 @@ ;;; TODO: return-host and return-port cannot be get ... (defmethod socket-receive ((usocket datagram-usocket) buffer length &key (element-type '(unsigned-byte 8))) + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16))) ; port (let* ((socket (socket usocket)) (real-length (or length +max-datagram-packet-size+)) (byte-array (jnew-array $*byte real-length)) Modified: usocket/trunk/backend/allegro.lisp ============================================================================== --- usocket/trunk/backend/allegro.lisp (original) +++ usocket/trunk/backend/allegro.lisp Fri Apr 1 12:52:18 2011 @@ -155,6 +155,10 @@ (socket:send-to s buffer length :remote-host host :remote-port port)))) (defmethod socket-receive ((socket datagram-usocket) buffer length &key) + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16))) ; port (with-mapped-conditions (socket) (let ((s (socket socket))) (socket:receive-from s length :buffer buffer :extract t)))) Modified: usocket/trunk/backend/clisp.lisp ============================================================================== --- usocket/trunk/backend/clisp.lisp (original) +++ usocket/trunk/backend/clisp.lisp Fri Apr 1 12:52:18 2011 @@ -44,40 +44,80 @@ (mapcar #'host-to-vector-quad (posix:hostent-addr-list hostent))))) -#+win32 -(defun remap-maybe-for-win32 (z) - (mapcar #'(lambda (x) - (cons (mapcar #'(lambda (y) - (+ 10000 y)) - (car x)) - (cdr x))) - z)) - +;; Format: ((UNIX Windows) . CONDITION) (defparameter +clisp-error-map+ - #+win32 - (append (remap-maybe-for-win32 +unix-errno-condition-map+) - (remap-maybe-for-win32 +unix-errno-error-map+)) #-win32 - (append +unix-errno-condition-map+ - +unix-errno-error-map+)) + `((:EADDRINUSE . address-in-use-error) + (:EADDRNOTAVAIL . address-not-available-error) + (:EBADF . bad-file-descriptor-error) + (:ECONNREFUSED . connection-refused-error) + (:ECONNRESET . connection-reset-error) + (:ECONNABORTED . connection-aborted-error) + (:EINVAL . invalid-argument-error) + (:ENOBUFS . no-buffers-error) + (:ENOMEM . out-of-memory-error) + (:ENOTSUP . operation-not-supported-error) + (:EPERM . operation-not-permitted-error) + (:EPROTONOSUPPORT . protocol-not-supported-error) + (:ESOCKTNOSUPPORT . socket-type-not-supported-error) + (:ENETUNREACH . network-unreachable-error) + (:ENETDOWN . network-down-error) + (:ENETRESET . network-reset-error) + (:ESHUTDOWN . already-shutdown-error) + (:ETIMEDOUT . timeout-error) + (:EHOSTDOWN . host-down-error) + (:EHOSTUNREACH . host-unreachable-error)) + #+win32 + `((:WSAEADDRINUSE . address-in-use-error) + (:WSAEADDRNOTAVAIL . address-not-available-error) + (:WSAEBADF . bad-file-descriptor-error) + (:WSAECONNREFUSED . connection-refused-error) + (:WSAECONNRESET . connection-reset-error) + (:WSAECONNABORTED . connection-aborted-error) + (:WSAEINVAL . invalid-argument-error) + (:WSAENOBUFS . no-buffers-error) + (:WSAENOMEM . out-of-memory-error) + (:WSAENOTSUP . operation-not-supported-error) + (:WSAEPERM . operation-not-permitted-error) + (:WSAEPROTONOSUPPORT . protocol-not-supported-error) + (:WSAESOCKTNOSUPPORT . socket-type-not-supported-error) + (:WSAENETUNREACH . network-unreachable-error) + (:WSAENETDOWN . network-down-error) + (:WSAENETRESET . network-reset-error) + (:WSAESHUTDOWN . already-shutdown-error) + (:WSAETIMEDOUT . timeout-error) + (:WSAEHOSTDOWN . host-down-error) + (:WSAEHOSTUNREACH . host-unreachable-error))) (defun handle-condition (condition &optional (socket nil)) "Dispatch correct usocket condition." - (typecase condition - (system::simple-os-error - (let ((usock-err - (cdr (assoc (car (simple-condition-format-arguments condition)) - +clisp-error-map+ :test #'member)))) - (when usock-err ;; don't claim the error if we don't know - ;; it's actually a socket error ... - (if (subtypep usock-err 'error) - (error usock-err :socket socket) - (signal usock-err :socket socket))))))) + (let (error-keyword error-string) + (typecase condition + (system::simple-os-error + (let ((errno (car (simple-condition-format-arguments condition)))) + (setq error-keyword (os:errno errno) + error-string (os:strerror errno)))) + (simple-error + (let ((keyword + (car (simple-condition-format-arguments condition)))) + (setq error-keyword keyword + error-string (os:strerror keyword)))) + (error (error 'unknown-error :real-error condition)) + (condition (signal 'unknown-condition :real-condition condition))) + (when error-keyword + (let ((usocket-error + (cdr (assoc error-keyword +clisp-error-map+ :test #'eq)))) + (if usocket-error + (if (subtypep usocket-error 'error) + (error usocket-error :socket socket) + (signal usocket-error :socket socket)) + (error "Unknown OS error: ~A (~A)" error-string error-keyword)))))) (defun socket-connect (host port &key (protocol :stream) (element-type 'character) timeout deadline (nodelay t nodelay-specified) local-host local-port) - (declare (ignore nodelay)) + (declare (ignore nodelay) + (ignorable timeout local-host local-port)) (when deadline (unsupported 'deadline 'socket-connect)) (when nodelay-specified (unsupported 'nodelay 'socket-connect)) (case protocol @@ -97,13 +137,11 @@ (make-stream-socket :socket socket :stream socket))) ;; the socket is a stream too (:datagram - #+rawsock + #+(or rawsock ffi) (socket-create-datagram (or local-port *auto-port*) :local-host (or local-host *wildcard-host*) - :remote-host host + :remote-host (and host (host-to-vector-quad host)) :remote-port port) - #+(and ffi (not rawsock)) - () #-(or rawsock ffi) (unsupported '(protocol :datagram) 'socket-connect)))) @@ -147,7 +185,7 @@ (remove-waiter (wait-list usocket) usocket)) (socket:socket-server-close (socket usocket))) -(defmethod get-local-name ((usocket usocket)) +(defmethod get-local-name ((usocket stream-usocket)) (multiple-value-bind (address port) (socket:socket-stream-local (socket usocket) t) @@ -162,13 +200,13 @@ (defmethod get-local-address ((usocket usocket)) (nth-value 0 (get-local-name usocket))) -(defmethod get-peer-address ((usocket stream-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 stream-usocket)) +(defmethod get-peer-port ((usocket usocket)) (nth-value 1 (get-peer-name usocket))) (defun %setup-wait-list (wait-list) @@ -235,17 +273,22 @@ "Returns the buffer, the number of octets copied into the buffer (received) and the address of the sender as values." (let* ((sock (socket socket)) - (sockaddr (unless (connected-p socket) - (rawsock:make-sockaddr :inet))) - (rv (if sockaddr - (rawsock:recvfrom sock buffer sockaddr :start 0 :end length) - (rawsock:recv sock buffer :start 0 :end length))) - (host 0) (port 0)) - (unless (connected-p socket) - (let ((data (rawsock:sockaddr-data sockaddr))) - (setq host (ip-from-octet-buffer data :start 4) - port (port-from-octet-buffer data :start 2)))) - (values buffer rv host port))) + (sockaddr (rawsock:make-sockaddr :inet)) + (real-length (or length +max-datagram-packet-size+)) + (real-buffer (or buffer + (make-array real-length + :element-type '(unsigned-byte 8))))) + (let ((rv (rawsock:recvfrom sock real-buffer sockaddr + :start 0 :end real-length)) + (host 0) (port 0)) + (unless (connected-p socket) + (let ((data (rawsock:sockaddr-data sockaddr))) + (setq host (ip-from-octet-buffer data :start 4) + port (port-from-octet-buffer data :start 2)))) + (values (if buffer real-buffer (subseq real-buffer 0 rv)) + rv + host + port)))) (defmethod socket-send ((socket datagram-usocket) buffer length &key host port) "Returns the number of octets sent." @@ -256,19 +299,40 @@ (make-sockaddr_in) (host-byte-order host) port)))) + (real-length (or length (length buffer))) + (real-buffer (if (typep buffer '(simple-array (unsigned-byte 8) (*))) + buffer + (make-array real-length + :element-type '(unsigned-byte 8) + :initial-contents (subseq buffer 0 real-length)))) (rv (if (and host port) - (rawsock:sendto sock buffer sockaddr + (rawsock:sendto sock real-buffer sockaddr :start 0 - :end length) - (rawsock:send sock buffer + :end real-length) + (rawsock:send sock real-buffer :start 0 - :end length)))) + :end real-length)))) rv)) (defmethod socket-close ((usocket datagram-usocket)) (when (wait-list usocket) (remove-waiter (wait-list usocket) usocket)) (rawsock:sock-close (socket usocket))) + + (declaim (inline get-socket-name)) + (defun get-socket-name (socket function) + (let ((sockaddr (rawsock:make-sockaddr :inet (make-sockaddr_in)))) + (funcall function socket sockaddr) + (let ((data (rawsock:sockaddr-data sockaddr))) + (values (hbo-to-vector-quad (ip-from-octet-buffer data :start 2)) + (port-from-octet-buffer data :start 0))))) + + (defmethod get-local-name ((usocket datagram-usocket)) + (get-socket-name (socket usocket) 'rawsock:getsockname)) + + (defmethod get-peer-name ((usocket datagram-usocket)) + (get-socket-name (socket usocket) 'rawsock:getpeername)) + ) ; progn ;;; @@ -278,27 +342,22 @@ #+(and ffi (not rawsock)) (progn ;; C primitive types - (ffi:def-c-type size_t) - (ffi:def-c-type in_addr_t ffi:uint32) - (ffi:def-c-type in_port_t ffi:uint16) - (ffi:def-c-type sa_family_t ffi:uint8) - (ffi:def-c-type socklen_t ffi:uint32) + (ffi:def-c-type socklen_t ffi:uint32) ;; C structures (ffi:def-c-struct sockaddr - (sa_len ffi:uint8) - (sa_family sa_family_t) + #+macos (sa_len ffi:uint8) + (sa_family #-macos ffi:ushort + #+macos ffi:uint8) (sa_data (ffi:c-array ffi:char 14))) - #+ignore - (ffi:def-c-struct in_addr - (s_addr in_addr_t)) - (ffi:def-c-struct sockaddr_in - (sin_len ffi:uint8) - (sin_family sa_family_t) - (sin_port in_port_t) - (sin_addr in_addr_t) ; should be struct in_addr + #+macos (sin_len ffi:uint8) + (sin_family #-macos ffi:short + #+macos ffi:uint8) + (sin_port #-macos ffi:ushort + #+macos ffi:uint16) + (sin_addr ffi:uint32) (sin_zero (ffi:c-array ffi:char 8))) (ffi:def-c-struct timeval @@ -308,7 +367,7 @@ ;; foreign functions (ffi:def-call-out %sendto (:name "sendto") (:arguments (socket ffi:int) - (buffer (ffi:c-ptr ffi:uint8)) + (buffer ffi:c-pointer) (length ffi:int) (flags ffi:int) (address (ffi:c-ptr sockaddr)) @@ -319,13 +378,24 @@ #+win32 :stdc-stdcall) (:return-type ffi:int)) + (ffi:def-call-out %send (:name "send") + (:arguments (socket ffi:int) + (buffer ffi:c-pointer) + (length ffi:int) + (flags ffi:int)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + (ffi:def-call-out %recvfrom (:name "recvfrom") (:arguments (socket ffi:int) - (buffer (ffi:c-ptr ffi:uint8) :out) + (buffer ffi:c-pointer) (length ffi:int) (flags ffi:int) - (address (ffi:c-ptr sockaddr) :out) - (address-len (ffi:c-ptr ffi:int) :out)) + (address (ffi:c-ptr sockaddr) :in-out) + (address-len (ffi:c-ptr ffi:int) :in-out)) #+win32 (:library "WS2_32") #-win32 (:library :default) (:language #-win32 :stdc @@ -342,6 +412,34 @@ #+win32 :stdc-stdcall) (:return-type ffi:int)) + (ffi:def-call-out %connect (:name "connect") + (:arguments (socket ffi:int) + (address (ffi:c-ptr sockaddr) :in) + (address_len socklen_t)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %bind (:name "bind") + (:arguments (socket ffi:int) + (address (ffi:c-ptr sockaddr) :in) + (address_len socklen_t)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %close (:name #-win32 "close" #+win32 "closesocket") + (:arguments (socket ffi:int)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + (ffi:def-call-out %getsockopt (:name "getsockopt") (:arguments (sockfd ffi:int) (level ffi:int) @@ -366,18 +464,221 @@ #+win32 :stdc-stdcall) (:return-type ffi:int)) + (ffi:def-call-out %htonl (:name "htonl") + (:arguments (hostlong ffi:uint32)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:uint32)) + + (ffi:def-call-out %htons (:name "htons") + (:arguments (hostshort ffi:uint16)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:uint16)) + + (ffi:def-call-out %ntohl (:name "ntohl") + (:arguments (netlong ffi:uint32)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:uint32)) + + (ffi:def-call-out %ntohs (:name "ntohs") + (:arguments (netshort ffi:uint16)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:uint16)) + + (ffi:def-call-out %getsockname (:name "getsockname") + (:arguments (sockfd ffi:int) + (localaddr (ffi:c-ptr sockaddr) :in-out) + (addrlen (ffi:c-ptr socklen_t) :in-out)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %getpeername (:name "getpeername") + (:arguments (sockfd ffi:int) + (peeraddr (ffi:c-ptr sockaddr) :in-out) + (addrlen (ffi:c-ptr socklen_t) :in-out)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + ;; socket constants (defconstant +socket-af-inet+ 2) - (defconstant +socket-pf-unspec+ 0) (defconstant +socket-sock-dgram+ 2) + (defconstant +socket-ip-proto-udp+ 17) + (defconstant +sockopt-so-rcvtimeo+ #-linux #x1006 #+linux 20 "Socket receive timeout") - (defun open-udp-socket (&key local-address local-port read-timeout) - "Open a unconnected UDP socket. For binding on address ANY(*), just not set LOCAL-ADDRESS (NIL), -for binding on random free unused port, set LOCAL-PORT to 0." - (let ((socket-fd (%socket +socket-af-inet+ +socket-sock-dgram+ +socket-pf-unspec+))) - (if socket-fd - (progn - ) - (error "cannot create socket")))) + (defparameter *length-of-sockaddr_in* (ffi:sizeof 'sockaddr_in)) + + (declaim (inline fill-sockaddr_in)) + (defun fill-sockaddr_in (sockaddr host port) + (let ((hbo (host-to-hbo host))) + (ffi:with-c-place (place sockaddr) + #+macos + (setf (ffi:slot place 'sin_len) *length-of-sockaddr_in*) + (setf (ffi:slot place 'sin_family) +socket-af-inet+ + (ffi:slot place 'sin_port) (%htons port) + (ffi:slot place 'sin_addr) (%htonl hbo))) + sockaddr)) + + (defun socket-create-datagram (local-port + &key (local-host *wildcard-host*) + remote-host + remote-port) + (let ((sock (%socket +socket-af-inet+ +socket-sock-dgram+ +socket-ip-proto-udp+)) + (lsock_addr (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in) + local-host local-port)) + (rsock_addr (when remote-host + (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in) + remote-host (or remote-port local-port))))) + (unless (plusp sock) + (error "SOCKET-CREATE-DATAGRAM ERROR (socket): ~A" (os:errno))) + (unwind-protect + (let ((rv (%bind sock (ffi:cast (ffi:foreign-value lsock_addr) 'sockaddr) + *length-of-sockaddr_in*))) + (unless (zerop rv) + (error "SOCKET-CREATE-DATAGRAM ERROR (bind): ~A" (os:errno))) + (when rsock_addr + (let ((rv (%connect sock + (ffi:cast (ffi:foreign-value rsock_addr) 'sockaddr) + *length-of-sockaddr_in*))) + (unless (zerop rv) + (error "SOCKET-CREATE-DATAGRAM ERROR (connect): ~A" (os:errno)))))) + (ffi:foreign-free lsock_addr) + (when remote-host + (ffi:foreign-free rsock_addr))) + (make-datagram-socket sock :connected-p (if rsock_addr t nil)))) + + (defun finalize-datagram-usocket (object) + (when (datagram-usocket-p object) + (socket-close object))) + + (defmethod initialize-instance :after ((usocket datagram-usocket) &key) + (setf (slot-value usocket 'recv-buffer) + (ffi:allocate-shallow 'ffi:uint8 :count +max-datagram-packet-size+)) + ;; finalize the object + (ext:finalize usocket 'finalize-datagram-usocket)) + + (defmethod socket-close ((usocket datagram-usocket)) + (when (wait-list usocket) + (remove-waiter (wait-list usocket) usocket)) + (with-slots (recv-buffer socket) usocket + (ffi:foreign-free recv-buffer) + (zerop (%close socket)))) + + (defmethod socket-receive ((usocket datagram-usocket) buffer length &key) + (let ((remote-address (ffi:allocate-shallow 'sockaddr_in)) + (remote-address-length (ffi:allocate-shallow 'ffi:int)) + nbytes (host 0) (port 0)) + (setf (ffi:foreign-value remote-address-length) + *length-of-sockaddr_in*) + (unwind-protect + (multiple-value-bind (n address address-length) + (%recvfrom (socket usocket) + (ffi:foreign-address (slot-value usocket 'recv-buffer)) + +max-datagram-packet-size+ + 0 ; flags + (ffi:cast (ffi:foreign-value remote-address) 'sockaddr) + (ffi:foreign-value remote-address-length)) + (when (minusp n) + (error "SOCKET-RECEIVE ERROR: ~A" (os:errno))) + (setq nbytes n) + (when (= address-length *length-of-sockaddr_in*) + (let ((data (sockaddr-sa_data address))) + (setq host (ip-from-octet-buffer data :start 2) + port (port-from-octet-buffer data)))) + (cond ((plusp n) + (let ((return-buffer (ffi:foreign-value (slot-value usocket 'recv-buffer)))) + (if buffer ; replace exist buffer of create new return buffer + (let ((end-1 (min (or length (length buffer)) +max-datagram-packet-size+)) + (end-2 (min n +max-datagram-packet-size+))) + (replace buffer return-buffer :end1 end-1 :end2 end-2)) + (setq buffer (subseq return-buffer 0 (min n +max-datagram-packet-size+)))))) + ((zerop n)))) + (ffi:foreign-free remote-address) + (ffi:foreign-free remote-address-length)) + (values buffer nbytes host port))) + + ;; implementation note: different from socket-receive, we know how many bytes we want to send everytime, + ;; so, a send buffer will not needed, and if there is a buffer, it's hard to fill its content like those + ;; in LispWorks. So, we allocate new foreign buffer for holding data (unknown sequence subtype) every time. + ;; + ;; I don't know if anyone is watching my coding work, but I think this design is reasonable for CLISP. + (defmethod socket-send ((usocket datagram-usocket) buffer length &key host port) + (declare (type sequence buffer) + (type integer length)) + (let ((remote-address (when (and host port) + (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in) host port))) + (send-buffer (let ((buffer-length (length buffer))) + (if (> buffer-length (* length 2)) + ;; if buffer is too big, then we copy out a subseq and only allocate as need + (ffi:allocate-deep 'ffi:uint8 (subseq buffer 0 length) :count length :read-only t) + ;; then we allocate the whole buffer directly, that should be faster. + (ffi:allocate-deep 'ffi:uint8 buffer :count (length buffer) :read-only t)))) + (real-length (min length +max-datagram-packet-size+)) + (nbytes 0)) + (unwind-protect + (let ((n (if remote-address + (%sendto (socket usocket) + (ffi:foreign-address send-buffer) + real-length + 0 ; flags + (ffi:cast (ffi:foreign-value remote-address) 'sockaddr) + *length-of-sockaddr_in*) + (%send (socket usocket) + (ffi:foreign-address send-buffer) + real-length + 0)))) + (cond ((plusp n) + (setq nbytes n)) + ((zerop n) + (setq nbytes n)) + (t (error "SOCKET-SEND ERROR: ~A" (os:errno))))) + (ffi:foreign-free send-buffer) + (when remote-address + (ffi:foreign-free remote-address)) + nbytes))) + + (declaim (inline get-socket-name)) + (defun get-socket-name (socket function) + (let ((address (ffi:allocate-shallow 'sockaddr_in)) + (address-length (ffi:allocate-shallow 'ffi:int)) + (host 0) (port 0)) + (setf (ffi:foreign-value address-length) *length-of-sockaddr_in*) + (unwind-protect + (multiple-value-bind (rv return-address return-address-length) + (funcall function socket + (ffi:cast (ffi:foreign-value address) 'sockaddr) + (ffi:foreign-value address-length)) + (declare (ignore return-address-length)) + (if (zerop rv) + (let ((data (sockaddr-sa_data return-address))) + (setq host (ip-from-octet-buffer data :start 2) + port (port-from-octet-buffer data))) + (error "GET-SOCKET-NAME ERROR: ~A" (os:errno)))) + (ffi:foreign-free address) + (ffi:foreign-free address-length)) + (values (hbo-to-vector-quad host) port))) + + (defmethod get-local-name ((usocket datagram-usocket)) + (get-socket-name (socket usocket) '%getsockname)) + + (defmethod get-peer-name ((usocket datagram-usocket)) + (get-socket-name (socket usocket) '%getpeername)) + ) ; progn Modified: usocket/trunk/backend/cmucl.lisp ============================================================================== --- usocket/trunk/backend/cmucl.lisp (original) +++ usocket/trunk/backend/cmucl.lisp Fri Apr 1 12:52:18 2011 @@ -183,6 +183,10 @@ (%unix-send (socket usocket) buffer length 0)))) (defmethod socket-receive ((usocket datagram-usocket) buffer length &key) + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16))) ; port (let ((real-buffer (or buffer (make-array length :element-type '(unsigned-byte 8)))) (real-length (or length @@ -190,8 +194,7 @@ (multiple-value-bind (nbytes remote-host remote-port) (with-mapped-conditions (usocket) (ext:inet-recvfrom (socket usocket) real-buffer real-length)) - (when (plusp nbytes) - (values real-buffer nbytes remote-host remote-port))))) + (values real-buffer nbytes remote-host remote-port)))) (defmethod get-local-name ((usocket usocket)) (multiple-value-bind @@ -269,17 +272,17 @@ (multiple-value-bind (secs musecs) (split-timeout (or timeout 1)) - (multiple-value-bind - (count err) - (unix:unix-fast-select (1+ (reduce #'max - (wait-list-%wait wait-list))) - (alien:addr rfds) nil nil - (when timeout secs) musecs) + (multiple-value-bind (count err) + (unix:unix-fast-select (1+ (reduce #'max + (wait-list-%wait wait-list))) + (alien:addr rfds) nil nil + (when timeout secs) musecs) + (declare (ignore err)) (if (<= 0 count) ;; process the result... (dolist (x (wait-list-waiters wait-list)) (when (unix:fd-isset (socket x) rfds) (setf (state x) :READ))) - (progn - ;;###FIXME generate an error, except for EINTR - ))))))) + (progn + ;;###FIXME generate an error, except for EINTR + ))))))) Modified: usocket/trunk/backend/lispworks.lisp ============================================================================== --- usocket/trunk/backend/lispworks.lisp (original) +++ usocket/trunk/backend/lispworks.lisp Fri Apr 1 12:52:18 2011 @@ -81,6 +81,8 @@ (defconstant *socket_sock_dgram* 2 "Connectionless, unreliable datagrams of fixed maximum length.") +(defconstant *socket_ip_proto_udp* 17) + (defconstant *sockopt_so_rcvtimeo* #-linux #x1006 #+linux 20 @@ -186,7 +188,7 @@ "Open a unconnected UDP socket. For binding on address ANY(*), just not set LOCAL-ADDRESS (NIL), for binding on random free unused port, set LOCAL-PORT to 0." - (let ((socket-fd (comm::socket comm::*socket_af_inet* *socket_sock_dgram* comm::*socket_pf_unspec*))) + (let ((socket-fd (comm::socket comm::*socket_af_inet* *socket_sock_dgram* *socket_ip_proto_udp*))) (if socket-fd (progn (when read-timeout (set-socket-receive-timeout socket-fd read-timeout)) @@ -358,15 +360,14 @@ :element-type '(unsigned-byte 8) :allocation :static))) +(defvar *length-of-sockaddr_in* + (fli:size-of '(:struct comm::sockaddr_in))) + (defun send-message (socket-fd message buffer &optional (length (length buffer)) host service) "Send message to a socket, using sendto()/send()" (declare (type integer socket-fd) (type sequence buffer)) - (fli:with-dynamic-foreign-objects ((client-addr (:struct comm::sockaddr_in)) - (len :int - #-(or lispworks4 lispworks5.0) ; <= 5.0 - :initial-element - (fli:size-of '(:struct comm::sockaddr_in)))) + (fli:with-dynamic-foreign-objects ((client-addr (:struct comm::sockaddr_in))) (fli:with-dynamic-lisp-array-pointer (ptr message :type '(:unsigned :byte)) (replace message buffer :end2 length) (if (and host service) @@ -374,7 +375,7 @@ (comm::initialize-sockaddr_in client-addr comm::*socket_af_inet* host service "udp") (%sendto socket-fd ptr (min length +max-datagram-packet-size+) 0 (fli:copy-pointer client-addr :type '(:struct comm::sockaddr)) - (fli:dereference len))) + *length-of-sockaddr_in*)) (comm::%send socket-fd ptr (min length +max-datagram-packet-size+) 0))))) (defmethod socket-send ((socket datagram-usocket) buffer length &key host port) @@ -397,8 +398,9 @@ (fli:with-dynamic-foreign-objects ((client-addr (:struct comm::sockaddr_in)) (len :int #-(or lispworks4 lispworks5.0) ; <= 5.0 - :initial-element - (fli:size-of '(:struct comm::sockaddr_in)))) + :initial-element *length-of-sockaddr_in*)) + #+(or lispworks4 lispworks5.0) ; <= 5.0 + (setf (fli:dereference len) *length-of-sockaddr_in*) (fli:with-dynamic-lisp-array-pointer (ptr message :type '(:unsigned :byte)) ;; setup new read timeout (when read-timeout @@ -433,6 +435,10 @@ (values nil n 0 0))))))) (defmethod socket-receive ((socket datagram-usocket) buffer length &key timeout) + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16))) ; port (multiple-value-bind (buffer size host port) (receive-message (socket socket) (slot-value socket 'recv-buffer) Modified: usocket/trunk/backend/sbcl.lisp ============================================================================== --- usocket/trunk/backend/sbcl.lisp (original) +++ usocket/trunk/backend/sbcl.lisp Fri Apr 1 12:52:18 2011 @@ -387,6 +387,10 @@ (defmethod socket-receive ((socket datagram-usocket) buffer length &key (element-type '(unsigned-byte 8))) + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16))) ; port (with-mapped-conditions (socket) (let ((s (socket socket))) (sb-bsd-sockets:socket-receive s buffer length :element-type element-type)))) Modified: usocket/trunk/backend/scl.lisp ============================================================================== --- usocket/trunk/backend/scl.lisp (original) +++ usocket/trunk/backend/scl.lisp Fri Apr 1 12:52:18 2011 @@ -145,6 +145,10 @@ (scl-map-socket-error errno :socket socket))))) (defmethod socket-receive ((socket datagram-usocket) buffer length &key) + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16))) ; port (let ((s (socket socket))) (let ((real-buffer (or buffer (make-array length :element-type '(unsigned-byte 8)))) Modified: usocket/trunk/test/test-usocket.lisp ============================================================================== --- usocket/trunk/test/test-usocket.lisp (original) +++ usocket/trunk/test/test-usocket.lisp Fri Apr 1 12:52:18 2011 @@ -118,13 +118,11 @@ (unwind-protect (progn (format (usocket:socket-stream sock) - "GET / HTTP/1.0~c~c~c~c" - #\Return #\linefeed #\Return #\linefeed) + "GET / HTTP/1.0~2%") (force-output (usocket:socket-stream sock)) - (read-line (usocket:socket-stream sock))) + (subseq (read-line (usocket:socket-stream sock)) 0 15)) (usocket:socket-close sock)))) - #+(or mcl clisp) "HTTP/1.1 200 OK" - #-(or mcl clisp) #.(format nil "HTTP/1.1 200 OK~A" #\Return) nil) + "HTTP/1.1 200 OK") (deftest socket-name.1 (with-caught-conditions (nil nil) @@ -188,14 +186,12 @@ (unwind-protect (progn (format (usocket:socket-stream sock) - "GET / HTTP/1.0~c~c~c~c" - #\Return #\linefeed #\Return #\linefeed) + "GET / HTTP/1.0~2%") (force-output (usocket:socket-stream sock)) (usocket:wait-for-input sock :timeout *wait-for-input-timeout*) - (read-line (usocket:socket-stream sock))) + (subseq (read-line (usocket:socket-stream sock)) 0 15)) (usocket:socket-close sock)))) - #+(or mcl clisp) "HTTP/1.1 200 OK" - #-(or mcl clisp) #.(format nil "HTTP/1.1 200 OK~A" #\Return) nil) + "HTTP/1.1 200 OK") (defun run-usocket-tests () (do-tests)) Modified: usocket/trunk/usocket-test.asd ============================================================================== --- usocket/trunk/usocket-test.asd (original) +++ usocket/trunk/usocket-test.asd Fri Apr 1 12:52:18 2011 @@ -16,7 +16,7 @@ :name "usocket test" :author "Erik Enge" :maintainer "Chun Tian (binghe)" - :version "0.1.0" + :version "0.2.0" :licence "MIT" :description "Tests for usocket" :depends-on (:usocket Modified: usocket/trunk/usocket.lisp ============================================================================== --- usocket/trunk/usocket.lisp (original) +++ usocket/trunk/usocket.lisp Fri Apr 1 12:52:18 2011 @@ -99,18 +99,20 @@ ((connected-p :type boolean :accessor connected-p :initarg :connected-p) - #+(or cmu scl lispworks) + #+(or cmu + scl + lispworks + (and clisp ffi (not rawsock))) (%open-p :type boolean :accessor %open-p :initform t :documentation "Flag to indicate if usocket is open, for GC on implementions operate on raw socket fd.") + #+(or lispworks + (and clisp ffi (not rawsock))) + (recv-buffer :documentation "Private RECV buffer.") #+lispworks - (recv-buffer - :documentation "Private RECV buffer.") - #+lispworks - (send-buffer - :documentation "Private SEND buffer.")) + (send-buffer :documentation "Private SEND buffer.")) (:documentation "UDP (inet-datagram) socket")) (defun usocket-p (socket) From ctian at common-lisp.net Fri Apr 1 16:55:57 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 12:55:57 -0400 Subject: [usocket-cvs] r636 - usocket/tags/0.5.1 Message-ID: Author: ctian Date: Fri Apr 1 12:55:57 2011 New Revision: 636 Log: Created tag 0.5.1. Added: usocket/tags/0.5.1/ - copied from r635, /usocket/branches/0.5.x/ From ctian at common-lisp.net Fri Apr 1 17:00:03 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 13:00:03 -0400 Subject: [usocket-cvs] r637 - public_html/releases Message-ID: Author: ctian Date: Fri Apr 1 13:00:01 2011 New Revision: 637 Log: usocket-0.5.1 source tarball Added: public_html/releases/usocket-0.5.1.tar.gz (contents, props changed) Added: public_html/releases/usocket-0.5.1.tar.gz ============================================================================== Binary file. No diff available. From ctian at common-lisp.net Fri Apr 1 17:01:34 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 13:01:34 -0400 Subject: [usocket-cvs] r638 - public_html/releases Message-ID: Author: ctian Date: Fri Apr 1 13:01:33 2011 New Revision: 638 Log: Add asc file and modify links Added: public_html/releases/usocket-0.5.1.tar.gz.asc Modified: public_html/releases/usocket-latest.tar.gz public_html/releases/usocket-latest.tar.gz.asc Added: public_html/releases/usocket-0.5.1.tar.gz.asc ============================================================================== --- (empty file) +++ public_html/releases/usocket-0.5.1.tar.gz.asc Fri Apr 1 13:01:33 2011 @@ -0,0 +1,7 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.11 (Darwin) + +iEYEABECAAYFAk2WBEQACgkQny6v4+l8uLD5WwCg38v7uAIFjxVE4yeA+nu0BbGJ +ic8AoJOGSyNPi7OwVPHPt02ALnHdWsx3 +=uppv +-----END PGP SIGNATURE----- Modified: public_html/releases/usocket-latest.tar.gz ============================================================================== --- public_html/releases/usocket-latest.tar.gz (original) +++ public_html/releases/usocket-latest.tar.gz Fri Apr 1 13:01:33 2011 @@ -1 +1 @@ -link usocket-0.5.0.tar.gz \ No newline at end of file +link usocket-0.5.1.tar.gz \ No newline at end of file Modified: public_html/releases/usocket-latest.tar.gz.asc ============================================================================== --- public_html/releases/usocket-latest.tar.gz.asc (original) +++ public_html/releases/usocket-latest.tar.gz.asc Fri Apr 1 13:01:33 2011 @@ -1 +1 @@ -link usocket-0.5.0.tar.gz.asc \ No newline at end of file +link usocket-0.5.1.tar.gz.asc \ No newline at end of file From ctian at common-lisp.net Fri Apr 1 17:07:27 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 01 Apr 2011 13:07:27 -0400 Subject: [usocket-cvs] r639 - public_html Message-ID: Author: ctian Date: Fri Apr 1 13:07:26 2011 New Revision: 639 Log: Release 0.5.1 Modified: public_html/index.shtml Modified: public_html/index.shtml ============================================================================== --- public_html/index.shtml (original) +++ public_html/index.shtml Fri Apr 1 13:07:26 2011 @@ -1,5 +1,5 @@ - + USOCKET @@ -98,7 +98,8 @@ to the commit -message mailing list. To use the latest development +message +mailing list. To use the latest development version, make sure you have Subversion installed and execute this command:

 $ svn checkout svn://common-lisp.net/project/usocket/svn/usocket/trunk usocket-svn
@@ -128,6 +129,7 @@ +
Summary + Apr 2, 2011
+ + 0.5.1
+ + Improved +CLISP support using FFI; Lots of bugfix for CMUCL, SBCL, +LispWorks, etc.
+ + + Mar 12, 2011 0.5.0 - UDP support; Lots of bugfixes since 0.4.1; support for WAIT-FOR-INPUT for - SBCL and ECL on Win32; new platform added: Macintosh Common Lisp - (5.0 and up) + UDP support; Lots of bugfixes since 0.4.1; support for +WAIT-FOR-INPUT for SBCL and ECL on Win32; new platform added: Macintosh +Common Lisp (5.0 and up) Dec 27, 2008 @@ -500,6 +512,7 @@ fix +
issue #6 and API preparation for server side sockets (not in this release) From ctian at common-lisp.net Sun Apr 10 14:29:36 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Sun, 10 Apr 2011 10:29:36 -0400 Subject: [usocket-cvs] r640 - usocket/branches/0.5.x/backend Message-ID: Author: ctian Date: Sun Apr 10 10:29:35 2011 New Revision: 640 Log: [CLISP] Fixed WAIT-FOR-INPUT, this made Hunchentoot working on CLISP. (Thanks to Anton Vodonosov ) Modified: usocket/branches/0.5.x/backend/clisp.lisp Modified: usocket/branches/0.5.x/backend/clisp.lisp ============================================================================== --- usocket/branches/0.5.x/backend/clisp.lisp (original) +++ usocket/branches/0.5.x/backend/clisp.lisp Sun Apr 10 10:29:35 2011 @@ -232,9 +232,9 @@ (socket:socket-status request-list))) (sockets (wait-list-waiters wait-list))) (do* ((x (pop sockets) (pop sockets)) - (y (pop status-list) (pop status-list))) + (y (cdr (pop status-list)) (cdr (pop status-list)))) ((null x)) - (when (eq y :INPUT) + (when (member y '(T :INPUT)) (setf (state x) :READ))) wait-list)))) From ctian at common-lisp.net Sun Apr 10 14:30:08 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Sun, 10 Apr 2011 10:30:08 -0400 Subject: [usocket-cvs] r641 - usocket/branches/0.5.x Message-ID: Author: ctian Date: Sun Apr 10 10:30:07 2011 New Revision: 641 Log: Update ChangeLog Modified: usocket/branches/0.5.x/CHANGES Modified: usocket/branches/0.5.x/CHANGES ============================================================================== --- usocket/branches/0.5.x/CHANGES (original) +++ usocket/branches/0.5.x/CHANGES Sun Apr 10 10:30:07 2011 @@ -1,10 +1,6 @@ -0.5.0: +0.5.2: -* New supported platform: Macintosh Common Lisp (5.0 and up, plus RMCL) -* Support for UDP (datagram-usocket) was added (for all supported platform except MCL) -* Add WAIT-FOR-INPUT support for SBCL and ECL on win32. -* Simple TCP and UDP server API: SOCKET-SERVER -* Lots of bug fixed since 0.4.1 +* Bugfix: CLISP's WAIT-FOR-INPUT misused underlying CLISP API, this made Hunchentoot working on CLISP. (Thanks to Anton Vodonosov ) 0.5.1: @@ -21,6 +17,14 @@ * Bugfix: [CMUCL] Fixed SOCKET-SEND on unconnected usockets under Unicode version of CMUCL. * Bugfix: [CLISP] Fixed and confirmed UDP (Datagram) support (RAWSOCK version). +0.5.0: + +* New supported platform: Macintosh Common Lisp (5.0 and up, plus RMCL) +* Support for UDP (datagram-usocket) was added (for all supported platform except MCL) +* Add WAIT-FOR-INPUT support for SBCL and ECL on win32. +* Simple TCP and UDP server API: SOCKET-SERVER +* Lots of bug fixed since 0.4.1 + [TODO] * New feature: CLISP support some advanced TCP features which CLISP's SOCKET interface not provide From ctian at common-lisp.net Fri Apr 15 18:05:55 2011 From: ctian at common-lisp.net (Chun Tian (binghe)) Date: Fri, 15 Apr 2011 14:05:55 -0400 Subject: [usocket-cvs] r642 - usocket/trunk Message-ID: Author: ctian Date: Fri Apr 15 14:05:55 2011 New Revision: 642 Log: Fixed compilation warnings in SOCKET-OPTION, patched by Robert Brown Modified: usocket/trunk/option.lisp Modified: usocket/trunk/option.lisp ============================================================================== --- usocket/trunk/option.lisp (original) +++ usocket/trunk/option.lisp Fri Apr 15 14:05:55 2011 @@ -41,7 +41,9 @@ (defmethod socket-option ((usocket stream-usocket) (option (eql :receive-timeout)) &key) + (declare (ignore option)) (let ((socket (socket usocket))) + (declare (ignorable socket)) #+abcl () ; TODO #+allegro @@ -65,9 +67,11 @@ (defmethod (setf socket-option) (new-value (usocket stream-usocket) (option (eql :receive-timeout)) &key) - (declare (type number new-value)) + (declare (type number new-value) + (ignore option)) (let ((socket (socket usocket)) (timeout new-value)) + (declare (ignorable socket timeout)) #+abcl () ; TODO #+allegro