summaryrefslogtreecommitdiff
path: root/Presence/XMPPServer.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Presence/XMPPServer.hs')
-rw-r--r--Presence/XMPPServer.hs120
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
37import Nesting 37import Nesting
38import EventUtil 38import EventUtil
39import Server 39import Server
40import ResourcePolicy (getResourceName)
40 41
41peerport = 5269 42peerport = 5269
42clientport = 5222 43clientport = 5222
@@ -101,10 +102,10 @@ data Stanza
101 stanzaChan :: TChan (Maybe XML.Event) } 102 stanzaChan :: TChan (Maybe XML.Event) }
102-} 103-}
103 104
104data StanzaType = Unrecognized | Ping | Pong | BindResource (Maybe Text) 105data StanzaType = Unrecognized | Ping | Pong | RequestResource (Maybe Text) | SetResource
105 deriving Show 106 deriving Show
106 107
107data StanzaOrigin = LocalPeer | NetworkOrigin ConnectionKey 108data StanzaOrigin = LocalPeer | NetworkOrigin ConnectionKey (TChan Stanza)
108 109
109data Stanza = Stanza 110data 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
145sendReply 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
144grokStanzaIQGet :: Monad m => XML.Event -> NestingXML o m (Maybe StanzaType) 170grokStanzaIQGet :: Monad m => XML.Event -> NestingXML o m (Maybe StanzaType)
145grokStanzaIQGet stanza = do 171grokStanzaIQGet 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
359consid Nothing = id
360consid (Just sid) = (("id",[ContentText sid]):)
361
362iq_bind_reply :: Maybe Text -> Text -> [XML.Event]
363iq_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{-
337greet namespace = 375greet 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
345goodbye = 384goodbye =
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
545socketFromKey :: Server k -> k -> IO Socket
546socketFromKey sv k = do
547 return todo
548
504monitor sv params = do 549monitor 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