diff options
-rw-r--r-- | Presence/XMPPServer.hs | 8 | ||||
-rw-r--r-- | presence.cabal | 1 | ||||
-rwxr-xr-x | t | 2 | ||||
-rw-r--r-- | xmppServer.hs | 68 |
4 files changed, 63 insertions, 16 deletions
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs index aae5e97a..f029810d 100644 --- a/Presence/XMPPServer.hs +++ b/Presence/XMPPServer.hs | |||
@@ -68,6 +68,7 @@ import qualified Data.Set as Set | |||
68 | import qualified System.Random | 68 | import qualified System.Random |
69 | import qualified Network.BSD as BSD | 69 | import qualified Network.BSD as BSD |
70 | import Data.Void (Void) | 70 | import Data.Void (Void) |
71 | import System.Endian (toBE32) | ||
71 | 72 | ||
72 | import GetHostByAddr (getHostByAddr) | 73 | import GetHostByAddr (getHostByAddr) |
73 | import qualified Control.Concurrent.STM.UpdateStream as Slotted | 74 | import qualified Control.Concurrent.STM.UpdateStream as Slotted |
@@ -254,10 +255,15 @@ peerKeyToResolvedNames :: ConnectionKey -> IO [Text] | |||
254 | peerKeyToResolvedNames k@(ClientKey { localAddress=addr }) = return [] | 255 | peerKeyToResolvedNames k@(ClientKey { localAddress=addr }) = return [] |
255 | peerKeyToResolvedNames k@(PeerKey { callBackAddress=addr }) = do | 256 | peerKeyToResolvedNames k@(PeerKey { callBackAddress=addr }) = do |
256 | handleIO_ (return []) $ do | 257 | handleIO_ (return []) $ do |
257 | ent <- getHostByAddr addr -- AF_UNSPEC addr | 258 | ent <- getHostByAddr (unmap6mapped4 addr) -- AF_UNSPEC addr |
258 | let names = BSD.hostName ent : BSD.hostAliases ent | 259 | let names = BSD.hostName ent : BSD.hostAliases ent |
259 | return $ map Text.pack $ nub names | 260 | return $ map Text.pack $ nub names |
260 | 261 | ||
262 | unmap6mapped4 addr@(SockAddrInet6 port _ (0,0,0xFFFF,a) _) = | ||
263 | SockAddrInet port (toBE32 a) | ||
264 | unmap6mapped4 addr = addr | ||
265 | |||
266 | |||
261 | 267 | ||
262 | wlog :: String -> IO () | 268 | wlog :: String -> IO () |
263 | wlog s = putStrLn s >> hFlush stdout | 269 | wlog s = putStrLn s >> hFlush stdout |
diff --git a/presence.cabal b/presence.cabal index 30081d17..aaa5603a 100644 --- a/presence.cabal +++ b/presence.cabal | |||
@@ -26,4 +26,5 @@ executable presence | |||
26 | c-sources: Presence/monitortty.c | 26 | c-sources: Presence/monitortty.c |
27 | hs-source-dirs: . Presence | 27 | hs-source-dirs: . Presence |
28 | ghc-prof-options: -DNOUTMP | 28 | ghc-prof-options: -DNOUTMP |
29 | ghc-options: -O2 -fwarn-unused-binds -threaded | ||
29 | 30 | ||
@@ -1,5 +1,5 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | args="-fwarn-unused-imports -rtsopts -DRENDERFLUSH -optP-include -optPdist/build/autogen/cabal_macros.h" | 2 | args="-threaded -fwarn-unused-imports -rtsopts -DRENDERFLUSH -optP-include -optPdist/build/autogen/cabal_macros.h" |
3 | 3 | ||
4 | root=${0%/*} | 4 | root=${0%/*} |
5 | cd "$root" | 5 | cd "$root" |
diff --git a/xmppServer.hs b/xmppServer.hs index 598ffe72..3752218a 100644 --- a/xmppServer.hs +++ b/xmppServer.hs | |||
@@ -1,6 +1,7 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | 1 | {-# LANGUAGE OverloadedStrings #-} |
2 | {-# LANGUAGE TupleSections #-} | 2 | {-# LANGUAGE TupleSections #-} |
3 | import System.Posix.Signals | 3 | import System.Posix.Signals |
4 | import Control.Concurrent (threadDelay,forkIO,forkOS,killThread,throwTo) | ||
4 | import Control.Concurrent.STM | 5 | import Control.Concurrent.STM |
5 | import Control.Concurrent.STM.TMVar | 6 | import Control.Concurrent.STM.TMVar |
6 | import Control.Monad.Trans.Resource (runResourceT) | 7 | import Control.Monad.Trans.Resource (runResourceT) |
@@ -146,10 +147,31 @@ make6mapped4 addr@(SockAddrInet port a) = SockAddrInet6 port 0 (0,0,0xFFFF,fromB | |||
146 | 147 | ||
147 | resolvePeer :: Text -> IO [SockAddr] | 148 | resolvePeer :: Text -> IO [SockAddr] |
148 | resolvePeer addrtext = do | 149 | resolvePeer addrtext = do |
149 | fmap (map $ make6mapped4 . addrAddress) $ | 150 | r <- atomically newEmptyTMVar |
150 | getAddrInfo (Just $ defaultHints { addrFlags = [ AI_CANONNAME, AI_V4MAPPED ]}) | 151 | mvar <- atomically newEmptyTMVar |
152 | rt <- forkOS $ resolver r mvar | ||
153 | tt <- forkIO $ timer r rt | ||
154 | atomically $ putTMVar mvar tt | ||
155 | atomically $ readTMVar r | ||
156 | where | ||
157 | resolver r mvar = do | ||
158 | xs <- handle (\e -> let _ = isDoesNotExistError e in return []) | ||
159 | $ do fmap (map $ make6mapped4 . addrAddress) $ | ||
160 | getAddrInfo (Just $ defaultHints { addrFlags = [ AI_CANONNAME, AI_V4MAPPED ]}) | ||
151 | (Just $ Text.unpack $ strip_brackets addrtext) | 161 | (Just $ Text.unpack $ strip_brackets addrtext) |
152 | (Just "5269") | 162 | (Just "5269") |
163 | did <- atomically $ tryPutTMVar r xs | ||
164 | when did $ do | ||
165 | tt <- atomically $ readTMVar mvar | ||
166 | throwTo tt (ErrorCall "Interrupted delay") | ||
167 | return () | ||
168 | timer r rt = do | ||
169 | handle (\(ErrorCall _)-> return ()) $ do | ||
170 | threadDelay 1000000 | ||
171 | did <- atomically $ tryPutTMVar r [] | ||
172 | when did $ do | ||
173 | putStrLn $ "timeout resolving: "++show addrtext | ||
174 | killThread rt | ||
153 | 175 | ||
154 | strip_brackets s = | 176 | strip_brackets s = |
155 | case Text.uncons s of | 177 | case Text.uncons s of |
@@ -388,12 +410,14 @@ rewriteJIDForClient laddr jid = do | |||
388 | else peerKeyToResolvedName (PeerKey addr) | 410 | else peerKeyToResolvedName (PeerKey addr) |
389 | return (mine,(n,h',r)) | 411 | return (mine,(n,h',r)) |
390 | 412 | ||
413 | sameAddress laddr addr = laddr `withPort` 0 == addr `withPort` 0 | ||
414 | |||
391 | multiplyJIDForClient :: SockAddr -> Text -> IO (Bool,[(Maybe Text,Text,Maybe Text)]) | 415 | multiplyJIDForClient :: SockAddr -> Text -> IO (Bool,[(Maybe Text,Text,Maybe Text)]) |
392 | multiplyJIDForClient laddr jid = do | 416 | multiplyJIDForClient laddr jid = do |
393 | let (n,h,r) = splitJID jid | 417 | let (n,h,r) = splitJID jid |
394 | maddr <- parseAddress (strip_brackets h) | 418 | maddr <- parseAddress (strip_brackets h) |
395 | flip (maybe $ return (False,[(n,ip6literal h,r)])) maddr $ \addr -> do | 419 | flip (maybe $ return (False,[(n,ip6literal h,r)])) maddr $ \addr -> do |
396 | let mine = laddr `withPort` 0 == addr `withPort` 0 | 420 | let mine = sameAddress laddr addr |
397 | names <- if mine then fmap (:[]) textHostName | 421 | names <- if mine then fmap (:[]) textHostName |
398 | else peerKeyToResolvedNames (PeerKey addr) | 422 | else peerKeyToResolvedNames (PeerKey addr) |
399 | return (mine,map (\h' -> (n,h',r)) names) | 423 | return (mine,map (\h' -> (n,h',r)) names) |
@@ -529,10 +553,11 @@ informClientPresence state k stanza = do | |||
529 | 553 | ||
530 | informPeerPresence state k stanza = do | 554 | informPeerPresence state k stanza = do |
531 | -- Presence must indicate full JID with resource... | 555 | -- Presence must indicate full JID with resource... |
532 | putStrLn $ "xmppInformPeerPresence checking from address..." | 556 | putStrLn $ "xmppInformPeerPresence checking from address..." |
533 | flip (maybe $ return ()) (stanzaFrom stanza) $ \from -> do | 557 | flip (maybe $ return ()) (stanzaFrom stanza) $ \from -> do |
534 | let (muser,h,mresource) = splitJID from | 558 | let (muser,h,mresource) = splitJID from |
535 | flip (maybe $ return ()) mresource $ \resource -> do | 559 | putStrLn $ "xmppInformPeerPresence from = " ++ show from |
560 | -- flip (maybe $ return ()) mresource $ \resource -> do | ||
536 | flip (maybe $ return ()) muser $ \user -> do | 561 | flip (maybe $ return ()) muser $ \user -> do |
537 | 562 | ||
538 | clients <- atomically $ do | 563 | clients <- atomically $ do |
@@ -542,13 +567,25 @@ informPeerPresence state k stanza = do | |||
542 | let umap = maybe Map.empty id $ Map.lookup k rbp | 567 | let umap = maybe Map.empty id $ Map.lookup k rbp |
543 | rp = case (presenceShow $ stanzaType stanza) of | 568 | rp = case (presenceShow $ stanzaType stanza) of |
544 | Offline -> | 569 | Offline -> |
545 | maybe (Map.empty) | 570 | maybe Map.empty |
546 | (Map.delete resource . resources) | 571 | (\resource -> |
547 | $ Map.lookup user umap | 572 | maybe (Map.empty) |
548 | _ -> maybe (Map.singleton resource stanza) | 573 | (Map.delete resource . resources) |
549 | (Map.insert resource stanza . resources ) | 574 | $ Map.lookup user umap) |
550 | $ Map.lookup user umap | 575 | mresource |
576 | |||
577 | _ ->maybe Map.empty | ||
578 | (\resource -> | ||
579 | maybe (Map.singleton resource stanza) | ||
580 | (Map.insert resource stanza . resources ) | ||
581 | $ Map.lookup user umap) | ||
582 | mresource | ||
551 | umap' = Map.insert user (RemotePresence rp) umap | 583 | umap' = Map.insert user (RemotePresence rp) umap |
584 | |||
585 | flip (maybe $ return []) (case presenceShow $ stanzaType stanza of | ||
586 | Offline -> Just () | ||
587 | _ -> mresource >> Just ()) | ||
588 | $ \_ -> do | ||
552 | writeTVar (remotesByPeer state) $ Map.insert k umap' rbp | 589 | writeTVar (remotesByPeer state) $ Map.insert k umap' rbp |
553 | -- TODO: Store or delete the stanza (remotesByPeer) | 590 | -- TODO: Store or delete the stanza (remotesByPeer) |
554 | 591 | ||
@@ -565,11 +602,13 @@ informPeerPresence state k stanza = do | |||
565 | -- For now, all "available" clients (available = sent initial presence) | 602 | -- For now, all "available" clients (available = sent initial presence) |
566 | is_avail <- atomically $ clientIsAvailable client | 603 | is_avail <- atomically $ clientIsAvailable client |
567 | when is_avail $ do | 604 | when is_avail $ do |
605 | putStrLn $ "reversing for client: " ++ show from | ||
568 | froms <- do | 606 | froms <- do |
569 | let ClientKey laddr = ck | 607 | let ClientKey laddr = ck |
570 | (_,trip) <- multiplyJIDForClient laddr from | 608 | (_,trip) <- multiplyJIDForClient laddr from |
571 | return (map unsplitJID trip) | 609 | return (map unsplitJID trip) |
572 | putStrLn $ "sending to client: " ++ show (stanzaType stanza) | 610 | |
611 | putStrLn $ "sending to client: " ++ show (stanzaType stanza,froms) | ||
573 | forM_ froms $ \from' -> do | 612 | forM_ froms $ \from' -> do |
574 | dup <- cloneStanza stanza | 613 | dup <- cloneStanza stanza |
575 | sendModifiedStanzaToClient (dup { stanzaFrom=Just from' }) | 614 | sendModifiedStanzaToClient (dup { stanzaFrom=Just from' }) |
@@ -802,11 +841,12 @@ peerSubscriptionRequest state fail k stanza chan = do | |||
802 | 841 | ||
803 | -- TODO: if peer-connection is to self, then auto-approve local user. | 842 | -- TODO: if peer-connection is to self, then auto-approve local user. |
804 | 843 | ||
805 | -- Catch exception in case the user does not exist | ||
806 | handle (\e -> let _ = isDoesNotExistError e in fail) $ do | ||
807 | -- add from-address to to's pending | 844 | -- add from-address to to's pending |
808 | addrs <- resolvePeer from_h | 845 | addrs <- resolvePeer from_h |
809 | 846 | ||
847 | -- Catch exception in case the user does not exist | ||
848 | if null addrs then fail else do | ||
849 | |||
810 | let from' = unsplitJID fromtup | 850 | let from' = unsplitJID fromtup |
811 | 851 | ||
812 | already_pending <- | 852 | already_pending <- |