@@ -11,6 +11,10 @@ module Network.Socket.SockAddr (
1111 , recvBufMsg
1212 ) where
1313
14+ import Control.Exception (try , throwIO , IOException )
15+ import System.Directory (removeFile )
16+ import System.IO.Error (isAlreadyInUseError , isDoesNotExistError )
17+
1418import qualified Network.Socket.Buffer as G
1519import qualified Network.Socket.Name as G
1620import qualified Network.Socket.Syscall as G
@@ -41,7 +45,27 @@ connect = G.connect
4145-- 'defaultPort' is passed then the system assigns the next available
4246-- use port.
4347bind :: Socket -> SockAddr -> IO ()
44- bind = G. bind
48+ bind s a = case a of
49+ SockAddrUnix p -> do
50+ -- gracefully handle the fact that UNIX systems don't clean up closed UNIX
51+ -- domain sockets, inspired by https://stackoverflow.com/a/13719866
52+ res <- try (G. bind s a)
53+ case res of
54+ Right () -> pure ()
55+ Left e -> if not (isAlreadyInUseError (e :: IOException ))
56+ then throwIO e
57+ else do
58+ -- socket might be in use, try to connect
59+ res2 <- try (G. connect s a)
60+ case res2 of
61+ Right () -> close s >> throwIO e
62+ Left e2 -> if not (isDoesNotExistError (e2 :: IOException ))
63+ then throwIO e
64+ else do
65+ -- socket not actually in use, remove it and retry bind
66+ removeFile p
67+ G. bind s a
68+ _ -> G. bind s a
4569
4670-- | Accept a connection. The socket must be bound to an address and
4771-- listening for connections. The return value is a pair @(conn,
0 commit comments