summaryrefslogtreecommitdiff
path: root/Presence
diff options
context:
space:
mode:
Diffstat (limited to 'Presence')
-rw-r--r--Presence/FGConsole.hs1
-rw-r--r--Presence/LocalPeerCred.hs95
-rw-r--r--Presence/Server.hs15
-rw-r--r--Presence/UTmp.hs2
-rw-r--r--Presence/XMPPServer.hs67
-rw-r--r--Presence/main.hs15
6 files changed, 156 insertions, 39 deletions
diff --git a/Presence/FGConsole.hs b/Presence/FGConsole.hs
index fc1ece65..93b9a590 100644
--- a/Presence/FGConsole.hs
+++ b/Presence/FGConsole.hs
@@ -14,7 +14,6 @@ import Control.Monad
14import Foreign.C.Error 14import Foreign.C.Error
15import Foreign.C 15import Foreign.C
16 16
17import Todo
18import Debug.Trace 17import Debug.Trace
19import System.Posix.Signals 18import System.Posix.Signals
20 19
diff --git a/Presence/LocalPeerCred.hs b/Presence/LocalPeerCred.hs
new file mode 100644
index 00000000..c58fe288
--- /dev/null
+++ b/Presence/LocalPeerCred.hs
@@ -0,0 +1,95 @@
1module LocalPeerCred where
2
3import Data.ByteString.Lazy.Char8 as L hiding (map,putStrLn,tail,splitAt,tails,filter)
4import qualified Data.ByteString.Lazy.Char8 as L (splitAt)
5import qualified Data.ByteString.Lazy as W8
6import Data.List (tails)
7import System.IO ( withFile, IOMode(..))
8import Data.Maybe
9import Data.Binary
10import Data.Bits
11import Network.Socket
12import System.Posix.Types
13import Debug.Trace
14-- import System.Environment (getArgs)
15
16xs ?? n | n < 0 = Nothing
17[] ?? _ = Nothing
18(x:_) ?? 0 = Just x
19(_:xs) ?? n = xs ?? (n-1)
20
21parseHex bs = L.concat . parseHex' $ bs
22 where
23 parseHex' bs =
24 let (dnib,ts) = L.splitAt 2 bs
25 parseNibble x = W8.pack $ group2 toW8 (W8.unpack $ W8.map hexDigit x)
26 hexDigit d = d - (if d>0x39 then 0x37 else 0x30)
27 group2 f (x:y:ys) = f x y : group2 f ys
28 group2 _ _ = []
29 toW8 a b = shift a 4 .|. b
30 in parseNibble dnib :
31 if L.null ts
32 then []
33 else parseHex' ts
34
35getLocalPeerCred' (SockAddrInet portn host) = do
36 let port = fromEnum portn
37 trace ("tcp4 "++show(port,host)) $ withFile "/proc/net/tcp" ReadMode (parseProcNet port host)
38
39getLocalPeerCred' (SockAddrInet6 portn flow host scope) = do
40 let port = fromEnum portn
41 trace "tcp6" $ withFile "/proc/net/tcp6" ReadMode (parseProcNet port host)
42
43getLocalPeerCred' addr@(SockAddrUnix _) =
44 -- TODO: parse /proc/net/unix
45 -- see also: Network.Socket.getPeerCred
46 return Nothing
47
48getLocalPeerCred sock = do
49 addr <- getPeerName sock
50 muid <- getLocalPeerCred' addr
51 case muid of
52 Just uid -> return uid
53 Nothing -> return undefined -- trace "proc failed." $ fmap (CUid . fromIntegral . sndOf3) (getPeerCred sock)
54 where sndOf3 (pid,uid,gid) = uid
55
56from16 :: Word16 -> Int
57from16 = fromEnum
58
59as16 :: Word16 -> Word16
60as16 = id
61
62parseProcNet port host h = do
63 tcp <- hGetContents h
64 let u = do
65 ls <- listToMaybe . tail . tails . L.lines $ tcp
66 let ws = map L.words ls
67 let rs = ( catMaybes . flip map ws $ \xs -> do
68 let ys = snd (Prelude.splitAt 1 xs)
69 localaddr <- listToMaybe ys
70 let zs = L.splitWith (==':') localaddr
71 addr <- fmap parseHex $ listToMaybe zs
72 port <- fmap (fromIntegral . as16 . decode . parseHex) $ listToMaybe $ snd (Prelude.splitAt 1 zs)
73 let ys' = snd (Prelude.splitAt 5 (tail ys))
74 uid <- listToMaybe ys'
75 let peer = (port,decode addr)
76 user = toEnum (read (unpack uid) ::Int) ::UserID -- CUid . fromIntegral $ (read (unpack uid)::Int)
77 return $ trace ("peer:"++show(peer,user)) (peer,user)
78 )
79 fmap snd . listToMaybe $ filter ((===(port,host)).fst) rs
80 trace ("found:"++show u) $ u `seq` return u
81 where
82 a === b = let r= a==b in trace ("Comparing "++show (a,b)++"-->"++show r) r
83
84{-
85main = do
86 args <- getArgs
87 let addr = fromJust $ do
88 port <- args ?? 0
89 host <- args ?? 1
90 return $ SockAddrInet (toEnum . fromIntegral . readInt $ port) (toEnum (read host::Int))
91 readInt x = read x :: Int
92
93 r <- getLocalPeerCred' addr
94 putStrLn $ "r = " ++ show r
95-}
diff --git a/Presence/Server.hs b/Presence/Server.hs
index feefea2b..adc3de84 100644
--- a/Presence/Server.hs
+++ b/Presence/Server.hs
@@ -4,18 +4,14 @@
4module Server where 4module Server where
5 5
6import Network.Socket 6import Network.Socket
7import qualified Data.ByteString as S (ByteString)
8import Data.ByteString.Lazy.Char8 as L 7import Data.ByteString.Lazy.Char8 as L
9 ( ByteString 8 ( fromChunks
10 , hPutStrLn
11 , fromChunks
12 , putStrLn ) 9 , putStrLn )
13import Data.ByteString.Char8 10import Data.ByteString.Char8
14 ( hGetNonBlocking 11 ( hGetNonBlocking
15 ) 12 )
16import System.IO 13import System.IO
17 ( Handle 14 ( IOMode(..)
18 , IOMode(..)
19 , hSetBuffering 15 , hSetBuffering
20 , BufferMode(..) 16 , BufferMode(..)
21 , hWaitForInput 17 , hWaitForInput
@@ -23,8 +19,6 @@ import System.IO
23 , hIsEOF 19 , hIsEOF
24 ) 20 )
25import Control.Monad 21import Control.Monad
26import Control.Monad.Fix (fix)
27import Todo
28import Control.Concurrent (forkIO) 22import Control.Concurrent (forkIO)
29import Control.Exception (handle,SomeException(..)) 23import Control.Exception (handle,SomeException(..))
30import Data.HList 24import Data.HList
@@ -54,8 +48,11 @@ doServer port g startCon = runServer2 port (runConn2 g)
54 runConn2 g st (sock,_) = do 48 runConn2 g st (sock,_) = do
55 h <- socketToHandle sock ReadWriteMode 49 h <- socketToHandle sock ReadWriteMode
56 hSetBuffering h NoBuffering 50 hSetBuffering h NoBuffering
57 st'' <- startCon (h .*. st) 51 st'' <- startCon sock (h .*. st)
58 let doException (SomeException e) = Prelude.putStrLn ("\n\nexception: " ++ show e ++ "\n\n") 52 let doException (SomeException e) = Prelude.putStrLn ("\n\nexception: " ++ show e ++ "\n\n")
53 handle doException $ do
54 -- PEER CRED: (0,4294967295,4294967295)
55 -- PEER NAME: 127.0.0.1:37253
59 handle doException $ fix $ \loop -> do 56 handle doException $ fix $ \loop -> do
60 let continue () = hIsEOF h >>= flip when loop . not 57 let continue () = hIsEOF h >>= flip when loop . not
61 packet <- getPacket h 58 packet <- getPacket h
diff --git a/Presence/UTmp.hs b/Presence/UTmp.hs
index c94dcef2..c2549a88 100644
--- a/Presence/UTmp.hs
+++ b/Presence/UTmp.hs
@@ -6,7 +6,6 @@ import qualified Data.ByteString as S
6import qualified Data.ByteString.Char8 as C 6import qualified Data.ByteString.Char8 as C
7import Data.BitSyntax 7import Data.BitSyntax
8import Data.Functor.Identity 8import Data.Functor.Identity
9import Foreign.C.String
10import Data.Maybe 9import Data.Maybe
11import System.Posix.Signals 10import System.Posix.Signals
12import System.Posix.Types 11import System.Posix.Types
@@ -17,7 +16,6 @@ import Data.Int
17import Control.Monad.Error.Class 16import Control.Monad.Error.Class
18import System.IO.Error 17import System.IO.Error
19 18
20import Todo
21 19
22utmp_file = "/var/run/utmp" 20utmp_file = "/var/run/utmp"
23 21
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs
index 591acad6..05b12b73 100644
--- a/Presence/XMPPServer.hs
+++ b/Presence/XMPPServer.hs
@@ -1,6 +1,7 @@
1{-# LANGUAGE OverloadedStrings #-} 1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE ScopedTypeVariables #-} 2{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE ViewPatterns #-} 3{-# LANGUAGE ViewPatterns #-}
4{-# LANGUAGE TupleSections #-}
4module XMPPServer ( listenForXmppClients ) where 5module XMPPServer ( listenForXmppClients ) where
5 6
6import Data.HList.TypeEqGeneric1() 7import Data.HList.TypeEqGeneric1()
@@ -9,27 +10,25 @@ import ByteStringOperators
9 10
10import Server 11import Server
11import Data.ByteString.Lazy.Char8 as L 12import Data.ByteString.Lazy.Char8 as L
12 ( ByteString 13 ( hPutStrLn
13 , hPutStrLn
14 , unlines 14 , unlines
15 , pack 15 , pack
16 , unpack 16 , unpack )
17 , init )
18import qualified Data.ByteString.Lazy.Char8 as L 17import qualified Data.ByteString.Lazy.Char8 as L
19 ( putStrLn ) 18 ( putStrLn )
20import System.IO 19import System.IO
21 ( Handle 20 ( Handle
22 ) 21 )
23import Control.Concurrent (forkIO)
24import Control.Concurrent.Chan
25import Data.HList 22import Data.HList
26import AdaptServer 23import AdaptServer
27import Text.XML.HaXml.Lex (xmlLex) 24import Text.XML.HaXml.Lex (xmlLex)
28import Text.XML.HaXml.Parse (xmlParseWith,element,doctypedecl,processinginstruction,elemOpenTag,elemCloseTag) 25import Text.XML.HaXml.Parse (xmlParseWith,element,{-doctypedecl,-}processinginstruction,elemOpenTag,elemCloseTag)
29import Text.XML.HaXml.Types as Hax (ElemTag,QName(..),Namespace(..),Element(..),Content(..),AttValue(..)) 26import Text.XML.HaXml.Types as Hax (ElemTag,QName(..),Namespace(..),Element(..),Content(..),AttValue(..))
30import qualified Text.XML.HaXml.Types as Hax (Element)
31import Data.Maybe 27import Data.Maybe
32import Debug.Trace 28import Debug.Trace
29import Control.Arrow
30import LocalPeerCred
31import Network.Socket
33 32
34 33
35 34
@@ -51,17 +50,21 @@ greet host = L.unlines
51 , "</stream:features>" 50 , "</stream:features>"
52 ] 51 ]
53 52
54startCon st = do 53startCon sock st = do
55 let h = hOccursFst st :: Handle 54 let h = hOccursFst st :: Handle
55 cred <- getLocalPeerCred sock
56 Prelude.putStrLn $ "PEER CRED: "++show cred
57 pname <- getPeerName sock
58 Prelude.putStrLn $ "PEER NAME: "++show pname
56 return (ConnectionFinalizer (return ()) .*. st) 59 return (ConnectionFinalizer (return ()) .*. st)
57 60
58iq_query_unavailable host id mjid xmlns = L.unlines $ 61iq_query_unavailable host id mjid xmlns kind = L.unlines $
59 [ "<iq type='error'" 62 [ "<iq type='error'"
60 , " from='" <++> host <++> "'" 63 , " from='" <++> host <++> "'"
61 , case mjid of Just jid -> " to='" <++> jid <++> "'" 64 , case mjid of Just jid -> " to='" <++> jid <++> "'"
62 Nothing -> "" 65 Nothing -> ""
63 , " id='" <++> id <++> "'>" 66 , " id='" <++> id <++> "'>"
64 , " <query xmlns='" <++> xmlns <++> "'/>" 67 , " <" <++> kind <++> " xmlns='" <++> xmlns <++> "'/>"
65 , " <error type='cancel'>" 68 , " <error type='cancel'>"
66 , " <service-unavailable" 69 , " <service-unavailable"
67 , " xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" 70 , " xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
@@ -71,6 +74,7 @@ iq_query_unavailable host id mjid xmlns = L.unlines $
71 74
72tagattrs tag content = Prelude.concatMap (\(CElem (Elem _ a _) _)->a) 75tagattrs tag content = Prelude.concatMap (\(CElem (Elem _ a _) _)->a)
73 $ Prelude.filter (bindElem tag) content 76 $ Prelude.filter (bindElem tag) content
77anytagattrs content = Prelude.concatMap (\(CElem (Elem n a _) _)->map (second (n,)) a) content
74 78
75bindElem tag (CElem (Elem (N n) _ _) _) | n==tag = True 79bindElem tag (CElem (Elem (N n) _ _) _) | n==tag = True
76bindElem _ _ = False 80bindElem _ _ = False
@@ -132,13 +136,37 @@ iqresponse host (Elem _ attrs content) = do
132 Just (iqresult host id Nothing)) 136 Just (iqresult host id Nothing))
133 137
134 "get" -> trace ("iq-get "++show (attrs,content)) $ do 138 "get" -> trace ("iq-get "++show (attrs,content)) $ do
135 xmlns <- fmap pack $ 139 (tag,as) <- lookup (N "xmlns") (anytagattrs content)
136 lookup (N "xmlns") (tagattrs "query" content) 140 xmlns <- fmap pack $ listToMaybe . astring $ as
137 >>= listToMaybe . astring 141 let servicekind = case tag of { (N s) -> pack s ; _ -> "query" }
138 Just (iq_query_unavailable host id Nothing xmlns) 142 case xmlns of
143 "urn:xmpp:ping" -> do
144 let to = case fmap pack (lookup (N "from") attrs >>= unattr) of
145 Just jid -> "to='" <++> jid <++> "' "
146 Nothing -> ""
147 Just $ "<iq from='" <++> host <++> "' " <++> to <++> "id='" <++> id <++> "' type='result'/>"
148
149 _ -> Just (iq_query_unavailable host id Nothing xmlns servicekind)
139 _ -> Nothing 150 _ -> Nothing
140 151
141 152-- <presence>
153-- <priority>1</priority>
154-- <c xmlns='http://jabber.org/protocol/caps'
155-- node='http://pidgin.im/'
156-- hash='sha-1' ver='lV6i//bt2U8Rm0REcX8h4F3Nk3M='
157-- ext='voice-v1 camera-v1 video-v1'/>
158-- <x xmlns='vcard-temp:x:update'/>
159-- </presence>
160
161presence_response host (Elem _ attrs content) = do
162 -- let id = fmap pack (lookup (N "id") attrs >>= unattr)
163 typ <- fmap pack (lookup (N "type") attrs >>= unattr)
164 case typ of
165 "subscribe" -> do
166 -- <presence to='guest@localhost' type='subscribe'/>
167 to <- fmap pack (lookup (N "to") attrs >>= unattr)
168 Just $ "<presence to='" <++> to <++> "' type='subscribed'/>"
169 _ -> Nothing
142 170
143doCon st elem cont = do 171doCon st elem cont = do
144 let h = hOccursFst st :: Handle 172 let h = hOccursFst st :: Handle
@@ -152,8 +180,13 @@ doCon st elem cont = do
152 hsend (greet host) 180 hsend (greet host)
153 Element e@(Elem (N "iq") _ _) -> 181 Element e@(Elem (N "iq") _ _) ->
154 case iqresponse host e of 182 case iqresponse host e of
155 Nothing -> trace "no respones" $ return () 183 Nothing -> trace "IGNORE: no response to <iq>" $ return ()
156 Just r -> hsend r 184 Just r -> hsend r
185 Element e@(Elem (N "presence") _ _) ->
186 case presence_response host e of
187 Nothing -> trace "IGNORE: no response to <presence>" $ return ()
188 Just r -> hsend r
189
157 _ -> return () -- putStrLn $ "unhandled: "++show v 190 _ -> return () -- putStrLn $ "unhandled: "++show v
158 191
159 putStrLn (show elem) 192 putStrLn (show elem)
diff --git a/Presence/main.hs b/Presence/main.hs
index b0f73a9e..7df81903 100644
--- a/Presence/main.hs
+++ b/Presence/main.hs
@@ -1,12 +1,9 @@
1{-# LANGUAGE CPP #-} 1{-# LANGUAGE CPP #-}
2 2
3import System.Directory 3import System.Directory
4import System.IO
5import Control.Monad 4import Control.Monad
6import System.Posix.Signals 5import System.Posix.Signals
7import System.Posix.Types 6import System.Posix.Types
8import Control.Monad.Error.Class
9import Control.Exception (throw)
10import System.Posix.Process 7import System.Posix.Process
11import Data.Maybe 8import Data.Maybe
12 9
@@ -18,8 +15,7 @@ import FGConsole
18import XMPPServer 15import XMPPServer
19import Data.HList 16import Data.HList
20import Network.Socket (sClose) 17import Network.Socket (sClose)
21import Control.Concurrent (threadDelay) 18import Control.Exception
22import Control.Exception (handle,SomeException(..))
23 19
24jid user host rsrc = user ++ "@" ++ host ++ "/" ++ rsrc 20jid user host rsrc = user ++ "@" ++ host ++ "/" ++ rsrc
25 21
@@ -81,22 +77,21 @@ sendUSR1 pid = do
81 77
82getStartupAction [] = throw (userError "pid file?") >> return (Right "") 78getStartupAction [] = throw (userError "pid file?") >> return (Right "")
83getStartupAction (p:ps) = do 79getStartupAction (p:ps) = do
84 catch 80 handle onEr $
85 ( do 81 ( do
86 pid <- fmap CPid (readFile p >>= readIO) 82 pid <- fmap CPid (readFile p >>= readIO)
87 -- signal pid 83 -- signal pid
88 return (Left pid) ) 84 return (Left pid) )
89 onEr
90 where 85 where
91 onEr e = do 86 onEr (SomeException _) = do
92 pid <- getProcessID 87 pid <- getProcessID
93 putStrLn $ "starting pid = "++show pid 88 putStrLn $ "starting pid = "++show pid
94 catch (do 89 handle (\(SomeException _) -> getStartupAction ps)
90 (do
95 writeFile p (show pid) 91 writeFile p (show pid)
96 putStrLn $ "writing "++show p 92 putStrLn $ "writing "++show p
97 -- start daemon 93 -- start daemon
98 return (Right p) ) 94 return (Right p) )
99 (\_ -> getStartupAction ps)
100 95
101runOnce ps run notify = getStartupAction ps >>= doit 96runOnce ps run notify = getStartupAction ps >>= doit
102 where 97 where