Hello,
I discovered in my boundary testing of with-open-socket that it sort of has a funny behavior I didn't expect.
Basically, I had a top level code like this in a blocking i/o tcp ipv4 client talking to a server:
(with-open-socket (socket :stuff :things)
;; set up i/o handlers, each wrap their reads and writes around ;; handler-case. A disconnector on the sockets removes the io handlers, but ;; doesn't close the socket since with-open-socket should do it.
(handler-case ;; run forever until empty (meaning we disconnected from the server), ;; then return. (event-dispatch *base*)
(hangup () (format t "Hangup while writing to server~%"))
(end-of-file () (format t "End of file from server~%"))))
Now, what happened was, under certain conditions where there is inflight data on the sockets, a registered handler could get a signaled condition, specifically hangup, that tells me the server went away on a write. This is expected. I disconnect the socket which removes the i/o handlers, which causes event-dispatch to return since there are no registered handlers.... and then bam! The with-open-stream performs a (finish-output) and (close) on the socket and I get _another_ hangup condition!
So I had to rewrite the code like this moving the handler-case up one scope:
(handler-case (with-open-socket (socket :things :stuff) ;; set up i/o handlers, each wrap their reads and writes around ;; handler-case. A disconnector on the sockets removes the io handlers, but ;; doesn't close the socket since with-open-socket should do it. (event-dispatch *base*))
(hangup () (format t "Hangup while writing to server~%"))
(end-of-file () (format t "End of file from server~%"))))
Is this a to be expected scenario in condition handling with respect to with-open-socket? Is this idiomatic code?
Should the disconnector function close the socket even though with-open-socket also closes it? I'm not sure of the right thing to do here.
Thank you.
-pete