stop cleanly when there's a IO error accessing the Handle
All other exceptions are let through, but IO errors accessing the handle are to be expected, so quietly ignore.
This commit is contained in:
parent
ae69ebfc7c
commit
483dbcdbef
3 changed files with 70 additions and 60 deletions
|
@ -32,7 +32,8 @@ run (_remotename:address:[]) = forever $ do
|
||||||
| otherwise = parseAddressPort address
|
| otherwise = parseAddressPort address
|
||||||
go service = do
|
go service = do
|
||||||
ready
|
ready
|
||||||
connectService onionaddress onionport service >>= exitWith
|
res <- connectService onionaddress onionport service
|
||||||
|
exitWith (fromMaybe (ExitFailure 1) res)
|
||||||
ready = do
|
ready = do
|
||||||
putStrLn ""
|
putStrLn ""
|
||||||
hFlush stdout
|
hFlush stdout
|
||||||
|
@ -47,7 +48,7 @@ parseAddressPort s =
|
||||||
Nothing -> giveup "onion address must include port number"
|
Nothing -> giveup "onion address must include port number"
|
||||||
Just p -> (OnionAddress a, p)
|
Just p -> (OnionAddress a, p)
|
||||||
|
|
||||||
connectService :: OnionAddress -> OnionPort -> Service -> IO ExitCode
|
connectService :: OnionAddress -> OnionPort -> Service -> IO (Maybe ExitCode)
|
||||||
connectService address port service = do
|
connectService address port service = do
|
||||||
state <- Annex.new =<< Git.CurrentRepo.get
|
state <- Annex.new =<< Git.CurrentRepo.get
|
||||||
Annex.eval state $ do
|
Annex.eval state $ do
|
||||||
|
|
|
@ -30,7 +30,7 @@ import Control.Concurrent.Async
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString.Lazy as L
|
||||||
|
|
||||||
type RunProto = forall a m. (MonadIO m, MonadMask m) => Proto a -> m a
|
type RunProto = forall a m. (MonadIO m, MonadMask m) => Proto a -> m (Maybe a)
|
||||||
|
|
||||||
data S = S
|
data S = S
|
||||||
{ repo :: Repo
|
{ repo :: Repo
|
||||||
|
@ -40,58 +40,66 @@ data S = S
|
||||||
|
|
||||||
-- Implementation of the protocol, communicating with a peer
|
-- Implementation of the protocol, communicating with a peer
|
||||||
-- over a Handle. No Local actions will be run.
|
-- over a Handle. No Local actions will be run.
|
||||||
runNetProtoHandle :: (MonadIO m, MonadMask m) => Handle -> Handle -> Repo -> Proto a -> m a
|
runNetProtoHandle :: (MonadIO m, MonadMask m) => Handle -> Handle -> Repo -> Proto a -> m (Maybe a)
|
||||||
runNetProtoHandle i o r = go
|
runNetProtoHandle i o r = go
|
||||||
where
|
where
|
||||||
go :: RunProto
|
go :: RunProto
|
||||||
go (Pure a) = pure a
|
go (Pure v) = pure (Just v)
|
||||||
go (Free (Net n)) = runNetHandle (S r i o) go n
|
go (Free (Net n)) = runNetHandle (S r i o) go n
|
||||||
go (Free (Local _)) = error "local actions not allowed"
|
go (Free (Local _)) = return Nothing
|
||||||
|
|
||||||
runNetHandle :: (MonadIO m, MonadMask m) => S -> RunProto -> NetF (Proto a) -> m a
|
runNetHandle :: (MonadIO m, MonadMask m) => S -> RunProto -> NetF (Proto a) -> m (Maybe a)
|
||||||
runNetHandle s runner f = case f of
|
runNetHandle s runner f = case f of
|
||||||
SendMessage m next -> do
|
SendMessage m next -> do
|
||||||
liftIO $ do
|
v <- liftIO $ tryIO $ do
|
||||||
hPutStrLn (ohdl s) (unwords (formatMessage m))
|
hPutStrLn (ohdl s) (unwords (formatMessage m))
|
||||||
hFlush (ohdl s)
|
hFlush (ohdl s)
|
||||||
runner next
|
case v of
|
||||||
|
Left _e -> return Nothing
|
||||||
|
Right () -> runner next
|
||||||
ReceiveMessage next -> do
|
ReceiveMessage next -> do
|
||||||
l <- liftIO $ hGetLine (ihdl s)
|
v <- liftIO $ tryIO $ hGetLine (ihdl s)
|
||||||
case parseMessage l of
|
case v of
|
||||||
Just m -> runner (next m)
|
Left _e -> return Nothing
|
||||||
Nothing -> runner $ do
|
Right l -> case parseMessage l of
|
||||||
let e = ERROR $ "protocol parse error: " ++ show l
|
Just m -> runner (next m)
|
||||||
net $ sendMessage e
|
Nothing -> runner $ do
|
||||||
next e
|
let e = ERROR $ "protocol parse error: " ++ show l
|
||||||
|
net $ sendMessage e
|
||||||
|
next e
|
||||||
SendBytes _len b next -> do
|
SendBytes _len b next -> do
|
||||||
liftIO $ do
|
v <- liftIO $ tryIO $ do
|
||||||
L.hPut (ohdl s) b
|
L.hPut (ohdl s) b
|
||||||
hFlush (ohdl s)
|
hFlush (ohdl s)
|
||||||
runner next
|
case v of
|
||||||
|
Left _e -> return Nothing
|
||||||
|
Right () -> runner next
|
||||||
ReceiveBytes (Len n) next -> do
|
ReceiveBytes (Len n) next -> do
|
||||||
b <- liftIO $ L.hGet (ihdl s) (fromIntegral n)
|
v <- liftIO $ tryIO $ L.hGet (ihdl s) (fromIntegral n)
|
||||||
runner (next b)
|
case v of
|
||||||
|
Left _e -> return Nothing
|
||||||
|
Right b -> runner (next b)
|
||||||
CheckAuthToken u t next -> do
|
CheckAuthToken u t next -> do
|
||||||
authed <- return True -- TODO XXX FIXME really check
|
authed <- return True -- TODO XXX FIXME really check
|
||||||
runner (next authed)
|
runner (next authed)
|
||||||
Relay hin hout next ->
|
Relay hin hout next -> do
|
||||||
runRelay runner hin hout >>= runner . next
|
v <- liftIO $ runRelay runner hin hout
|
||||||
RelayService service next ->
|
case v of
|
||||||
runRelayService s runner service >> runner next
|
Nothing -> return Nothing
|
||||||
|
Just exitcode -> runner (next exitcode)
|
||||||
|
RelayService service next -> do
|
||||||
|
v <- liftIO $ runRelayService s runner service
|
||||||
|
case v of
|
||||||
|
Nothing -> return Nothing
|
||||||
|
Just () -> runner next
|
||||||
|
|
||||||
runRelay
|
runRelay :: RunProto -> RelayHandle -> RelayHandle -> IO (Maybe ExitCode)
|
||||||
:: MonadIO m
|
runRelay runner (RelayHandle hout) (RelayHandle hin) = bracket setup cleanup go
|
||||||
=> RunProto
|
|
||||||
-> RelayHandle
|
|
||||||
-> RelayHandle
|
|
||||||
-> m ExitCode
|
|
||||||
runRelay runner (RelayHandle hout) (RelayHandle hin) = liftIO $
|
|
||||||
bracket setup cleanup go
|
|
||||||
where
|
where
|
||||||
setup = do
|
setup = do
|
||||||
v <- newEmptyMVar
|
v <- newEmptyMVar
|
||||||
void $ forkIO $ relayFeeder runner v
|
void $ async $ relayFeeder runner v
|
||||||
void $ forkIO $ relayReader v hout
|
void $ async $ relayReader v hout
|
||||||
return v
|
return v
|
||||||
|
|
||||||
cleanup _ = do
|
cleanup _ = do
|
||||||
|
@ -100,13 +108,8 @@ runRelay runner (RelayHandle hout) (RelayHandle hin) = liftIO $
|
||||||
|
|
||||||
go v = relayHelper runner v hin
|
go v = relayHelper runner v hin
|
||||||
|
|
||||||
runRelayService
|
runRelayService :: S -> RunProto -> Service -> IO (Maybe ())
|
||||||
:: MonadIO m
|
runRelayService s runner service = bracket setup cleanup go
|
||||||
=> S
|
|
||||||
-> RunProto
|
|
||||||
-> Service
|
|
||||||
-> m ()
|
|
||||||
runRelayService s runner service = liftIO $ bracket setup cleanup go
|
|
||||||
where
|
where
|
||||||
cmd = case service of
|
cmd = case service of
|
||||||
UploadPack -> "upload-pack"
|
UploadPack -> "upload-pack"
|
||||||
|
@ -123,28 +126,29 @@ runRelayService s runner service = liftIO $ bracket setup cleanup go
|
||||||
, std_in = CreatePipe
|
, std_in = CreatePipe
|
||||||
}
|
}
|
||||||
v <- newEmptyMVar
|
v <- newEmptyMVar
|
||||||
feeder <- async $ relayFeeder runner v
|
void $ async $ relayFeeder runner v
|
||||||
reader <- async $ relayReader v hout
|
void $ async $ relayReader v hout
|
||||||
waiter <- async $ waitexit v pid
|
waiter <- async $ waitexit v pid
|
||||||
return (v, feeder, reader, waiter, hin, hout, pid)
|
return (v, waiter, hin, hout, pid)
|
||||||
|
|
||||||
cleanup (_, feeder, reader, waiter, hin, hout, pid) = do
|
cleanup (_, waiter, hin, hout, pid) = do
|
||||||
hPutStrLn stderr "!!!!\n\nIN CLEANUP"
|
hPutStrLn stderr "!!!!\n\nIN CLEANUP"
|
||||||
hFlush stderr
|
hFlush stderr
|
||||||
hClose hin
|
hClose hin
|
||||||
hClose hout
|
hClose hout
|
||||||
cancel reader
|
|
||||||
cancel waiter
|
cancel waiter
|
||||||
void $ waitForProcess pid
|
void $ waitForProcess pid
|
||||||
|
|
||||||
go (v, _, _, _, hin, _, _) = do
|
go (v, _, hin, _, _) = do
|
||||||
exitcode <- relayHelper runner v hin
|
r <- relayHelper runner v hin
|
||||||
runner $ net $ relayToPeer (RelayDone exitcode)
|
case r of
|
||||||
|
Nothing -> return Nothing
|
||||||
|
Just exitcode -> runner $ net $ relayToPeer (RelayDone exitcode)
|
||||||
|
|
||||||
waitexit v pid = putMVar v . RelayDone =<< waitForProcess pid
|
waitexit v pid = putMVar v . RelayDone =<< waitForProcess pid
|
||||||
|
|
||||||
-- Processes RelayData as it is put into the MVar.
|
-- Processes RelayData as it is put into the MVar.
|
||||||
relayHelper :: RunProto -> MVar RelayData -> Handle -> IO ExitCode
|
relayHelper :: RunProto -> MVar RelayData -> Handle -> IO (Maybe ExitCode)
|
||||||
relayHelper runner v hin = loop
|
relayHelper runner v hin = loop
|
||||||
where
|
where
|
||||||
loop = do
|
loop = do
|
||||||
|
@ -155,11 +159,13 @@ relayHelper runner v hin = loop
|
||||||
hFlush hin
|
hFlush hin
|
||||||
loop
|
loop
|
||||||
RelayToPeer b -> do
|
RelayToPeer b -> do
|
||||||
runner $ net $ relayToPeer (RelayToPeer b)
|
r <- runner $ net $ relayToPeer (RelayToPeer b)
|
||||||
loop
|
case r of
|
||||||
|
Nothing -> return Nothing
|
||||||
|
Just () -> loop
|
||||||
RelayDone exitcode -> do
|
RelayDone exitcode -> do
|
||||||
runner $ net $ relayToPeer (RelayDone exitcode)
|
_ <- runner $ net $ relayToPeer (RelayDone exitcode)
|
||||||
return exitcode
|
return (Just exitcode)
|
||||||
|
|
||||||
-- Takes input from the peer, and puts it into the MVar for processing.
|
-- Takes input from the peer, and puts it into the MVar for processing.
|
||||||
-- Repeats until the peer tells it it's done.
|
-- Repeats until the peer tells it it's done.
|
||||||
|
@ -167,11 +173,14 @@ relayFeeder :: RunProto -> MVar RelayData -> IO ()
|
||||||
relayFeeder runner v = loop
|
relayFeeder runner v = loop
|
||||||
where
|
where
|
||||||
loop = do
|
loop = do
|
||||||
rd <- runner $ net relayFromPeer
|
mrd <- runner $ net relayFromPeer
|
||||||
putMVar v rd
|
case mrd of
|
||||||
case rd of
|
Nothing -> return ()
|
||||||
RelayDone _ -> return ()
|
Just rd -> do
|
||||||
_ -> loop
|
putMVar v rd
|
||||||
|
case rd of
|
||||||
|
RelayDone _ -> return ()
|
||||||
|
_ -> loop
|
||||||
|
|
||||||
-- Reads input from the Handle and puts it into the MVar for relaying to
|
-- Reads input from the Handle and puts it into the MVar for relaying to
|
||||||
-- the peer. Continues until EOF on the Handle.
|
-- the peer. Continues until EOF on the Handle.
|
||||||
|
|
|
@ -45,5 +45,5 @@ server th@(TransportHandle (LocalRepo r) _) = do
|
||||||
forkIO $ do
|
forkIO $ do
|
||||||
debugM "remotedaemon" "handling a connection"
|
debugM "remotedaemon" "handling a connection"
|
||||||
h <- torHandle conn
|
h <- torHandle conn
|
||||||
runNetProtoHandle h h r (serve u)
|
_ <- runNetProtoHandle h h r (serve u)
|
||||||
hClose h
|
hClose h
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue