-
Notifications
You must be signed in to change notification settings - Fork 2
/
connect_to_tracker.erl
168 lines (152 loc) · 6.44 KB
/
connect_to_tracker.erl
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
%%%---------------------------------------------------------------------
%%% Created by: Fredrik Gustafsson.
%%% Creation date: 2001-11-07
%%%---------------------------------------------------------------------
%%% Description module connecting to a tracker
%%%---------------------------------------------------------------------
%%% What this module does:
%%% Connects to a specified tracker returning information
%%%---------------------------------------------------------------------
%%% Exports
%%%---------------------------------------------------------------------
%%% start()
%%% spawn_links a new process to init function
%%%---------------------------------------------------------------------
%%% make_list()
%%% Makes a proper list of the links in the torrent-file
%%%---------------------------------------------------------------------
-module(connect_to_tracker).
-export([start/4, make_list/2]).
start(Dl_pid, Peers_pid, Length, File_storage_pid) ->
spawn_link(fun() -> init(Dl_pid, Peers_pid, Length, File_storage_pid) end).
%%--------------------------------------------------------------------
%% Function: init/4
%% Purpose: waits for the first connect message and then
%% Args: Dl_pid: Pid of Download_manager
%% Peers_pid: Pid of Peers
%% Length: The total length of the file(s)
%% File_storage_pid: Pid of File_storage
%%--------------------------------------------------------------------
init(Dl_pid, Peers_pid, Length, File_storage_pid) ->
Info_sha = sha:shaurl(download_manager:get_info_clean(Dl_pid)),
My_id = download_manager:get_my_id(Dl_pid),
loop(Info_sha, 10000, My_id, none, "6881", Length, Peers_pid, Dl_pid,
File_storage_pid).
%%--------------------------------------------------------------------
%% Function:loop/8
%% Purpose: Connects to a specified tracker and spawning
%% a function in peers to insert the peers received from the tracker.
%% Updating the specified tracker with amount uploaded and downloaded
%% Args: Info: The info-hash for the torrent-file
%% Time: Interval between connections the tracker
%% Tracker: The url to tracker
%% Length: The total size of the file(s) downloaded
%% Peers_pid: Pid of peers module
%% Dl_pid: Pid of Download_manager module
%% File_storage_pid: Pid of file_storage_pid
%%--------------------------------------------------------------------
loop(Info, Time, My_id, Tracker, Port, Length, Peers_pid, Dl_pid,
File_storage_pid) ->
receive
{connect, From, H} ->
io:format("CONNECTING TO TRACKER~n"),
{Peers, Min_time} = get_info(H ++ "?info_hash=" ++ Info
++ "&peer_id=" ++ My_id ++ "&port="
++ Port
++ "&uploaded=0&downloaded=0&left="
++ integer_to_list(Length)
++ "&compact=1&event=started"),
From ! {ok, Peers},
loop(Info, Min_time, My_id, H, Port, Length, Peers_pid,
Dl_pid, File_storage_pid)
after 10000 ->
case Tracker of
none ->
loop(Info, Time, My_id, Tracker, Port, Length, Peers_pid,
Dl_pid, File_storage_pid);
_ ->
io:format("~nCONNECT TO TRACKER~n"),
{We_have, Uploaded} = get_current_pieces(File_storage_pid),
Left = Length - We_have,
io:format("~n~nBits left=~w~n~n", [Left]),
{Peers, Min_time} = get_info(Tracker ++ "?info_hash="
++ Info ++ "&peer_id="
++ My_id ++ "&port="
++ Port
++ "&uploaded="
++ integer_to_list(Uploaded)
++ "&downloaded="
++ integer_to_list(We_have)
++ "&left="
++ integer_to_list(Left)
++ "&compact=1"),
spawn(peers, insert_new_peers, [Peers, Peers_pid, Dl_pid]),
Dl_pid ! {this_tracker, Tracker},
loop(Info, Min_time, My_id, Tracker, Port, Length,
Peers_pid, Dl_pid, File_storage_pid)
end
end.
%%--------------------------------------------------------------------
%% Function: get_current_pieces/1
%% Purpose: Requests the current downloaded amout
%% and uploaded.
%% Args: File_storage_pid: Pid of file_storage module
%% Returns: How_much: how much we downloaded
%% Uploaded: The current uploaded data
%%--------------------------------------------------------------------
get_current_pieces(File_storage_pid) ->
{How_much, Uploaded} = mutex:request(File_storage_pid, how_much, []),
mutex:received(File_storage_pid),
{How_much, Uploaded}.
%%--------------------------------------------------------------------
%% Function: get_info/1
%% Purpose: Connecting to tracker
%% Args: Url: The url to the tracker
%% Returns: Peers handed back by the tracker and
%% Minimum requesting time to the tracker.
%%--------------------------------------------------------------------
get_info(Url) ->
inets:start(),
{ok, {_,_,Result}} = httpc:request(Url),
{{dict, Response_from_tracker}, _Remainder} =
bencode:decode(list_to_binary(Result)),
{get_peers(Response_from_tracker), get_time(Response_from_tracker)}.
%%--------------------------------------------------------------------
%% Function: get_peers/1
%% Purpose: Fetch peer list from tracker response.
%% Args: Response_from_tracker: The response from the tracker
%% Returns: The peers in a list.
%%--------------------------------------------------------------------
get_peers(Response_from_tracker) ->
case dict:find(<<"peers">>, Response_from_tracker) of
error ->
exit(self(), kill);
{ok, Peers} ->
binary_to_list(Peers)
end.
%%--------------------------------------------------------------------
%% Function: get_time/1
%% Purpose: Hands back the minimum interval between connections to
%% tracker.
%% Args: Response_from_tracker: The response from the tracker.
%% Returns: The minimum interval between connections to tracker.
%%--------------------------------------------------------------------
get_time(Response_from_tracker) ->
case dict:find(<<"interval">>, Response_from_tracker) of
error ->
exit(self(), kill);
{ok, Interval} ->
Interval
end.
%%--------------------------------------------------------------------
%% Defined at top of file under exported functions
%%--------------------------------------------------------------------
make_list([], New_list) ->
New_list;
make_list([{_, H}|T], New_list) ->
case string:substr(binary_to_list(list_to_binary(H)), 1, 1) of
"u" ->
make_list(T, New_list);
_ ->
make_list(T, [binary_to_list(list_to_binary(H))|New_list])
end.