diff options
Diffstat (limited to 'src/Network')
-rw-r--r-- | src/Network/QueryResponse.hs | 76 |
1 files changed, 40 insertions, 36 deletions
diff --git a/src/Network/QueryResponse.hs b/src/Network/QueryResponse.hs index 221c2284..9262132f 100644 --- a/src/Network/QueryResponse.hs +++ b/src/Network/QueryResponse.hs | |||
@@ -45,7 +45,7 @@ import System.Timeout | |||
45 | -- > r <- sendQuery client method q | 45 | -- > r <- sendQuery client method q |
46 | -- > -- Quit client. | 46 | -- > -- Quit client. |
47 | -- > quitServer | 47 | -- > quitServer |
48 | forkListener :: Client err meth tid addr x ctx -> IO (IO ()) | 48 | forkListener :: Client err meth tid addr x -> IO (IO ()) |
49 | forkListener client = do | 49 | forkListener client = do |
50 | thread_id <- forkIO $ do | 50 | thread_id <- forkIO $ do |
51 | myThreadId >>= flip labelThread "listener" | 51 | myThreadId >>= flip labelThread "listener" |
@@ -58,21 +58,21 @@ forkListener client = do | |||
58 | -- out if 'forkListener' was never invoked to spawn a thread receive and | 58 | -- out if 'forkListener' was never invoked to spawn a thread receive and |
59 | -- dispatch the response. | 59 | -- dispatch the response. |
60 | sendQuery :: | 60 | sendQuery :: |
61 | forall err a b tbl x ctx meth tid addr. | 61 | forall err a b tbl x meth tid addr. |
62 | Client err meth tid addr x ctx -- ^ A query/response implementation. | 62 | Client err meth tid addr x -- ^ A query/response implementation. |
63 | -> MethodSerializer addr x ctx meth a b -- ^ Information for marshalling the query. | 63 | -> MethodSerializer addr x meth a b -- ^ Information for marshalling the query. |
64 | -> a -- ^ The outbound query. | 64 | -> a -- ^ The outbound query. |
65 | -> addr -- ^ Destination address of query. | 65 | -> addr -- ^ Destination address of query. |
66 | -> IO (Maybe b) -- ^ The response, or 'Nothing' if it timed out. | 66 | -> IO (Maybe b) -- ^ The response, or 'Nothing' if it timed out. |
67 | sendQuery (Client net d err pending whoami) meth q addr = do | 67 | sendQuery (Client net d err pending whoami _) meth q addr = do |
68 | mvar <- newEmptyMVar | 68 | mvar <- newEmptyMVar |
69 | tid <- atomically $ do | 69 | tid <- atomically $ do |
70 | tbl <- readTVar pending | 70 | tbl <- readTVar pending |
71 | let (tid, tbl') = dispatchRegister (tableMethods d) mvar tbl | 71 | let (tid, tbl') = dispatchRegister (tableMethods d) mvar tbl |
72 | writeTVar pending tbl' | 72 | writeTVar pending tbl' |
73 | return tid | 73 | return tid |
74 | (self,ctx) <- whoami | 74 | self <- whoami |
75 | sendMessage net addr (wrapQuery meth ctx self addr q) | 75 | sendMessage net addr (wrapQuery meth self addr q) |
76 | mres <- timeout (methodTimeout meth) $ takeMVar mvar | 76 | mres <- timeout (methodTimeout meth) $ takeMVar mvar |
77 | case mres of | 77 | case mres of |
78 | Just x -> return $ Just $ unwrapResponse meth x | 78 | Just x -> return $ Just $ unwrapResponse meth x |
@@ -84,21 +84,25 @@ sendQuery (Client net d err pending whoami) meth q addr = do | |||
84 | -- * Implementing a query\/response 'Client'. | 84 | -- * Implementing a query\/response 'Client'. |
85 | 85 | ||
86 | -- | All inputs required to implement a query\/response client. | 86 | -- | All inputs required to implement a query\/response client. |
87 | data Client err meth tid addr x ctx = forall tbl. Client | 87 | data Client err meth tid addr x = forall tbl. Client |
88 | { -- | The 'Transport' used to dispatch and receive packets. | 88 | { -- | The 'Transport' used to dispatch and receive packets. |
89 | clientNet :: Transport err addr x | 89 | clientNet :: Transport err addr x |
90 | -- | Methods for handling inbound packets. | 90 | -- | Methods for handling inbound packets. |
91 | , clientDispatcher :: DispatchMethods tbl err meth tid addr x ctx | 91 | , clientDispatcher :: DispatchMethods tbl err meth tid addr x |
92 | -- | Methods for reporting various conditions. | 92 | -- | Methods for reporting various conditions. |
93 | , clientErrorReporter :: ErrorReporter addr x meth tid err | 93 | , clientErrorReporter :: ErrorReporter addr x meth tid err |
94 | -- | State necessary for routing inbound responses and assigning unique | 94 | -- | State necessary for routing inbound responses and assigning unique |
95 | -- /tid/ values for outgoing queries. | 95 | -- /tid/ values for outgoing queries. |
96 | , clientPending :: TVar tbl | 96 | , clientPending :: TVar tbl |
97 | -- | An action yielding this client\'s own address along with some | 97 | -- | An action yielding this client\'s own address. It is invoked once |
98 | -- context neccessary for serializing outgoing packets. It is invoked | 98 | -- on each outbound and inbound packet. It is valid for this to always |
99 | -- once on each outbound and inbound packet. It is valid for this to | 99 | -- return the same value. |
100 | -- always return the same value. | 100 | , clientAddress :: IO addr |
101 | , clientContext :: IO (addr,ctx) | 101 | -- | Transform a query /tid/ value to an appropriate response /tid/ |
102 | -- value. Normally, this would be the identity transformation, but if | ||
103 | -- /tid/ includes a unique cryptographic nonce, then it should be | ||
104 | -- generated here. | ||
105 | , clientResponseId :: tid -> IO tid | ||
102 | } | 106 | } |
103 | 107 | ||
104 | -- | An incomming message can be classified into three cases. | 108 | -- | An incomming message can be classified into three cases. |
@@ -108,13 +112,13 @@ data MessageClass err meth tid | |||
108 | | IsResponse tid -- ^ A response to a outgoing query we associated with a /tid/ value. | 112 | | IsResponse tid -- ^ A response to a outgoing query we associated with a /tid/ value. |
109 | | IsUnknown err -- ^ None of the above. | 113 | | IsUnknown err -- ^ None of the above. |
110 | 114 | ||
111 | -- | Handler for an inbound query of type _x_ from an address of type _addr_. | 115 | -- | Handler for an inbound query of type /x/ from an address of type _addr_. |
112 | data MethodHandler err tid addr x ctx = forall a b. MethodHandler | 116 | data MethodHandler err tid addr x = forall a b. MethodHandler |
113 | { -- | Parse the query into a more specific type for this method. | 117 | { -- | Parse the query into a more specific type for this method. |
114 | methodParse :: x -> Either err a | 118 | methodParse :: x -> Either err a |
115 | -- | Serialize the response for transmission, given a context /ctx/ and the origin | 119 | -- | Serialize the response for transmission, given a context /ctx/ and the origin |
116 | -- and destination addresses. | 120 | -- and destination addresses. |
117 | , methodSerialize :: ctx -> tid -> addr -> addr -> b -> x | 121 | , methodSerialize :: tid -> addr -> addr -> b -> x |
118 | -- | Fully typed action to perform upon the query. The remote origin | 122 | -- | Fully typed action to perform upon the query. The remote origin |
119 | -- address of the query is provided to the handler. | 123 | -- address of the query is provided to the handler. |
120 | , methodAction :: addr -> a -> IO b | 124 | , methodAction :: addr -> a -> IO b |
@@ -123,20 +127,19 @@ data MethodHandler err tid addr x ctx = forall a b. MethodHandler | |||
123 | -- | Attempt to invoke a 'MethodHandler' upon a given inbound query. If the | 127 | -- | Attempt to invoke a 'MethodHandler' upon a given inbound query. If the |
124 | -- parse is successful, the returned IO action will construct our reply. | 128 | -- parse is successful, the returned IO action will construct our reply. |
125 | -- Otherwise, a parse err is returned. | 129 | -- Otherwise, a parse err is returned. |
126 | dispatchQuery :: MethodHandler err tid addr x ctx -- ^ Handler to invoke. | 130 | dispatchQuery :: MethodHandler err tid addr x -- ^ Handler to invoke. |
127 | -> ctx -- ^ Arbitrary context used during serialization. | 131 | -> tid -- ^ The transaction id for this query\/response session. |
128 | -> tid -- ^ The transaction id for this query\/response session. | 132 | -> addr -- ^ Our own address, to which the query was sent. |
129 | -> addr -- ^ Our own address, to which the query was sent. | 133 | -> x -- ^ The query packet. |
130 | -> x -- ^ The query packet. | 134 | -> addr -- ^ The origin address of the query. |
131 | -> addr -- ^ The origin address of the query. | ||
132 | -> Either err (IO x) | 135 | -> Either err (IO x) |
133 | dispatchQuery (MethodHandler unwrapQ wrapR f) ctx tid self x addr = | 136 | dispatchQuery (MethodHandler unwrapQ wrapR f) tid self x addr = |
134 | fmap (\a -> wrapR ctx tid self addr <$> f addr a) $ unwrapQ x | 137 | fmap (\a -> wrapR tid self addr <$> f addr a) $ unwrapQ x |
135 | 138 | ||
136 | -- | These four parameters are required to implement an ougoing query. A | 139 | -- | These four parameters are required to implement an ougoing query. A |
137 | -- peer-to-peer algorithm will define a 'MethodSerializer' for every 'MethodHandler' that | 140 | -- peer-to-peer algorithm will define a 'MethodSerializer' for every 'MethodHandler' that |
138 | -- might be returned by 'lookupHandler'. | 141 | -- might be returned by 'lookupHandler'. |
139 | data MethodSerializer addr x ctx meth a b = MethodSerializer | 142 | data MethodSerializer addr x meth a b = MethodSerializer |
140 | { -- | Seconds to wait for a response. | 143 | { -- | Seconds to wait for a response. |
141 | methodTimeout :: Int | 144 | methodTimeout :: Int |
142 | -- | A method identifier used for error reporting. This needn't be the | 145 | -- | A method identifier used for error reporting. This needn't be the |
@@ -146,7 +149,7 @@ data MethodSerializer addr x ctx meth a b = MethodSerializer | |||
146 | -- The /addr/ arguments are, respectively, our own origin address and the | 149 | -- The /addr/ arguments are, respectively, our own origin address and the |
147 | -- destination of the request. The /ctx/ argument is useful for attaching | 150 | -- destination of the request. The /ctx/ argument is useful for attaching |
148 | -- auxillary notations on all outgoing packets. | 151 | -- auxillary notations on all outgoing packets. |
149 | , wrapQuery :: ctx -> addr -> addr -> a -> x | 152 | , wrapQuery :: addr -> addr -> a -> x |
150 | -- | Parse an inbound packet /x/ into a response /b/ for this query. | 153 | -- | Parse an inbound packet /x/ into a response /b/ for this query. |
151 | , unwrapResponse :: x -> b | 154 | , unwrapResponse :: x -> b |
152 | } | 155 | } |
@@ -274,11 +277,11 @@ transactionMethods (TableMethods insert delete lookup) generate = TransactionMet | |||
274 | } | 277 | } |
275 | 278 | ||
276 | -- | A set of methods neccessary for dispatching incomming packets. | 279 | -- | A set of methods neccessary for dispatching incomming packets. |
277 | data DispatchMethods tbl err meth tid addr x ctx = DispatchMethods | 280 | data DispatchMethods tbl err meth tid addr x = DispatchMethods |
278 | { -- | Clasify an inbound packet as a query or response. | 281 | { -- | Clasify an inbound packet as a query or response. |
279 | classifyInbound :: x -> MessageClass err meth tid | 282 | classifyInbound :: x -> MessageClass err meth tid |
280 | -- | Lookup the handler for a inbound query. | 283 | -- | Lookup the handler for a inbound query. |
281 | , lookupHandler :: meth -> Maybe (MethodHandler err tid addr x ctx) | 284 | , lookupHandler :: meth -> Maybe (MethodHandler err tid addr x) |
282 | -- | Methods for handling incomming responses. | 285 | -- | Methods for handling incomming responses. |
283 | , tableMethods :: TransactionMethods tbl tid x | 286 | , tableMethods :: TransactionMethods tbl tid x |
284 | } | 287 | } |
@@ -326,10 +329,10 @@ contramapE f (ErrorReporter pe mh unk tim) | |||
326 | -- 'fix' in a forked thread that loops until 'awaitMessage' returns 'Nothing' | 329 | -- 'fix' in a forked thread that loops until 'awaitMessage' returns 'Nothing' |
327 | -- or throws an exception. | 330 | -- or throws an exception. |
328 | handleMessage :: | 331 | handleMessage :: |
329 | Client err meth tid addr x ctx | 332 | Client err meth tid addr x |
330 | -> IO () | 333 | -> IO () |
331 | -> IO () | 334 | -> IO () |
332 | handleMessage (Client net d err pending whoami) again = do | 335 | handleMessage (Client net d err pending whoami responseID) again = do |
333 | awaitMessage net >>= \case | 336 | awaitMessage net >>= \case |
334 | Just (Left e) -> do reportParseError err e | 337 | Just (Left e) -> do reportParseError err e |
335 | again | 338 | again |
@@ -338,10 +341,11 @@ handleMessage (Client net d err pending whoami) again = do | |||
338 | IsQuery meth tid -> case lookupHandler d meth of | 341 | IsQuery meth tid -> case lookupHandler d meth of |
339 | Nothing -> reportMissingHandler err meth addr plain | 342 | Nothing -> reportMissingHandler err meth addr plain |
340 | Just m -> do | 343 | Just m -> do |
341 | (self,ctx) <- whoami | 344 | self <- whoami |
345 | tid' <- responseID tid | ||
342 | either (reportParseError err) | 346 | either (reportParseError err) |
343 | (>>= sendMessage net addr) | 347 | (>>= sendMessage net addr) |
344 | (dispatchQuery m ctx tid self plain addr) | 348 | (dispatchQuery m tid' self plain addr) |
345 | IsResponse tid -> do | 349 | IsResponse tid -> do |
346 | action <- atomically $ do | 350 | action <- atomically $ do |
347 | ts0 <- readTVar pending | 351 | ts0 <- readTVar pending |