summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSam T <sta.cs.vsu@gmail.com>2013-04-04 18:40:32 +0400
committerSam T <sta.cs.vsu@gmail.com>2013-04-04 18:40:32 +0400
commita532ae52a00c053a59540e7041a4f132cfe34f0e (patch)
tree90a4fcf80c99edce8a29df9dc8bc9df3c7c9b0aa /src
parent20b55a89a4fb4a812a8cff5c9a4da2999c36eff4 (diff)
+ peer id generation
Diffstat (limited to 'src')
-rw-r--r--src/Network/Torrent/PeerID.hs113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/Network/Torrent/PeerID.hs b/src/Network/Torrent/PeerID.hs
new file mode 100644
index 00000000..35c70c9d
--- /dev/null
+++ b/src/Network/Torrent/PeerID.hs
@@ -0,0 +1,113 @@
1{-# LANGUAGE OverloadedStrings #-}
2-- | Recommended method for generation of the peer ID's is 'newPeerID',
3-- though this module exports some other goodies for custom generation.
4--
5module Network.Torrent.PeerID
6 ( PeerID(PeerID, getPeerID)
7 -- * Encoding styles
8 , azureusStyle, shadowStyle
9 -- * Defaults
10 , defaultClientID, defaultVersionNumber
11 -- * Generation
12 , newPeerID, timestampByteString
13 -- * Extra
14 , byteStringPadded
15 ) where
16
17import Control.Applicative
18import Data.ByteString (ByteString)
19import qualified Data.ByteString as B
20import qualified Data.ByteString.Char8 as BC
21import qualified Data.ByteString.Lazy as BL
22import qualified Data.ByteString.Builder as B
23import Data.Foldable (foldMap)
24import Data.Monoid ((<>))
25import Data.Version (versionBranch)
26import Data.Time.Clock (getCurrentTime)
27import Data.Time.Format (formatTime)
28import System.Locale (defaultTimeLocale)
29
30import Paths_network_torrent (version)
31
32
33-- | Peer identifier is exactly 20 bytes long bytestring.
34newtype PeerID = PeerID { getPeerID :: ByteString }
35 deriving (Show, Eq, Ord)
36
37-- | Azureus-style encoding:
38-- * 1 byte : '-'
39-- * 2 bytes: client id
40-- * 4 bytes: version number
41-- * 1 byte : '-'
42-- * 12 bytes: random number
43--
44azureusStyle :: ByteString -- ^ 2 character client ID, padded with 'H'.
45 -> ByteString -- ^ Version number, padded with 'X'.
46 -> ByteString -- ^ Random number, padded with '0'.
47 -> PeerID -- ^ Azureus-style encoded peer ID.
48azureusStyle cid ver rnd = PeerID $ BL.toStrict $ B.toLazyByteString $
49 B.char8 '-' <>
50 byteStringPadded cid 2 'H' <>
51 byteStringPadded ver 4 'X' <>
52 B.char8 '-' <>
53 byteStringPadded rnd 12 '0'
54
55-- | Shadow-style encoding:
56-- * 1 byte : client id.
57-- * 0-4 bytes: version number. If less than 4 then padded with '-' char.
58-- * 15 bytes : random number. If length is less than 15 then padded with '0' char.
59--
60shadowStyle :: Char -- ^ Client ID.
61 -> ByteString -- ^ Version number.
62 -> ByteString -- ^ Random number.
63 -> PeerID -- ^ Shadow style encoded peer ID.
64shadowStyle cid ver rnd = PeerID $ BL.toStrict $ B.toLazyByteString $
65 B.char8 cid <>
66 byteStringPadded ver 4 '-' <>
67 byteStringPadded rnd 15 '0'
68
69
70-- | "HS" - 2 bytes long client identifier.
71defaultClientID :: ByteString
72defaultClientID = "HS"
73
74-- | Gives exactly 4 bytes long version number for any version of the package.
75-- Version is taken from .cabal.
76defaultVersionNumber :: ByteString
77defaultVersionNumber = B.take 4 (BC.pack (foldMap show (versionBranch version)))
78
79-- | Gives 15 characters long decimal timestamp such that:
80-- * 6 bytes : first 6 characters from picoseconds obtained with %q.
81-- * 1 bytes : character '.' for readability.
82-- * 9..* bytes: number of whole seconds since the Unix epoch (!)REVERSED.
83-- Can be used both with shadow and azureus style encoding. This format is
84-- used to make the ID's readable(for debugging) and more or less random.
85--
86timestampByteString :: IO ByteString
87timestampByteString = (BC.pack . format) <$> getCurrentTime
88 where
89 format t = take 6 (formatTime defaultTimeLocale "%q" t) ++ "." ++
90 take 9 (reverse (formatTime defaultTimeLocale "%s" t))
91
92-- | Here we use Azureus-style encoding with the following args:
93-- * 'HS' for the client id.
94-- * Version of the package for the version number
95-- * UTC time day ++ day time for the random number.
96--
97newPeerID :: IO PeerID
98newPeerID = azureusStyle defaultClientID defaultVersionNumber
99 <$> timestampByteString
100
101-- | length < size: Complete bytestring by given charaters.
102-- length = size: Output bytestring as is.
103-- length > size: Drop last (length - size) charaters from a given bytestring.
104--
105byteStringPadded :: ByteString -- ^ bytestring to be padded.
106 -> Int -- ^ size of result builder.
107 -> Char -- ^ character used for padding.
108 -> B.Builder
109byteStringPadded bs s c =
110 B.byteString (B.take s bs) <>
111 B.byteString (BC.replicate padLen c)
112 where
113 padLen = s - max (B.length bs) s \ No newline at end of file