fix p2phttp server to not get stuck

Process 1 command, then stop. Hopefully each of the Handlers will only
need 1 command.
This commit is contained in:
Joey Hess 2024-07-09 14:26:30 -04:00
parent 3d13521479
commit dcd77ee555
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
2 changed files with 26 additions and 9 deletions

View file

@ -131,9 +131,7 @@ withLocalP2PConnections a = do
(const True) h2 h1 (const True) h2 h1
(ConnIdent (Just "http client")) (ConnIdent (Just "http client"))
runst <- liftIO $ mkrunst connparams runst <- liftIO $ mkrunst connparams
-- TODO is this right? It needs to exit let server = P2P.serveOneCommandAuthed
-- when the client stops sending messages.
let server = P2P.serveAuthed
(connectionServerMode connparams) (connectionServerMode connparams)
(connectionServerUUID connparams) (connectionServerUUID connparams)
let protorunner = void $ let protorunner = void $

View file

@ -42,6 +42,7 @@ import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import qualified Data.Set as S import qualified Data.Set as S
import Data.Char import Data.Char
import Data.Maybe
import Data.Time.Clock.POSIX import Data.Time.Clock.POSIX
import Control.Applicative import Control.Applicative
import Control.DeepSeq import Control.DeepSeq
@ -472,7 +473,14 @@ data ServerHandler a
-- Server loop, getting messages from the client and handling them -- Server loop, getting messages from the client and handling them
serverLoop :: (Message -> Proto (ServerHandler a)) -> Proto (Maybe a) serverLoop :: (Message -> Proto (ServerHandler a)) -> Proto (Maybe a)
serverLoop a = do serverLoop a = serveOneMessage a serverLoop
-- Get one message from the client and handle it.
serveOneMessage
:: (Message -> Proto (ServerHandler a))
-> ((Message -> Proto (ServerHandler a)) -> Proto (Maybe a))
-> Proto (Maybe a)
serveOneMessage a cont = do
mcmd <- net receiveMessage mcmd <- net receiveMessage
case mcmd of case mcmd of
-- When the client sends ERROR to the server, the server -- When the client sends ERROR to the server, the server
@ -480,16 +488,16 @@ serverLoop a = do
-- is in, and so not possible to recover. -- is in, and so not possible to recover.
Just (ERROR _) -> return Nothing Just (ERROR _) -> return Nothing
-- When the client sends an unparsable message, the server -- When the client sends an unparsable message, the server
-- responds with an error message, and loops. This allows -- responds with an error message, and continues. This allows
-- expanding the protocol with new messages. -- expanding the protocol with new messages.
Nothing -> do Nothing -> do
net $ sendMessage (ERROR "unknown command") net $ sendMessage (ERROR "unknown command")
serverLoop a cont a
Just cmd -> do Just cmd -> do
v <- a cmd v <- a cmd
case v of case v of
ServerGot r -> return (Just r) ServerGot r -> return (Just r)
ServerContinue -> serverLoop a ServerContinue -> cont a
-- If the client sends an unexpected message, -- If the client sends an unexpected message,
-- the server will respond with ERROR, and -- the server will respond with ERROR, and
-- always continues processing messages. -- always continues processing messages.
@ -501,7 +509,7 @@ serverLoop a = do
-- support some new feature, and fall back. -- support some new feature, and fall back.
ServerUnexpected -> do ServerUnexpected -> do
net $ sendMessage (ERROR "unexpected command") net $ sendMessage (ERROR "unexpected command")
serverLoop a cont a
-- | Serve the protocol, with an unauthenticated peer. Once the peer -- | Serve the protocol, with an unauthenticated peer. Once the peer
-- successfully authenticates, returns their UUID. -- successfully authenticates, returns their UUID.
@ -530,7 +538,18 @@ data ServerMode
-- | Serve the protocol, with a peer that has authenticated. -- | Serve the protocol, with a peer that has authenticated.
serveAuthed :: ServerMode -> UUID -> Proto () serveAuthed :: ServerMode -> UUID -> Proto ()
serveAuthed servermode myuuid = void $ serverLoop handler serveAuthed servermode myuuid = void $ serverLoop $
serverHandler servermode myuuid
-- | Serve a single command in the protocol, the same as serveAuthed,
-- but without looping to handle the next command.
serveOneCommandAuthed :: ServerMode -> UUID -> Proto ()
serveOneCommandAuthed servermode myuuid = fromMaybe () <$>
serveOneMessage (serverHandler servermode myuuid)
(const $ pure Nothing)
serverHandler :: ServerMode -> UUID -> Message -> Proto (ServerHandler ())
serverHandler servermode myuuid = handler
where where
handler (VERSION theirversion) = do handler (VERSION theirversion) = do
let v = min theirversion maxProtocolVersion let v = min theirversion maxProtocolVersion