diff options
-rw-r--r-- | Presence/ConnectionKey.hs | 9 | ||||
-rw-r--r-- | Presence/DNSCache.hs | 22 | ||||
-rw-r--r-- | Presence/PeerResolve.hs | 12 | ||||
-rw-r--r-- | Presence/Presence.hs | 389 | ||||
-rw-r--r-- | Presence/XMPPServer.hs | 285 | ||||
-rw-r--r-- | ToxManager.hs | 4 | ||||
-rw-r--r-- | ToxToXMPP.hs | 6 | ||||
-rw-r--r-- | examples/dhtd.hs | 4 | ||||
-rw-r--r-- | src/Network/Tox/NodeId.hs | 20 |
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 | |||
3 | import Network.Socket ( SockAddr(..) ) | 3 | import Network.Socket ( SockAddr(..) ) |
4 | import SockAddr () | 4 | import SockAddr () |
5 | 5 | ||
6 | data ConnectionKey | 6 | newtype PeerAddress = PeerAddress SockAddr |
7 | = PeerKey { callBackAddress :: SockAddr } | 7 | deriving (Eq,Ord,Show) |
8 | | ClientKey { localAddress :: SockAddr } | 8 | |
9 | deriving (Show, Ord, Eq) | 9 | newtype 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 | |||
27 | import Control.Concurrent.Lifted | 28 | import Control.Concurrent.Lifted |
28 | import GHC.Conc (labelThread) | 29 | import GHC.Conc (labelThread) |
29 | #endif | 30 | #endif |
31 | import Control.Arrow | ||
30 | import Control.Concurrent.STM | 32 | import Control.Concurrent.STM |
31 | import Data.Text ( Text ) | 33 | import Data.Text ( Text ) |
32 | import Network.Socket ( SockAddr(..), AddrInfoFlag(..), defaultHints, getAddrInfo, AddrInfo(..) ) | 34 | import Network.Socket ( SockAddr(..), AddrInfoFlag(..), defaultHints, getAddrInfo, AddrInfo(..) ) |
@@ -44,6 +46,7 @@ import Data.List | |||
44 | import Data.Ord | 46 | import Data.Ord |
45 | import Data.Maybe | 47 | import Data.Maybe |
46 | import System.IO.Error | 48 | import System.IO.Error |
49 | import System.IO.Unsafe | ||
47 | 50 | ||
48 | import SockAddr () | 51 | import SockAddr () |
49 | import ControlMaybe ( handleIO_ ) | 52 | import ControlMaybe ( handleIO_ ) |
@@ -144,7 +147,7 @@ rawForwardResolve dns onFail timeout addrtext = do | |||
144 | return () | 147 | return () |
145 | 148 | ||
146 | strip_brackets :: Text -> Text | 149 | strip_brackets :: Text -> Text |
147 | strip_brackets s = | 150 | strip_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 | ||
271 | splitAtPort :: String -> (String,String) | ||
272 | splitAtPort 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 | |||
280 | unsafeParseAddress :: String -> Maybe SockAddr | ||
281 | unsafeParseAddress 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 | |||
268 | withPort :: SockAddr -> Int -> SockAddr | 288 | withPort :: SockAddr -> Int -> SockAddr |
269 | withPort (SockAddrInet _ a) port = SockAddrInet (toEnum port) a | 289 | withPort (SockAddrInet _ a) port = SockAddrInet (toEnum port) a |
270 | withPort (SockAddrInet6 _ a b c) port = SockAddrInet6 (toEnum port) a b c | 290 | withPort (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 | |||
17 | global_dns_cache :: DNSCache | 18 | global_dns_cache :: DNSCache |
18 | global_dns_cache = unsafePerformIO $ newDNSCache | 19 | global_dns_cache = unsafePerformIO $ newDNSCache |
19 | 20 | ||
20 | resolvePeer :: Text -> IO [SockAddr] | 21 | resolvePeer :: Text -> IO [PeerAddress] |
21 | resolvePeer addrtext = forwardResolve global_dns_cache addrtext | 22 | resolvePeer addrtext = map PeerAddress <$> forwardResolve global_dns_cache addrtext |
22 | 23 | ||
23 | peerKeyToResolvedNames :: ConnectionKey -> IO [Text] | 24 | peerKeyToResolvedNames :: PeerAddress -> IO [Text] |
24 | peerKeyToResolvedNames k@(ClientKey { localAddress=addr }) = return [] | 25 | peerKeyToResolvedNames (PeerAddress addr) |
25 | peerKeyToResolvedNames 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) | |||
53 | import Crypto.Tox (decodeSecret) | 53 | import Crypto.Tox (decodeSecret) |
54 | import DPut | 54 | import DPut |
55 | 55 | ||
56 | isPeerKey :: ConnectionKey -> Bool | 56 | {- |
57 | isPeerKey :: ClientAddress -> Bool | ||
57 | isPeerKey k = case k of { PeerKey {} -> True ; _ -> False } | 58 | isPeerKey k = case k of { PeerKey {} -> True ; _ -> False } |
58 | 59 | ||
59 | isClientKey :: ConnectionKey -> Bool | 60 | isClientKey :: ClientAddress -> Bool |
60 | isClientKey k = case k of { ClientKey {} -> True ; _ -> False } | 61 | isClientKey k = case k of { ClientKey {} -> True ; _ -> False } |
62 | -} | ||
61 | 63 | ||
62 | localJID :: Text -> Text -> Text -> IO Text | 64 | localJID :: Text -> Text -> Text -> IO Text |
63 | localJID user "." resource = do | 65 | localJID user "." resource = do |
@@ -86,20 +88,21 @@ data ToxManager k = ToxManager | |||
86 | } | 88 | } |
87 | 89 | ||
88 | data PresenceState = forall status. PresenceState | 90 | data 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 | ||
101 | newPresenceState :: Maybe ConsoleWriter | 104 | newPresenceState :: 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 |
105 | newPresenceState cw toxman xmpp = atomically $ do | 108 | newPresenceState 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 | ||
124 | nameForClient :: PresenceState -> ConnectionKey -> IO Text | 129 | nameForClient :: PresenceState -> ClientAddress -> IO Text |
125 | nameForClient state k = do | 130 | nameForClient 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 | ||
166 | data LocalPresence = LocalPresence | 170 | data 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 | ||
180 | pcSingletonNetworkClient :: ConnectionKey | 184 | pcSingletonNetworkClient :: ClientAddress -> ClientState -> LocalPresence |
181 | -> ClientState -> LocalPresence | ||
182 | pcSingletonNetworkClient key client = | 185 | pcSingletonNetworkClient key client = |
183 | LocalPresence | 186 | LocalPresence |
184 | { networkClients = Map.singleton key client | 187 | { networkClients = Map.singleton key client |
185 | } | 188 | } |
186 | 189 | ||
187 | pcInsertNetworkClient :: ConnectionKey -> ClientState -> LocalPresence -> LocalPresence | 190 | pcInsertNetworkClient :: ClientAddress -> ClientState -> LocalPresence -> LocalPresence |
188 | pcInsertNetworkClient key client pc = | 191 | pcInsertNetworkClient key client pc = |
189 | pc { networkClients = Map.insert key client (networkClients pc) } | 192 | pc { networkClients = Map.insert key client (networkClients pc) } |
190 | 193 | ||
191 | pcRemoveNewtworkClient :: ConnectionKey | 194 | pcRemoveNewtworkClient :: ClientAddress |
192 | -> LocalPresence -> Maybe LocalPresence | 195 | -> LocalPresence -> Maybe LocalPresence |
193 | pcRemoveNewtworkClient key pc = if pcIsEmpty pc' then Nothing | 196 | pcRemoveNewtworkClient 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 | ||
217 | chooseResourceName :: PresenceState | 220 | chooseResourceName :: PresenceState |
218 | -> ConnectionKey -> SockAddr -> Maybe Text -> Maybe Text -> IO Text | 221 | -> ClientAddress -> Remote SockAddr -> Maybe Text -> Maybe Text -> IO Text |
219 | chooseResourceName state k addr clientsNameForMe desired = do | 222 | chooseResourceName 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. |
303 | forClient :: PresenceState -> ConnectionKey -> IO b -> (ClientState -> IO b) -> IO b | 306 | forClient :: PresenceState -> ClientAddress -> IO b -> (ClientState -> IO b) -> IO b |
304 | forClient state k fallback f = do | 307 | forClient 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 | ||
310 | tellClientHisName :: PresenceState -> ConnectionKey -> IO Text | 313 | tellClientHisName :: PresenceState -> ClientAddress -> IO Text |
311 | tellClientHisName state k = forClient state k fallback go | 314 | tellClientHisName 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 | |||
316 | toMapUnit :: Ord k => [k] -> Map k () | 319 | toMapUnit :: Ord k => [k] -> Map k () |
317 | toMapUnit xs = Map.fromList $ map (,()) xs | 320 | toMapUnit xs = Map.fromList $ map (,()) xs |
318 | 321 | ||
319 | resolveAllPeers :: [Text] -> IO (Map SockAddr ()) | 322 | resolveAllPeers :: [Text] -> IO (Map PeerAddress ()) |
320 | resolveAllPeers hosts = fmap (toMapUnit . concat) $ Prelude.mapM (fmap (take 1) . resolvePeer) hosts | 323 | resolveAllPeers 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. |
324 | rosterGetStuff | 327 | rosterGetStuff |
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] |
327 | rosterGetStuff what state k = forClient state k (return []) | 330 | rosterGetStuff 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 | ||
349 | rosterGetBuddies :: PresenceState -> ConnectionKey -> IO [Text] | 352 | rosterGetBuddies :: PresenceState -> ClientAddress -> IO [Text] |
350 | rosterGetBuddies state k = rosterGetStuff ConfigFiles.getBuddies state k | 353 | rosterGetBuddies state k = rosterGetStuff ConfigFiles.getBuddies state k |
351 | 354 | ||
352 | rosterGetSolicited :: PresenceState -> ConnectionKey -> IO [Text] | 355 | rosterGetSolicited :: PresenceState -> ClientAddress -> IO [Text] |
353 | rosterGetSolicited = rosterGetStuff ConfigFiles.getSolicited | 356 | rosterGetSolicited = rosterGetStuff ConfigFiles.getSolicited |
354 | 357 | ||
355 | -- XXX: Should we be connecting to these peers? | 358 | -- XXX: Should we be connecting to these peers? |
356 | rosterGetOthers :: PresenceState -> ConnectionKey -> IO [Text] | 359 | rosterGetOthers :: PresenceState -> ClientAddress -> IO [Text] |
357 | rosterGetOthers = rosterGetStuff ConfigFiles.getOthers | 360 | rosterGetOthers = rosterGetStuff ConfigFiles.getOthers |
358 | 361 | ||
359 | rosterGetSubscribers :: PresenceState -> ConnectionKey -> IO [Text] | 362 | rosterGetSubscribers :: PresenceState -> ClientAddress -> IO [Text] |
360 | rosterGetSubscribers = rosterGetStuff ConfigFiles.getSubscribers | 363 | rosterGetSubscribers = rosterGetStuff ConfigFiles.getSubscribers |
361 | 364 | ||
362 | data Conn = Conn { connChan :: TChan Stanza | 365 | data 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 | ||
416 | sendProbesAndSolicitations :: PresenceState | 419 | sendProbesAndSolicitations :: PresenceState -> PeerAddress -> Local SockAddr -> TChan Stanza -> IO () |
417 | -> ConnectionKey -> SockAddr -> TChan Stanza -> IO () | 420 | sendProbesAndSolicitations state k (Local laddr) chan = do |
418 | sendProbesAndSolicitations 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 | ||
442 | newConn :: PresenceState -> ConnectionKey -> ConnectionData -> TChan Stanza -> IO () | 442 | |
443 | newConn state k cdta outchan = do | 443 | newConn :: PresenceState -> SockAddr -> ConnectionData -> TChan Stanza -> IO () |
444 | atomically $ modifyTVar' (keyToChan state) | 444 | newConn 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 | ||
450 | delclient :: (Alternative m, Monad m) => | 456 | delclient :: (Alternative m, Monad m) => |
451 | ConnectionKey -> m LocalPresence -> m LocalPresence | 457 | ClientAddress -> m LocalPresence -> m LocalPresence |
452 | delclient k mlp = do | 458 | delclient 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 | ||
458 | eofConn :: PresenceState -> ConnectionKey -> IO () | 464 | eofConn :: PresenceState -> SockAddr -> ConnectionData -> IO () |
459 | eofConn state k = do | 465 | eofConn 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 | 494 | parseRemoteAddress :: Text -> IO (Maybe (Remote SockAddr)) |
487 | -- came in on. The returned JID parts are suitable for unsplitJID to create a | 495 | parseRemoteAddress 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. | ||
492 | rewriteJIDForClient :: SockAddr -> Text -> [Text] -> IO (Bool,(Maybe Text,Text,Maybe Text)) | ||
493 | rewriteJIDForClient 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. |
506 | peerKeyToResolvedName :: [Text] -> ConnectionKey -> IO Text | 501 | peerKeyToResolvedName :: [Text] -> PeerAddress -> IO Text |
507 | peerKeyToResolvedName buds k@(ClientKey { localAddress=addr }) = return "ErrorClIeNt1" | ||
508 | peerKeyToResolvedName buds pk = do | 502 | peerKeyToResolvedName 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. | ||
515 | rewriteJIDForClient :: Local SockAddr -> Text -> [Text] -> IO (Bool,(Maybe Text,Text,Maybe Text)) | ||
516 | rewriteJIDForClient (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. |
518 | multiplyJIDForClient :: SockAddr -> Text -> IO (Bool,[(Maybe Text,Text,Maybe Text)]) | 528 | multiplyJIDForClient :: ClientAddress -> Text -> IO (Bool,[(Maybe Text,Text,Maybe Text)]) |
519 | multiplyJIDForClient laddr jid = do | 529 | multiplyJIDForClient 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 | ||
529 | addrTextToKey :: Text -> IO (Maybe ConnectionKey) | 540 | guardPortStrippedAddress :: Text -> Local SockAddr -> IO (Maybe ()) |
530 | addrTextToKey h = do | 541 | guardPortStrippedAddress h (Local laddr) = do |
531 | maddr <- parseAddress (strip_brackets h) | ||
532 | return (fmap PeerKey maddr) | ||
533 | |||
534 | guardPortStrippedAddress :: Text -> SockAddr -> IO (Maybe ()) | ||
535 | guardPortStrippedAddress 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. |
547 | rewriteJIDForPeer :: Text -> IO (Maybe (Text,SockAddr)) | 553 | rewriteJIDForPeer :: Text -> IO (Maybe (Text,PeerAddress)) |
548 | rewriteJIDForPeer jid = do | 554 | rewriteJIDForPeer 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 () |
568 | deliverMessage state fail msg = | 574 | deliverMessage 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 | ||
645 | setClientFlag :: PresenceState -> ConnectionKey -> Int8 -> IO () | 655 | setClientFlag :: PresenceState -> ClientAddress -> Int8 -> IO () |
646 | setClientFlag state k flag = | 656 | setClientFlag 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 () | |||
653 | setClientFlag0 client flag = | 663 | setClientFlag0 client flag = |
654 | modifyTVar' (clientFlags client) (\flgs -> flgs .|. flag) | 664 | modifyTVar' (clientFlags client) (\flgs -> flgs .|. flag) |
655 | 665 | ||
656 | informSentRoster :: PresenceState -> ConnectionKey -> IO () | 666 | informSentRoster :: PresenceState -> ClientAddress -> IO () |
657 | informSentRoster state k = do | 667 | informSentRoster state k = do |
658 | setClientFlag state k cf_interested | 668 | setClientFlag state k cf_interested |
659 | 669 | ||
660 | 670 | ||
661 | subscribedPeers :: Text -> Text -> IO [SockAddr] | 671 | subscribedPeers :: Text -> Text -> IO [PeerAddress] |
662 | subscribedPeers user profile = do | 672 | subscribedPeers 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. |
668 | clientJID :: Conn -> ClientState -> Text | 678 | clientJID :: Conn -> ClientState -> Text |
669 | clientJID con client = unsplitJID ( Just $ clientUser client | 679 | clientJID 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. |
676 | informClientPresence :: PresenceState | 689 | informClientPresence :: PresenceState |
677 | -> ConnectionKey -> StanzaWrap (LockedChan Event) -> IO () | 690 | -> ClientAddress -> StanzaWrap (LockedChan Event) -> IO () |
678 | informClientPresence state k stanza = do | 691 | informClientPresence 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 | ||
682 | informClientPresence0 :: PresenceState | 695 | informClientPresence0 :: 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 | ||
708 | informPeerPresence :: PresenceState | 721 | informPeerPresence :: PresenceState |
709 | -> ConnectionKey | 722 | -> PeerAddress |
710 | -> StanzaWrap (LockedChan Event) | 723 | -> StanzaWrap (LockedChan Event) |
711 | -> IO () | 724 | -> IO () |
712 | informPeerPresence state k stanza = do | 725 | informPeerPresence 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 | |||
777 | consoleClients _ = return Map.empty | 789 | consoleClients _ = return Map.empty |
778 | 790 | ||
779 | 791 | ||
780 | answerProbe :: PresenceState | 792 | answerProbe :: PresenceState -> Maybe Text -> PeerAddress -> TChan Stanza -> IO () |
781 | -> Maybe Text -> ConnectionKey -> TChan Stanza -> IO () | ||
782 | answerProbe state mto k chan = do | 793 | answerProbe 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. |
841 | sendCachedPresence :: PresenceState -> ConnectionKey -> IO () | 855 | sendCachedPresence :: PresenceState -> ClientAddress -> IO () |
842 | sendCachedPresence state k = do | 856 | sendCachedPresence 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 |
887 | addToRosterFile doit whose profile to addrs = | 900 | addToRosterFile 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 |
899 | removeFromRosterFile doit whose profile to addrs = | 912 | removeFromRosterFile 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 |
926 | modifyRosterFile doit whose profile to addrs bAdd = do | 939 | modifyRosterFile 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 | ||
954 | clientSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () | 967 | clientSubscriptionRequest :: PresenceState -> IO () -> ClientAddress -> Stanza -> TChan Stanza -> IO () |
955 | clientSubscriptionRequest state fail k stanza chan = do | 968 | clientSubscriptionRequest 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 | ||
1023 | resolvedFromRoster | 1038 | resolvedFromRoster |
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)] |
1026 | resolvedFromRoster doit u profile = do | 1041 | resolvedFromRoster 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 | ||
1033 | clientCons :: PresenceState | 1048 | clientCons :: PresenceState |
1034 | -> Map ConnectionKey t -> Text -> IO [(t, ClientState)] | 1049 | -> Map ClientAddress t -> Text -> IO [(t, ClientState)] |
1035 | clientCons state ktc u = map snd <$> clientCons' state ktc u | 1050 | clientCons state ktc u = map snd <$> clientCons' state ktc u |
1036 | 1051 | ||
1037 | clientCons' :: PresenceState | 1052 | clientCons' :: PresenceState |
1038 | -> Map ConnectionKey t -> Text -> IO [(ConnectionKey,(t, ClientState))] | 1053 | -> Map ClientAddress t -> Text -> IO [(ClientAddress,(t, ClientState))] |
1039 | clientCons' state ktc u = do | 1054 | clientCons' 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 | ||
1050 | peerSubscriptionRequest :: PresenceState -> IO () -> ConnectionKey -> Stanza -> TChan Stanza -> IO () | 1065 | releventProfiles :: ConnectionType -> Text -> IO [Text] |
1066 | releventProfiles XMPP _ = return ["."] | ||
1067 | releventProfiles ctyp user = do | ||
1068 | -- TODO: Return all the ".tox" profiles that a user has under his | ||
1069 | -- .presence/ directory. | ||
1070 | return [] | ||
1071 | |||
1072 | peerSubscriptionRequest :: PresenceState -> IO () -> PeerAddress -> Stanza -> TChan Stanza -> IO () | ||
1051 | peerSubscriptionRequest state fail k stanza chan = do | 1073 | peerSubscriptionRequest 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 | ||
1129 | clientInformSubscription :: PresenceState | 1147 | clientInformSubscription :: PresenceState |
1130 | -> IO () | 1148 | -> IO () |
1131 | -> ConnectionKey | 1149 | -> ClientAddress |
1132 | -> StanzaWrap (LockedChan Event) | 1150 | -> StanzaWrap (LockedChan Event) |
1133 | -> IO () | 1151 | -> IO () |
1134 | clientInformSubscription state fail k stanza = do | 1152 | clientInformSubscription 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 | ||
1193 | peerInformSubscription :: PresenceState | 1212 | peerInformSubscription :: PresenceState |
1194 | -> IO () | 1213 | -> IO () |
1195 | -> ConnectionKey | 1214 | -> PeerAddress |
1196 | -> StanzaWrap (LockedChan Event) | 1215 | -> StanzaWrap (LockedChan Event) |
1197 | -> IO () | 1216 | -> IO () |
1198 | peerInformSubscription state fail k stanza = do | 1217 | peerInformSubscription 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 @@ | |||
7 | module XMPPServer | 7 | module 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 | |||
85 | import Data.Maybe | 91 | import Data.Maybe |
86 | import Data.Monoid ( (<>) ) | 92 | import Data.Monoid ( (<>) ) |
87 | import Data.Text (Text) | 93 | import Data.Text (Text) |
88 | import qualified Data.Text as Text (pack,unpack,words,intercalate) | 94 | import qualified Data.Text as Text (pack,unpack,words,intercalate,drop) |
89 | import Data.Char (chr,ord) | 95 | import Data.Char (chr,ord) |
90 | import qualified Data.Map as Map | 96 | import qualified Data.Map as Map |
91 | import Data.Set (Set, (\\) ) | 97 | import 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 | ||
170 | data StanzaOrigin = LocalPeer | NetworkOrigin ConnectionKey (TChan Stanza) | 176 | data StanzaOrigin = LocalPeer |
177 | | PeerOrigin PeerAddress (TChan Stanza) | ||
178 | | ClientOrigin ClientAddress (TChan Stanza) | ||
179 | |||
171 | 180 | ||
172 | data StanzaWrap a = Stanza | 181 | data StanzaWrap a = Stanza |
173 | { stanzaType :: StanzaType | 182 | { stanzaType :: StanzaType |
@@ -182,6 +191,9 @@ data StanzaWrap a = Stanza | |||
182 | 191 | ||
183 | type Stanza = StanzaWrap (LockedChan XML.Event) | 192 | type Stanza = StanzaWrap (LockedChan XML.Event) |
184 | 193 | ||
194 | newtype Local a = Local a deriving (Eq,Ord,Show) | ||
195 | newtype Remote a = Remote a deriving (Eq,Ord,Show) | ||
196 | |||
185 | data XMPPServerParameters = | 197 | data 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. |
274 | peerKeyToText :: ConnectionKey -> Text | 285 | peerKeyToText :: PeerAddress -> Text |
275 | peerKeyToText (PeerKey { callBackAddress=addr }) = addrToText addr | 286 | peerKeyToText (PeerAddress addr) = addrToText addr |
276 | peerKeyToText (ClientKey { localAddress=addr }) = "ErrorClIeNt0" | ||
277 | 287 | ||
278 | 288 | ||
279 | wlog :: String -> IO () | 289 | wlog :: 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 | ||
908 | data ClientOrPeer = IsClient | IsPeer | ||
898 | 909 | ||
899 | xmppInbound :: Server ConnectionKey ConnectionData releaseKey XML.Event | 910 | xmppInbound :: 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 () |
908 | xmppInbound sv xmpp k laddr pingflag stanzas output donevar = doNestingXML $ do | 918 | xmppInbound 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 | ||
1247 | forkConnection :: Server ConnectionKey ConnectionData releaseKey XML.Event | 1248 | forkConnection :: 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) |
1256 | forkConnection sv xmpp k (ConnectionData laddr _) pingflag src snk stanzas = do | 1257 | forkConnection 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 | ||
1401 | peerKey :: SocketLike sock => Maybe SockAddr -> sock -> IO (ConnectionKey,ConnectionData) | 1408 | peerKey :: SocketLike sock => Maybe SockAddr -> sock -> IO (SockAddr,ConnectionData) |
1402 | peerKey outgoingPeerPort sock = do | 1409 | peerKey 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 | ||
1412 | clientKey :: SocketLike sock => sock -> IO (ConnectionKey,ConnectionData) | 1419 | clientKey :: SocketLike sock => sock -> IO (SockAddr,ConnectionData) |
1413 | clientKey sock = do | 1420 | clientKey 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 | ||
1418 | xmlifyRosterItems :: Monad m => Set Text -> Text -> Set Text -> ConduitM i Event m () | 1425 | xmlifyRosterItems :: Monad m => Set Text -> Text -> Set Text -> ConduitM i Event m () |
1419 | xmlifyRosterItems solicited stype set = mapM_ item (Set.toList set) | 1426 | xmlifyRosterItems solicited stype set = mapM_ item (Set.toList set) |
@@ -1429,14 +1436,15 @@ xmlifyRosterItems solicited stype set = mapM_ item (Set.toList set) | |||
1429 | sendRoster :: | 1436 | sendRoster :: |
1430 | StanzaWrap a | 1437 | StanzaWrap a |
1431 | -> XMPPServerParameters | 1438 | -> XMPPServerParameters |
1432 | -> ConnectionKey | 1439 | -> ClientAddress |
1433 | -> TChan Stanza | 1440 | -> TChan Stanza |
1434 | -> IO () | 1441 | -> IO () |
1435 | sendRoster query xmpp clientKey replyto = do | 1442 | sendRoster 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 | ||
1485 | socketFromKey :: Server ConnectionKey ConnectionData releaseKey XML.Event -> ConnectionKey -> IO SockAddr | 1491 | socketFromKey :: Server SockAddr ConnectionData releaseKey XML.Event -> ClientAddress -> IO (Remote SockAddr) |
1486 | socketFromKey sv k = do | 1492 | socketFromKey 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 | ||
1497 | class StanzaFirstTag a where | 1500 | class 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 | ||
1654 | monitor :: | 1657 | monitor :: |
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 |
1659 | monitor sv params xmpp = do | 1662 | monitor 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 | ||
1823 | data ConnectionData = ConnectionData | 1830 | data 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 | ||
1837 | addrToPeerKey :: Remote SockAddr -> PeerAddress | ||
1838 | addrToPeerKey (Remote raddr) = PeerAddress raddr | ||
1839 | |||
1840 | addrFromClientKey :: ClientAddress -> Local SockAddr | ||
1841 | addrFromClientKey (ClientAddress laddr) = Local laddr | ||
1842 | |||
1843 | classifyConnection :: SockAddr -> ConnectionData -> Either (PeerAddress, Local SockAddr) | ||
1844 | (ClientAddress, Remote SockAddr) | ||
1845 | classifyConnection saddr dta = case cdAddr dta of | ||
1846 | Left laddr -> Left (PeerAddress saddr, laddr) | ||
1847 | Right raddr -> Right (ClientAddress saddr, raddr) | ||
1848 | |||
1829 | data XMPPServer | 1849 | data 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 | ||
1835 | grokPeer :: XMPPServer -> ConnectionKey -> (SockAddr, ConnectionParameters ConnectionKey ConnectionData, Miliseconds) | 1855 | grokPeer :: XMPPServer -> SockAddr -> (SockAddr, ConnectionParameters SockAddr ConnectionData, Miliseconds) |
1836 | grokPeer sv (PeerKey addr) = (addr, _xmpp_peer_params sv, 10000) | 1856 | grokPeer sv addr = (addr, _xmpp_peer_params sv, 10000) |
1857 | |||
1837 | 1858 | ||
1838 | xmppConnections :: XMPPServer -> IO (Connection.Manager TCPStatus Text) | 1859 | xmppConnections :: XMPPServer -> IO (Connection.Manager TCPStatus Text) |
1839 | xmppConnections xsv@XMPPServer{_xmpp_sv=sv} = tcpManager (grokPeer xsv) (Just . Text.pack) resolvPeer sv | 1860 | xmppConnections 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 | ||
1844 | xmppEventChannel :: XMPPServer -> TChan ((ConnectionKey, ConnectionData), ConnectionEvent Event) | 1865 | xmppEventChannel :: XMPPServer -> TChan ((SockAddr, ConnectionData), ConnectionEvent Event) |
1845 | xmppEventChannel XMPPServer{_xmpp_sv=sv} = serverEvent sv | 1866 | xmppEventChannel XMPPServer{_xmpp_sv=sv} = serverEvent sv |
1846 | 1867 | ||
1847 | quitXmpp :: XMPPServer -> IO () | 1868 | quitXmpp :: 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 | |||
26 | import Presence | 26 | import Presence |
27 | import Text.Read | 27 | import Text.Read |
28 | import ToxToXMPP | 28 | import ToxToXMPP |
29 | import XMPPServer (ConnectionKey) | 29 | import XMPPServer (ClientAddress) |
30 | import DPut | 30 | import 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 |
57 | toxman announcer toxbkts tox presence = ToxManager | 57 | toxman 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 (..)) |
63 | import Presence | 63 | import Presence |
64 | import Text.Read | 64 | import Text.Read |
65 | import XMPPServer (ConnectionKey) | 65 | import XMPPServer (ClientAddress) |
66 | #ifdef THREAD_DEBUG | 66 | #ifdef THREAD_DEBUG |
67 | import Control.Concurrent.Lifted.Instrument | 67 | import 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 | ||
126 | type JabberClients = Map.Map ConnectionKey PerClient | 126 | type JabberClients = Map.Map ClientAddress PerClient |
127 | 127 | ||
128 | data PerClient = PerClient | 128 | data 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. |
1538 | announceToxJabberPeer :: PublicKey -- ^ This node's long-term user key. | 1538 | announceToxJabberPeer :: 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. | |||
1547 | announceToxJabberPeer me them echan laddr saddr pingflag tsrc tsnk | 1547 | announceToxJabberPeer 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 | |||
278 | b64digit '/' = True | 278 | b64digit '/' = True |
279 | b64digit c = ('0' <= c && c <= '9') || ( 'a' <= c && c <= 'z') || ( 'A' <= c && c <= 'Z') | 279 | b64digit c = ('0' <= c && c <= '9') || ( 'a' <= c && c <= 'z') || ( 'A' <= c && c <= 'Z') |
280 | 280 | ||
281 | ip_w_port :: Int -> RP.ReadP (IP, PortNumber) | ||
282 | ip_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 | |||
281 | instance Read NodeInfo where | 291 | instance 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 |