{- Copyright (c) 2005 Jesper Louis Andersen Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -} ----------------------------------------------------------------------------- -- C O N J U R E -- -- How small a Bittorrent implementation can you actually do? -- -- The current Bittorrent implementation is about 10.000 lines. Let us -- Beat that by lengths. ----------------------------------------------------------------------------- import qualified Config import qualified Conjure.OptionParser import qualified Conjure.InterestStatThread as IST import qualified Conjure.PeerThread as PT import qualified Conjure.Torrent as Torrent import qualified Conjure.Version as Version import qualified FS.Storage () import qualified Data.List.Shuffle () import qualified Control.Concurrent.HoldTimer () import Control.Concurrent.STM.TChan.Atomic import qualified Conjure.WireProtocol () import qualified TrackerClient as TC import qualified Conjure.NaivePiecePicker as NPP import qualified FS.FSThread as FST import Conjure.Logger import Control.Concurrent import Control.Concurrent.STM import Control.Monad (liftM) import System import System.IO (hPutStr) import System.Random (randomRIO) import Network (PortID(..), listenOn, accept) import List (isPrefixOf) main :: IO () main = do (flags, torrentname) <- getArgs >>= Conjure.OptionParser.getOpts -- this is mostly just faking, what is faked here should be done -- right in other modules and imported. initLogger flags putStrLn $ Version.showVersionHeader Version.conjure_version putStrLn $ "Conjure is currently non-functional, read DEVELOPING\n" ++ " if you want to help out" torrent <- liftM (either (error . show) id) $ Torrent.readTorrentFile torrentname debugM "Conjure" $ "Flags are: " ++ show flags debugM "Conjure" $ "Torrent is:\n" ++ Torrent.ppShow torrent debugM "Conjure" "Firing up InterestThread" size <- return $ Torrent.infoNumPieces torrent cp <- Config.readCfg let cutoff = Config.getRarestFirstCutoffPoint cp --(_, ist_chan) <- IST.runThread size cutoff IST.runThread size cutoff infoM "Conjure" "Firing up FSThread" (_, _, piecesMVar) <- FST.runThread torrent pieces <- readMVar piecesMVar infoM "Conjure" ("FSThread found these pieces: " ++ show pieces) infoM "Conjure" $ "Firing up NaivePickerThread - alternative to IST" (_, picker_chan) <- NPP.runThread torrent debugM "Conjure" "Files to get:" mapM_ ((debugM "Conjure").show) (Torrent.fileInfo torrent) node_id <- liftM ("conjure-----" ++) $ sequence (replicate 8 $ randomRIO ('a', 'z')) node_id' <- liftM ("conjure-----" ++) $ sequence (replicate 8 $ randomRIO ('a', 'z')) debugM "Conjure" "Starting dummy listener" let port = 6881 sock <- listenOn (PortNumber port) forkIO (do (h, _, _) <- accept sock hPutStr h ("\19BitTorrent protocol" ++ replicate 8 '\0' ++ Torrent.infoHash torrent ++ node_id)) response <- TC.queryTracker torrent node_id Nothing port 0 0 (sum $ map (fromIntegral . snd) $ Torrent.fileInfo torrent) (Just "started") debugM "Conjure" $ "Tracker response: " ++ show response debugM "Conjure" $ "Press Ctrl-C to interrupt" debugM "Conjure" $ "Starting PeerThread" let peer = head $ filter (not.("conjure" `isPrefixOf`).TC.peerId) $ TC.trackerPeers response report_chan <- atomically newTChan PT.runThread peer torrent node_id (sendMessage report_chan) (sendMessage picker_chan) PT.runThread peer torrent node_id' (sendMessage report_chan) (sendMessage picker_chan) loop report_chan where loop ch = do r <- recvMessage ch debugM "Conjure" $ "Main: received report " ++ show r loop ch