mirror of https://github.com/voidlizard/hbs2
upnp gateway detection
This commit is contained in:
parent
55e2f1cc32
commit
de48525d02
|
@ -4,12 +4,15 @@ module DetectGateway (detectGatewayLoop) where
|
||||||
import HBS2.Prelude.Plated
|
import HBS2.Prelude.Plated
|
||||||
import HBS2.Clock
|
import HBS2.Clock
|
||||||
import HBS2.Net.Messaging
|
import HBS2.Net.Messaging
|
||||||
import HBS2.Net.Proto.Types
|
|
||||||
import HBS2.OrDie
|
import HBS2.OrDie
|
||||||
import HBS2.Net.Messaging.UDP
|
import HBS2.Net.Messaging.UDP
|
||||||
|
import HBS2.Events
|
||||||
|
import HBS2.Net.IP.Addr
|
||||||
|
|
||||||
import HBS2.System.Logger.Simple
|
import HBS2.System.Logger.Simple
|
||||||
|
import PeerTypes
|
||||||
|
|
||||||
|
import Data.Char (isSpace)
|
||||||
import Data.Attoparsec.Text as Atto
|
import Data.Attoparsec.Text as Atto
|
||||||
import Data.Functor
|
import Data.Functor
|
||||||
import Control.Concurrent.Async
|
import Control.Concurrent.Async
|
||||||
|
@ -19,10 +22,33 @@ import Data.ByteString.Lazy.Char8 (ByteString)
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Data.Text.Encoding qualified as T
|
import Data.Text.Encoding qualified as T
|
||||||
import Data.Text as T
|
import Data.Text as T
|
||||||
import Data.List qualified as List
|
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Data.Either
|
||||||
|
import Data.Function
|
||||||
|
|
||||||
detectGatewayLoop :: forall m . (MonadIO m) => m ()
|
checkHTTPHead :: Text -> Bool
|
||||||
|
checkHTTPHead s = parseOnly pHead s & fromRight False
|
||||||
|
|
||||||
|
checkIGDString :: Text -> Bool
|
||||||
|
checkIGDString s = parseOnly pIGD s & fromRight False
|
||||||
|
|
||||||
|
pHead :: Parser Bool
|
||||||
|
pHead = do
|
||||||
|
void $ string "HTTP/"
|
||||||
|
skipWhile (not . isSpace) -- >> skipWhile isSpace
|
||||||
|
void skipSpace
|
||||||
|
void $ string "200"
|
||||||
|
pure True
|
||||||
|
|
||||||
|
pIGD :: Parser Bool
|
||||||
|
pIGD = do
|
||||||
|
-- ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1
|
||||||
|
void $ string "ST:"
|
||||||
|
void skipSpace
|
||||||
|
void $ string "urn:schemas-upnp-org:device:InternetGatewayDevice:1"
|
||||||
|
pure True
|
||||||
|
|
||||||
|
detectGatewayLoop :: forall e m . (MonadIO m, EventEmitter e (UPnPGatewayDetect e) m) => m ()
|
||||||
detectGatewayLoop = do
|
detectGatewayLoop = do
|
||||||
|
|
||||||
mlisten <- newMessagingUDPMulticast upnpMulticast
|
mlisten <- newMessagingUDPMulticast upnpMulticast
|
||||||
|
@ -36,34 +62,39 @@ detectGatewayLoop = do
|
||||||
udpMessListen <- liftIO $ async $ runMessagingUDP mlisten
|
udpMessListen <- liftIO $ async $ runMessagingUDP mlisten
|
||||||
|
|
||||||
|
|
||||||
reqLoop <- liftIO $ async $ forever do
|
let waitIGDAnswer = liftIO $ race (pause @'Seconds 5 >> pure Nothing) $
|
||||||
sendTo mlisten (To upaddr) (From upaddr) gwDetectMsg
|
fix \next -> do
|
||||||
pause @'Seconds 10
|
|
||||||
|
|
||||||
forever $ do
|
|
||||||
debug "detectGatewayLoop"
|
|
||||||
|
|
||||||
answ <- receive @_ @UDP @ByteString mlisten (To upaddr)
|
answ <- receive @_ @UDP @ByteString mlisten (To upaddr)
|
||||||
|
|
||||||
gwAddrs <- forM answ $ \(From sa,msg) -> do
|
gwAddrs <- forM answ $ \(From sa,msg) -> do
|
||||||
let txt = foldMap T.words $ T.lines $ T.decodeUtf8 $ LBS.toStrict msg
|
let txt = T.lines $ T.decodeUtf8 $ LBS.toStrict msg
|
||||||
debug $ pretty sa <+> pretty (show msg)
|
trace $ "ANSW:" <+> pretty txt
|
||||||
|
let isAnsw = headMay txt <&> checkHTTPHead
|
||||||
|
let isIGD = or $ fmap checkIGDString txt
|
||||||
|
if isAnsw == Just True && isIGD then
|
||||||
|
pure (Just sa)
|
||||||
|
else
|
||||||
pure Nothing
|
pure Nothing
|
||||||
-- maybe1 (List.find (== "urn:schemas-upnp-org:device:InternetGatewayDevice:1") txt)
|
|
||||||
-- (pure Nothing)
|
|
||||||
-- (const $ pure $ Just sa)
|
|
||||||
|
|
||||||
pure ()
|
let gwAddr = headMay $ catMaybes gwAddrs
|
||||||
-- let gwAddr = headMay $ catMaybes gwAddrs
|
|
||||||
|
|
||||||
-- TODO: what-if-more-than-one-gateway
|
-- TODO: what-if-more-than-one-gateway
|
||||||
-- maybe1 gwAddr none $ \gwa -> do
|
maybe1 gwAddr next $ \gwa -> do
|
||||||
-- debug $ "FOUND FIRST GATEWAY:" <+> pretty gwa
|
pure (Just gwa)
|
||||||
|
|
||||||
-- FIXME: remove-debug-hardcode
|
forever do
|
||||||
-- pause @'Seconds 30
|
debug "detectGatewayLoop"
|
||||||
|
sendTo mlisten (To upaddr) (From upaddr) gwDetectMsg
|
||||||
|
mbGwa <- waitIGDAnswer <&> fromRight Nothing
|
||||||
|
|
||||||
-- void $ liftIO $ waitAnyCatchCancel [udpMessSend] -- , udpMessListen]
|
maybe1 mbGwa (pause @'Seconds 60) $ \gwa -> do
|
||||||
|
let wa = pause @'Seconds 1200
|
||||||
|
let a = getHostPort (T.pack $ show $ pretty gwa)
|
||||||
|
maybe1 a wa $ \(s,_) -> do
|
||||||
|
debug $ "found some gateway:" <+> pretty s
|
||||||
|
emit @e UPnPGatewayDetectKey (UPnPGatewayDetect s)
|
||||||
|
wa
|
||||||
|
|
||||||
|
void $ liftIO $ waitAnyCatchCancel [udpMessListen]
|
||||||
|
|
||||||
where
|
where
|
||||||
upnpMulticast = "239.255.255.250:1900"
|
upnpMulticast = "239.255.255.250:1900"
|
||||||
|
|
|
@ -538,7 +538,7 @@ runPeer opts = Exception.handle myException $ do
|
||||||
debug "sending local peer announce"
|
debug "sending local peer announce"
|
||||||
request localMulticast (PeerAnnounce @e pnonce)
|
request localMulticast (PeerAnnounce @e pnonce)
|
||||||
|
|
||||||
peerThread detectGatewayLoop
|
peerThread (detectGatewayLoop @e)
|
||||||
|
|
||||||
peerThread (checkMetrics metrics)
|
peerThread (checkMetrics metrics)
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,27 @@ instance EventType ( Event e (DownloadReq e) ) where
|
||||||
instance Expires (EventKey e (DownloadReq e)) where
|
instance Expires (EventKey e (DownloadReq e)) where
|
||||||
expiresIn = const Nothing
|
expiresIn = const Nothing
|
||||||
|
|
||||||
|
data UPnPGatewayDetect e
|
||||||
|
|
||||||
|
data instance EventKey e (UPnPGatewayDetect e) =
|
||||||
|
UPnPGatewayDetectKey
|
||||||
|
deriving (Generic,Typeable,Eq)
|
||||||
|
|
||||||
|
newtype instance Event e (UPnPGatewayDetect e) =
|
||||||
|
UPnPGatewayDetect String
|
||||||
|
deriving (Typeable)
|
||||||
|
|
||||||
|
instance Typeable (UPnPGatewayDetect e) => Hashable (EventKey e (UPnPGatewayDetect e)) where
|
||||||
|
hashWithSalt salt _ = hashWithSalt salt (someTypeRep p)
|
||||||
|
where
|
||||||
|
p = Proxy @DownloadReq
|
||||||
|
|
||||||
|
instance EventType ( Event e (UPnPGatewayDetect e) ) where
|
||||||
|
isPersistent = True
|
||||||
|
|
||||||
|
instance Expires (EventKey e (UPnPGatewayDetect e)) where
|
||||||
|
expiresIn = const Nothing
|
||||||
|
|
||||||
type DownloadFromPeerStuff e m = ( MyPeer e
|
type DownloadFromPeerStuff e m = ( MyPeer e
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, Request e (BlockInfo e) m
|
, Request e (BlockInfo e) m
|
||||||
|
|
Loading…
Reference in New Issue