summaryrefslogtreecommitdiff
path: root/xmppServer.hs
diff options
context:
space:
mode:
Diffstat (limited to 'xmppServer.hs')
-rw-r--r--xmppServer.hs119
1 files changed, 100 insertions, 19 deletions
diff --git a/xmppServer.hs b/xmppServer.hs
index 69b6cec5..7b352b8a 100644
--- a/xmppServer.hs
+++ b/xmppServer.hs
@@ -10,7 +10,7 @@ import Network.Socket
10 , getAddrInfo 10 , getAddrInfo
11 , defaultHints 11 , defaultHints
12 , addrFlags 12 , addrFlags
13 , AddrInfoFlag(AI_CANONNAME,AI_V4MAPPED) 13 , AddrInfoFlag(AI_CANONNAME,AI_V4MAPPED,AI_NUMERICHOST)
14 , SockAddr(..) 14 , SockAddr(..)
15 ) 15 )
16import System.Endian (fromBE32) 16import System.Endian (fromBE32)
@@ -71,9 +71,10 @@ data ClientState = ClientState
71 71
72data PresenceState = PresenceState 72data PresenceState = PresenceState
73 { clients :: TVar (Map ConnectionKey ClientState) 73 { clients :: TVar (Map ConnectionKey ClientState)
74 , clientsByUser :: TVar (Map Text (ConnectionKey,ClientState)) -- TODO: should be list
74 , associatedPeers :: TVar (Map SockAddr ()) 75 , associatedPeers :: TVar (Map SockAddr ())
75 , server :: TMVar XMPPServer 76 , server :: TMVar XMPPServer
76 , writeTos :: TVar (Map ConnectionKey (TChan Stanza)) 77 , writeTos :: TVar (Map ConnectionKey Conn)
77 } 78 }
78 79
79 80
@@ -84,9 +85,14 @@ resolvePeer :: Text -> IO [SockAddr]
84resolvePeer addrtext = do 85resolvePeer addrtext = do
85 fmap (map $ make6mapped4 . addrAddress) $ 86 fmap (map $ make6mapped4 . addrAddress) $
86 getAddrInfo (Just $ defaultHints { addrFlags = [ AI_CANONNAME, AI_V4MAPPED ]}) 87 getAddrInfo (Just $ defaultHints { addrFlags = [ AI_CANONNAME, AI_V4MAPPED ]})
87 (Just $ Text.unpack addrtext) 88 (Just $ Text.unpack $ strip_brackets addrtext)
88 (Just "5269") 89 (Just "5269")
89 90
91strip_brackets s =
92 case Text.uncons s of
93 Just ('[',t) -> Text.takeWhile (/=']') t
94 _ -> s
95
90 96
91getConsolePids :: PresenceState -> IO [(Text,ProcessID)] 97getConsolePids :: PresenceState -> IO [(Text,ProcessID)]
92getConsolePids state = do 98getConsolePids state = do
@@ -109,8 +115,10 @@ chooseResourceName state k addr desired = do
109 , clientUser = user 115 , clientUser = user
110 , clientPid = pid } 116 , clientPid = pid }
111 117
112 atomically $ 118 atomically $ do
113 modifyTVar' (clients state) $ Map.insert k client 119 modifyTVar' (clients state) $ Map.insert k client
120 modifyTVar' (clientsByUser state) $ Map.insert (clientUser client) (k,client)
121
114 localJID (clientUser client) (clientResource client) 122 localJID (clientUser client) (clientResource client)
115 123
116 where 124 where
@@ -174,11 +182,58 @@ rosterGetSolicited = rosterGetStuff ConfigFiles.getSolicited
174rosterGetOthers = rosterGetStuff ConfigFiles.getOthers 182rosterGetOthers = rosterGetStuff ConfigFiles.getOthers
175rosterGetSubscribers = rosterGetStuff ConfigFiles.getSubscribers 183rosterGetSubscribers = rosterGetStuff ConfigFiles.getSubscribers
176 184
177newConn state k outchan = 185data Conn = Conn { connChan :: TChan Stanza
178 atomically $ modifyTVar' (writeTos state) $ Map.insert k outchan 186 , auxAddr :: SockAddr }
187
188newConn state k addr outchan =
189 atomically $ modifyTVar' (writeTos state)
190 $ Map.insert k Conn { connChan = outchan
191 , auxAddr = addr }
179 192
180eofConn state k = atomically $ modifyTVar' (writeTos state) $ Map.delete k 193eofConn state k = atomically $ modifyTVar' (writeTos state) $ Map.delete k
181 194
195rewriteJIDForClient1:: Text -> IO (Maybe ((Maybe Text,Text,Maybe Text),SockAddr))
196rewriteJIDForClient1 jid = do
197 let (n,h,r) = splitJID jid
198 maddr <- fmap listToMaybe $ resolvePeer h
199 flip (maybe $ return Nothing) maddr $ \addr -> do
200 h' <- peerKeyToResolvedName (PeerKey addr)
201 return $ Just ((n,h',r), addr)
202
203parseAddress :: Text -> IO (Maybe SockAddr)
204parseAddress addr_str = do
205 info <- getAddrInfo (Just $ defaultHints { addrFlags = [ AI_NUMERICHOST ] })
206 (Just . Text.unpack $ addr_str)
207 (Just "0")
208 return . listToMaybe $ map addrAddress info
209
210todo = error "Unimplemented"
211
212
213-- | for example: 2001-db8-85a3-8d3-1319-8a2e-370-7348.ipv6-literal.net
214ip6literal :: Text -> Text
215ip6literal addr = Text.map dash addr <> ".ipv6-literal.net"
216 where
217 dash ':' = '-'
218 dash x = x
219
220withPort (SockAddrInet _ a) port = SockAddrInet (toEnum port) a
221withPort (SockAddrInet6 _ a b c) port = SockAddrInet6 (toEnum port) a b c
222
223-- | The given address is taken to be the local address for the socket this JID
224-- came in on. The returned JID parts are suitable for unsplitJID to create a
225-- valid JID for communicating to a client. The returned Bool is True when the
226-- host part refers to this local host (i.e. it equals the given SockAddr).
227rewriteJIDForClient :: SockAddr -> Text -> IO (Bool,(Maybe Text,Text,Maybe Text))
228rewriteJIDForClient laddr jid = do
229 let (n,h,r) = splitJID jid
230 maddr <- parseAddress (strip_brackets h)
231 flip (maybe $ return (False,(n,ip6literal h,r))) maddr $ \addr -> do
232 let mine = laddr `withPort` 0 == addr `withPort` 0
233 h' <- if mine then textHostName
234 else peerKeyToResolvedName (PeerKey addr)
235 return (mine,(n,h',r))
236
182rewriteJIDForPeer :: Text -> IO (Maybe (Text,SockAddr)) 237rewriteJIDForPeer :: Text -> IO (Maybe (Text,SockAddr))
183rewriteJIDForPeer jid = do 238rewriteJIDForPeer jid = do
184 let (n,h,r) = splitJID jid 239 let (n,h,r) = splitJID jid
@@ -188,28 +243,54 @@ rewriteJIDForPeer jid = do
188 to' = unsplitJID (n,h',r) 243 to' = unsplitJID (n,h',r)
189 in (to',addr) 244 in (to',addr)
190 245
191deliverMessage state fail msg = do 246deliverMessage state fail msg =
192 mto <- do 247 case stanzaOrigin msg of
193 flip (maybe $ return Nothing) (stanzaTo msg) $ \to -> do 248 NetworkOrigin senderk@(ClientKey {}) _ -> do
194 rewriteJIDForPeer to 249 mto <- do
195 flip (maybe fail) mto $ \(to',addr) -> do 250 flip (maybe $ return Nothing) (stanzaTo msg) $ \to -> do
196 from' <- do 251 rewriteJIDForPeer to
197 flip (maybe $ return Nothing) (stanzaFrom msg) $ \from -> do 252 flip (maybe fail) mto $ \(to',addr) -> do
198 m <- rewriteJIDForPeer from 253 let k = PeerKey addr
199 return $ fmap fst m 254 chans <- atomically $ readTVar (writeTos state)
200 let k = PeerKey addr 255 flip (maybe fail) (Map.lookup k chans) $ \(Conn { connChan=chan
201 chans <- atomically $ readTVar (writeTos state) 256 , auxAddr=laddr }) -> do
202 flip (maybe fail) (Map.lookup k chans) $ \chan -> do 257 (n,r) <- forClient state senderk (return (Nothing,Nothing))
203 sendModifiedStanzaToPeer (msg { stanzaTo=Just to', stanzaFrom=from' }) chan 258 $ \c -> return (Just (clientUser c), Just (clientResource c))
259 -- original 'from' address is discarded.
260 let from' = unsplitJID (n,addrToText laddr,r)
261 sendModifiedStanzaToPeer (msg { stanzaTo=Just to', stanzaFrom=Just from' }) chan
262 NetworkOrigin senderk@(PeerKey {}) _ -> do
263 chans <- atomically $ readTVar (writeTos state)
264 flip (maybe fail) (Map.lookup senderk chans)
265 $ \(Conn { connChan=sender_chan
266 , auxAddr=laddr }) -> do
267 flip (maybe fail) (stanzaTo msg) $ \to -> do
268 (mine,(n,h,r)) <- rewriteJIDForClient laddr to
269 if not mine then fail else do
270 let to' = unsplitJID (n,h,r)
271 from' <- do
272 flip (maybe $ return Nothing) (stanzaFrom msg) $ \from -> do
273 (_,trip) <- rewriteJIDForClient laddr from
274 return . Just $ unsplitJID trip
275 cmap <- atomically . readTVar $ clientsByUser state
276 flip (maybe fail) n $ \n -> do
277 flip (maybe fail) (Map.lookup n cmap) $ \(k,_) -> do
278 flip (maybe fail) (Map.lookup k chans) $ \Conn { connChan=chan} -> do
279 sendModifiedStanzaToClient (msg { stanzaTo=Just to'
280 , stanzaFrom=from' })
281 chan
282
204 283
205main = runResourceT $ do 284main = runResourceT $ do
206 state <- liftIO . atomically $ do 285 state <- liftIO . atomically $ do
207 clients <- newTVar Map.empty 286 clients <- newTVar Map.empty
287 clientsByUser <- newTVar Map.empty
208 associatedPeers <- newTVar Map.empty 288 associatedPeers <- newTVar Map.empty
209 xmpp <- newEmptyTMVar 289 xmpp <- newEmptyTMVar
210 writeTos <- newTVar Map.empty 290 writeTos <- newTVar Map.empty
211 return PresenceState 291 return PresenceState
212 { clients = clients 292 { clients = clients
293 , clientsByUser = clientsByUser
213 , associatedPeers = associatedPeers 294 , associatedPeers = associatedPeers
214 , writeTos = writeTos 295 , writeTos = writeTos
215 , server = xmpp 296 , server = xmpp