Repository navigation
Expand file tree
/
Copy pathtracker.py
More file actions
335 lines (267 loc) · 11.2 KB
/
Copy pathtracker.py
File metadata and controls
335 lines (267 loc) · 11.2 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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
import threading
import socket
from P2P_network import PeerFunct
from tracker_P2P_conn import PeerCommTracker
import sqlite3
from sqlite3 import Error
import socket
import struct
import threading
import time
import traceback
from P2P_connections import *
from queue import Queue
import operator
import ast # use to convert strings of sorts to dictionary/list
#from tracker import *
q = Queue()
def btdebug(msg):
"""
Prints a message to the screen with the name of the current thread
"""
print("[%s] %s" % (str(threading.currentThread().getName()), msg))
"""
Implements the core functionality of peers within a P2P network
"""
class PeerFunctTracker(object):
def __init__(self, serverport, blockchain=None, myid=None, serverhost=None):
"""
When an instance of the 'PeerFunct' class is created this special
method is called, initialising a peer. The peer will have the ability
to catalog up to 'maxpeers' number of peers and will listen on a
given server port with a defined peer name (id) and host address (IP).
If the host address is not supplied, it'll be determined by trying and
connecting to an internet host.
Arguements:
self -- instantiated variable
maxpeers -- maximum number of peers catalogued
serverport -- port on which the peer will listen for requests
serverhost -- IP address of the peer
myid -- unique peer identifier (tuple of (IP:port) in absence of an id)
Attributes:
self.peerlock -- allows for regulated access of common variables of incomming requests
self.peers -- dictionary of peers {peerid : (IP,port)}
self.handlers -- dictionary of methods
self.shutdown -- used to terminate main loop
"""
self.blockchain = blockchain
self.debug = 1
self.serverport = int(serverport)
if serverhost:
self.serverhost = serverhost
else:
self.__initserverhost()
if myid:
self.myid = myid
else:
self.myid = '%s:%d' % (self.serverhost, self.serverport)
self.peerlock = threading.Lock()
self.shutdown = False
self.handlers = {"GETADDR": self.addr}
def __initserverhost(self):
"""
Attempts to connect to an Internet host inorder to determine the local
machine's IP address.
- The arguments used with socket method allows communication using
IPv4 protocol with a TCP connection.
- s.getsockname delivers (IP,port)
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("www.google.com", 80))
self.serverhost = s.getsockname()[0]
s.close()
def __debug(self, msg):
"""
If self.debug is greater than 0 the 'btdebug' function call is made with
'msg' as the argument.
Argument:
msg -- the error message to be relayed as an argument to 'btdebug'
"""
if self.debug:
btdebug(msg)
def __handlepeer(self, clientsock):
"""
The thread started in the the main method calls this function with
clientsock as the argument. The method starts by a method call on the
clientsock object, which return the IP and port of the client peer.
Then the 'peerconn' object is used to instantiate the 'P2Pconn' class
with IP, port and clientsock as arguments.
#clientsock.send(str.encode('Welcome, type your info'))
#print("The socket is\n")
#print(clientsock)
#data = clientsock.recv(2048)
#reply = 'Your method is :' + data.decode('utf-8')
#print(reply)
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#s.connect('localhost',5777)
#s.sendall(str.encode(reply))
#print("\nSent")
"""
self.__debug('New child' + str(threading.currentThread().getName()))
self.__debug('Connected' + str(clientsock.getpeername()))
host, port = clientsock.getpeername()
print(clientsock)
peercomm = PeerComm(host, port, clientsock, debug=False)
try:
msgtype, msgdata = peercomm.recv()
if msgtype not in self.handlers:
self.__debug('Not handled: %s' % (msgtype))
else:
self.__debug('Handing peer msg: %s' % (msgtype))
# calls the self.msgdata method from the handlers dict
self.handlers[msgtype](peercomm)
hostpeer, addrpeer = peercomm.s.getpeername()
#print("Sent Data Nisal:" + str(msgdata))
self.__update_peer_as_active_or_add_new_peer(hostpeer, addrpeer, str(msgdata))
except KeyboardInterrupt:
raise
except:
if self.debug:
traceback.print_exc()
self.__debug('disconnecting' + str(clientsock.getpeername()))
peercomm.close()
#clientsock.send(str.encode('Welcome, type your info\n'))
def create_connection(self):
try:
conn = sqlite3.connect("peers.sqlite3")
return conn
except Error as e:
print("Error Establishing Connection with Database")
return conn
def check_for_active_peers(self):
threading.Timer(5, self.check_for_active_peers).start()
print("Sending Pings to all hosts...")
conn = self.create_connection()
with conn:
cur = conn.cursor()
cur.execute("SELECT IP,Port FROM Peers;")
rows = cur.fetchall()
for row in rows:
self.send_ping_2_peer( row[0], row[1])
conn.close()
def send_ping_2_peer(self, serverhost, serverport):
"""
This method send a message to a select peer
"""
try:
dict_gb = {'HELLO': None}
peercomm = PeerComm(serverhost, serverport)
peercomm.send(str(dict_gb))
str_recv = peercomm.s.recv(2048)
str_recv = str_recv.decode('utf-8')
s.close()
except:
print("Peer with IP:" + serverhost + " and port:" + serverport + " was not active!")
def __update_peer_as_active_or_add_new_peer(self, peerip, peerport, listening_port):
# check if peer is in database and update
conn = self.create_connection()
with conn:
cur = conn.cursor()
print("Connected Peer details:" + str(peerip) + "/" + str(peerport))
query1 = "SELECT IP,Port FROM Peers WHERE IP=\'" + str(peerip) + "\' AND Port=\'" + str(listening_port) + "\';"
#print(query1)
cur.execute(query1)
rows = cur.fetchall()
if len(rows) > 0:
print("Peer is already in list, updated dates")
query2 = "UPDATE Peers SET LastUpdated=datetime() WHERE IP=\'" + str(peerip) + "\' AND Port=\'" + str(listening_port) + "\';"
cur.execute(query2)
conn.commit()
else:
database2 = "peers.sqlite3"
print("New Peer, added to List")
iquery = "INSERT INTO Peers (IP, Port, LastUpdated) VALUES (\'" + str(peerip) + "\', \'" + str(listening_port) + "\', datetime());"
#print(iquery)
cur.execute(iquery)
conn.commit()
conn.close()
def addr(self, peercomm, data=None):
peer_list = []
conn = self.create_connection()
with conn:
peer_list = self.return_all_active_peers()
host, addr = peercomm.s.getpeername()
peer_list_dic = dict()
for item in peer_list:
peer_list_dic[item[0]+":"+item[1]] = (item[0], int(item[1]))
peercomm.s.sendto(bytes(str(peer_list_dic), 'utf-8'), (host, addr))
peercomm.s.close()
conn.close()
def ping(self, peercomm):
host, addr = peercomm.s.getpeername()
peercomm.s.sendto(bytes("ping", 'utf-8'), (host, addr))
def makeserversocket(self, port, backlog=5):
"""
This method constructs a socket for the peer to communicate with other
peers. It begins by creating a socket object 's', followed by using the
'setsockopt' method which allows for disconnected peers to reconnect to
the peer on re-entry into the network (if this command is not used ,the host
peer might flag that partiuclar port where the communicating peer was
once connected to). Further on, the object 's' is bound to a port of the
host peer. The IP of the peer need not be stated, as it's implicitly the
localhost. The IP will only be required by the connecting peer. The method
is terminated with a socket listen command and the socket object is returned.
The object can later be used to accept incoming connections.
The backlog argument indicates how many incomming connections should be
queued up. Albeit a value of 5 is used, this might be rendered useless
with a multithreaded server.
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', port))
print("Listening")
s.listen(backlog)
return s
def send2peer(self, serverhost, serverport):
"""
This method send a message to a select peer
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((serverhost, serverport))
s.sendall(b'getlistofblocks')
str_recv = s.recv(2048)
print(str(str_recv.decode('utf-8')))
s.close()
#s.sendall(str.encode('\nsup dickheads\n my life is shit\n how about yours'))
def return_all_active_peers(self):
list_of_peers = []
conn = self.create_connection()
with conn:
cur = conn.cursor()
query4 = "SELECT IP,Port FROM Peers WHERE LastUpdated > datetime('now','-10 minutes') LIMIT 20;"
cur.execute(query4)
rows = cur.fetchall()
#print("fuck: {}".format(rows))
for row in rows:
list_of_peers.append(row)
print("Returned Peers: " + str(list_of_peers))
conn.close()
return list_of_peers
def main(self):
self.check_for_active_peers()
s = self.makeserversocket(self.serverport)
# s.settimeout(2)
self.__debug(' Tracker Server started: %s (%s:%d)' %
(self.myid, self.serverhost, self.serverport))
print(type(self.myid))
while not self.shutdown:
try:
self.__debug('Listening for connections...')
clientsock, clientaddr = s.accept()
# clientsock.settimeout(None)
t = threading.Thread(target=self.__handlepeer,
args=[clientsock])
t.start()
except KeyboardInterrupt:
print('KeyboardInterrupt : terminating main')
self.shutdown = True
continue
except:
if self.debug:
traceback.print_exc()
continue
self.__debug('Exiting main loop')
s.close()
if __name__ == '__main__':
pft = PeerFunctTracker(5009)
pft.main()