aboutsummaryrefslogtreecommitdiff
path: root/RemoteDaemon/Transport/Tor.hs
diff options
context:
space:
mode:
authorGravatar Joey Hess <joeyh@joeyh.name>2016-12-09 16:02:43 -0400
committerGravatar Joey Hess <joeyh@joeyh.name>2016-12-09 16:02:43 -0400
commit46f3063131f7711208c1134b31caf999e375306d (patch)
tree47ab66581b0d2de95865b0f7948db041f6589935 /RemoteDaemon/Transport/Tor.hs
parent1eeae43d88c924dfac7c004ff7aeb67e17c52a13 (diff)
remotedaemon: git change detection over tor hidden service
Diffstat (limited to 'RemoteDaemon/Transport/Tor.hs')
-rw-r--r--RemoteDaemon/Transport/Tor.hs73
1 files changed, 63 insertions, 10 deletions
diff --git a/RemoteDaemon/Transport/Tor.hs b/RemoteDaemon/Transport/Tor.hs
index 5ea06ac2c..20320cadd 100644
--- a/RemoteDaemon/Transport/Tor.hs
+++ b/RemoteDaemon/Transport/Tor.hs
@@ -1,11 +1,11 @@
-{- git-remote-daemon, tor hidden service transport
+{- git-remote-daemon, tor hidden service server and transport
-
- Copyright 2016 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU GPL version 3 or higher.
-}
-module RemoteDaemon.Transport.Tor (server) where
+module RemoteDaemon.Transport.Tor (server, transport) where
import Common
import qualified Annex
@@ -16,20 +16,23 @@ import RemoteDaemon.Common
import Utility.Tor
import Utility.FileMode
import Utility.AuthToken
-import P2P.Protocol
+import P2P.Protocol as P2P
import P2P.IO
import P2P.Annex
import P2P.Auth
+import P2P.Address
import Annex.UUID
import Types.UUID
import Messages
import Git
+import Git.Command
import System.PosixCompat.User
-import Network.Socket
import Control.Concurrent
import System.Log.Logger (debugM)
import Control.Concurrent.STM
+import Control.Concurrent.Async
+import qualified Network.Socket as S
-- Run tor hidden service.
server :: TransportHandle -> IO ()
@@ -44,17 +47,17 @@ server th@(TransportHandle (LocalRepo r) _) = do
let ident = fromUUID u
let sock = hiddenServiceSocketFile uid ident
nukeFile sock
- soc <- socket AF_UNIX Stream defaultProtocol
- bind soc (SockAddrUnix sock)
+ soc <- S.socket S.AF_UNIX S.Stream S.defaultProtocol
+ S.bind soc (S.SockAddrUnix sock)
-- Allow everyone to read and write to the socket; tor is probably
-- running as a different user. Connections have to authenticate
-- to do anything, so it's fine that other local users can connect.
modifyFileMode sock $ addModes
[groupReadMode, groupWriteMode, otherReadMode, otherWriteMode]
- listen soc 2
+ S.listen soc 2
debugM "remotedaemon" "Tor hidden service running"
forever $ do
- (conn, _) <- accept soc
+ (conn, _) <- S.accept soc
h <- setupHandle conn
ok <- atomically $ ifM (isFullTBQueue q)
( return False
@@ -97,7 +100,7 @@ serveClient th u r q = bracket setup cleanup start
, connIhdl = h
, connOhdl = h
}
- v <- liftIO $ runNetProto conn $ serveAuth u
+ v <- liftIO $ runNetProto conn $ P2P.serveAuth u
case v of
Right (Just theiruuid) -> authed conn theiruuid
Right Nothing -> liftIO $
@@ -110,7 +113,57 @@ serveClient th u r q = bracket setup cleanup start
authed conn theiruuid =
bracket watchChangedRefs (liftIO . stopWatchingChangedRefs) $ \crh -> do
v' <- runFullProto (Serving theiruuid crh) conn $
- serveAuthed u
+ P2P.serveAuthed u
case v' of
Right () -> return ()
Left e -> liftIO $ debugM "remotedaemon" ("Tor connection error: " ++ e)
+
+-- Connect to peer's tor hidden service.
+transport :: Transport
+transport (RemoteRepo r _) url@(RemoteURI uri) th ichan ochan =
+ case unformatP2PAddress (show uri) of
+ Nothing -> return ()
+ Just addr -> robustConnection 1 $ do
+ g <- liftAnnex th Annex.gitRepo
+ bracket (connectPeer g addr) closeConnection (go addr)
+ where
+ go addr conn = do
+ myuuid <- liftAnnex th getUUID
+ authtoken <- fromMaybe nullAuthToken
+ <$> liftAnnex th (loadP2PRemoteAuthToken addr)
+ res <- runNetProto conn $
+ P2P.auth myuuid authtoken
+ case res of
+ Right (Just theiruuid)
+ | getUncachedUUID r == theiruuid -> do
+ send (CONNECTED url)
+ status <- handlecontrol
+ `race` handlepeer conn
+ send (DISCONNECTED url)
+ return $ either id id status
+ | otherwise -> return ConnectionStopping
+ _ -> return ConnectionClosed
+
+ send msg = atomically $ writeTChan ochan msg
+
+ handlecontrol = do
+ msg <- atomically $ readTChan ichan
+ case msg of
+ STOP -> return ConnectionStopping
+ LOSTNET -> return ConnectionStopping
+ _ -> handlecontrol
+
+ handlepeer conn = do
+ v <- runNetProto conn P2P.notifyChange
+ case v of
+ Right (Just (ChangedRefs shas)) -> do
+ whenM (checkNewShas th shas) $
+ fetch
+ handlepeer conn
+ _ -> return ConnectionClosed
+
+ fetch = do
+ send (SYNCING url)
+ ok <- inLocalRepo th $
+ runBool [Param "fetch", Param $ Git.repoDescribe r]
+ send (DONESYNCING url ok)