summaryrefslogtreecommitdiffhomepage
path: root/Storage/Network.hs
blob: c124761fe9cef9fd5579814b0008f06546a037a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
{- Copyright 2016 Joey Hess <id@joeyh.name>
 -
 - Licensed under the GNU AGPL version 3 or higher.
 -}

{-# LANGUAGE OverloadedStrings #-}

module Storage.Network (
	Server(..),
	networkServers,
	networkStorage,
	torableManager
) where

import Types
import Types.Storage
import Data.List
import Data.Char
import HTTP
import HTTP.Client
import Servant.Client
import Network.Wai.Handler.Warp (Port)
import Network.HTTP.Client hiding (port, host)
import Network.HTTP.Client.Internal (Connection, makeConnection)
import Control.Monad.Trans.Except (ExceptT, runExceptT)
import qualified Network.Socket
import Network.Socket.ByteString (sendAll, recv)
import Network.Socks5
import qualified Data.ByteString.UTF8 as BU8

type HostName = String

data Server = Server
	{ serverName :: HostName
	, serverPort :: Port
	}

serverUrl :: Server -> BaseUrl
serverUrl srv = BaseUrl Http (serverName srv) (serverPort srv) ""

networkServers :: IO [Server]
networkServers = return 
	[ Server "localhost" 8080
	, Server "localhost" 8080
	, Server "localhost" 8080
	]

networkStorage :: Server -> Storage
networkStorage server = Storage
	{ storeShare = store server
	, retrieveShare = retrieve server
	, obscureShares = obscure server
	, countShares = count server
	, moveShares = move server
	}

store :: Server -> StorableObjectIdent -> Share -> IO StoreResult
store srv i (Share _n o) = 
	serverRequest srv StoreFailure id $ \pow ->
		putObject i pow o

retrieve :: Server -> ShareNum -> StorableObjectIdent -> IO RetrieveResult
retrieve srv n i = 
	serverRequest srv RetrieveFailure (RetrieveSuccess . Share n) $
		getObject i

-- | Servers should automatically obscure, so do nothing.
-- (Could upload chaff.)
obscure :: Server -> IO ObscureResult
obscure _ = return ObscureSuccess

count :: Server -> IO CountResult
count srv = serverRequest srv CountFailure id countObjects

-- | Not needed for servers.
move :: Server -> Storage -> IO ()
move _ _ = error "move is not implemented for servers"

serverRequest
	:: Server
	-> (String -> a)
	-> (r -> a)
	-> (Maybe ProofOfWork -> Manager -> BaseUrl -> ExceptT ServantError IO (ProofOfWorkRequirement r))
	-> IO a
serverRequest srv onerr onsuccess a = go Nothing =<< newManager torableManager
  where
	url = serverUrl srv
	go pow manager = do
		res <- runExceptT $ a pow manager url
		case res of
			Left err -> return $ onerr $ 
				"server failure: " ++ show err
			Right (Result r) -> return $ onsuccess r
			Right needpow -> error "NEEDPOW" -- loop with pow

-- | HTTP Manager supporting tor .onion and regular hosts
torableManager :: ManagerSettings
torableManager = defaultManagerSettings
	{ managerRawConnection = return conn
	}
  where
	conn addr host port
		| ".onion" `isSuffixOf` map toLower host = torConnection host port
		| otherwise = do
			regular <- managerRawConnection defaultManagerSettings
			regular addr host port

torConnection :: HostName -> Port -> IO Connection
torConnection onionaddress p = do
	(socket, _) <- socksConnect torsockconf socksaddr
	socketConnection socket 8192
  where
	torsocksport = 9050
	torsockconf = defaultSocksConf "127.0.0.1" torsocksport
	socksdomain = SocksAddrDomainName (BU8.fromString onionaddress)
	socksaddr = SocksAddress socksdomain (fromIntegral p)

socketConnection :: Network.Socket.Socket -> Int -> IO Connection
socketConnection socket chunksize = makeConnection
	(recv socket chunksize)
	(sendAll socket)
	(Network.Socket.close socket)