summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Presence/ConnectionKey.hs9
-rw-r--r--Presence/DNSCache.hs22
-rw-r--r--Presence/PeerResolve.hs12
-rw-r--r--Presence/Presence.hs389
-rw-r--r--Presence/XMPPServer.hs285
-rw-r--r--ToxManager.hs4
-rw-r--r--ToxToXMPP.hs6
-rw-r--r--examples/dhtd.hs4
-rw-r--r--src/Network/Tox/NodeId.hs20
9 files changed, 409 insertions, 342 deletions
diff --git a/Presence/ConnectionKey.hs b/Presence/ConnectionKey.hs
index 944f4f6f..f0180455 100644
--- a/Presence/ConnectionKey.hs
+++ b/Presence/ConnectionKey.hs
@@ -3,8 +3,9 @@ module ConnectionKey where
3import Network.Socket ( SockAddr(..) ) 3import Network.Socket ( SockAddr(..) )
4import SockAddr () 4import SockAddr ()
5 5
6data ConnectionKey 6newtype PeerAddress = PeerAddress SockAddr
7 = PeerKey { callBackAddress :: SockAddr } 7 deriving (Eq,Ord,Show)
8 | ClientKey { localAddress :: SockAddr } 8
9 deriving (Show, Ord, Eq) 9newtype ClientAddress = ClientAddress SockAddr
10 deriving (Eq,Ord,Show)
10 11
diff --git a/Presence/DNSCache.hs b/Presence/DNSCache.hs
index ce35752e..c5154e34 100644
--- a/Presence/DNSCache.hs
+++ b/Presence/DNSCache.hs
@@ -17,6 +17,7 @@ module DNSCache
17 , forwardResolve 17 , forwardResolve
18 , newDNSCache 18 , newDNSCache
19 , parseAddress 19 , parseAddress
20 , unsafeParseAddress
20 , strip_brackets 21 , strip_brackets
21 , withPort 22 , withPort
22 ) where 23 ) where
@@ -27,6 +28,7 @@ import Control.Concurrent.Lifted.Instrument
27import Control.Concurrent.Lifted 28import Control.Concurrent.Lifted
28import GHC.Conc (labelThread) 29import GHC.Conc (labelThread)
29#endif 30#endif
31import Control.Arrow
30import Control.Concurrent.STM 32import Control.Concurrent.STM
31import Data.Text ( Text ) 33import Data.Text ( Text )
32import Network.Socket ( SockAddr(..), AddrInfoFlag(..), defaultHints, getAddrInfo, AddrInfo(..) ) 34import Network.Socket ( SockAddr(..), AddrInfoFlag(..), defaultHints, getAddrInfo, AddrInfo(..) )
@@ -44,6 +46,7 @@ import Data.List
44import Data.Ord 46import Data.Ord
45import Data.Maybe 47import Data.Maybe
46import System.IO.Error 48import System.IO.Error
49import System.IO.Unsafe
47 50
48import SockAddr () 51import SockAddr ()
49import ControlMaybe ( handleIO_ ) 52import ControlMaybe ( handleIO_ )
@@ -144,7 +147,7 @@ rawForwardResolve dns onFail timeout addrtext = do
144 return () 147 return ()
145 148
146strip_brackets :: Text -> Text 149strip_brackets :: Text -> Text
147strip_brackets s = 150strip_brackets s =
148 case Text.uncons s of 151 case Text.uncons s of
149 Just ('[',t) -> Text.takeWhile (/=']') t 152 Just ('[',t) -> Text.takeWhile (/=']') t
150 _ -> s 153 _ -> s
@@ -265,6 +268,23 @@ parseAddress addr_str = do
265 return . listToMaybe $ map addrAddress info 268 return . listToMaybe $ map addrAddress info
266 269
267 270
271splitAtPort :: String -> (String,String)
272splitAtPort s = second sanitizePort $ case s of
273 ('[':t) -> break (==']') t
274 _ -> break (==':') s
275 where
276 sanitizePort (']':':':p) = p
277 sanitizePort (':':p) = p
278 sanitizePort _ = "0"
279
280unsafeParseAddress :: String -> Maybe SockAddr
281unsafeParseAddress addr_str = unsafePerformIO $ do
282 let (ipstr,portstr) = splitAtPort addr_str
283 info <- getAddrInfo (Just $ defaultHints { addrFlags = [ AI_NUMERICHOST ] })
284 (Just ipstr)
285 (Just portstr)
286 return . listToMaybe $ map addrAddress info
287
268withPort :: SockAddr -> Int -> SockAddr 288withPort :: SockAddr -> Int -> SockAddr
269withPort (SockAddrInet _ a) port = SockAddrInet (toEnum port) a 289withPort (SockAddrInet _ a) port = SockAddrInet (toEnum port) a
270withPort (SockAddrInet6 _ a b c) port = SockAddrInet6 (toEnum port) a b c 290withPort (SockAddrInet6 _ a b c) port = SockAddrInet6 (toEnum port) a b c
diff --git a/Presence/PeerResolve.hs b/Presence/PeerResolve.hs
index 900688c3..62becfe1 100644
--- a/Presence/PeerResolve.hs
+++ b/Presence/PeerResolve.hs
@@ -2,6 +2,7 @@ module PeerResolve
2 ( peerKeyToResolvedNames 2 ( peerKeyToResolvedNames
3 , resolvePeer 3 , resolvePeer
4 , parseAddress 4 , parseAddress
5 , unsafeParseAddress
5 , strip_brackets 6 , strip_brackets
6 , withPort 7 , withPort
7 ) where 8 ) where
@@ -17,11 +18,10 @@ import ConnectionKey
17global_dns_cache :: DNSCache 18global_dns_cache :: DNSCache
18global_dns_cache = unsafePerformIO $ newDNSCache 19global_dns_cache = unsafePerformIO $ newDNSCache
19 20
20resolvePeer :: Text -> IO [SockAddr] 21resolvePeer :: Text -> IO [PeerAddress]
21resolvePeer addrtext = forwardResolve global_dns_cache addrtext 22resolvePeer addrtext = map PeerAddress <$> forwardResolve global_dns_cache addrtext
22 23
23peerKeyToResolvedNames :: ConnectionKey -> IO [Text] 24peerKeyToResolvedNames :: PeerAddress -> IO [Text]
24peerKeyToResolvedNames k@(ClientKey { localAddress=addr }) = return [] 25peerKeyToResolvedNames (PeerAddress addr)
25peerKeyToResolvedNames k@(PeerKey { callBackAddress=addr }) = do 26 = reverseResolve global_dns_cache addr
26 reverseResolve global_dns_cache addr
27 27
diff --git a/Presence/Presence.hs b/Presence/Presence.hs
index af6597b6..244bbead 100644
--- a/Presence/Presence.hs
+++ b/Presence/Presence.hs
@@ -53,11 +53,13 @@ import Network.Tox.NodeId (key2id)
53import Crypto.Tox (decodeSecret) 53import Crypto.Tox (decodeSecret)
54import DPut 54import DPut
55 55
56isPeerKey :: ConnectionKey -> Bool 56{-
57isPeerKey :: ClientAddress -> Bool
57isPeerKey k = case k of { PeerKey {} -> True ; _ -> False } 58isPeerKey k = case k of { PeerKey {} -> True ; _ -> False }
58 59
59isClientKey :: ConnectionKey -> Bool 60isClientKey :: ClientAddress -> Bool
60isClientKey k = case k of { ClientKey {} -> True ; _ -> False } 61isClientKey k = case k of { ClientKey {} -> True ; _ -> False }
62-}
61 63
62localJID :: Text -> Text -> Text -> IO Text 64localJID :: Text -> Text -> Text -> IO Text
63localJID user "." resource = do 65localJID user "." resource = do
@@ -86,20 +88,21 @@ data ToxManager k = ToxManager
86 } 88 }
87 89
88data PresenceState = forall status. PresenceState 90data PresenceState = forall status. PresenceState
89 { clients :: TVar (Map ConnectionKey ClientState) 91 { clients :: TVar (Map ClientAddress ClientState)
90 , clientsByUser :: TVar (Map Text LocalPresence) 92 , clientsByUser :: TVar (Map Text LocalPresence)
91 , clientsByProfile :: TVar (Map Text LocalPresence) 93 , clientsByProfile :: TVar (Map Text LocalPresence)
92 , remotesByPeer :: TVar (Map ConnectionKey 94 , remotesByPeer :: TVar (Map PeerAddress
93 (Map UserName RemotePresence)) 95 (Map UserName RemotePresence))
94 , server :: TMVar (XMPPServer, Connection.Manager status Text) 96 , server :: TMVar (XMPPServer, Connection.Manager status Text)
95 , keyToChan :: TVar (Map ConnectionKey Conn) 97 , ckeyToChan :: TVar (Map ClientAddress Conn)
98 , pkeyToChan :: TVar (Map PeerAddress Conn)
96 , consoleWriter :: Maybe ConsoleWriter 99 , consoleWriter :: Maybe ConsoleWriter
97 , toxManager :: Maybe (ToxManager ConnectionKey) 100 , toxManager :: Maybe (ToxManager ClientAddress)
98 } 101 }
99 102
100 103
101newPresenceState :: Maybe ConsoleWriter 104newPresenceState :: Maybe ConsoleWriter
102 -> Maybe (PresenceState -> ToxManager ConnectionKey) 105 -> Maybe (PresenceState -> ToxManager ClientAddress)
103 -> TMVar (XMPPServer, Connection.Manager status Text) 106 -> TMVar (XMPPServer, Connection.Manager status Text)
104 -> IO PresenceState 107 -> IO PresenceState
105newPresenceState cw toxman xmpp = atomically $ do 108newPresenceState cw toxman xmpp = atomically $ do
@@ -107,13 +110,15 @@ newPresenceState cw toxman xmpp = atomically $ do
107 clientsByUser <- newTVar Map.empty 110 clientsByUser <- newTVar Map.empty
108 clientsByProfile <- newTVar Map.empty 111 clientsByProfile <- newTVar Map.empty
109 remotesByPeer <- newTVar Map.empty 112 remotesByPeer <- newTVar Map.empty
110 keyToChan <- newTVar Map.empty 113 ckeyToChan <- newTVar Map.empty
114 pkeyToChan <- newTVar Map.empty
111 let st = PresenceState 115 let st = PresenceState
112 { clients = clients 116 { clients = clients
113 , clientsByUser = clientsByUser 117 , clientsByUser = clientsByUser
114 , clientsByProfile = clientsByProfile 118 , clientsByProfile = clientsByProfile
115 , remotesByPeer = remotesByPeer 119 , remotesByPeer = remotesByPeer
116 , keyToChan = keyToChan 120 , ckeyToChan = ckeyToChan
121 , pkeyToChan = pkeyToChan
117 , server = xmpp 122 , server = xmpp
118 , consoleWriter = cw 123 , consoleWriter = cw
119 , toxManager = Nothing 124 , toxManager = Nothing
@@ -121,7 +126,7 @@ newPresenceState cw toxman xmpp = atomically $ do
121 return $ st { toxManager = fmap ($ st) toxman } 126 return $ st { toxManager = fmap ($ st) toxman }
122 127
123 128
124nameForClient :: PresenceState -> ConnectionKey -> IO Text 129nameForClient :: PresenceState -> ClientAddress -> IO Text
125nameForClient state k = do 130nameForClient state k = do
126 mc <- atomically $ do 131 mc <- atomically $ do
127 cmap <- readTVar (clients state) 132 cmap <- readTVar (clients state)
@@ -139,9 +144,8 @@ presenceHooks state verbosity mclient mpeer = XMPPServerParameters
139 { xmppChooseResourceName = chooseResourceName state 144 { xmppChooseResourceName = chooseResourceName state
140 , xmppTellClientHisName = tellClientHisName state 145 , xmppTellClientHisName = tellClientHisName state
141 , xmppTellMyNameToClient = nameForClient state 146 , xmppTellMyNameToClient = nameForClient state
142 , xmppTellMyNameToPeer = \addr -> return $ addrToText addr 147 , xmppTellMyNameToPeer = \(Local addr) -> return $ addrToText addr
143 , xmppTellPeerHisName = return . peerKeyToText 148 , xmppTellPeerHisName = return . peerKeyToText
144 , xmppTellClientNameOfPeer = flip peerKeyToResolvedName
145 , xmppNewConnection = newConn state 149 , xmppNewConnection = newConn state
146 , xmppEOF = eofConn state 150 , xmppEOF = eofConn state
147 , xmppRosterBuddies = rosterGetBuddies state 151 , xmppRosterBuddies = rosterGetBuddies state
@@ -164,7 +168,7 @@ presenceHooks state verbosity mclient mpeer = XMPPServerParameters
164 168
165 169
166data LocalPresence = LocalPresence 170data LocalPresence = LocalPresence
167 { networkClients :: Map ConnectionKey ClientState 171 { networkClients :: Map ClientAddress ClientState
168 -- TODO: loginClients 172 -- TODO: loginClients
169 } 173 }
170 174
@@ -177,18 +181,17 @@ data RemotePresence = RemotePresence
177 181
178 182
179 183
180pcSingletonNetworkClient :: ConnectionKey 184pcSingletonNetworkClient :: ClientAddress -> ClientState -> LocalPresence
181 -> ClientState -> LocalPresence
182pcSingletonNetworkClient key client = 185pcSingletonNetworkClient key client =
183 LocalPresence 186 LocalPresence
184 { networkClients = Map.singleton key client 187 { networkClients = Map.singleton key client
185 } 188 }
186 189
187pcInsertNetworkClient :: ConnectionKey -> ClientState -> LocalPresence -> LocalPresence 190pcInsertNetworkClient :: ClientAddress -> ClientState -> LocalPresence -> LocalPresence
188pcInsertNetworkClient key client pc = 191pcInsertNetworkClient key client pc =
189 pc { networkClients = Map.insert key client (networkClients pc) } 192 pc { networkClients = Map.insert key client (networkClients pc) }
190 193
191pcRemoveNewtworkClient :: ConnectionKey 194pcRemoveNewtworkClient :: ClientAddress
192 -> LocalPresence -> Maybe LocalPresence 195 -> LocalPresence -> Maybe LocalPresence
193pcRemoveNewtworkClient key pc = if pcIsEmpty pc' then Nothing 196pcRemoveNewtworkClient key pc = if pcIsEmpty pc' then Nothing
194 else Just pc' 197 else Just pc'
@@ -215,8 +218,8 @@ identifyTTY' ttypids uid inode = ttypid
215 textify (tty,pid) = (fmap lazyByteStringToText tty, pid) 218 textify (tty,pid) = (fmap lazyByteStringToText tty, pid)
216 219
217chooseResourceName :: PresenceState 220chooseResourceName :: PresenceState
218 -> ConnectionKey -> SockAddr -> Maybe Text -> Maybe Text -> IO Text 221 -> ClientAddress -> Remote SockAddr -> Maybe Text -> Maybe Text -> IO Text
219chooseResourceName state k addr clientsNameForMe desired = do 222chooseResourceName state k (Remote addr) clientsNameForMe desired = do
220 muid <- getLocalPeerCred' addr 223 muid <- getLocalPeerCred' addr
221 (mtty,pid) <- getTTYandPID muid 224 (mtty,pid) <- getTTYandPID muid
222 user <- getJabberUserForId muid 225 user <- getJabberUserForId muid
@@ -297,17 +300,17 @@ chooseResourceName state k addr clientsNameForMe desired = do
297 ) 300 )
298 muid 301 muid
299 302
300-- Perform action with 'ClientState' associated with the given 'ConnectionKey'. 303-- Perform action with 'ClientState' associated with the given 'ClientAddress'.
301-- If there is no associated 'ClientState', then perform the supplied fallback 304-- If there is no associated 'ClientState', then perform the supplied fallback
302-- action. 305-- action.
303forClient :: PresenceState -> ConnectionKey -> IO b -> (ClientState -> IO b) -> IO b 306forClient :: PresenceState -> ClientAddress -> IO b -> (ClientState -> IO b) -> IO b
304forClient state k fallback f = do 307forClient state k fallback f = do
305 mclient <- atomically $ do 308 mclient <- atomically $ do
306 cs <- readTVar (clients state) 309 cs <- readTVar (clients state)
307 return $ Map.lookup k cs 310 return $ Map.lookup k cs
308 maybe fallback f mclient 311 maybe fallback f mclient
309 312
310tellClientHisName :: PresenceState -> ConnectionKey -> IO Text 313tellClientHisName :: PresenceState -> ClientAddress -> IO Text
311tellClientHisName state k = forClient state k fallback go 314tellClientHisName state k = forClient state k fallback go
312 where 315 where
313 fallback = localJID "nobody" "." "fallback" 316 fallback = localJID "nobody" "." "fallback"
@@ -316,14 +319,14 @@ tellClientHisName state k = forClient state k fallback go
316toMapUnit :: Ord k => [k] -> Map k () 319toMapUnit :: Ord k => [k] -> Map k ()
317toMapUnit xs = Map.fromList $ map (,()) xs 320toMapUnit xs = Map.fromList $ map (,()) xs
318 321
319resolveAllPeers :: [Text] -> IO (Map SockAddr ()) 322resolveAllPeers :: [Text] -> IO (Map PeerAddress ())
320resolveAllPeers hosts = fmap (toMapUnit . concat) $ Prelude.mapM (fmap (take 1) . resolvePeer) hosts 323resolveAllPeers hosts = fmap (toMapUnit . concat) $ Prelude.mapM (fmap (take 1) . resolvePeer) hosts
321 324
322 325
323-- Read a roster file and start trying to connect to all relevent peers. 326-- Read a roster file and start trying to connect to all relevent peers.
324rosterGetStuff 327rosterGetStuff
325 :: (ConfigFiles.User -> ConfigFiles.Profile -> IO [L.ByteString]) 328 :: (ConfigFiles.User -> ConfigFiles.Profile -> IO [L.ByteString])
326 -> PresenceState -> ConnectionKey -> IO [Text] 329 -> PresenceState -> ClientAddress -> IO [Text]
327rosterGetStuff what state k = forClient state k (return []) 330rosterGetStuff what state k = forClient state k (return [])
328 $ \client -> do 331 $ \client -> do
329 jids <- configText what (clientUser client) (clientProfile client) 332 jids <- configText what (clientUser client) (clientProfile client)
@@ -335,7 +338,7 @@ rosterGetStuff what state k = forClient state k (return [])
335 -- Grok peers to associate with from the roster: 338 -- Grok peers to associate with from the roster:
336 forM_ hosts $ \host -> do 339 forM_ hosts $ \host -> do
337 -- We need either conns :: Connection.Manager TCPStatus Text 340 -- We need either conns :: Connection.Manager TCPStatus Text
338 -- or toxman :: ToxManager ConnectionKey 341 -- or toxman :: ToxManager ClientAddress
339 -- It is decided by checking hostnames for .tox ending. 342 -- It is decided by checking hostnames for .tox ending.
340 let policySetter = fromMaybe (Connection.setPolicy conns host) $ do 343 let policySetter = fromMaybe (Connection.setPolicy conns host) $ do
341 toxman <- toxManager state 344 toxman <- toxManager state
@@ -346,17 +349,17 @@ rosterGetStuff what state k = forClient state k (return [])
346 atomically $ putTMVar svVar (sv,conns) 349 atomically $ putTMVar svVar (sv,conns)
347 return jids 350 return jids
348 351
349rosterGetBuddies :: PresenceState -> ConnectionKey -> IO [Text] 352rosterGetBuddies :: PresenceState -> ClientAddress -> IO [Text]
350rosterGetBuddies state k = rosterGetStuff ConfigFiles.getBuddies state k 353rosterGetBuddies state k = rosterGetStuff ConfigFiles.getBuddies state k
351 354
352rosterGetSolicited :: PresenceState -> ConnectionKey -> IO [Text] 355rosterGetSolicited :: PresenceState -> ClientAddress -> IO [Text]
353rosterGetSolicited = rosterGetStuff ConfigFiles.getSolicited 356rosterGetSolicited = rosterGetStuff ConfigFiles.getSolicited
354 357
355-- XXX: Should we be connecting to these peers? 358-- XXX: Should we be connecting to these peers?
356rosterGetOthers :: PresenceState -> ConnectionKey -> IO [Text] 359rosterGetOthers :: PresenceState -> ClientAddress -> IO [Text]
357rosterGetOthers = rosterGetStuff ConfigFiles.getOthers 360rosterGetOthers = rosterGetStuff ConfigFiles.getOthers
358 361
359rosterGetSubscribers :: PresenceState -> ConnectionKey -> IO [Text] 362rosterGetSubscribers :: PresenceState -> ClientAddress -> IO [Text]
360rosterGetSubscribers = rosterGetStuff ConfigFiles.getSubscribers 363rosterGetSubscribers = rosterGetStuff ConfigFiles.getSubscribers
361 364
362data Conn = Conn { connChan :: TChan Stanza 365data Conn = Conn { connChan :: TChan Stanza
@@ -413,23 +416,20 @@ getBuddiesAndSolicited state pred
413 -- of (Bool,Text) for processing outside. 416 -- of (Bool,Text) for processing outside.
414 return (isbud,u,user,profile) 417 return (isbud,u,user,profile)
415 418
416sendProbesAndSolicitations :: PresenceState 419sendProbesAndSolicitations :: PresenceState -> PeerAddress -> Local SockAddr -> TChan Stanza -> IO ()
417 -> ConnectionKey -> SockAddr -> TChan Stanza -> IO () 420sendProbesAndSolicitations state k (Local laddr) chan = do
418sendProbesAndSolicitations state k laddr chan = do
419 -- get all buddies & solicited matching k for all users 421 -- get all buddies & solicited matching k for all users
420 xs <- getBuddiesAndSolicited state $ \case 422 xs <- getBuddiesAndSolicited state $ \case
421 h | ".tox" `Text.isSuffixOf` h -> return False -- Tox probes/solicitations are handled in ToxToXMPP module. 423 h | ".tox" `Text.isSuffixOf` h -> return False -- Tox probes/solicitations are handled in ToxToXMPP module.
422 h -> do 424 h -> do
423 addrs <- nub `fmap` resolvePeer h 425 addrs <- nub `fmap` resolvePeer h
424 case k of 426 return $ k `elem` addrs -- Only for this peer /k/.
425 ClientKey _ -> return False -- Solicitations and probes are only for peers.
426 PeerKey a -> return $ a `elem` addrs -- Only for this peer /k/.
427 forM_ xs $ \(isbud,u,user,profile) -> do 427 forM_ xs $ \(isbud,u,user,profile) -> do
428 let make = if isbud then presenceProbe 428 let make = if isbud then presenceProbe
429 else presenceSolicitation 429 else presenceSolicitation
430 toh = peerKeyToText k 430 toh = peerKeyToText k
431 jid = unsplitJID (u,toh,Nothing) 431 jid = unsplitJID (u,toh,Nothing)
432 me = addrToText laddr 432 me = addrToText laddr -- xmppTellMyNameToPeer
433 from = if isbud then me -- probe from server 433 from = if isbud then me -- probe from server
434 else -- solicitation from particular user 434 else -- solicitation from particular user
435 unsplitJID (Just user,me,Nothing) 435 unsplitJID (Just user,me,Nothing)
@@ -439,38 +439,35 @@ sendProbesAndSolicitations state k laddr chan = do
439 atomically $ writeTChan chan stanza 439 atomically $ writeTChan chan stanza
440 -- reverse xs `seq` return () 440 -- reverse xs `seq` return ()
441 441
442newConn :: PresenceState -> ConnectionKey -> ConnectionData -> TChan Stanza -> IO () 442
443newConn state k cdta outchan = do 443newConn :: PresenceState -> SockAddr -> ConnectionData -> TChan Stanza -> IO ()
444 atomically $ modifyTVar' (keyToChan state) 444newConn state saddr cdta outchan =
445 $ Map.insert k Conn { connChan = outchan 445 case classifyConnection saddr cdta of
446 , auxData = cdta } 446 Left (pkey,laddr) -> do
447 when (isPeerKey k) 447 atomically $ modifyTVar' (pkeyToChan state)
448 $ sendProbesAndSolicitations state k (cdAddr cdta) outchan 448 $ Map.insert pkey Conn { connChan = outchan
449 , auxData = cdta }
450 sendProbesAndSolicitations state pkey laddr outchan
451 Right (ckey,_) -> do
452 atomically $ modifyTVar' (ckeyToChan state)
453 $ Map.insert ckey Conn { connChan = outchan
454 , auxData = cdta }
449 455
450delclient :: (Alternative m, Monad m) => 456delclient :: (Alternative m, Monad m) =>
451 ConnectionKey -> m LocalPresence -> m LocalPresence 457 ClientAddress -> m LocalPresence -> m LocalPresence
452delclient k mlp = do 458delclient k mlp = do
453 lp <- mlp 459 lp <- mlp
454 let nc = Map.delete k $ networkClients lp 460 let nc = Map.delete k $ networkClients lp
455 guard $ not (Map.null nc) 461 guard $ not (Map.null nc)
456 return $ lp { networkClients = nc } 462 return $ lp { networkClients = nc }
457 463
458eofConn :: PresenceState -> ConnectionKey -> IO () 464eofConn :: PresenceState -> SockAddr -> ConnectionData -> IO ()
459eofConn state k = do 465eofConn state saddr cdta = do
460 atomically $ modifyTVar' (keyToChan state) $ Map.delete k 466 atomically $ case classifyConnection saddr cdta of
461 case k of 467 Left (pkey,_) -> modifyTVar' (pkeyToChan state) $ Map.delete pkey
462 ClientKey {} -> do 468 Right (ckey,_) -> modifyTVar' (ckeyToChan state) $ Map.delete ckey
463 forClient state k (return ()) $ \client -> do 469 case classifyConnection saddr cdta of
464 forM_ (toxManager state) $ \toxman -> do 470 Left (k,_) -> do
465 case Text.splitAt 43 (clientProfile client) of
466 (pub,".tox") -> deactivateAccount toxman k (clientProfile client)
467 _ -> return ()
468 stanza <- makePresenceStanza "jabber:server" Nothing Offline
469 informClientPresence state k stanza
470 atomically $ do
471 modifyTVar' (clientsByUser state) $ Map.alter (delclient k) (clientUser client)
472 modifyTVar' (clientsByProfile state) $ Map.alter (delclient k) (clientProfile client)
473 PeerKey {} -> do
474 let h = peerKeyToText k 471 let h = peerKeyToText k
475 jids <- atomically $ do 472 jids <- atomically $ do
476 rbp <- readTVar (remotesByPeer state) 473 rbp <- readTVar (remotesByPeer state)
@@ -482,29 +479,26 @@ eofConn state k = do
482 forM_ jids $ \jid -> do 479 forM_ jids $ \jid -> do
483 stanza <- makePresenceStanza "jabber:client" (Just jid) Offline 480 stanza <- makePresenceStanza "jabber:client" (Just jid) Offline
484 informPeerPresence state k stanza 481 informPeerPresence state k stanza
482 Right (k,_) -> do
483 forClient state k (return ()) $ \client -> do
484 forM_ (toxManager state) $ \toxman -> do
485 case Text.splitAt 43 (clientProfile client) of
486 (pub,".tox") -> deactivateAccount toxman k (clientProfile client)
487 _ -> return ()
488 stanza <- makePresenceStanza "jabber:server" Nothing Offline
489 informClientPresence state k stanza
490 atomically $ do
491 modifyTVar' (clientsByUser state) $ Map.alter (delclient k) (clientUser client)
492 modifyTVar' (clientsByProfile state) $ Map.alter (delclient k) (clientProfile client)
485 493
486-- | The given address is taken to be the local address for the socket this JID 494parseRemoteAddress :: Text -> IO (Maybe (Remote SockAddr))
487-- came in on. The returned JID parts are suitable for unsplitJID to create a 495parseRemoteAddress s = fmap Remote <$> parseAddress s
488-- valid JID for communicating to a client. The returned Bool is True when the
489-- host part refers to this local host (i.e. it equals the given SockAddr).
490-- If there are multiple results, it will prefer one which is a member of the
491-- given list in the last argument.
492rewriteJIDForClient :: SockAddr -> Text -> [Text] -> IO (Bool,(Maybe Text,Text,Maybe Text))
493rewriteJIDForClient laddr jid buds = do
494 let (n,h,r) = splitJID jid
495 maddr <- parseAddress (strip_brackets h)
496 fromMaybe (return (False,(n,ip6literal h,r))) $ maddr <&> \addr -> do
497 let mine = laddr `withPort` 0 == addr `withPort` 0
498 h' <- if mine then textHostName
499 else peerKeyToResolvedName buds (PeerKey addr)
500 return (mine,(n,h',r))
501 496
502-- This attempts to reverse resolve a peers address to give the human-friendly 497-- This attempts to reverse resolve a peers address to give the human-friendly
503-- domain name as it appears in the roster. It prefers host names that occur 498-- domain name as it appears in the roster. It prefers host names that occur
504-- in the given list of JIDs, but will fall back to any reverse-resolved name 499-- in the given list of JIDs, but will fall back to any reverse-resolved name
505-- and if it was unable to reverse the address, it will yield an ip address. 500-- and if it was unable to reverse the address, it will yield an ip address.
506peerKeyToResolvedName :: [Text] -> ConnectionKey -> IO Text 501peerKeyToResolvedName :: [Text] -> PeerAddress -> IO Text
507peerKeyToResolvedName buds k@(ClientKey { localAddress=addr }) = return "ErrorClIeNt1"
508peerKeyToResolvedName buds pk = do 502peerKeyToResolvedName buds pk = do
509 ns <- peerKeyToResolvedNames pk 503 ns <- peerKeyToResolvedNames pk
510 let hs = map (\jid -> let (_,h,_)=splitJID jid in h) buds 504 let hs = map (\jid -> let (_,h,_)=splitJID jid in h) buds
@@ -512,27 +506,39 @@ peerKeyToResolvedName buds pk = do
512 return $ fromMaybe (peerKeyToText pk) (listToMaybe ns') 506 return $ fromMaybe (peerKeyToText pk) (listToMaybe ns')
513 507
514 508
509-- | The given address is taken to be the local address for the socket this JID
510-- came in on. The returned JID parts are suitable for unsplitJID to create a
511-- valid JID for communicating to a client. The returned Bool is True when the
512-- host part refers to this local host (i.e. it equals the given SockAddr).
513-- If there are multiple results, it will prefer one which is a member of the
514-- given list in the last argument.
515rewriteJIDForClient :: Local SockAddr -> Text -> [Text] -> IO (Bool,(Maybe Text,Text,Maybe Text))
516rewriteJIDForClient (Local laddr) jid buds = do
517 let (n,h,r) = splitJID jid
518 maddr <- parseAddress (strip_brackets h)
519 fromMaybe (return (False,(n,ip6literal h,r))) $ maddr <&> \saddr -> do
520 let mine = sameAddress laddr saddr
521 h' <- if mine then textHostName
522 else peerKeyToResolvedName buds (addrToPeerKey $ Remote saddr)
523 return (mine,(n,h',r))
524
515-- Given a local address and an IP-address JID, we return True if the JID is 525-- Given a local address and an IP-address JID, we return True if the JID is
516-- local, False otherwise. Additionally, a list of equivalent hostname JIDS 526-- local, False otherwise. Additionally, a list of equivalent hostname JIDS
517-- are returned. 527-- are returned.
518multiplyJIDForClient :: SockAddr -> Text -> IO (Bool,[(Maybe Text,Text,Maybe Text)]) 528multiplyJIDForClient :: ClientAddress -> Text -> IO (Bool,[(Maybe Text,Text,Maybe Text)])
519multiplyJIDForClient laddr jid = do 529multiplyJIDForClient k jid = do
520 let (n,h,r) = splitJID jid 530 let (n,h,r) = splitJID jid
521 maddr <- parseAddress (strip_brackets h) 531 maddr <- parseAddress (strip_brackets h)
522 fromMaybe (return (False,[(n,ip6literal h,r)])) $ maddr <&> \addr -> do 532 fromMaybe (return (False,[(n,ip6literal h,r)])) $ maddr <&> \saddr -> do
523 let mine = sameAddress laddr addr 533 let Local laddr = addrFromClientKey k
534 mine = sameAddress laddr saddr
524 names <- if mine then fmap (:[]) textHostName 535 names <- if mine then fmap (:[]) textHostName
525 else peerKeyToResolvedNames (PeerKey addr) 536 else peerKeyToResolvedNames (addrToPeerKey $ Remote saddr)
526 return (mine,map (\h' -> (n,h',r)) names) 537 return (mine,map (\h' -> (n,h',r)) names)
527 538
528 539
529addrTextToKey :: Text -> IO (Maybe ConnectionKey) 540guardPortStrippedAddress :: Text -> Local SockAddr -> IO (Maybe ())
530addrTextToKey h = do 541guardPortStrippedAddress h (Local laddr) = do
531 maddr <- parseAddress (strip_brackets h)
532 return (fmap PeerKey maddr)
533
534guardPortStrippedAddress :: Text -> SockAddr -> IO (Maybe ())
535guardPortStrippedAddress h laddr = do
536 maddr <- fmap (fmap (`withPort` 0)) $ parseAddress (strip_brackets h) 542 maddr <- fmap (fmap (`withPort` 0)) $ parseAddress (strip_brackets h)
537 let laddr' = laddr `withPort` 0 543 let laddr' = laddr `withPort` 0
538 return $ maddr >>= guard . (==laddr') 544 return $ maddr >>= guard . (==laddr')
@@ -541,15 +547,15 @@ guardPortStrippedAddress h laddr = do
541-- | Accepts a textual representation of a domainname 547-- | Accepts a textual representation of a domainname
542-- JID suitable for client connections, and returns the 548-- JID suitable for client connections, and returns the
543-- coresponding ipv6 address JID suitable for peers paired 549-- coresponding ipv6 address JID suitable for peers paired
544-- with a SockAddr with the address part of that JID in 550-- with a PeerAddress with the address part of that JID in
545-- binary form. If no suitable address could be resolved 551-- binary form. If no suitable address could be resolved
546-- for the given name, Nothing is returned. 552-- for the given name, Nothing is returned.
547rewriteJIDForPeer :: Text -> IO (Maybe (Text,SockAddr)) 553rewriteJIDForPeer :: Text -> IO (Maybe (Text,PeerAddress))
548rewriteJIDForPeer jid = do 554rewriteJIDForPeer jid = do
549 let (n,h,r) = splitJID jid 555 let (n,h,r) = splitJID jid
550 maddr <- fmap listToMaybe $ resolvePeer h 556 maddr <- fmap listToMaybe $ resolvePeer h
551 return $ flip fmap maddr $ \addr -> 557 return $ flip fmap maddr $ \addr ->
552 let h' = addrToText addr 558 let h' = peerKeyToText addr
553 to' = unsplitJID (n,h',r) 559 to' = unsplitJID (n,h',r)
554 in (to',addr) 560 in (to',addr)
555 561
@@ -567,14 +573,15 @@ deliverMessage :: PresenceState
567 -> IO () 573 -> IO ()
568deliverMessage state fail msg = 574deliverMessage state fail msg =
569 case stanzaOrigin msg of 575 case stanzaOrigin msg of
570 NetworkOrigin senderk@(ClientKey {}) _ -> do 576 ClientOrigin senderk _ -> do
571 -- Case 1. Client -> Peer 577 -- Case 1. Client -> Peer
572 mto <- fmap join $ mapM rewriteJIDForPeer (stanzaTo msg) 578 mto <- fmap join $ mapM rewriteJIDForPeer (stanzaTo msg)
573 fromMaybe fail {- reverse lookup failure -} $ mto <&> \(to',addr) -> do 579 fromMaybe fail {- reverse lookup failure -} $ mto <&> \(to',k) -> do
574 let k = PeerKey addr 580 chans <- atomically $ readTVar (pkeyToChan state)
575 chans <- atomically $ readTVar (keyToChan state) 581 fromMaybe fail $ (Map.lookup k chans) <&> \Conn { connChan = chan
576 fromMaybe fail $ (Map.lookup k chans) <&> \(Conn { connChan = chan 582 , auxData = ConnectionData (Left (Local laddr))
577 , auxData = ConnectionData laddr ctyp }) -> do 583 ctyp
584 } -> do
578 (n,r) <- forClient state senderk (return (Nothing,Nothing)) 585 (n,r) <- forClient state senderk (return (Nothing,Nothing))
579 $ \c -> return (Just (clientUser c), Just (clientResource c)) 586 $ \c -> return (Just (clientUser c), Just (clientResource c))
580 -- original 'from' address is discarded. 587 -- original 'from' address is discarded.
@@ -582,11 +589,14 @@ deliverMessage state fail msg =
582 -- dup <- atomically $ cloneStanza (msg { stanzaTo=Just to', stanzaFrom=Just from' }) 589 -- dup <- atomically $ cloneStanza (msg { stanzaTo=Just to', stanzaFrom=Just from' })
583 let dup = (msg { stanzaTo=Just to', stanzaFrom=Just from' }) 590 let dup = (msg { stanzaTo=Just to', stanzaFrom=Just from' })
584 sendModifiedStanzaToPeer dup chan 591 sendModifiedStanzaToPeer dup chan
585 NetworkOrigin senderk@(PeerKey {}) _ -> do 592 PeerOrigin senderk _ -> do
586 key_to_chan <- atomically $ readTVar (keyToChan state) 593 (pchans,cchans) <- atomically $ do
587 fromMaybe fail $ (Map.lookup senderk key_to_chan) 594 pc <- readTVar (pkeyToChan state)
595 cc <- readTVar (ckeyToChan state)
596 return (pc,cc)
597 fromMaybe fail $ (Map.lookup senderk pchans)
588 <&> \(Conn { connChan = sender_chan 598 <&> \(Conn { connChan = sender_chan
589 , auxData = ConnectionData laddr ctyp }) -> do 599 , auxData = ConnectionData (Left laddr) ctyp }) -> do
590 fromMaybe fail $ (stanzaTo msg) <&> \to -> do 600 fromMaybe fail $ (stanzaTo msg) <&> \to -> do
591 (mine,(n,h,r)) <- rewriteJIDForClient laddr to [] 601 (mine,(n,h,r)) <- rewriteJIDForClient laddr to []
592 if not mine then fail else do 602 if not mine then fail else do
@@ -600,7 +610,7 @@ deliverMessage state fail msg =
600 let ks = Map.keys (networkClients presence_container) 610 let ks = Map.keys (networkClients presence_container)
601 chans = do 611 chans = do
602 (k,client) <- Map.toList $ networkClients presence_container 612 (k,client) <- Map.toList $ networkClients presence_container
603 chan <- maybeToList $ Map.lookup k key_to_chan 613 chan <- maybeToList $ Map.lookup k cchans
604 return (clientProfile client, clientUser client, chan) 614 return (clientProfile client, clientUser client, chan)
605 forM chans $ \(profile,user,chan) -> do 615 forM chans $ \(profile,user,chan) -> do
606 buds <- configText ConfigFiles.getBuddies user profile 616 buds <- configText ConfigFiles.getBuddies user profile
@@ -642,7 +652,7 @@ deliverMessage state fail msg =
642 chan 652 chan
643 653
644 654
645setClientFlag :: PresenceState -> ConnectionKey -> Int8 -> IO () 655setClientFlag :: PresenceState -> ClientAddress -> Int8 -> IO ()
646setClientFlag state k flag = 656setClientFlag state k flag =
647 atomically $ do 657 atomically $ do
648 cmap <- readTVar (clients state) 658 cmap <- readTVar (clients state)
@@ -653,12 +663,12 @@ setClientFlag0 :: ClientState -> Int8 -> STM ()
653setClientFlag0 client flag = 663setClientFlag0 client flag =
654 modifyTVar' (clientFlags client) (\flgs -> flgs .|. flag) 664 modifyTVar' (clientFlags client) (\flgs -> flgs .|. flag)
655 665
656informSentRoster :: PresenceState -> ConnectionKey -> IO () 666informSentRoster :: PresenceState -> ClientAddress -> IO ()
657informSentRoster state k = do 667informSentRoster state k = do
658 setClientFlag state k cf_interested 668 setClientFlag state k cf_interested
659 669
660 670
661subscribedPeers :: Text -> Text -> IO [SockAddr] 671subscribedPeers :: Text -> Text -> IO [PeerAddress]
662subscribedPeers user profile = do 672subscribedPeers user profile = do
663 jids <- configText ConfigFiles.getSubscribers user profile 673 jids <- configText ConfigFiles.getSubscribers user profile
664 let hosts = map ((\(_,h,_)->h) . splitJID) jids 674 let hosts = map ((\(_,h,_)->h) . splitJID) jids
@@ -667,20 +677,23 @@ subscribedPeers user profile = do
667-- | this JID is suitable for peers, not clients. 677-- | this JID is suitable for peers, not clients.
668clientJID :: Conn -> ClientState -> Text 678clientJID :: Conn -> ClientState -> Text
669clientJID con client = unsplitJID ( Just $ clientUser client 679clientJID con client = unsplitJID ( Just $ clientUser client
670 , addrToText $ cdAddr $ auxData con 680 , either (\(Local a) -> addrToText a) -- my host name, for peers
681 (error $ unlines [ "clientJID wrongly used for client connection!"
682 , "TODO: my host name for clients? nameForClient? localJID?"])
683 $ cdAddr $ auxData con
671 , Just $ clientResource client) 684 , Just $ clientResource client)
672 685
673-- | Send presence notification to subscribed peers. 686-- | Send presence notification to subscribed peers.
674-- Note that a full JID from address will be added to the 687-- Note that a full JID from address will be added to the
675-- stanza if it is not present. 688-- stanza if it is not present.
676informClientPresence :: PresenceState 689informClientPresence :: PresenceState
677 -> ConnectionKey -> StanzaWrap (LockedChan Event) -> IO () 690 -> ClientAddress -> StanzaWrap (LockedChan Event) -> IO ()
678informClientPresence state k stanza = do 691informClientPresence state k stanza = do
679 forClient state k (return ()) $ \client -> do 692 forClient state k (return ()) $ \client -> do
680 informClientPresence0 state (Just k) client stanza 693 informClientPresence0 state (Just k) client stanza
681 694
682informClientPresence0 :: PresenceState 695informClientPresence0 :: PresenceState
683 -> Maybe ConnectionKey 696 -> Maybe ClientAddress
684 -> ClientState 697 -> ClientState
685 -> StanzaWrap (LockedChan Event) 698 -> StanzaWrap (LockedChan Event)
686 -> IO () 699 -> IO ()
@@ -692,8 +705,8 @@ informClientPresence0 state mbk client stanza = do
692 atomically $ setClientFlag0 client cf_available 705 atomically $ setClientFlag0 client cf_available
693 maybe (return ()) (sendCachedPresence state) mbk 706 maybe (return ()) (sendCachedPresence state) mbk
694 addrs <- subscribedPeers (clientUser client) (clientProfile client) 707 addrs <- subscribedPeers (clientUser client) (clientProfile client)
695 ktc <- atomically $ readTVar (keyToChan state) 708 ktc <- atomically $ readTVar (pkeyToChan state)
696 let connected = mapMaybe (flip Map.lookup ktc . PeerKey) addrs 709 let connected = mapMaybe (flip Map.lookup ktc) addrs
697 forM_ connected $ \con -> do 710 forM_ connected $ \con -> do
698 let from' = clientJID con client 711 let from' = clientJID con client
699 mto <- runTraversableT $ do 712 mto <- runTraversableT $ do
@@ -706,7 +719,7 @@ informClientPresence0 state mbk client stanza = do
706 (connChan con) 719 (connChan con)
707 720
708informPeerPresence :: PresenceState 721informPeerPresence :: PresenceState
709 -> ConnectionKey 722 -> PeerAddress
710 -> StanzaWrap (LockedChan Event) 723 -> StanzaWrap (LockedChan Event)
711 -> IO () 724 -> IO ()
712informPeerPresence state k stanza = do 725informPeerPresence state k stanza = do
@@ -749,7 +762,7 @@ informPeerPresence state k stanza = do
749 762
750 -- all clients, we'll filter available/authorized later 763 -- all clients, we'll filter available/authorized later
751 764
752 ktc <- readTVar (keyToChan state) 765 ktc <- readTVar (ckeyToChan state)
753 runTraversableT $ do 766 runTraversableT $ do
754 (ck,client) <- liftMT $ fmap Map.toList $ readTVar (clients state) 767 (ck,client) <- liftMT $ fmap Map.toList $ readTVar (clients state)
755 con <- liftMaybe $ Map.lookup ck ktc 768 con <- liftMaybe $ Map.lookup ck ktc
@@ -762,8 +775,7 @@ informPeerPresence state k stanza = do
762 when is_avail $ do 775 when is_avail $ do
763 putStrLn $ "reversing for client: " ++ show from 776 putStrLn $ "reversing for client: " ++ show from
764 froms <- do -- flip (maybe $ return [from]) k . const $ do 777 froms <- do -- flip (maybe $ return [from]) k . const $ do
765 let ClientKey laddr = ck 778 (_,trip) <- multiplyJIDForClient ck from
766 (_,trip) <- multiplyJIDForClient laddr from
767 return (map unsplitJID trip) 779 return (map unsplitJID trip)
768 780
769 putStrLn $ "sending to client: " ++ show (stanzaType stanza,froms) 781 putStrLn $ "sending to client: " ++ show (stanzaType stanza,froms)
@@ -777,35 +789,37 @@ consoleClients PresenceState{ consoleWriter = Just cw } = readTVar (cwClients cw
777consoleClients _ = return Map.empty 789consoleClients _ = return Map.empty
778 790
779 791
780answerProbe :: PresenceState 792answerProbe :: PresenceState -> Maybe Text -> PeerAddress -> TChan Stanza -> IO ()
781 -> Maybe Text -> ConnectionKey -> TChan Stanza -> IO ()
782answerProbe state mto k chan = do 793answerProbe state mto k chan = do
783 -- putStrLn $ "answerProbe! " ++ show (stanzaType stanza) 794 -- putStrLn $ "answerProbe! " ++ show (stanzaType stanza)
784 (ktc,cmap) <- atomically $ (,) <$> readTVar (keyToChan state) 795 ktc <- atomically $ readTVar (pkeyToChan state)
785 <*> readTVar (clients state)
786 muser <- runTraversableT $ do 796 muser <- runTraversableT $ do
787 to <- liftT $ mto 797 to <- liftT $ mto
788 conn <- liftT $ Map.lookup k ktc 798 conn <- liftT $ Map.lookup k ktc
789 let (mu,h,_) = splitJID to -- TODO: currently resource-id is ignored on presence 799 let (mu,h,_) = splitJID to -- TODO: currently resource-id is ignored on presence
790 -- probes. Is this correct? Check the spec. 800 -- probes. Is this correct? Check the spec.
791 liftMT $ guardPortStrippedAddress h (cdAddr $ auxData conn) 801 Left laddr = cdAddr $ auxData conn
802 liftMT $ guardPortStrippedAddress h laddr
792 u <- liftT mu 803 u <- liftT mu
793 let ch = addrToText (cdAddr $ auxData conn) 804 -- ORIG let ch = addrToText (auxAddr conn)
794 profile = fromMaybe "." $ clientProfile <$> Map.lookup k cmap 805 -- ORIG return (u,conn,ch)
795 return (u,profile,conn,ch) 806 let ch = addrToText a where Local a = laddr
807 return (u,conn,ch)
796 808
797 forM_ muser $ \(u,profile,conn,ch) -> do 809 forM_ muser $ \(u,conn,ch) -> do
798 810
811 profiles <- releventProfiles (cdType $ auxData conn) u
812 forM_ profiles $ \profile -> do
813
814 -- only subscribed peers should get probe replies
799 resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u profile 815 resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u profile
800 let gaddrs = groupBy (\a b -> snd a == snd b) (sort resolved_subs) 816 let gaddrs = groupBy sameHost (sort resolved_subs)
817 sameHost a b = (snd a == snd b) -- (==) `on` snd
801 whitelist = do 818 whitelist = do
802 xs <- gaddrs 819 xs <- gaddrs -- group of subscribed jids on the same host
803 x <- take 1 xs 820 x <- take 1 xs -- the host from the group
804 guard $ snd x==k 821 guard $ snd x==k -- only hosts matching the key /k/
805 mapMaybe fst xs 822 mapMaybe fst xs -- all users subscribed at the remote peer /k/
806
807 -- -- only subscribed peers should get probe replies
808 -- addrs <- subscribedPeers u
809 823
810 -- TODO: notify remote peer that they are unsubscribed? 824 -- TODO: notify remote peer that they are unsubscribed?
811 -- reply <- makeInformSubscription "jabber:server" to from False 825 -- reply <- makeInformSubscription "jabber:server" to from False
@@ -838,16 +852,15 @@ answerProbe state mto k chan = do
838 852
839-- Send friend requests and remote presences stored in remotesByPeer to XMPP 853-- Send friend requests and remote presences stored in remotesByPeer to XMPP
840-- clients. 854-- clients.
841sendCachedPresence :: PresenceState -> ConnectionKey -> IO () 855sendCachedPresence :: PresenceState -> ClientAddress -> IO ()
842sendCachedPresence state k = do 856sendCachedPresence state k = do
843 forClient state k (return ()) $ \client -> do 857 forClient state k (return ()) $ \client -> do
844 rbp <- atomically $ readTVar (remotesByPeer state) 858 rbp <- atomically $ readTVar (remotesByPeer state)
845 jids <- configText ConfigFiles.getBuddies (clientUser client) (clientProfile client) 859 jids <- configText ConfigFiles.getBuddies (clientUser client) (clientProfile client)
846 let hosts = map ((\(_,h,_)->h) . splitJID) jids 860 let hosts = map ((\(_,h,_)->h) . splitJID) jids
847 addrs <- resolveAllPeers hosts 861 addrs <- resolveAllPeers hosts
848 let onlines = rbp `Map.intersection` Map.mapKeys PeerKey addrs 862 let onlines = rbp `Map.intersection` addrs
849 ClientKey laddr = k 863 mcon <- atomically $ do ktc <- readTVar (ckeyToChan state)
850 mcon <- atomically $ do ktc <- readTVar (keyToChan state)
851 return $ Map.lookup k ktc 864 return $ Map.lookup k ktc
852 forM_ mcon $ \con -> do 865 forM_ mcon $ \con -> do
853 forM_ (Map.toList onlines) $ \(pk, umap) -> do 866 forM_ (Map.toList onlines) $ \(pk, umap) -> do
@@ -855,7 +868,7 @@ sendCachedPresence state k = do
855 let h = peerKeyToText pk 868 let h = peerKeyToText pk
856 forM_ (Map.toList $ resources rp) $ \(resource,stanza) -> do 869 forM_ (Map.toList $ resources rp) $ \(resource,stanza) -> do
857 let jid = unsplitJID (Just user,h,Just resource) 870 let jid = unsplitJID (Just user,h,Just resource)
858 (mine,js) <- multiplyJIDForClient laddr jid 871 (mine,js) <- multiplyJIDForClient k jid
859 forM_ js $ \jid -> do 872 forM_ js $ \jid -> do
860 let from' = unsplitJID jid 873 let from' = unsplitJID jid
861 dup <- cloneStanza stanza 874 dup <- cloneStanza stanza
@@ -883,7 +896,7 @@ addToRosterFile ::
883 -> t1) 896 -> t1)
884 -> Text -- user 897 -> Text -- user
885 -> Text -- profile 898 -> Text -- profile
886 -> Text -> [SockAddr] -> t1 899 -> Text -> [PeerAddress] -> t1
887addToRosterFile doit whose profile to addrs = 900addToRosterFile doit whose profile to addrs =
888 modifyRosterFile doit whose profile to addrs True 901 modifyRosterFile doit whose profile to addrs True
889 902
@@ -895,7 +908,7 @@ removeFromRosterFile ::
895 -> t1) 908 -> t1)
896 -> Text -- user 909 -> Text -- user
897 -> Text -- profile 910 -> Text -- profile
898 -> Text -> [SockAddr] -> t1 911 -> Text -> [PeerAddress] -> t1
899removeFromRosterFile doit whose profile to addrs = 912removeFromRosterFile doit whose profile to addrs =
900 modifyRosterFile doit whose profile to addrs False 913 modifyRosterFile doit whose profile to addrs False
901 914
@@ -920,7 +933,7 @@ modifyRosterFile ::
920 -> Text -- ^ user 933 -> Text -- ^ user
921 -> Text -- ^ profile 934 -> Text -- ^ profile
922 -> Text -- ^ JID that will be added or removed a hostname 935 -> Text -- ^ JID that will be added or removed a hostname
923 -> [SockAddr] -- ^ Alias addresses for hostname in the JID. 936 -> [PeerAddress] -- ^ Alias addresses for hostname in the JID.
924 -> Bool -- ^ True if adding, otherwise False 937 -> Bool -- ^ True if adding, otherwise False
925 -> t1 938 -> t1
926modifyRosterFile doit whose profile to addrs bAdd = do 939modifyRosterFile doit whose profile to addrs bAdd = do
@@ -951,7 +964,7 @@ modifyRosterFile doit whose profile to addrs bAdd = do
951 (guard bAdd >> Just (textToLazyByteString to)) 964 (guard bAdd >> Just (textToLazyByteString to))
952 965
953 966
954clientSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () 967clientSubscriptionRequest :: PresenceState -> IO () -> ClientAddress -> Stanza -> TChan Stanza -> IO ()
955clientSubscriptionRequest state fail k stanza chan = do 968clientSubscriptionRequest state fail k stanza chan = do
956 forClient state k fail $ \client -> do 969 forClient state k fail $ \client -> do
957 fromMaybe fail $ (splitJID <$> stanzaTo stanza) <&> \(mu,h,_) -> do 970 fromMaybe fail $ (splitJID <$> stanzaTo stanza) <&> \(mu,h,_) -> do
@@ -967,7 +980,7 @@ clientSubscriptionRequest state fail k stanza chan = do
967 addToRosterFile ConfigFiles.modifySolicited cuser cprof to addrs 980 addToRosterFile ConfigFiles.modifySolicited cuser cprof to addrs
968 removeFromRosterFile ConfigFiles.modifyBuddies cuser cprof to addrs 981 removeFromRosterFile ConfigFiles.modifyBuddies cuser cprof to addrs
969 resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers cuser cprof 982 resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers cuser cprof
970 let is_subscribed = not . null $ [ (mu, PeerKey a) | a <- addrs ] 983 let is_subscribed = not . null $ [ (mu, a) | a <- addrs ]
971 `intersect` resolved_subs 984 `intersect` resolved_subs
972 -- subscribers: "from" 985 -- subscribers: "from"
973 -- buddies: "to" 986 -- buddies: "to"
@@ -975,16 +988,18 @@ clientSubscriptionRequest state fail k stanza chan = do
975 case state of 988 case state of
976 PresenceState { server = svVar } -> do 989 PresenceState { server = svVar } -> do
977 990
978 (ktc,(sv,conns)) <- atomically $ 991 (cktc,pktc,(sv,conns)) <- atomically $ do
979 liftM2 (,) (readTVar $ keyToChan state) 992 cktc <- readTVar $ ckeyToChan state
980 (takeTMVar svVar) 993 pktc <- readTVar $ pkeyToChan state
994 sc <- takeTMVar svVar
995 return (cktc,pktc,sc)
981 996
982 -- Update roster for each client. 997 -- Update roster for each client.
983 case stanzaType stanza of 998 case stanzaType stanza of
984 PresenceRequestSubscription True -> do 999 PresenceRequestSubscription True -> do
985 hostname <- nameForClient state k 1000 hostname <- nameForClient state k
986 let cjid = unsplitJID (Just $ clientUser client, hostname,Nothing) 1001 let cjid = unsplitJID (Just $ clientUser client, hostname,Nothing)
987 chans <- clientCons state ktc (clientUser client) 1002 chans <- clientCons state cktc (clientUser client)
988 forM_ chans $ \( Conn { connChan=chan }, client ) -> do 1003 forM_ chans $ \( Conn { connChan=chan }, client ) -> do
989 -- roster update ask="subscribe" 1004 -- roster update ask="subscribe"
990 update <- makeRosterUpdate cjid to 1005 update <- makeRosterUpdate cjid to
@@ -996,13 +1011,13 @@ clientSubscriptionRequest state fail k stanza chan = do
996 _ -> return () 1011 _ -> return ()
997 1012
998 -- Send friend request to peer. 1013 -- Send friend request to peer.
999 let dsts = ktc `Map.intersection` 1014 let dsts = pktc `Map.intersection` toMapUnit addrs
1000 Map.fromList [ (PeerKey a, ()) | a <- addrs ]
1001 forM_ (Map.toList dsts) $ \(pk,con) -> do 1015 forM_ (Map.toList dsts) $ \(pk,con) -> do
1002 -- if already connected, send solicitation ... 1016 -- if already connected, send solicitation ...
1003 -- let from = clientJID con client 1017 -- let from = clientJID con client
1004 let from = unsplitJID ( Just $ clientUser client 1018 let Left laddr = cdAddr $ auxData con
1005 , addrToText $ cdAddr $ auxData con 1019 from = unsplitJID ( Just $ clientUser client
1020 , (\(Local a) -> addrToText a) $ laddr
1006 , Nothing ) 1021 , Nothing )
1007 mb <- rewriteJIDForPeer to 1022 mb <- rewriteJIDForPeer to
1008 forM_ mb $ \(to',addr) -> do 1023 forM_ mb $ \(to',addr) -> do
@@ -1022,20 +1037,20 @@ clientSubscriptionRequest state fail k stanza chan = do
1022 1037
1023resolvedFromRoster 1038resolvedFromRoster
1024 :: (ConfigFiles.User -> ConfigFiles.Profile -> IO [L.ByteString]) 1039 :: (ConfigFiles.User -> ConfigFiles.Profile -> IO [L.ByteString])
1025 -> UserName -> Text -> IO [(Maybe UserName, ConnectionKey)] 1040 -> UserName -> Text -> IO [(Maybe UserName, PeerAddress)]
1026resolvedFromRoster doit u profile = do 1041resolvedFromRoster doit u profile = do
1027 subs <- configText doit u profile 1042 subs <- configText doit u profile
1028 runTraversableT $ do 1043 runTraversableT $ do
1029 (mu,h,_) <- liftT $ splitJID `fmap` subs 1044 (mu,h,_) <- liftT $ splitJID `fmap` subs
1030 addr <- liftMT $ fmap nub $ resolvePeer h 1045 addr <- liftMT $ fmap nub $ resolvePeer h
1031 return (mu,PeerKey addr) 1046 return (mu,addr)
1032 1047
1033clientCons :: PresenceState 1048clientCons :: PresenceState
1034 -> Map ConnectionKey t -> Text -> IO [(t, ClientState)] 1049 -> Map ClientAddress t -> Text -> IO [(t, ClientState)]
1035clientCons state ktc u = map snd <$> clientCons' state ktc u 1050clientCons state ktc u = map snd <$> clientCons' state ktc u
1036 1051
1037clientCons' :: PresenceState 1052clientCons' :: PresenceState
1038 -> Map ConnectionKey t -> Text -> IO [(ConnectionKey,(t, ClientState))] 1053 -> Map ClientAddress t -> Text -> IO [(ClientAddress,(t, ClientState))]
1039clientCons' state ktc u = do 1054clientCons' state ktc u = do
1040 mlp <- atomically $ do 1055 mlp <- atomically $ do
1041 cmap <- readTVar $ clientsByUser state 1056 cmap <- readTVar $ clientsByUser state
@@ -1047,7 +1062,14 @@ clientCons' state ktc u = do
1047 return (k,(con,client)) 1062 return (k,(con,client))
1048 return $ mapMaybe doit ks 1063 return $ mapMaybe doit ks
1049 1064
1050peerSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () 1065releventProfiles :: ConnectionType -> Text -> IO [Text]
1066releventProfiles XMPP _ = return ["."]
1067releventProfiles ctyp user = do
1068 -- TODO: Return all the ".tox" profiles that a user has under his
1069 -- .presence/ directory.
1070 return []
1071
1072peerSubscriptionRequest :: PresenceState -> IO () -> PeerAddress -> Stanza -> TChan Stanza -> IO ()
1051peerSubscriptionRequest state fail k stanza chan = do 1073peerSubscriptionRequest state fail k stanza chan = do
1052 putStrLn $ "Handling pending subscription from remote" 1074 putStrLn $ "Handling pending subscription from remote"
1053 fromMaybe fail $ (stanzaFrom stanza) <&> \from -> do 1075 fromMaybe fail $ (stanzaFrom stanza) <&> \from -> do
@@ -1056,24 +1078,20 @@ peerSubscriptionRequest state fail k stanza chan = do
1056 (mfrom_u,from_h,_) = splitJID from 1078 (mfrom_u,from_h,_) = splitJID from
1057 to <- return $ unsplitJID (mto_u,h,Nothing) -- delete resource 1079 to <- return $ unsplitJID (mto_u,h,Nothing) -- delete resource
1058 from <- return $ unsplitJID (mfrom_u,from_h,Nothing) -- delete resource 1080 from <- return $ unsplitJID (mfrom_u,from_h,Nothing) -- delete resource
1059 (ktc,cmap) <- atomically $ (,) <$> readTVar (keyToChan state) 1081 (pktc,cktc,cmap) <- atomically $ do
1060 <*> readTVar (clients state) 1082 cktc <- readTVar (ckeyToChan state)
1061 fromMaybe fail $ (Map.lookup k ktc) 1083 pktc <- readTVar (pkeyToChan state)
1062 <&> \Conn { auxData=ConnectionData laddr ctyp } -> do 1084 cmap <- readTVar (clients state)
1085 return (pktc,cktc,cmap)
1086 fromMaybe fail $ (Map.lookup k pktc)
1087 <&> \Conn { auxData=ConnectionData (Left laddr) ctyp } -> do
1063 (mine,totup) <- rewriteJIDForClient laddr to [] 1088 (mine,totup) <- rewriteJIDForClient laddr to []
1064 if not mine then fail else do 1089 if not mine then fail else do
1065 (_,fromtup) <- rewriteJIDForClient laddr from [] 1090 (_,fromtup) <- rewriteJIDForClient laddr from []
1066 fromMaybe fail $ mto_u <&> \u -> do 1091 fromMaybe fail $ mto_u <&> \u -> do
1067 fromMaybe fail $ mfrom_u <&> \from_u -> do 1092 fromMaybe fail $ mfrom_u <&> \from_u -> do
1068 let profile = fromMaybe "." $ clientProfile <$> Map.lookup k cmap 1093 profiles <- releventProfiles ctyp u
1069 -- XXX profile is wrong. 1094 forM_ profiles $ \profile -> do
1070 -- TODO Likely the problem is that k is a peer ConnectionKey and of course
1071 -- will have no entry in the cmap. Thus giving "." even though it ought
1072 -- to be using a tox profile.
1073 --
1074 -- Solution 1: Only .tox peers go in a tox profile.
1075 -- Solution 2: Duplicate non .tox peers in all profiles.
1076 -- Solution 3: Only one profile is active at a time.
1077 resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u profile 1095 resolved_subs <- resolvedFromRoster ConfigFiles.getSubscribers u profile
1078 let already_subscribed = elem (mfrom_u,k) resolved_subs 1096 let already_subscribed = elem (mfrom_u,k) resolved_subs
1079 is_wanted = case stanzaType stanza of 1097 is_wanted = case stanzaType stanza of
@@ -1116,7 +1134,7 @@ peerSubscriptionRequest state fail k stanza chan = do
1116 when (not already_pending) $ do 1134 when (not already_pending) $ do
1117 -- contact ∉ subscribers & contact ∉ pending --> MUST 1135 -- contact ∉ subscribers & contact ∉ pending --> MUST
1118 1136
1119 chans <- clientCons state ktc u 1137 chans <- clientCons state cktc u
1120 forM_ chans $ \( Conn { connChan=chan }, client ) -> do 1138 forM_ chans $ \( Conn { connChan=chan }, client ) -> do
1121 -- send to clients 1139 -- send to clients
1122 -- TODO: interested/available clients only? 1140 -- TODO: interested/available clients only?
@@ -1128,7 +1146,7 @@ peerSubscriptionRequest state fail k stanza chan = do
1128 1146
1129clientInformSubscription :: PresenceState 1147clientInformSubscription :: PresenceState
1130 -> IO () 1148 -> IO ()
1131 -> ConnectionKey 1149 -> ClientAddress
1132 -> StanzaWrap (LockedChan Event) 1150 -> StanzaWrap (LockedChan Event)
1133 -> IO () 1151 -> IO ()
1134clientInformSubscription state fail k stanza = do 1152clientInformSubscription state fail k stanza = do
@@ -1139,7 +1157,7 @@ clientInformSubscription state fail k stanza = do
1139 addrs <- resolvePeer h 1157 addrs <- resolvePeer h
1140 -- remove from pending 1158 -- remove from pending
1141 buds <- resolvedFromRoster ConfigFiles.getBuddies (clientUser client) (clientProfile client) 1159 buds <- resolvedFromRoster ConfigFiles.getBuddies (clientUser client) (clientProfile client)
1142 let is_buddy = not . null $ map ((mu,) . PeerKey) addrs `intersect` buds 1160 let is_buddy = not . null $ map (mu,) addrs `intersect` buds
1143 removeFromRosterFile ConfigFiles.modifyPending (clientUser client) (clientProfile client) to addrs 1161 removeFromRosterFile ConfigFiles.modifyPending (clientUser client) (clientProfile client) to addrs
1144 let (relationship,addf,remf) = 1162 let (relationship,addf,remf) =
1145 case stanzaType stanza of 1163 case stanzaType stanza of
@@ -1160,12 +1178,13 @@ clientInformSubscription state fail k stanza = do
1160 putStrLn $ "cbu = " ++ show (fmap (fmap clientPid . networkClients) cbu) 1178 putStrLn $ "cbu = " ++ show (fmap (fmap clientPid . networkClients) cbu)
1161 1179
1162 -- send roster update to clients 1180 -- send roster update to clients
1163 (clients,ktc) <- atomically $ do 1181 (clients,ktc,pktc) <- atomically $ do
1164 cbu <- readTVar (clientsByUser state) 1182 cbu <- readTVar (clientsByUser state)
1165 let mlp = Map.lookup (clientUser client) cbu 1183 let mlp = Map.lookup (clientUser client) cbu
1166 let cs = maybe [] (Map.toList . networkClients) mlp 1184 let cs = maybe [] (Map.toList . networkClients) mlp
1167 ktc <- readTVar (keyToChan state) 1185 ktc <- readTVar (ckeyToChan state)
1168 return (cs,ktc) 1186 pktc <- readTVar (pkeyToChan state)
1187 return (cs,ktc,pktc)
1169 forM_ clients $ \(ck, client) -> do 1188 forM_ clients $ \(ck, client) -> do
1170 is_intereseted <- atomically $ clientIsInterested client 1189 is_intereseted <- atomically $ clientIsInterested client
1171 putStrLn $ "clientIsInterested: "++show is_intereseted 1190 putStrLn $ "clientIsInterested: "++show is_intereseted
@@ -1179,8 +1198,8 @@ clientInformSubscription state fail k stanza = do
1179 sendModifiedStanzaToClient update (connChan con) 1198 sendModifiedStanzaToClient update (connChan con)
1180 1199
1181 -- notify peer 1200 -- notify peer
1182 let dsts = Map.fromList $ map ((,()) . PeerKey) addrs 1201 let dsts = toMapUnit addrs
1183 cdsts = ktc `Map.intersection` dsts 1202 cdsts = pktc `Map.intersection` dsts
1184 forM_ (Map.toList cdsts) $ \(pk,con) -> do 1203 forM_ (Map.toList cdsts) $ \(pk,con) -> do
1185 let from = clientJID con client 1204 let from = clientJID con client
1186 to' = unsplitJID (mu, peerKeyToText pk, Nothing) 1205 to' = unsplitJID (mu, peerKeyToText pk, Nothing)
@@ -1192,18 +1211,21 @@ clientInformSubscription state fail k stanza = do
1192 1211
1193peerInformSubscription :: PresenceState 1212peerInformSubscription :: PresenceState
1194 -> IO () 1213 -> IO ()
1195 -> ConnectionKey 1214 -> PeerAddress
1196 -> StanzaWrap (LockedChan Event) 1215 -> StanzaWrap (LockedChan Event)
1197 -> IO () 1216 -> IO ()
1198peerInformSubscription state fail k stanza = do 1217peerInformSubscription state fail k stanza = do
1199 putStrLn $ "TODO: peerInformSubscription" 1218 putStrLn $ "TODO: peerInformSubscription"
1200 -- remove from solicited 1219 -- remove from solicited
1201 fromMaybe fail $ (stanzaFrom stanza) <&> \from -> do 1220 fromMaybe fail $ (stanzaFrom stanza) <&> \from -> do
1202 (ktc,cmap) <- atomically $ (,) <$> readTVar (keyToChan state) 1221 (ktc,cktc,cmap) <- atomically $ do
1203 <*> readTVar (clients state) 1222 pktc <- readTVar (pkeyToChan state)
1223 cktc <- readTVar (ckeyToChan state)
1224 cmap <- readTVar (clients state)
1225 return (pktc,cktc,cmap)
1204 fromMaybe fail $ (Map.lookup k ktc) 1226 fromMaybe fail $ (Map.lookup k ktc)
1205 <&> \(Conn { connChan=sender_chan 1227 <&> \(Conn { connChan=sender_chan
1206 , auxData =ConnectionData laddr ctyp }) -> do 1228 , auxData =ConnectionData (Left laddr) ctyp }) -> do
1207 (_,(from_u,from_h,_)) <- rewriteJIDForClient laddr from [] 1229 (_,(from_u,from_h,_)) <- rewriteJIDForClient laddr from []
1208 let from'' = unsplitJID (from_u,from_h,Nothing) 1230 let from'' = unsplitJID (from_u,from_h,Nothing)
1209 muser = do 1231 muser = do
@@ -1215,10 +1237,11 @@ peerInformSubscription state fail k stanza = do
1215 -- This would allow us to answer anonymous probes with 'unsubscribed'. 1237 -- This would allow us to answer anonymous probes with 'unsubscribed'.
1216 fromMaybe fail $ muser <&> \user -> do 1238 fromMaybe fail $ muser <&> \user -> do
1217 addrs <- resolvePeer from_h 1239 addrs <- resolvePeer from_h
1218 let profile = fromMaybe "." $ clientProfile <$> Map.lookup k cmap 1240 profiles <- releventProfiles ctyp user
1241 forM_ profiles $ \profile -> do
1219 was_solicited <- removeFromRosterFile ConfigFiles.modifySolicited user profile from'' addrs 1242 was_solicited <- removeFromRosterFile ConfigFiles.modifySolicited user profile from'' addrs
1220 subs <- resolvedFromRoster ConfigFiles.getSubscribers user profile 1243 subs <- resolvedFromRoster ConfigFiles.getSubscribers user profile
1221 let is_sub = not . null $ map ((from_u,) . PeerKey) addrs `intersect` subs 1244 let is_sub = not . null $ map (from_u,) addrs `intersect` subs
1222 putStrLn $ "DEBUG peerInformSubscription (is_sub,typ)=" ++ show (is_sub,stanzaType stanza) 1245 putStrLn $ "DEBUG peerInformSubscription (is_sub,typ)=" ++ show (is_sub,stanzaType stanza)
1223 let (relationship,addf,remf) = 1246 let (relationship,addf,remf) =
1224 case stanzaType stanza of 1247 case stanzaType stanza of
@@ -1234,7 +1257,7 @@ peerInformSubscription state fail k stanza = do
1234 addToRosterFile addf user profile from'' addrs 1257 addToRosterFile addf user profile from'' addrs
1235 removeFromRosterFile remf user profile from'' addrs 1258 removeFromRosterFile remf user profile from'' addrs
1236 1259
1237 chans <- clientCons' state ktc user 1260 chans <- clientCons' state cktc user
1238 forM_ chans $ \(ckey,(Conn { connChan=chan }, client)) -> do 1261 forM_ chans $ \(ckey,(Conn { connChan=chan }, client)) -> do
1239 hostname <- nameForClient state ckey 1262 hostname <- nameForClient state ckey
1240 let to' = unsplitJID (Just user, hostname, Nothing) 1263 let to' = unsplitJID (Just user, hostname, Nothing)
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs
index 8d294698..1de6a26a 100644
--- a/Presence/XMPPServer.hs
+++ b/Presence/XMPPServer.hs
@@ -7,11 +7,17 @@
7module XMPPServer 7module XMPPServer
8 ( xmppServer 8 ( xmppServer
9 , quitXmpp 9 , quitXmpp
10 , ConnectionKey(..) 10 , ClientAddress
11 , PeerAddress
12 , Local(..)
13 , Remote(..)
11 , ConnectionData(..) 14 , ConnectionData(..)
12 , ConnectionType(..) 15 , ConnectionType(..)
13 , XMPPServerParameters(..) 16 , XMPPServerParameters(..)
14 , XMPPServer 17 , XMPPServer
18 , classifyConnection
19 , addrToPeerKey
20 , addrFromClientKey
15 , xmppConnections 21 , xmppConnections
16 , xmppEventChannel 22 , xmppEventChannel
17 , StanzaWrap(..) 23 , StanzaWrap(..)
@@ -85,7 +91,7 @@ import Data.XML.Types as XML
85import Data.Maybe 91import Data.Maybe
86import Data.Monoid ( (<>) ) 92import Data.Monoid ( (<>) )
87import Data.Text (Text) 93import Data.Text (Text)
88import qualified Data.Text as Text (pack,unpack,words,intercalate) 94import qualified Data.Text as Text (pack,unpack,words,intercalate,drop)
89import Data.Char (chr,ord) 95import Data.Char (chr,ord)
90import qualified Data.Map as Map 96import qualified Data.Map as Map
91import Data.Set (Set, (\\) ) 97import Data.Set (Set, (\\) )
@@ -167,7 +173,10 @@ data StanzaType
167 | InternalCacheId Text 173 | InternalCacheId Text
168 deriving (Show,Eq) 174 deriving (Show,Eq)
169 175
170data StanzaOrigin = LocalPeer | NetworkOrigin ConnectionKey (TChan Stanza) 176data StanzaOrigin = LocalPeer
177 | PeerOrigin PeerAddress (TChan Stanza)
178 | ClientOrigin ClientAddress (TChan Stanza)
179
171 180
172data StanzaWrap a = Stanza 181data StanzaWrap a = Stanza
173 { stanzaType :: StanzaType 182 { stanzaType :: StanzaType
@@ -182,6 +191,9 @@ data StanzaWrap a = Stanza
182 191
183type Stanza = StanzaWrap (LockedChan XML.Event) 192type Stanza = StanzaWrap (LockedChan XML.Event)
184 193
194newtype Local a = Local a deriving (Eq,Ord,Show)
195newtype Remote a = Remote a deriving (Eq,Ord,Show)
196
185data XMPPServerParameters = 197data XMPPServerParameters =
186 XMPPServerParameters 198 XMPPServerParameters
187 { -- | Called when a client requests a resource id. The first Maybe indicates 199 { -- | Called when a client requests a resource id. The first Maybe indicates
@@ -190,36 +202,35 @@ data XMPPServerParameters =
190 -- 202 --
191 -- Note: The returned domain will be discarded and replaced with the result of 203 -- Note: The returned domain will be discarded and replaced with the result of
192 -- 'xmppTellMyNameToClient'. 204 -- 'xmppTellMyNameToClient'.
193 xmppChooseResourceName :: ConnectionKey -> SockAddr -> Maybe Text -> Maybe Text -> IO Text 205 xmppChooseResourceName :: ClientAddress -> Remote SockAddr -> Maybe Text -> Maybe Text -> IO Text
194 , -- | This should indicate the server's hostname that all client's see. 206 , -- | This should indicate the server's hostname that all client's see.
195 xmppTellMyNameToClient :: ConnectionKey -> IO Text 207 xmppTellMyNameToClient :: ClientAddress -> IO Text
196 , xmppTellMyNameToPeer :: SockAddr -> IO Text 208 , xmppTellMyNameToPeer :: Local SockAddr -> IO Text
197 , xmppTellClientHisName :: ConnectionKey -> IO Text 209 , xmppTellClientHisName :: ClientAddress -> IO Text
198 , xmppTellPeerHisName :: ConnectionKey -> IO Text 210 , xmppTellPeerHisName :: PeerAddress -> IO Text
199 , xmppNewConnection :: ConnectionKey -> ConnectionData -> TChan Stanza -> IO () 211 , xmppNewConnection :: SockAddr -> ConnectionData -> TChan Stanza -> IO ()
200 , xmppEOF :: ConnectionKey -> IO () 212 , xmppEOF :: SockAddr -> ConnectionData -> IO ()
201 , xmppRosterBuddies :: ConnectionKey -> IO [Text] 213 , xmppRosterBuddies :: ClientAddress -> IO [Text]
202 , xmppRosterSubscribers :: ConnectionKey -> IO [Text] 214 , xmppRosterSubscribers :: ClientAddress -> IO [Text]
203 , xmppRosterSolicited :: ConnectionKey -> IO [Text] 215 , xmppRosterSolicited :: ClientAddress -> IO [Text]
204 , xmppRosterOthers :: ConnectionKey -> IO [Text] 216 , xmppRosterOthers :: ClientAddress -> IO [Text]
205 , -- | Called when after sending a roster to a client. Usually this means 217 , -- | Called when after sending a roster to a client. Usually this means
206 -- the client status should change from "available" to "interested". 218 -- the client status should change from "available" to "interested".
207 xmppSubscribeToRoster :: ConnectionKey -> IO () 219 xmppSubscribeToRoster :: ClientAddress -> IO ()
208 -- , xmppLookupClientJID :: ConnectionKey -> IO Text 220 -- , xmppLookupClientJID :: SockAddr -> IO Text
209 , xmppTellClientNameOfPeer :: ConnectionKey -> [Text] -> IO Text
210 , xmppDeliverMessage :: (IO ()) -> Stanza -> IO () 221 , xmppDeliverMessage :: (IO ()) -> Stanza -> IO ()
211 -- | Called whenever a local client's presence changes. 222 -- | Called whenever a local client's presence changes.
212 , xmppInformClientPresence :: ConnectionKey -> Stanza -> IO () 223 , xmppInformClientPresence :: ClientAddress -> Stanza -> IO ()
213 -- | Called whenever a remote peer's presence changes. 224 -- | Called whenever a remote peer's presence changes.
214 , xmppInformPeerPresence :: ConnectionKey -> Stanza -> IO () 225 , xmppInformPeerPresence :: PeerAddress -> Stanza -> IO ()
215 , -- | Called when a remote peer requests our status. 226 , -- | Called when a remote peer requests our status.
216 xmppAnswerProbe :: ConnectionKey -> Stanza -> TChan Stanza -> IO () 227 xmppAnswerProbe :: PeerAddress -> Stanza -> TChan Stanza -> IO ()
217 , xmppClientSubscriptionRequest :: IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () 228 , xmppClientSubscriptionRequest :: IO () -> ClientAddress -> Stanza -> TChan Stanza -> IO ()
218 , -- | Called when a remote peer sends subscription request. 229 , -- | Called when a remote peer sends subscription request.
219 xmppPeerSubscriptionRequest :: IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () 230 xmppPeerSubscriptionRequest :: IO () -> PeerAddress -> Stanza -> TChan Stanza -> IO ()
220 , xmppClientInformSubscription :: IO () -> ConnectionKey -> Stanza -> IO () 231 , xmppClientInformSubscription :: IO () -> ClientAddress -> Stanza -> IO ()
221 , -- | Called when a remote peer informs us of our subscription status. 232 , -- | Called when a remote peer informs us of our subscription status.
222 xmppPeerInformSubscription :: IO () -> ConnectionKey -> Stanza -> IO () 233 xmppPeerInformSubscription :: IO () -> PeerAddress -> Stanza -> IO ()
223 , xmppVerbosity :: IO Int 234 , xmppVerbosity :: IO Int
224 , xmppClientBind :: Maybe SockAddr 235 , xmppClientBind :: Maybe SockAddr
225 , xmppPeerBind :: Maybe SockAddr 236 , xmppPeerBind :: Maybe SockAddr
@@ -270,10 +281,9 @@ addrToText (addr@(SockAddrInet6 _ _ _ _)) = Text.pack $ stripColon (show addr)
270 where 281 where
271 (pre,bracket) = break (==']') s 282 (pre,bracket) = break (==']') s
272 283
273-- Shows (as Text) the IP address associated with the given ConnectionKey. 284-- Shows (as Text) the IP address associated with the given SockAddr.
274peerKeyToText :: ConnectionKey -> Text 285peerKeyToText :: PeerAddress -> Text
275peerKeyToText (PeerKey { callBackAddress=addr }) = addrToText addr 286peerKeyToText (PeerAddress addr) = addrToText addr
276peerKeyToText (ClientKey { localAddress=addr }) = "ErrorClIeNt0"
277 287
278 288
279wlog :: String -> IO () 289wlog :: String -> IO ()
@@ -895,26 +905,17 @@ makePong namespace mid to from =
895 , EventEndElement (mkname namespace "iq") 905 , EventEndElement (mkname namespace "iq")
896 ] 906 ]
897 907
908data ClientOrPeer = IsClient | IsPeer
898 909
899xmppInbound :: Server ConnectionKey ConnectionData releaseKey XML.Event 910xmppInbound :: Server SockAddr ConnectionData releaseKey XML.Event -- ^ XXX: unused
900 -> XMPPServerParameters 911 -> XMPPServerParameters -- ^ XXX: unused
901 -> ConnectionKey 912 -> (Text, IO Text, IO Text, TChan Stanza -> StanzaOrigin)
902 -> SockAddr 913 -> FlagCommand -- ^ action to check whether the connection needs a ping (XXX: unused)
903 -> FlagCommand -- ^ action to check whether the connection needs a ping
904 -> TChan Stanza -- ^ channel to announce incoming stanzas on 914 -> TChan Stanza -- ^ channel to announce incoming stanzas on
905 -> TChan Stanza -- ^ channel used to send stanzas 915 -> TChan Stanza -- ^ channel used to send stanzas
906 -> TMVar () -- ^ mvar that is filled when the connection quits 916 -> TMVar () -- ^ mvar that is filled when the connection quits
907 -> Sink XML.Event IO () 917 -> ConduitM Event o IO ()
908xmppInbound sv xmpp k laddr pingflag stanzas output donevar = doNestingXML $ do 918xmppInbound sv xmpp (namespace,tellmyname,tellyourname,mkorigin) pingflag stanzas output donevar = doNestingXML $ do
909 let (namespace,tellmyname,tellyourname) = case k of
910 ClientKey {} -> ( "jabber:client"
911 , xmppTellMyNameToClient xmpp k
912 , xmppTellClientHisName xmpp k
913 )
914 PeerKey {} -> ( "jabber:server"
915 , xmppTellMyNameToPeer xmpp laddr
916 , xmppTellPeerHisName xmpp k
917 )
918 me <- liftIO tellmyname 919 me <- liftIO tellmyname
919 withXML $ \begindoc -> do 920 withXML $ \begindoc -> do
920 when (begindoc==EventBeginDocument) $ do 921 when (begindoc==EventBeginDocument) $ do
@@ -948,7 +949,7 @@ xmppInbound sv xmpp k laddr pingflag stanzas output donevar = doNestingXML $ do
948 , stanzaChan = chan 949 , stanzaChan = chan
949 , stanzaClosers = clsrs 950 , stanzaClosers = clsrs
950 , stanzaInterrupt = donevar 951 , stanzaInterrupt = donevar
951 , stanzaOrigin = NetworkOrigin k output 952 , stanzaOrigin = mkorigin output
952 } 953 }
953 ioWriteChan stanzas s 954 ioWriteChan stanzas s
954 you <- liftIO tellyourname 955 you <- liftIO tellyourname
@@ -973,7 +974,7 @@ xmppInbound sv xmpp k laddr pingflag stanzas output donevar = doNestingXML $ do
973 , stanzaChan = chan 974 , stanzaChan = chan
974 , stanzaClosers = clsrs 975 , stanzaClosers = clsrs
975 , stanzaInterrupt = donevar 976 , stanzaInterrupt = donevar
976 , stanzaOrigin = NetworkOrigin k output 977 , stanzaOrigin = mkorigin output
977 } 978 }
978#endif 979#endif
979 stype -> ioWriteChan stanzas Stanza 980 stype -> ioWriteChan stanzas Stanza
@@ -986,7 +987,7 @@ xmppInbound sv xmpp k laddr pingflag stanzas output donevar = doNestingXML $ do
986 , stanzaChan = chan 987 , stanzaChan = chan
987 , stanzaClosers = clsrs 988 , stanzaClosers = clsrs
988 , stanzaInterrupt = donevar 989 , stanzaInterrupt = donevar
989 , stanzaOrigin = NetworkOrigin k output 990 , stanzaOrigin = mkorigin output
990 } 991 }
991 awaitCloser stanza_lvl 992 awaitCloser stanza_lvl
992 liftIO . atomically $ writeTVar clsrs Nothing 993 liftIO . atomically $ writeTVar clsrs Nothing
@@ -1244,19 +1245,23 @@ slotsToSource slots nesting lastStanza needsFlush rdone =
1244 ,readTMVar rdone >> return (return ()) 1245 ,readTMVar rdone >> return (return ())
1245 ] 1246 ]
1246 1247
1247forkConnection :: Server ConnectionKey ConnectionData releaseKey XML.Event 1248forkConnection :: Server SockAddr ConnectionData releaseKey XML.Event
1248 -> XMPPServerParameters 1249 -> XMPPServerParameters
1249 -> ConnectionKey 1250 -> SockAddr -- SockAddr (remote for peer, local for client)
1250 -> ConnectionData 1251 -> ConnectionData
1251 -> FlagCommand 1252 -> FlagCommand
1252 -> Source IO XML.Event 1253 -> Source IO XML.Event
1253 -> Sink (Flush XML.Event) IO () 1254 -> Sink (Flush XML.Event) IO ()
1254 -> TChan Stanza 1255 -> TChan Stanza
1255 -> IO (TChan Stanza) 1256 -> IO (TChan Stanza)
1256forkConnection sv xmpp k (ConnectionData laddr _) pingflag src snk stanzas = do 1257forkConnection sv xmpp saddr (ConnectionData auxAddr _) pingflag src snk stanzas = do
1257 let (namespace,tellmyname) = case k of 1258 let clientOrServer@(namespace,tellmyname,telltheirname,_) = case auxAddr of
1258 ClientKey {} -> ("jabber:client", xmppTellMyNameToClient xmpp k) 1259 Right _ -> ("jabber:client", xmppTellMyNameToClient xmpp (ClientAddress saddr)
1259 PeerKey {} -> ("jabber:server",xmppTellMyNameToPeer xmpp laddr) 1260 , xmppTellClientHisName xmpp (ClientAddress saddr)
1261 , ClientOrigin (ClientAddress saddr))
1262 Left laddr -> ("jabber:server", xmppTellMyNameToPeer xmpp laddr
1263 , xmppTellPeerHisName xmpp (PeerAddress saddr)
1264 , PeerOrigin (PeerAddress saddr))
1260 me <- tellmyname 1265 me <- tellmyname
1261 rdone <- atomically newEmptyTMVar 1266 rdone <- atomically newEmptyTMVar
1262 let isStarter (Left _) = True 1267 let isStarter (Left _) = True
@@ -1274,7 +1279,11 @@ forkConnection sv xmpp k (ConnectionData laddr _) pingflag src snk stanzas = do
1274 CL.sourceList (greet' namespace me) =$= CL.map Chunk 1279 CL.sourceList (greet' namespace me) =$= CL.map Chunk
1275 yield Flush 1280 yield Flush
1276 slot_src = slotsToSource slots nesting lastStanza needsFlush rdone 1281 slot_src = slotsToSource slots nesting lastStanza needsFlush rdone
1277 forkIO $ do myThreadId >>= flip labelThread ("post-queue."++show k) 1282 let lbl n = concat [ n
1283 , Text.unpack (Text.drop 7 namespace)
1284 , "."
1285 , show saddr ]
1286 forkIO $ do myThreadId >>= flip labelThread (lbl "post-queue.")
1278 (greet_src >> slot_src) $$ snk 1287 (greet_src >> slot_src) $$ snk
1279 last <- atomically $ readTVar lastStanza 1288 last <- atomically $ readTVar lastStanza
1280 es <- while (atomically . fmap not $ Slotted.isEmpty slots) 1289 es <- while (atomically . fmap not $ Slotted.isEmpty slots)
@@ -1298,14 +1307,14 @@ forkConnection sv xmpp k (ConnectionData laddr _) pingflag src snk stanzas = do
1298 _ -> True 1307 _ -> True
1299 -- TODO: Probably some stanzas should be queued or saved for re-connect. 1308 -- TODO: Probably some stanzas should be queued or saved for re-connect.
1300 mapM_ fail $ filter notError (maybeToList last ++ es') 1309 mapM_ fail $ filter notError (maybeToList last ++ es')
1301 wlog $ "end post-queue fork: " ++ show k 1310 wlog $ "end post-queue fork: " ++ (lbl "")
1302 1311
1303 output <- atomically newTChan 1312 output <- atomically newTChan
1304 hacks <- atomically $ newTVar Map.empty 1313 hacks <- atomically $ newTVar Map.empty
1305 msgids <- atomically $ newTVar [] 1314 msgids <- atomically $ newTVar []
1306 forkIO $ do 1315 forkIO $ do
1307 -- mapM_ (atomically . Slotted.push slots Nothing) greetPeer 1316 -- mapM_ (atomically . Slotted.push slots Nothing) greetPeer
1308 myThreadId >>= flip labelThread ("pre-queue."++show k) 1317 myThreadId >>= flip labelThread (lbl "pre-queue.")
1309 verbosity <- xmppVerbosity xmpp 1318 verbosity <- xmppVerbosity xmpp
1310 fix $ \loop -> do 1319 fix $ \loop -> do
1311 what <- atomically $ foldr1 orElse 1320 what <- atomically $ foldr1 orElse
@@ -1320,9 +1329,9 @@ forkConnection sv xmpp k (ConnectionData laddr _) pingflag src snk stanzas = do
1320 notping $ do 1329 notping $ do
1321 dup <- cloneStanza stanza 1330 dup <- cloneStanza stanza
1322 let typ = Strict8.pack $ c ++ "<-"++(concat . take 1 . words $ show (stanzaType dup))++" " 1331 let typ = Strict8.pack $ c ++ "<-"++(concat . take 1 . words $ show (stanzaType dup))++" "
1323 c = case k of 1332 c = case auxAddr of
1324 ClientKey {} -> "C" 1333 Right _ -> "C"
1325 PeerKey {} -> "P" 1334 Left _ -> "P"
1326 wlog "" 1335 wlog ""
1327 stanzaToConduit dup $$ prettyPrint typ 1336 stanzaToConduit dup $$ prettyPrint typ
1328 -- wlog $ "hacks: "++show (stanzaId stanza) 1337 -- wlog $ "hacks: "++show (stanzaId stanza)
@@ -1360,7 +1369,7 @@ forkConnection sv xmpp k (ConnectionData laddr _) pingflag src snk stanzas = do
1360 loop 1369 loop
1361 ,do pingflag >>= check 1370 ,do pingflag >>= check
1362 return $ do 1371 return $ do
1363 to <- xmppTellPeerHisName xmpp k -- addrToText (callBackAddress k) 1372 to <- telltheirname
1364 let from = me -- Look it up from Server object 1373 let from = me -- Look it up from Server object
1365 -- or pass it with Connection event. 1374 -- or pass it with Connection event.
1366 mid = Just "ping" 1375 mid = Just "ping"
@@ -1368,23 +1377,21 @@ forkConnection sv xmpp k (ConnectionData laddr _) pingflag src snk stanzas = do
1368 ping <- atomically $ wrapStanzaList ping0 1377 ping <- atomically $ wrapStanzaList ping0
1369 mapM_ (atomically . Slotted.push slots (Just $ PingSlot)) 1378 mapM_ (atomically . Slotted.push slots (Just $ PingSlot))
1370 ping 1379 ping
1371#ifdef PINGNOISE
1372 wlog "" 1380 wlog ""
1373 CL.sourceList ping0 $$ prettyPrint $ case k of 1381 CL.sourceList ping0 $$ prettyPrint $ case auxAddr of
1374 ClientKey {} -> "C<-Ping" 1382 Right _ -> "C<-Ping"
1375 PeerKey {} -> "P<-Ping " 1383 Left _ -> "P<-Ping "
1376#endif
1377 loop 1384 loop
1378 ,readTMVar rdone >> return (return ()) 1385 ,readTMVar rdone >> return (return ())
1379 ] 1386 ]
1380 what 1387 what
1381 wlog $ "end pre-queue fork: " ++ show k 1388 wlog $ "end pre-queue fork: " ++ show (lbl "")
1382 forkIO $ do 1389 forkIO $ do
1383 myThreadId >>= flip labelThread ("reader."++show k) 1390 myThreadId >>= flip labelThread (lbl "reader.")
1384 -- src $$ awaitForever (lift . putStrLn . takeWhile (/=' ') . show) 1391 -- src $$ awaitForever (lift . putStrLn . takeWhile (/=' ') . show)
1385 src $$ xmppInbound sv xmpp k laddr pingflag stanzas output rdone 1392 src $$ xmppInbound sv xmpp clientOrServer pingflag stanzas output rdone
1386 atomically $ putTMVar rdone () 1393 atomically $ putTMVar rdone ()
1387 wlog $ "end reader fork: " ++ show k 1394 wlog $ "end reader fork: " ++ lbl ""
1388 return output 1395 return output
1389 1396
1390{- 1397{-
@@ -1398,22 +1405,22 @@ data PeerState
1398 | PeerConnected (TChan Stanza) 1405 | PeerConnected (TChan Stanza)
1399-} 1406-}
1400 1407
1401peerKey :: SocketLike sock => Maybe SockAddr -> sock -> IO (ConnectionKey,ConnectionData) 1408peerKey :: SocketLike sock => Maybe SockAddr -> sock -> IO (SockAddr,ConnectionData)
1402peerKey outgoingPeerPort sock = do 1409peerKey bind_addr sock = do
1403 addr <- getSocketName sock 1410 laddr <- getSocketName sock
1404 peer <- 1411 raddr <-
1405 sIsConnected sock >>= \c -> 1412 sIsConnected sock >>= \c ->
1406 if c then getPeerName sock -- addr is normally socketName 1413 if c then getPeerName sock -- addr is normally socketName
1407 else return addr -- Weird hack: addr is would-be peer name 1414 else return laddr -- Weird hack: addr is would-be peer name
1408 laddr <- getSocketName sock 1415 -- Assume remote peers are listening on the same port that we do.
1409 let peerport = fromMaybe 5269 $ outgoingPeerPort >>= sockAddrPort 1416 let peerport = fromIntegral $ fromMaybe 5269 $ bind_addr >>= sockAddrPort
1410 return $ (PeerKey (peer `withPort` fromIntegral peerport),ConnectionData laddr XMPP) 1417 return $ (raddr `withPort` peerport,ConnectionData (Left (Local laddr)) XMPP)
1411 1418
1412clientKey :: SocketLike sock => sock -> IO (ConnectionKey,ConnectionData) 1419clientKey :: SocketLike sock => sock -> IO (SockAddr,ConnectionData)
1413clientKey sock = do 1420clientKey sock = do
1414 addr <- getSocketName sock 1421 laddr <- getSocketName sock
1415 paddr <- getPeerName sock 1422 raddr <- getPeerName sock
1416 return $ (ClientKey addr,ConnectionData paddr XMPP) 1423 return $ (laddr,ConnectionData (Right (Remote raddr)) XMPP)
1417 1424
1418xmlifyRosterItems :: Monad m => Set Text -> Text -> Set Text -> ConduitM i Event m () 1425xmlifyRosterItems :: Monad m => Set Text -> Text -> Set Text -> ConduitM i Event m ()
1419xmlifyRosterItems solicited stype set = mapM_ item (Set.toList set) 1426xmlifyRosterItems solicited stype set = mapM_ item (Set.toList set)
@@ -1429,14 +1436,15 @@ xmlifyRosterItems solicited stype set = mapM_ item (Set.toList set)
1429sendRoster :: 1436sendRoster ::
1430 StanzaWrap a 1437 StanzaWrap a
1431 -> XMPPServerParameters 1438 -> XMPPServerParameters
1432 -> ConnectionKey 1439 -> ClientAddress
1433 -> TChan Stanza 1440 -> TChan Stanza
1434 -> IO () 1441 -> IO ()
1435sendRoster query xmpp clientKey replyto = do 1442sendRoster query xmpp clientKey replyto = do
1436 let k = case stanzaOrigin query of 1443 let maddr = case stanzaOrigin query of
1437 NetworkOrigin k _ -> Just k 1444 ClientOrigin addr _ -> Just addr
1438 LocalPeer -> Nothing -- local peer requested roster? 1445 PeerOrigin {} -> Nothing -- remote peer requested roster?
1439 forM_ k $ \k -> do 1446 LocalPeer -> Nothing -- local peer requested roster?
1447 forM_ maddr $ \k -> do
1440 hostname <- xmppTellMyNameToClient xmpp clientKey 1448 hostname <- xmppTellMyNameToClient xmpp clientKey
1441 let getlist f = do 1449 let getlist f = do
1442 bs <- f xmpp k 1450 bs <- f xmpp k
@@ -1445,9 +1453,7 @@ sendRoster query xmpp clientKey replyto = do
1445 subscribers <- getlist xmppRosterSubscribers 1453 subscribers <- getlist xmppRosterSubscribers
1446 solicited <- getlist xmppRosterSolicited 1454 solicited <- getlist xmppRosterSolicited
1447 subnone0 <- getlist xmppRosterOthers 1455 subnone0 <- getlist xmppRosterOthers
1448 jid <- case k of 1456 jid <- xmppTellClientHisName xmpp k -- LookupClientJID xmpp k
1449 ClientKey {} -> xmppTellClientHisName xmpp k -- LookupClientJID xmpp k
1450 PeerKey {} -> xmppTellClientNameOfPeer xmpp k (Set.toList buddies)
1451 let subnone = Set.union solicited subnone0 \\ Set.union buddies subscribers 1457 let subnone = Set.union solicited subnone0 \\ Set.union buddies subscribers
1452 let subto = buddies \\ subscribers 1458 let subto = buddies \\ subscribers
1453 let subfrom = subscribers \\ buddies 1459 let subfrom = subscribers \\ buddies
@@ -1482,17 +1488,14 @@ sendRoster query xmpp clientKey replyto = do
1482 -} 1488 -}
1483 1489
1484 1490
1485socketFromKey :: Server ConnectionKey ConnectionData releaseKey XML.Event -> ConnectionKey -> IO SockAddr 1491socketFromKey :: Server SockAddr ConnectionData releaseKey XML.Event -> ClientAddress -> IO (Remote SockAddr)
1486socketFromKey sv k = do 1492socketFromKey sv (ClientAddress addr) = do
1487 map <- atomically $ readTVar (conmap sv) 1493 map <- atomically $ readTVar (conmap sv)
1488 let mcd = Map.lookup k map 1494 let mcd = Map.lookup addr map
1495 oops = Remote addr -- No connection data, so using incorrect address.
1489 case mcd of 1496 case mcd of
1490 Nothing -> case k of 1497 Nothing -> return oops
1491 ClientKey addr -> return addr 1498 Just cd -> return $ either (const oops) id $ cdAddr $ cdata cd
1492 PeerKey addr -> return addr
1493 -- XXX: ? wrong address
1494 -- Shouldnt happen anyway.
1495 Just cd -> return $ cdAddr $ cdata cd
1496 1499
1497class StanzaFirstTag a where 1500class StanzaFirstTag a where
1498 stanzaFirstTag :: StanzaWrap a -> IO XML.Event 1501 stanzaFirstTag :: StanzaWrap a -> IO XML.Event
@@ -1652,8 +1655,8 @@ makeErrorStanza stanza = do
1652 ] 1655 ]
1653 1656
1654monitor :: 1657monitor ::
1655 Server ConnectionKey ConnectionData releaseKey XML.Event 1658 Server SockAddr ConnectionData releaseKey XML.Event
1656 -> ConnectionParameters ConnectionKey ConnectionData 1659 -> ConnectionParameters SockAddr ConnectionData
1657 -> XMPPServerParameters 1660 -> XMPPServerParameters
1658 -> IO b 1661 -> IO b
1659monitor sv params xmpp = do 1662monitor sv params xmpp = do
@@ -1662,20 +1665,25 @@ monitor sv params xmpp = do
1662 quitVar <- atomically newEmptyTMVar 1665 quitVar <- atomically newEmptyTMVar
1663 fix $ \loop -> do 1666 fix $ \loop -> do
1664 action <- atomically $ foldr1 orElse 1667 action <- atomically $ foldr1 orElse
1665 [ readTChan chan >>= \((k,u),e) -> return $ do 1668 [ readTChan chan >>= \((addr,u),e) -> return $ do
1666 case e of 1669 case e of
1667 Connection pingflag xsrc xsnk -> do 1670 Connection pingflag xsrc xsnk
1668 wlog $ tomsg k "Connection" 1671 -> do wlog $ tomsg addr "Connection"
1669 outs <- forkConnection sv xmpp k u pingflag xsrc xsnk stanzas 1672 outs <- forkConnection sv xmpp addr u pingflag xsrc xsnk stanzas
1670 xmppNewConnection xmpp k u outs 1673 xmppNewConnection xmpp addr u outs
1671 ConnectFailure addr -> return () -- wlog $ tomsg k "ConnectFailure" 1674 ConnectFailure addr
1672 EOF -> do wlog $ tomsg k "EOF" 1675 -> do return () -- wlog $ tomsg k "ConnectFailure"
1673 xmppEOF xmpp k 1676 EOF -> do wlog $ tomsg addr "EOF"
1674 HalfConnection In -> do 1677 xmppEOF xmpp addr u
1675 wlog $ tomsg k "ReadOnly" 1678 HalfConnection In
1676 control sv (Connect (callBackAddress k) params) 1679 -> do wlog $ tomsg addr "ReadOnly"
1677 HalfConnection Out -> wlog $ tomsg k "WriteOnly" 1680 case cdAddr u of
1678 RequiresPing -> return () -- wlog $ tomsg k "RequiresPing" 1681 Left (Local _) -> control sv (Connect addr params)
1682 _ -> return () -- Don't call-back client connections.
1683 HalfConnection Out
1684 -> do wlog $ tomsg addr "WriteOnly"
1685 RequiresPing
1686 -> do return () -- wlog $ tomsg k "RequiresPing"
1679 , readTChan stanzas >>= \stanza -> return $ do 1687 , readTChan stanzas >>= \stanza -> return $ do
1680 {- 1688 {-
1681 dup <- case stanzaType stanza of 1689 dup <- case stanzaType stanza of
@@ -1692,7 +1700,7 @@ monitor sv params xmpp = do
1692 1700
1693 forkIO $ do 1701 forkIO $ do
1694 case stanzaOrigin stanza of 1702 case stanzaOrigin stanza of
1695 NetworkOrigin k@(ClientKey {}) replyto -> 1703 ClientOrigin k replyto ->
1696 case stanzaType stanza of 1704 case stanzaType stanza of
1697 RequestResource clientsNameForMe wanted -> do 1705 RequestResource clientsNameForMe wanted -> do
1698 sockaddr <- socketFromKey sv k 1706 sockaddr <- socketFromKey sv k
@@ -1755,7 +1763,7 @@ monitor sv params xmpp = do
1755 guard . not . null . mapMaybe (msgBody . snd) $ msgLangMap (stanzaType stanza) 1763 guard . not . null . mapMaybe (msgBody . snd) $ msgLangMap (stanzaType stanza)
1756 stanzaId stanza 1764 stanzaId stanza
1757 _ -> return () 1765 _ -> return ()
1758 NetworkOrigin k@(PeerKey {}) replyto -> 1766 PeerOrigin k replyto ->
1759 case stanzaType stanza of 1767 case stanzaType stanza of
1760 PresenceRequestStatus {} -> do 1768 PresenceRequestStatus {} -> do
1761 xmppAnswerProbe xmpp k stanza replyto 1769 xmppAnswerProbe xmpp k stanza replyto
@@ -1785,14 +1793,13 @@ monitor sv params xmpp = do
1785 Message {} -> do 1793 Message {} -> do
1786 case stanzaOrigin stanza of 1794 case stanzaOrigin stanza of
1787 LocalPeer {} -> return () 1795 LocalPeer {} -> return ()
1788 NetworkOrigin _ replyto -> deliver replyto 1796 ClientOrigin _ replyto -> deliver replyto
1797 PeerOrigin _ replyto -> deliver replyto
1789 Error {} -> do 1798 Error {} -> do
1790 case stanzaOrigin stanza of 1799 case stanzaOrigin stanza of
1791 LocalPeer {} -> return () 1800 LocalPeer {} -> return ()
1792 NetworkOrigin k replyto -> do 1801 ClientOrigin _ replyto -> deliver replyto
1793 -- wlog $ "delivering error: " ++show (stanzaId stanza) 1802 PeerOrigin _ replyto -> deliver replyto
1794 -- wlog $ " from: " ++ show k
1795 deliver replyto
1796 _ -> return () 1803 _ -> return ()
1797 -- We need to clone in the case the stanza is passed on as for Message. 1804 -- We need to clone in the case the stanza is passed on as for Message.
1798 verbosity <- xmppVerbosity xmpp 1805 verbosity <- xmppVerbosity xmpp
@@ -1803,9 +1810,9 @@ monitor sv params xmpp = do
1803 notping $ do 1810 notping $ do
1804 let typ = Strict8.pack $ c ++ "->"++(concat . take 1 . words $ show (stanzaType stanza))++" " 1811 let typ = Strict8.pack $ c ++ "->"++(concat . take 1 . words $ show (stanzaType stanza))++" "
1805 c = case stanzaOrigin stanza of 1812 c = case stanzaOrigin stanza of
1806 LocalPeer -> "*" 1813 LocalPeer -> "*"
1807 NetworkOrigin (ClientKey {}) _ -> "C" 1814 ClientOrigin {} -> "C"
1808 NetworkOrigin (PeerKey {}) _ -> "P" 1815 PeerOrigin {} -> "P"
1809 wlog "" 1816 wlog ""
1810 stanzaToConduit dup $$ prettyPrint typ 1817 stanzaToConduit dup $$ prettyPrint typ
1811 1818
@@ -1821,27 +1828,41 @@ data ConnectionType = XMPP | Tox
1821 deriving (Eq,Ord,Enum,Show,Read) 1828 deriving (Eq,Ord,Enum,Show,Read)
1822 1829
1823data ConnectionData = ConnectionData 1830data ConnectionData = ConnectionData
1824 { cdAddr :: SockAddr 1831 { cdAddr :: Either (Local SockAddr) -- Peer connection local address
1832 (Remote SockAddr) -- Client connection remote address
1825 , cdType :: ConnectionType 1833 , cdType :: ConnectionType
1826 } 1834 }
1827 deriving (Eq,Ord,Show) 1835 deriving (Eq,Ord,Show)
1828 1836
1837addrToPeerKey :: Remote SockAddr -> PeerAddress
1838addrToPeerKey (Remote raddr) = PeerAddress raddr
1839
1840addrFromClientKey :: ClientAddress -> Local SockAddr
1841addrFromClientKey (ClientAddress laddr) = Local laddr
1842
1843classifyConnection :: SockAddr -> ConnectionData -> Either (PeerAddress, Local SockAddr)
1844 (ClientAddress, Remote SockAddr)
1845classifyConnection saddr dta = case cdAddr dta of
1846 Left laddr -> Left (PeerAddress saddr, laddr)
1847 Right raddr -> Right (ClientAddress saddr, raddr)
1848
1829data XMPPServer 1849data XMPPServer
1830 = forall releaseKey. 1850 = forall releaseKey.
1831 XMPPServer { _xmpp_sv :: Server ConnectionKey ConnectionData releaseKey XML.Event 1851 XMPPServer { _xmpp_sv :: Server SockAddr ConnectionData releaseKey XML.Event
1832 , _xmpp_peer_params :: ConnectionParameters ConnectionKey ConnectionData 1852 , _xmpp_peer_params :: ConnectionParameters SockAddr ConnectionData
1833 } 1853 }
1834 1854
1835grokPeer :: XMPPServer -> ConnectionKey -> (SockAddr, ConnectionParameters ConnectionKey ConnectionData, Miliseconds) 1855grokPeer :: XMPPServer -> SockAddr -> (SockAddr, ConnectionParameters SockAddr ConnectionData, Miliseconds)
1836grokPeer sv (PeerKey addr) = (addr, _xmpp_peer_params sv, 10000) 1856grokPeer sv addr = (addr, _xmpp_peer_params sv, 10000)
1857
1837 1858
1838xmppConnections :: XMPPServer -> IO (Connection.Manager TCPStatus Text) 1859xmppConnections :: XMPPServer -> IO (Connection.Manager TCPStatus Text)
1839xmppConnections xsv@XMPPServer{_xmpp_sv=sv} = tcpManager (grokPeer xsv) (Just . Text.pack) resolvPeer sv 1860xmppConnections xsv@XMPPServer{_xmpp_sv=sv} = tcpManager (grokPeer xsv) (Just . Text.pack) resolve sv
1840 where 1861 where
1841 resolvPeer :: Text -> IO (Maybe ConnectionKey) 1862 resolve :: Text -> IO (Maybe SockAddr)
1842 resolvPeer str = fmap PeerKey <$> listToMaybe <$> resolvePeer str 1863 resolve hostname = listToMaybe . map (\(PeerAddress addr) -> addr) <$> resolvePeer hostname
1843 1864
1844xmppEventChannel :: XMPPServer -> TChan ((ConnectionKey, ConnectionData), ConnectionEvent Event) 1865xmppEventChannel :: XMPPServer -> TChan ((SockAddr, ConnectionData), ConnectionEvent Event)
1845xmppEventChannel XMPPServer{_xmpp_sv=sv} = serverEvent sv 1866xmppEventChannel XMPPServer{_xmpp_sv=sv} = serverEvent sv
1846 1867
1847quitXmpp :: XMPPServer -> IO () 1868quitXmpp :: XMPPServer -> IO ()
diff --git a/ToxManager.hs b/ToxManager.hs
index 6ffa4840..bcc4d86d 100644
--- a/ToxManager.hs
+++ b/ToxManager.hs
@@ -26,7 +26,7 @@ import qualified Network.Tox.Onion.Transport as Tox
26import Presence 26import Presence
27import Text.Read 27import Text.Read
28import ToxToXMPP 28import ToxToXMPP
29import XMPPServer (ConnectionKey) 29import XMPPServer (ClientAddress)
30import DPut 30import DPut
31 31
32 32
@@ -53,7 +53,7 @@ toxman :: Announcer
53 -> [(String,TVar (BucketList Tox.NodeInfo))] 53 -> [(String,TVar (BucketList Tox.NodeInfo))]
54 -> Tox.Tox JabberClients 54 -> Tox.Tox JabberClients
55 -> PresenceState 55 -> PresenceState
56 -> ToxManager ConnectionKey 56 -> ToxManager ClientAddress
57toxman announcer toxbkts tox presence = ToxManager 57toxman announcer toxbkts tox presence = ToxManager
58 { activateAccount = \k pubname seckey -> do 58 { activateAccount = \k pubname seckey -> do
59 dput XMan $ "toxman ACTIVATE " ++ show (Tox.key2id $ toPublic seckey) 59 dput XMan $ "toxman ACTIVATE " ++ show (Tox.key2id $ toPublic seckey)
diff --git a/ToxToXMPP.hs b/ToxToXMPP.hs
index d8b704b7..adeb7455 100644
--- a/ToxToXMPP.hs
+++ b/ToxToXMPP.hs
@@ -62,7 +62,7 @@ import qualified Network.Tox.Onion.Transport as Tox
62 ;import Network.Tox.Onion.Transport (OnionData (..)) 62 ;import Network.Tox.Onion.Transport (OnionData (..))
63import Presence 63import Presence
64import Text.Read 64import Text.Read
65import XMPPServer (ConnectionKey) 65import XMPPServer (ClientAddress)
66#ifdef THREAD_DEBUG 66#ifdef THREAD_DEBUG
67import Control.Concurrent.Lifted.Instrument 67import Control.Concurrent.Lifted.Instrument
68#else 68#else
@@ -123,7 +123,7 @@ key2jid nospam key = T.pack $ show $ NoSpamId nsp key
123 nlo = fromIntegral (0x0FFFF .&. nospam) :: Word16 123 nlo = fromIntegral (0x0FFFF .&. nospam) :: Word16
124 nhi = fromIntegral (0x0FFFF .&. (nospam `shiftR` 16)) :: Word16 124 nhi = fromIntegral (0x0FFFF .&. (nospam `shiftR` 16)) :: Word16
125 125
126type JabberClients = Map.Map ConnectionKey PerClient 126type JabberClients = Map.Map ClientAddress PerClient
127 127
128data PerClient = PerClient 128data PerClient = PerClient
129 { pcDeliveredFRs :: TVar (Set.Set Tox.FriendRequest) 129 { pcDeliveredFRs :: TVar (Set.Set Tox.FriendRequest)
@@ -328,7 +328,7 @@ dispatch tx (OnionRouted theirkey (OnionFriendRequest fr) ) = do
328 , txPresence = st } = tx 328 , txPresence = st } = tx
329 k2c <- atomically $ do 329 k2c <- atomically $ do
330 refs <- readTVar (accountExtra acnt) 330 refs <- readTVar (accountExtra acnt)
331 k2c <- Map.intersectionWith (,) refs <$> readTVar (keyToChan st) 331 k2c <- Map.intersectionWith (,) refs <$> readTVar (ckeyToChan st)
332 clients <- readTVar (clients st) 332 clients <- readTVar (clients st)
333 return $ Map.intersectionWith (,) k2c clients 333 return $ Map.intersectionWith (,) k2c clients
334 -- TODO: Below we're using a hard coded default as their jabber user id. 334 -- TODO: Below we're using a hard coded default as their jabber user id.
diff --git a/examples/dhtd.hs b/examples/dhtd.hs
index 8e34d4fe..7aa5cd2c 100644
--- a/examples/dhtd.hs
+++ b/examples/dhtd.hs
@@ -1537,7 +1537,7 @@ newXmmpSink session@(Tox.NCrypto { ncOutgoingQueue = outGoingQVar, ncPacketQueue
1537-- order to set up translating conduits that simulate a remote XMPP server. 1537-- order to set up translating conduits that simulate a remote XMPP server.
1538announceToxJabberPeer :: PublicKey -- ^ This node's long-term user key. 1538announceToxJabberPeer :: PublicKey -- ^ This node's long-term user key.
1539 -> PublicKey -- ^ Remote tox node's long-term user key. 1539 -> PublicKey -- ^ Remote tox node's long-term user key.
1540 -> TChan ((ConnectionKey,ConnectionData), Tcp.ConnectionEvent XML.Event) 1540 -> TChan ((SockAddr,ConnectionData), Tcp.ConnectionEvent XML.Event)
1541 -> SockAddr -- ^ Local bind address for incoming Tox packets. 1541 -> SockAddr -- ^ Local bind address for incoming Tox packets.
1542 -> SockAddr -- ^ Remote address for this connection. 1542 -> SockAddr -- ^ Remote address for this connection.
1543 -> STM Bool 1543 -> STM Bool
@@ -1547,7 +1547,7 @@ announceToxJabberPeer :: PublicKey -- ^ This node's long-term user key.
1547announceToxJabberPeer me them echan laddr saddr pingflag tsrc tsnk 1547announceToxJabberPeer me them echan laddr saddr pingflag tsrc tsnk
1548 = do 1548 = do
1549 atomically $ writeTChan echan 1549 atomically $ writeTChan echan
1550 ( (PeerKey saddr, ConnectionData laddr XMPPServer.Tox ) 1550 ( (saddr, ConnectionData (Left (Local laddr)) XMPPServer.Tox )
1551 , Tcp.Connection pingflag xsrc xsnk ) 1551 , Tcp.Connection pingflag xsrc xsnk )
1552 return Nothing 1552 return Nothing
1553 where 1553 where
diff --git a/src/Network/Tox/NodeId.hs b/src/Network/Tox/NodeId.hs
index e3c6fb36..3a732b43 100644
--- a/src/Network/Tox/NodeId.hs
+++ b/src/Network/Tox/NodeId.hs
@@ -278,6 +278,16 @@ b64digit '-' = True
278b64digit '/' = True 278b64digit '/' = True
279b64digit c = ('0' <= c && c <= '9') || ( 'a' <= c && c <= 'z') || ( 'A' <= c && c <= 'Z') 279b64digit c = ('0' <= c && c <= '9') || ( 'a' <= c && c <= 'z') || ( 'A' <= c && c <= 'Z')
280 280
281ip_w_port :: Int -> RP.ReadP (IP, PortNumber)
282ip_w_port i = do
283 ip <- RP.between (RP.char '[') (RP.char ']')
284 (IPv6 <$> RP.readS_to_P (readsPrec i))
285 RP.+++ (IPv4 <$> RP.readS_to_P (readsPrec i))
286 _ <- RP.char ':'
287 port <- toEnum <$> RP.readS_to_P (readsPrec i)
288 return (ip, port)
289
290
281instance Read NodeInfo where 291instance Read NodeInfo where
282 readsPrec i = RP.readP_to_S $ do 292 readsPrec i = RP.readP_to_S $ do
283 RP.skipSpaces 293 RP.skipSpaces
@@ -292,15 +302,7 @@ instance Read NodeInfo where
292 _ -> fail "Bad node id." 302 _ -> fail "Bad node id."
293 return (nid,addrstr) 303 return (nid,addrstr)
294 (nid,addrstr) <- ( nodeidAt RP.+++ ( (zeroID,) <$> parseAddr) ) 304 (nid,addrstr) <- ( nodeidAt RP.+++ ( (zeroID,) <$> parseAddr) )
295 let raddr = do 305 (ip,port) <- case RP.readP_to_S (ip_w_port i) addrstr of
296 ip <- RP.between (RP.char '[') (RP.char ']')
297 (IPv6 <$> RP.readS_to_P (readsPrec i))
298 RP.+++ (IPv4 <$> RP.readS_to_P (readsPrec i))
299 _ <- RP.char ':'
300 port <- toEnum <$> RP.readS_to_P (readsPrec i)
301 return (ip, port)
302
303 (ip,port) <- case RP.readP_to_S raddr addrstr of
304 [] -> fail "Bad address." 306 [] -> fail "Bad address."
305 ((ip,port),_):_ -> return (ip,port) 307 ((ip,port),_):_ -> return (ip,port)
306 return $ NodeInfo nid ip port 308 return $ NodeInfo nid ip port