]> git.rkrishnan.org Git - functorrent.git/blobdiff - src/FuncTorrent/Tracker/Udp.hs
WIP: UDP tracker, compiles
[functorrent.git] / src / FuncTorrent / Tracker / Udp.hs
index aa7bfd5a14551e3bb0a669082e21920a0c40d758..7467ce8cd5a6d707eea50d0d4a68043f6ea62c34 100644 (file)
  -}
 
 {-# LANGUAGE OverloadedStrings #-}
  -}
 
 {-# LANGUAGE OverloadedStrings #-}
-module Functorrent.Tracker.Udp
+module FuncTorrent.Tracker.Udp
        (
        ) where
 
 import Control.Applicative (liftA2)
        (
        ) where
 
 import Control.Applicative (liftA2)
-import Control.Monad.Error (ErrorT)
-import Control.Monad.Reader (ReaderT, runReaderT, ask)
+import Control.Monad.Reader (ReaderT, runReaderT, ask, liftIO)
 import Data.Binary (Binary(..), encode, decode)
 import Data.Binary.Get (Get, isEmpty, getWord32be, getByteString)
 import Data.Binary.Put (putWord16be, putWord64be, putWord32be, putByteString)
 import Data.Binary (Binary(..), encode, decode)
 import Data.Binary.Get (Get, isEmpty, getWord32be, getByteString)
 import Data.Binary.Put (putWord16be, putWord64be, putWord32be, putByteString)
-import Data.ByteString.Char8 as BC
-import Data.ByteString.Lazy (fromStrict)
-import Data.Word (Word32)
-import Network.Socket (Socket, SockAddr, sendTo, recvFrom)
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Char8 as BC
+import Data.ByteString.Lazy (fromStrict, toStrict)
+import Data.Word (Word32, Word64)
+import Network.Socket (Socket, Family( AF_INET ), SocketType( Datagram ), defaultProtocol, SockAddr(..), socket, inet_addr)
+import Network.Socket.ByteString (sendTo, recvFrom)
 import System.Random (randomIO)
 
 import System.Random (randomIO)
 
-import FuncTorrent.Tracker.Types (TrackerEventState(..), IP, Port)
+import FuncTorrent.Tracker.Types (TrackerEventState(..))
+import FuncTorrent.Utils (IP, Port, toIP, toPort)
 
 -- UDP tracker: http://bittorrent.org/beps/bep_0015.html
 data Action = Connect
 
 -- UDP tracker: http://bittorrent.org/beps/bep_0015.html
 data Action = Connect
@@ -47,7 +49,7 @@ data UDPRequest = ConnectReq Word32
                 | ScrapeReq Integer Integer ByteString
                 deriving (Show, Eq)
 
                 | ScrapeReq Integer Integer ByteString
                 deriving (Show, Eq)
 
-data UDPResponse = ConnectResp Integer Integer -- transaction_id connection_id
+data UDPResponse = ConnectResp Word32 Word64 -- transaction_id connection_id
                  | AnnounceResp Integer Integer Integer Integer [(IP, Port)] -- transaction_id interval leechers seeders [(ip, port)]
                  | ScrapeResp Integer Integer Integer Integer
                  | ErrorResp Integer String
                  | AnnounceResp Integer Integer Integer Integer [(IP, Port)] -- transaction_id interval leechers seeders [(ip, port)]
                  | ScrapeResp Integer Integer Integer Integer
                  | ErrorResp Integer String
@@ -117,31 +119,34 @@ instance Binary UDPResponse where
       3 -> do -- error response
         tid <- fromIntegral <$> getWord32be
         bs  <- getByteString 4
       3 -> do -- error response
         tid <- fromIntegral <$> getWord32be
         bs  <- getByteString 4
-        return $ ErrorResp tid $ unpack bs
+        return $ ErrorResp tid $ BC.unpack bs
       _ -> error ("unknown response action type: " ++ show a)
 
       _ -> error ("unknown response action type: " ++ show a)
 
-sendRequest :: UDPTrackerHandle -> UDPRequest -> IO ()
+sendRequest :: UDPTrackerHandle -> ByteString -> IO ()
 sendRequest h req = do
   n <- sendTo (sock h) req (addr h)
   -- sanity check with n?
   return ()
 
 sendRequest h req = do
   n <- sendTo (sock h) req (addr h)
   -- sanity check with n?
   return ()
 
-recvResponse :: UDPTrackerHandle -> ErrorT String IO UDPResponse
+recvResponse :: UDPTrackerHandle -> IO UDPResponse
 recvResponse h = do
 recvResponse h = do
-  (bs, nbytes, saddr) <- recvFrom (sock h) 20
-  -- check if nbytes is at least 16 bytes long
+  (bs, saddr) <- recvFrom (sock h) 32
   return $ decode $ fromStrict bs
 
   return $ decode $ fromStrict bs
 
-connectRequest :: ReaderT UDPTrackerHandle IO Integer
+connectRequest :: ReaderT UDPTrackerHandle IO ()
 connectRequest = do
   h <- ask
   let pkt = encode $ ConnectReq (tid h)
 connectRequest = do
   h <- ask
   let pkt = encode $ ConnectReq (tid h)
-  sendRequest h pkt
+  liftIO $ sendRequest h (toStrict pkt)
 
 
-connectResponse :: ReaderT UDPTrackerHandle IO Bool
-connectResponse = do
+connectResponse :: Word32 -> ReaderT UDPTrackerHandle IO Bool
+connectResponse itid = do
   h <- ask
   h <- ask
-  
+  resp <- liftIO $ recvResponse h
+  -- check if nbytes is at least 16 bytes long
+  case resp of
+    (ConnectResp tid cid) -> return $ tid == itid
+    _                     -> return False
 
 getIPPortPairs :: Get [(IP, Port)]
 getIPPortPairs = do
 
 getIPPortPairs :: Get [(IP, Port)]
 getIPPortPairs = do
@@ -154,22 +159,15 @@ getIPPortPairs = do
     ipportpairs <- getIPPortPairs
     return $ (ip, port) : ipportpairs
 
     ipportpairs <- getIPPortPairs
     return $ (ip, port) : ipportpairs
 
-getResponse :: Socket -> IO UDPResponse
-getResponse s = do
-  -- connect packet is 16 bytes long
-  -- announce packet is atleast 20 bytes long
-  bs <- recv s (16*1024)
-  return $ decode $ fromStrict bs
-
-
-udpTrackerLoop :: PortNumber -> String -> Metainfo -> TState -> IO String
-udpTrackerLoop port peerId m st = do
-  -- h <- connectTo "exodus.desync.com" (PortNumber 6969)
+startSession :: IP -> Port -> IO UDPTrackerHandle
+startSession ip port = do
   s <- socket AF_INET Datagram defaultProtocol
   s <- socket AF_INET Datagram defaultProtocol
-  hostAddr <- inet_addr "185.37.101.229"
+  hostAddr <- inet_addr ip
   putStrLn "connected to tracker"
   putStrLn "connected to tracker"
-  _ <- sendTo s (toStrict $ encode (ConnectReq 42)) (SockAddrInet 2710 hostAddr)
-  putStrLn "--> sent ConnectReq to tracker"
-  resp <- recv s 16
-  putStrLn "<-- recv ConnectResp from tracker"
-  return $ show resp
+  r <- randomIO
+  return $ UDPTrackerHandle { sock = s
+                            , tid = r
+                            , addr = (SockAddrInet (fromIntegral port) hostAddr) }
+  
+-- closeSession :: UDPTrackerHandle
+