diff options
Diffstat (limited to 'Presence/XMPPServer.hs')
-rw-r--r-- | Presence/XMPPServer.hs | 120 |
1 files changed, 87 insertions, 33 deletions
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs index 8afc3245..ceb83476 100644 --- a/Presence/XMPPServer.hs +++ b/Presence/XMPPServer.hs | |||
@@ -37,6 +37,7 @@ import ControlMaybe | |||
37 | import Nesting | 37 | import Nesting |
38 | import EventUtil | 38 | import EventUtil |
39 | import Server | 39 | import Server |
40 | import ResourcePolicy (getResourceName) | ||
40 | 41 | ||
41 | peerport = 5269 | 42 | peerport = 5269 |
42 | clientport = 5222 | 43 | clientport = 5222 |
@@ -101,10 +102,10 @@ data Stanza | |||
101 | stanzaChan :: TChan (Maybe XML.Event) } | 102 | stanzaChan :: TChan (Maybe XML.Event) } |
102 | -} | 103 | -} |
103 | 104 | ||
104 | data StanzaType = Unrecognized | Ping | Pong | BindResource (Maybe Text) | 105 | data StanzaType = Unrecognized | Ping | Pong | RequestResource (Maybe Text) | SetResource |
105 | deriving Show | 106 | deriving Show |
106 | 107 | ||
107 | data StanzaOrigin = LocalPeer | NetworkOrigin ConnectionKey | 108 | data StanzaOrigin = LocalPeer | NetworkOrigin ConnectionKey (TChan Stanza) |
108 | 109 | ||
109 | data Stanza = Stanza | 110 | data Stanza = Stanza |
110 | { stanzaType :: StanzaType | 111 | { stanzaType :: StanzaType |
@@ -141,6 +142,31 @@ prettyPrint prefix = | |||
141 | =$= CB.lines | 142 | =$= CB.lines |
142 | =$ CL.mapM_ (wlogb . (prefix <>)) | 143 | =$ CL.mapM_ (wlogb . (prefix <>)) |
143 | 144 | ||
145 | sendReply donevar stype reply replychan = do | ||
146 | if null reply then return () | ||
147 | else do | ||
148 | let stanzaTag = head reply | ||
149 | mid = lookupAttrib "id" (tagAttrs stanzaTag) | ||
150 | mfrom = lookupAttrib "from" (tagAttrs stanzaTag) | ||
151 | mto = lookupAttrib "to" (tagAttrs stanzaTag) | ||
152 | replyStanza <- liftIO . atomically $ do | ||
153 | replyChan <- newTChan | ||
154 | replyClsrs <- newTVar (Just []) | ||
155 | return Stanza { stanzaType = stype | ||
156 | , stanzaId = mid | ||
157 | , stanzaTo = mto -- todo: should this be reversed? | ||
158 | , stanzaFrom = mfrom -- todo: should this be reversed? | ||
159 | , stanzaChan = replyChan | ||
160 | , stanzaClosers = replyClsrs | ||
161 | , stanzaInterrupt = donevar | ||
162 | , stanzaOrigin = LocalPeer | ||
163 | } | ||
164 | ioWriteChan replychan replyStanza | ||
165 | void . liftIO . forkIO $ do | ||
166 | mapM_ (ioWriteChan $ stanzaChan replyStanza) reply | ||
167 | liftIO . atomically $ writeTVar (stanzaClosers replyStanza) Nothing | ||
168 | -- liftIO $ wlog "finished reply stanza" | ||
169 | |||
144 | grokStanzaIQGet :: Monad m => XML.Event -> NestingXML o m (Maybe StanzaType) | 170 | grokStanzaIQGet :: Monad m => XML.Event -> NestingXML o m (Maybe StanzaType) |
145 | grokStanzaIQGet stanza = do | 171 | grokStanzaIQGet stanza = do |
146 | mtag <- nextElement | 172 | mtag <- nextElement |
@@ -166,9 +192,9 @@ grokStanzaIQSet stanza = do | |||
166 | case fmap tagName mchild of | 192 | case fmap tagName mchild of |
167 | Just "{urn:ietf:params:xml:ns:xmpp-bind}resource" -> do | 193 | Just "{urn:ietf:params:xml:ns:xmpp-bind}resource" -> do |
168 | rsc <- XML.content -- TODO: MonadThrow??? | 194 | rsc <- XML.content -- TODO: MonadThrow??? |
169 | return . Just $ BindResource (Just rsc) | 195 | return . Just $ RequestResource (Just rsc) |
170 | Just _ -> return Nothing | 196 | Just _ -> return Nothing |
171 | Nothing -> return . Just $ BindResource Nothing | 197 | Nothing -> return . Just $ RequestResource Nothing |
172 | _ -> return Nothing | 198 | _ -> return Nothing |
173 | 199 | ||
174 | 200 | ||
@@ -227,35 +253,31 @@ xmppInbound sv k pingflag src stanzas output donevar = doNestingXML $ do | |||
227 | mfrom = lookupAttrib "from" (tagAttrs stanzaTag) | 253 | mfrom = lookupAttrib "from" (tagAttrs stanzaTag) |
228 | mto = lookupAttrib "to" (tagAttrs stanzaTag) | 254 | mto = lookupAttrib "to" (tagAttrs stanzaTag) |
229 | dispatch <- grokStanza namespace stanzaTag | 255 | dispatch <- grokStanza namespace stanzaTag |
230 | flip (maybe $ return ()) dispatch $ \dispatch -> | 256 | let unrecog = do |
257 | let stype = Unrecognized | ||
258 | s <- liftIO . atomically $ do | ||
259 | return Stanza | ||
260 | { stanzaType = stype | ||
261 | , stanzaId = mid | ||
262 | , stanzaTo = mto | ||
263 | , stanzaFrom = mfrom | ||
264 | , stanzaChan = chan | ||
265 | , stanzaClosers = clsrs | ||
266 | , stanzaInterrupt = donevar | ||
267 | , stanzaOrigin = NetworkOrigin k output | ||
268 | } | ||
269 | ioWriteChan stanzas s | ||
270 | flip (maybe $ unrecog) dispatch $ \dispatch -> | ||
231 | case dispatch of | 271 | case dispatch of |
232 | Ping -> do | 272 | Ping -> do |
233 | -- TODO: check that the to-address matches this server. | 273 | -- TODO: check that the to-address matches this server. |
234 | -- Otherwise it could be a client-to-client ping or a | 274 | -- Otherwise it could be a client-to-client ping or a |
235 | -- client-to-server for some other server. | 275 | -- client-to-server for some other server. |
236 | -- For now, assuming its for the immediate connection. | 276 | -- For now, assuming its for the immediate connection. |
237 | let to = maybe "todo" id mto | 277 | let pongto = maybe "todo" id mfrom |
238 | from = maybe "todo" id mfrom | 278 | pongfrom = maybe "todo" id mto |
239 | let pong = makePong namespace mid to from | 279 | pong = makePong namespace mid pongto pongfrom |
240 | -- liftIO $ wlog "got ping, sending pong..." | 280 | sendReply donevar Pong pong output |
241 | pongStanza <- liftIO . atomically $ do | ||
242 | pongChan <- newTChan | ||
243 | pongClsrs <- newTVar (Just []) | ||
244 | return Stanza { stanzaType = Pong | ||
245 | , stanzaId = mid | ||
246 | , stanzaTo = mto | ||
247 | , stanzaFrom = mfrom | ||
248 | , stanzaChan = pongChan | ||
249 | , stanzaClosers = pongClsrs | ||
250 | , stanzaInterrupt = donevar | ||
251 | , stanzaOrigin = LocalPeer | ||
252 | } | ||
253 | ioWriteChan output pongStanza | ||
254 | void . liftIO . forkIO $ do | ||
255 | mapM_ (ioWriteChan $ stanzaChan pongStanza) pong | ||
256 | liftIO . atomically $ writeTVar (stanzaClosers pongStanza) Nothing | ||
257 | -- liftIO $ wlog "finished pong stanza" | ||
258 | |||
259 | -- TODO: Remove this, it is only to generate a debug print | 281 | -- TODO: Remove this, it is only to generate a debug print |
260 | ioWriteChan stanzas Stanza | 282 | ioWriteChan stanzas Stanza |
261 | { stanzaType = Ping | 283 | { stanzaType = Ping |
@@ -265,7 +287,7 @@ xmppInbound sv k pingflag src stanzas output donevar = doNestingXML $ do | |||
265 | , stanzaChan = chan | 287 | , stanzaChan = chan |
266 | , stanzaClosers = clsrs | 288 | , stanzaClosers = clsrs |
267 | , stanzaInterrupt = donevar | 289 | , stanzaInterrupt = donevar |
268 | , stanzaOrigin = NetworkOrigin k | 290 | , stanzaOrigin = NetworkOrigin k output |
269 | } | 291 | } |
270 | stype -> ioWriteChan stanzas Stanza | 292 | stype -> ioWriteChan stanzas Stanza |
271 | { stanzaType = stype | 293 | { stanzaType = stype |
@@ -275,7 +297,7 @@ xmppInbound sv k pingflag src stanzas output donevar = doNestingXML $ do | |||
275 | , stanzaChan = chan | 297 | , stanzaChan = chan |
276 | , stanzaClosers = clsrs | 298 | , stanzaClosers = clsrs |
277 | , stanzaInterrupt = donevar | 299 | , stanzaInterrupt = donevar |
278 | , stanzaOrigin = NetworkOrigin k | 300 | , stanzaOrigin = NetworkOrigin k output |
279 | } | 301 | } |
280 | awaitCloser stanza_lvl | 302 | awaitCloser stanza_lvl |
281 | liftIO . atomically $ writeTVar clsrs Nothing | 303 | liftIO . atomically $ writeTVar clsrs Nothing |
@@ -334,6 +356,22 @@ greet' namespace host = | |||
334 | ] | 356 | ] |
335 | ] ++ streamFeatures namespace | 357 | ] ++ streamFeatures namespace |
336 | 358 | ||
359 | consid Nothing = id | ||
360 | consid (Just sid) = (("id",[ContentText sid]):) | ||
361 | |||
362 | iq_bind_reply :: Maybe Text -> Text -> [XML.Event] | ||
363 | iq_bind_reply mid jid = | ||
364 | [ EventBeginElement "{jabber:client}iq" (consid mid [("type",[ContentText "result"])]) | ||
365 | , EventBeginElement "{urn:ietf:params:xml:ns:xmpp-bind}bind" | ||
366 | [("xmlns",[ContentText "urn:ietf:params:xml:ns:xmpp-bind"])] | ||
367 | , EventBeginElement "{urn:ietf:params:xml:ns:xmpp-bind}jid" [] | ||
368 | , EventContent (ContentText jid) | ||
369 | , EventEndElement "{urn:ietf:params:xml:ns:xmpp-bind}jid" | ||
370 | , EventEndElement "{urn:ietf:params:xml:ns:xmpp-bind}bind" | ||
371 | , EventEndElement "{jabber:client}iq" | ||
372 | ] | ||
373 | |||
374 | {- | ||
337 | greet namespace = | 375 | greet namespace = |
338 | [ EventBeginDocument | 376 | [ EventBeginDocument |
339 | , EventBeginElement (streamP "stream") | 377 | , EventBeginElement (streamP "stream") |
@@ -341,6 +379,7 @@ greet namespace = | |||
341 | , attr "version" "1.0" | 379 | , attr "version" "1.0" |
342 | ] | 380 | ] |
343 | ] | 381 | ] |
382 | -} | ||
344 | 383 | ||
345 | goodbye = | 384 | goodbye = |
346 | [ EventEndElement (streamP "stream") | 385 | [ EventEndElement (streamP "stream") |
@@ -403,12 +442,14 @@ forkConnection sv k pingflag src snk stanzas = do | |||
403 | [Slotted.pull slots >>= \x -> do | 442 | [Slotted.pull slots >>= \x -> do |
404 | writeTVar needsFlush True | 443 | writeTVar needsFlush True |
405 | return $ do | 444 | return $ do |
445 | -- liftIO $ wlog $ "yielding Chunk: " ++ show x | ||
406 | yield (Chunk x) | 446 | yield (Chunk x) |
407 | slot_src | 447 | slot_src |
408 | ,do Slotted.isEmpty slots >>= check | 448 | ,do Slotted.isEmpty slots >>= check |
409 | readTVar needsFlush >>= check | 449 | readTVar needsFlush >>= check |
410 | writeTVar needsFlush False | 450 | writeTVar needsFlush False |
411 | return $ do | 451 | return $ do |
452 | -- liftIO $ wlog "yielding Flush" | ||
412 | yield Flush | 453 | yield Flush |
413 | slot_src | 454 | slot_src |
414 | ,readTMVar rdone >> return (return ()) | 455 | ,readTMVar rdone >> return (return ()) |
@@ -501,9 +542,14 @@ stanzaToConduit stanza = do | |||
501 | return (return ())] | 542 | return (return ())] |
502 | what | 543 | what |
503 | 544 | ||
545 | socketFromKey :: Server k -> k -> IO Socket | ||
546 | socketFromKey sv k = do | ||
547 | return todo | ||
548 | |||
504 | monitor sv params = do | 549 | monitor sv params = do |
505 | chan <- return $ serverEvent sv | 550 | chan <- return $ serverEvent sv |
506 | stanzas <- atomically newTChan | 551 | stanzas <- atomically newTChan |
552 | quitVar <- atomically newEmptyTMVar | ||
507 | fix $ \loop -> do | 553 | fix $ \loop -> do |
508 | action <- atomically $ foldr1 orElse | 554 | action <- atomically $ foldr1 orElse |
509 | [ readTChan chan >>= \(k,e) -> return $ do | 555 | [ readTChan chan >>= \(k,e) -> return $ do |
@@ -513,8 +559,7 @@ monitor sv params = do | |||
513 | let (xsrc,xsnk) = xmlStream conread conwrite | 559 | let (xsrc,xsnk) = xmlStream conread conwrite |
514 | forkConnection sv k pingflag xsrc xsnk stanzas | 560 | forkConnection sv k pingflag xsrc xsnk stanzas |
515 | return () | 561 | return () |
516 | ConnectFailure addr -> do | 562 | ConnectFailure addr -> return () -- wlog $ tomsg k "ConnectFailure" |
517 | wlog $ tomsg k "ConnectFailure" | ||
518 | EOF -> wlog $ tomsg k "EOF" | 563 | EOF -> wlog $ tomsg k "EOF" |
519 | HalfConnection In -> do | 564 | HalfConnection In -> do |
520 | wlog $ tomsg k "ReadOnly" | 565 | wlog $ tomsg k "ReadOnly" |
@@ -523,13 +568,22 @@ monitor sv params = do | |||
523 | RequiresPing -> return () -- wlog $ tomsg k "RequiresPing" | 568 | RequiresPing -> return () -- wlog $ tomsg k "RequiresPing" |
524 | _ -> return () | 569 | _ -> return () |
525 | , readTChan stanzas >>= \stanza -> return $ do | 570 | , readTChan stanzas >>= \stanza -> return $ do |
571 | forkIO $ do | ||
572 | case (stanzaType stanza,stanzaOrigin stanza) of | ||
573 | (RequestResource wanted, NetworkOrigin k@(ClientKey{}) replyto) -> do | ||
574 | sock <- socketFromKey sv k | ||
575 | rsc <- getResourceName sock wanted | ||
576 | let reply = iq_bind_reply (stanzaId stanza) rsc | ||
577 | sendReply quitVar SetResource reply replyto | ||
578 | _ -> return () | ||
526 | let typ = Strict8.pack $ c ++ "->"++(show (stanzaType stanza))++" " | 579 | let typ = Strict8.pack $ c ++ "->"++(show (stanzaType stanza))++" " |
527 | c = case stanzaOrigin stanza of | 580 | c = case stanzaOrigin stanza of |
528 | LocalPeer -> "*" | 581 | LocalPeer -> "*" |
529 | NetworkOrigin (ClientKey {}) -> "C" | 582 | NetworkOrigin (ClientKey {}) _ -> "C" |
530 | NetworkOrigin (PeerKey {}) -> "P" | 583 | NetworkOrigin (PeerKey {}) _ -> "P" |
531 | wlog "" | 584 | wlog "" |
532 | stanzaToConduit stanza $$ prettyPrint typ | 585 | stanzaToConduit stanza $$ prettyPrint typ |
586 | |||
533 | ] | 587 | ] |
534 | action | 588 | action |
535 | loop | 589 | loop |