Current implementation has the following defects:

* The socket stream ends up with a bogus name as it is created before
the socket is connected, making things harder to debug than they need
to be.

* In case of error, SB-BSD-SOCKETS:SOCKET-CLOSE was not being called
with :ABORT T.

* A unwind from SOCKET-CONNECT that didn't go through the handler leaked an FD.

* An innocent non-error SIGNAL for any reason during SOCKET-CONNECT
was taken to be a fatal error due to the handler on type T.

* On datagram sockets CONNECTED-P wasn't set.

Attached patch addresses these issues. Not deeply tested, though.

Cheers,

 -- Nikodemus
Index: backend/sbcl.lisp
===================================================================
--- backend/sbcl.lisp	(revision 574)
+++ backend/sbcl.lisp	(working copy)
@@ -199,6 +199,11 @@
                  (if usock-cond
                      (signal usock-cond :socket socket))))))
 
+(defvar *dummy-stream*
+  (let ((stream (make-broadcast-stream)))
+    (close stream)
+    stream))
+
 (defun socket-connect (host port &key (protocol :stream) (element-type 'character)
                        timeout deadline (nodelay t nodelay-specified)
                        local-host local-port
@@ -219,47 +224,53 @@
   (let ((socket (make-instance 'sb-bsd-sockets:inet-socket
                                :type protocol
                                :protocol (case protocol
-					   (:stream :tcp)
-					   (:datagram :udp)))))
-    (handler-case
-        (ecase protocol
-          (:stream
-	   (let* ((stream
-		   (sb-bsd-sockets:socket-make-stream socket
-						      :input t
-						      :output t
-						      :buffering :full
-						      #+sbcl #+sbcl
-						      :timeout timeout
-						      :element-type element-type))
-		  ;;###FIXME: The above line probably needs an :external-format
-		  (usocket (make-stream-socket :stream stream :socket socket))
-		  (ip (host-to-vector-quad host)))
-	     ;; binghe: use SOCKOPT-TCP-NODELAY as internal symbol
-	     ;;         to pass compilation on ECL without it.
-	     (when (and nodelay-specified sockopt-tcp-nodelay-p)
-	       (setf (sb-bsd-sockets::sockopt-tcp-nodelay socket) nodelay))
-	     (when (or local-host local-port)
-	       (sb-bsd-sockets:socket-bind socket
-					   (host-to-vector-quad
-					    (or local-host *wildcard-host*))
-					   (or local-port *auto-port*)))
-	     (with-mapped-conditions (usocket)
-	       (sb-bsd-sockets:socket-connect socket ip port))
-	     usocket))
-          (:datagram
-	   (when (or local-host local-port)
-	     (sb-bsd-sockets:socket-bind socket
-					 (host-to-vector-quad
-					  (or local-host *wildcard-host*))
-					 (or local-port *auto-port*)))
-	   (when (and host port)
-	     (sb-bsd-sockets:socket-connect socket (host-to-vector-quad host) port))
-	   (make-datagram-socket socket)))
-      (t (c)
-        ;; Make sure we don't leak filedescriptors
-        (sb-bsd-sockets:socket-close socket)
-        (error c)))))
+                                           (:stream :tcp)
+                                           (:datagram :udp))))
+        (ip (host-to-vector-quad host))
+        (local-host (host-to-vector-quad (or local-host *wildcard-host*)))
+        (local-port (or local-port *auto-port*))
+        usocket ok)
+    (unwind-protect
+         (progn
+           (ecase protocol
+             (:stream
+              ;; If make a real socket stream before the socket is
+              ;; connected, it gets a misleading name so supply a
+              ;; dummy value to start with.
+              (setf usocket (make-stream-socket :socket socket :stream *dummy-stream*))
+              ;; binghe: use SOCKOPT-TCP-NODELAY as internal symbol
+              ;;         to pass compilation on ECL without it.
+              (when (and nodelay-specified sockopt-tcp-nodelay-p)
+                (setf (sb-bsd-sockets::sockopt-tcp-nodelay socket) nodelay))
+              (when (or local-host local-port)
+                (sb-bsd-sockets:socket-bind socket local-host local-port))
+              (with-mapped-conditions (usocket)
+                (sb-bsd-sockets:socket-connect socket ip port)
+                ;; Now that we're connected make the stream.
+                (setf (socket-stream usocket)
+                      (sb-bsd-sockets:socket-make-stream socket
+                                                         :input t
+                                                         :output t
+                                                         :buffering :full
+                                                         #+sbcl #+sbcl
+                                                         :timeout timeout
+                                                         :element-type element-type))))
+             (:datagram
+              (when (or local-host local-port)
+                (sb-bsd-sockets:socket-bind socket
+                                            (host-to-vector-quad
+                                             (or local-host *wildcard-host*))
+                                            (or local-port *auto-port*)))
+              (setf usocket (make-datagram-socket socket))
+              (when (and host port)
+                (with-mapped-conditions (usocket)
+                  (sb-bsd-sockets:socket-connect socket ip port)
+                  (setf (connected-p usocket) t)))))
+           (setf ok t))
+      ;; Clean up in case of an error.
+      (unless ok
+        (sb-bsd-sockets:socket-close socket :abort t)))
+    usocket))
 
 (defun socket-listen (host port
                            &key reuseaddress
_______________________________________________
usocket-devel mailing list
usocket-devel@common-lisp.net
http://common-lisp.net/cgi-bin/mailman/listinfo/usocket-devel

Reply via email to