Ability to wrap existing FD #41

orthecreedence opened this Issue Dec 20, 2012 · 5 comments


None yet

2 participants


It would be nice if an app already has an existing FD (via usocket, cl+ssl, etc) to be able to wrap it in a cl-async socket.

Also need ability to wrap existing SSL fd.


This seems to work for bare sockets. SSL will probably be a bit more involved.

(defun wrap-existing-fd (new-fd)
  "Given an existing file descriptor, wraps it in a cl-async socket, ready for
   monitoring by libevent."
  (let* ((socket (as:tcp-connect "" 1 (lambda (sock data) nil) (lambda (ev) nil)))
         (bufferevent (as:socket-c socket))
         (fd (le:bufferevent-getfd bufferevent)))
    ;; close the temporary socket
    (le:evutil-closesocket fd)
    ;; set the new fd into the bufferevent
    (le:bufferevent-setfd bufferevent new-fd)
    ;; this socket now wraps the new fd

Done, turns out libevent had this ability all along, not many changes needed at all. tcp-connect now accepts an :fd arg, which can be used to pass in an existing file descriptor.

Here's a simple function to get an fd from a usocket socket object on a few lisps (inspired by cl+ssl's stream-fd method). Note that this is not included in cl-async, so will have to be a utility function in whatever app needs it:

(defun get-usocket-fd (connection)
  "Gets the fd from a usocket connection."
  (let* ((type (type-of connection))
         (stream (cond ((subtypep type 'usocket:stream-usocket)
                        (usocket:socket-stream connection))
                       ((subtypep type 'stream)
    (when stream
        (sb-sys:fd-stream-fd stream)
        (system:fd-stream-fd stream)
        (ccl::ioblock-device (ccl::stream-ioblock stream t))
        (ext:stream-handles stream))))

This handles simple TCP sockets in cl-async, but not SSL sockets. There is now an issue open for that item as well: issue #43.

jd commented Dec 28, 2012

Thanks @orthecreedence this looks great. I'm going to test this ASAP.

One suggestion reading the implementation, it's likely that it would be more clear if you'd split the tcp-connect function in two function, one being the low-level plugin of the fd into libevent, the other one doing the connect.

This would allow guys like me to not overlook tcp-connect because the name implies connect whereas the socket is already connected, and all is interesting here it the fd (whatever it's a socket or a file or anything else).


Very good suggestion. I'll create a lower-level init-connection function (name not set in stone) that inits a socket object and then have tcp-connect connect it. I'd like to not make breaking changes to tcp-connect if I can avoid it, so it might end up being a keyword parameter, but if it starts getting too convoluted I might split things up more. Just depends how it looks when I finish =].


Note, I create a new issue for this (issue #45)

@jd jd referenced this issue in marijnh/Postmodern Jan 2, 2013

Event loop integration #28

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment