/
main.c
155 lines (140 loc) · 4.08 KB
/
main.c
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
#include "main.h"
int getInt(struct evkeyvalq *GET, char * key){
char * tmp;
int ret=0;
tmp=evhttp_find_header(GET, key);
if(tmp){
ret=atoi(tmp);
}
return ret;
}
void tracker(struct evhttp_request *req, struct config *confg){
char * info_hash=0x00,
* client_ip=0x00,
* event=0x00;
int client_port=0,
left = 0,
compact = 0,
numwant = 0,
peer_worth = 0,
uploaded = 0,
downloaded = 0;
ev_uint16_t scoket_client_port=0x00;
uint32_t client_ip_addr=0;
//evhttp is strange sometimes...
struct evkeyvalq GET;
const struct evhttp_uri *uri = evhttp_request_get_evhttp_uri(req);
char *query = evhttp_uri_get_query(uri);
evhttp_parse_query_str(query, &GET);
info_hash=evhttp_find_header(&GET, "info_hash");
if(info_hash){
event=evhttp_find_header(&GET, "event");
left = getInt(&GET,"left");
//Only return a peer list if the client needs one.
//So the client must have something left to download and not completed or stopped.
//If the event is empty or non-present, return a list of peers.
if(left &&
(!event ||
event[0] == 0x00 ||
(strcmp(event, "completed") == 0 &&
strcmp(event, "stopped") == 0))){
//Build a list of peers for the response:
compact = getInt(&GET,"compact");
numwant = getInt(&GET,"numwant");
view_peer_list(confg, req, info_hash, numwant, compact);
}
client_ip = evhttp_find_header(&GET, "Ip");
if(client_ip){
client_ip_addr=inet_addr(client_ip);
}else{
//for compatibility, try a non-standard case
client_ip = evhttp_find_header(&GET, "ip");
if(client_ip){
client_ip_addr=inet_addr(client_ip);
}
}
if(client_ip_addr<=0){
//Looks like we got an invalid ip address as a GET param, recovering...
evhttp_connection_get_peer(req->evcon,
&client_ip,
&scoket_client_port);
client_ip_addr=inet_addr(client_ip);
}
client_port = getInt(&GET,"port");
//port 0 is valid... and is used by no one, ever.
if(client_port > 0 && client_port < 65536 && client_port != 80 && client_port != 443){
uploaded = getInt(&GET,"uploaded");
//Process event:
if(event){
if(strcmp(event, "stopped") == 0 ){
peer_worth=-1;
}else if(strcmp(event, "completed") == 0){
//This peer has every chunk, they are valuable
peer_worth=2;
}else if(strcmp(event, "started") == 0){
//This peer has nothing
peer_worth=0;
}else{
//Probably better than nothing.
peer_worth=1;
}
}else{
peer_worth=1;
}
downloaded = getInt(&GET,"downloaded");
if(uploaded>downloaded){
//This peer is healthy! (Or lying...)
peer_worth++;
}
if(peer_worth >= 0){
//Add the peer to the db, The recorded peer_worth is from 0-3
control_add_peer(confg, peer_worth, client_ip_addr, client_port, info_hash);
}else if(peer_worth < 0){
//This peer is worth less than
control_remove_peer(confg, client_ip_addr, client_port, info_hash);
}
}else{
//todo error invalid port
}
}else{
//todo error; no info_hash
}
}
BindSocket(int port) {
int r;
int nfd;
nfd = socket(AF_INET, SOCK_STREAM, 0);
if (nfd < 0) return -1;
int one = 1;
r = setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(int));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
r = bind(nfd, (struct sockaddr*)&addr, sizeof(addr));
if (r < 0) return -1;
r = listen(nfd, 10240);
if (r < 0) return -1;
int flags;
if ((flags = fcntl(nfd, F_GETFL, 0)) < 0
|| fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
return -1;
return nfd;
}
int main(int argc, char **argv) {
int cli;
int sock = BindSocket(12345);
struct config conf;
conf.store = store_open("tracker.db");
conf.max_peer_return=50;
conf.min_interval=300;
conf.max_peer_return=48;
struct event_base *base = event_init();
struct evhttp *httpd;
httpd = evhttp_new(base);
cli = evhttp_accept_socket(httpd, sock);
evhttp_set_gencb(httpd, tracker, (void *)&conf);
event_base_dispatch(base);
return 0;
}