-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtracker.cpp
More file actions
146 lines (124 loc) · 4.32 KB
/
tracker.cpp
File metadata and controls
146 lines (124 loc) · 4.32 KB
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
#include <iostream> // Basic IO
#include <stdlib.h> // exit()
#include <sys/types.h> // socket()
#include <sys/socket.h> // socket()
#include "helper_functions.h"
#include <pthread.h>
#include <atomic>
#include <map>
#include <vector>
#include "bencode_parser.h"
#include <algorithm>
// Type alias for vector of ip, port pairs
using ClientList = std::vector <std::pair<std::string, int>>;
// Set to true if termination of threads is needed
std::atomic <bool> terminateAllThreads;
// Filename -> Vector (IP, Port)
std::map < std::string, ClientList > mapping;
// Mutex for mapping
pthread_mutex_t mappingMutex;
// Function each thread executes
void* serverWorker(void*);
// Add the client details to mapping
void addToMapping(std::string, std::string, int);
// Get list of clients having this file
ClientList getClients(std::string);
int main(int argc, char* argv[])
{
// Check if arguments are valid
if(argc < 2)
{
printf("Usage: %s <Port Number>\n", argv[0]);
exit(EXIT_FAILURE);
}
// Get port number from command line
short listenPort = atoi(argv[1]);
// Number of clients which can queue up
const int QUEUED_LIMIT = 10;
// Number of server threads
const int THREAD_COUNT = 4;
// Create listening socket and set to listen
int listeningSocketFD = createTCPSocket();
bindToPort(listeningSocketFD, listenPort);
if(listen(listeningSocketFD, QUEUED_LIMIT) < 0)
{
perror("Listen failed");
exit(EXIT_FAILURE);
}
terminateAllThreads = false;
pthread_t threadID[THREAD_COUNT];
for(int i = 0; i < THREAD_COUNT; i++)
pthread_create(&threadID[i], NULL, serverWorker, (void*)&listeningSocketFD);
for(int i = 0; i < THREAD_COUNT; i++)
pthread_join(threadID[i], NULL);
closeSocket(listeningSocketFD);
return 0;
}
void* serverWorker(void* arg)
{
printf("Server Thread %lu created\n", pthread_self());
int listeningSocketFD = *(static_cast <int*> (arg));
while(!terminateAllThreads)
{
sockaddr_in clientAddr;
unsigned clientLen = sizeof(clientAddr);
memset(&clientAddr, 0, clientLen);
// Accept one client request
int sockFD = accept(listeningSocketFD,
(sockaddr*) &clientAddr,
(socklen_t*)&clientLen);
if(sockFD < 0)
{
perror("Accept failed");
closeSocket(listeningSocketFD);
printf("Terminating thread %lu\n", pthread_self());
terminateAllThreads = true;
pthread_exit(NULL);
}
std::string trackerRequest = recvAll(sockFD);
if(trackerRequest == "")
continue;
// Debug
printf("%s\n", trackerRequest.c_str());
BencodeParser bencodeParser(trackerRequest);
bencodeParser.print_details();
std::string trackerResponse = "";
ClientList clientList = getClients(bencodeParser.filename);
for(auto client : clientList)
{
trackerResponse += "2:ip";
trackerResponse += std::to_string(client.first.size()) + ":";
trackerResponse += client.first;
trackerResponse += "8:peerport";
trackerResponse += "i" + std::to_string(client.second) + "e";
}
if(trackerResponse == "")
trackerResponse = "empty";
int responseLen = trackerResponse.size();
if(sendAll(sockFD, trackerResponse.c_str(), responseLen) != 0)
{
perror("sendall() failed");
printf("Only sent %d bytes\n", responseLen);
}
// Add this client to mapping
addToMapping(bencodeParser.filename, inet_ntoa(clientAddr.sin_addr), bencodeParser.port);
// Serve client here
closeSocket(sockFD);
}
return NULL;
}
void addToMapping(std::string filename, std::string ip, int port)
{
// Add this client to the mapping
pthread_mutex_lock(&mappingMutex);
if(std::find(mapping[filename].begin(), mapping[filename].end(), make_pair(ip, port)) == mapping[filename].end())
mapping[filename].push_back({ip, port});
pthread_mutex_unlock(&mappingMutex);
}
ClientList getClients(std::string filename)
{
pthread_mutex_lock(&mappingMutex);
ClientList retVal(mapping[filename]);
pthread_mutex_unlock(&mappingMutex);
return retVal;
}