Skip to content

Instantly share code, notes, and snippets.

@abendayan
Last active December 10, 2018 11:15
Show Gist options
  • Save abendayan/5f5e09a8a3743d9ccfd3d4355a3a53b8 to your computer and use it in GitHub Desktop.
Save abendayan/5f5e09a8a3743d9ccfd3d4355a3a53b8 to your computer and use it in GitHub Desktop.
p2p
#!/usr/bin/env python
"""UDP hole punching client."""
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import time
import sys
class ClientProtocol(DatagramProtocol):
"""
Client protocol implementation.
The clients registers with the rendezvous server.
The rendezvous server returns connection details for the other peer.
The client Initializes a connection with the other peer and sends a
message.
"""
def startProtocol(self):
"""Register with the rendezvous server."""
self.server_connect = False
self.peer_init = False
self.peer_connect = False
self.peer_address = None
self.last_message = []
self.transport.write(b'0', (sys.argv[1], int(sys.argv[2])))
self.all_addresses = []
def toAddress(self, data):
"""Return an IPv4 address tuple."""
ip, port = data.split(':')
return (ip, int(port))
def sendMessage(self, message):
self.wait_for_ack = True
for address in self.all_addresses:
self.last_message.append((message, address))
self.transport.write(self.last_message)
def datagramReceived(self, datagram, host):
"""Handle incoming datagram messages."""
if not self.server_connect:
self.server_connect = True
self.transport.write('ok', (sys.argv[1], int(sys.argv[2])))
self.last_message.append(('ok', (sys.argv[1], int(sys.argv[2]))))
self.wait_for_ack = True
print 'Connected to server, waiting for peer...'
elif datagram.startswith('init'):
peer_address = self.toAddress(datagram.split('init ')[1])
self.all_addresses.append(peer_address)
host = self.transport.getHost().host
port = self.transport.getHost().port
msg = 'Message from %s %d' % (host, port)
self.all_addresses.append(peer_address)
print msg
for address in self.all_addresses:
if address != peer_address:
self.transport.write(msg, address)
elif ':' in datagram:
self.peer_address = self.toAddress(datagram)
self.all_addresses.append(self.peer_address)
host = self.transport.getHost().host
port = self.transport.getHost().port
msg = 'init %s:%d' % (host, port)
self.transport.write(msg, self.peer_address)
self.last_message.append((msg, self.peer_address))
print 'Sent init to %s:%d' % self.peer_address
else:
print 'Received:', datagram
if __name__ == '__main__':
if len(sys.argv) < 3:
print "Usage: ./client RENDEZVOUS_IP RENDEZVOUS_PORT"
sys.exit(1)
protocol = ClientProtocol()
t = reactor.listenUDP(0, protocol)
reactor.run()
from web3 import Web3
from web3 import TestRPCProvider
from os import path
import json
import web3
class ContractHandler:
def __init__(self):
self.web3 = Web3(web3.providers.rpc.HTTPProvider("http://bch63v-dns-reg1.westeurope.cloudapp.azure.com:8545"))
with open(str(path.join('.', 'contract.json')), 'r') as abi_definition:
self.abi = json.load(abi_definition)
self.contract_address ='0x4c9a6e78730de2e1af5461abb69345b503bb606605223e22492318e636144583'
self.contract = self.web3.eth.contract()
self.contract.abi = self.abi
self.contract.address = self.contract_address
if path.isfile("wallet.dat"):
self.wallet = web3.Account.privateKeyToAccount(open("wallet.dat", "rb").read())
else:
self.wallet = web3.Account.create()
open("wallet.dat", "wb").write(self.wallet.privateKey)
print(self.wallet.address, self.wallet.privateKey)
print(self.contract)
# def unlock(self):
# self.web3.personal.unlockAccount(your_ethereum_account,
# your_ethereum_password)
contract = ContractHandler()
#!/usr/bin/env python
"""UDP hole punching server."""
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
from itertools import combinations
import sys
class ServerProtocol(DatagramProtocol):
"""
Server protocol implementation.
Server listens for UDP messages. Once it receives a message it registers
this client for a peer link in the waiting list.
As soon as a second client connects, information about one client (public
IP address and port) is sent to the other and vice versa.
Those clients are now considered linked and removed from the waiting list.
"""
def __init__(self):
"""Initialize with empy address list."""
self.addresses = []
self.sitin = []
def addressString(self, address):
"""Return a string representation of an address."""
ip, port = address
return ':'.join([ip, str(port)])
def datagramReceived(self, datagram, message):
"""Handle incoming datagram messages."""
if datagram == b'0':
# New client
print 'Registration from %s:%d' % message
self.transport.write(b'ok', message)
self.addresses.append(message)
self.sitin.append(False)
if len(self.addresses) >= 2:
pairs_addresses = list(combinations(self.addresses, 2))
for address in pairs_addresses:
print address
msg_0 = self.addressString(address[1])
msg_1 = self.addressString(address[0])
self.transport.write(msg_0, address[0])
self.transport.write(msg_1, address[1])
print 'Linked peers'
elif datagram == b'1':
# This client sent the command sit in
self.sitin[self.addresses.index((message[0], message[1]))] = True
if len(self.addresses) >= 2 and (sum(self.sitin) == len(self.addresses)):
pairs_addresses = list(combinations(self.addresses, 2))
for address in pairs_addresses:
msg_0 = self.addressString(address[1])
msg_1 = self.addressString(address[0])
self.transport.write(msg_0, address[0])
self.transport.write(msg_1, address[1])
print 'Linked peers'
else:
print 'Message %s from %s:%d' % (datagram, message[0], message[1])
if __name__ == '__main__':
if len(sys.argv) < 2:
print "Usage: ./server.py PORT"
sys.exit(1)
port = int(sys.argv[1])
reactor.listenUDP(port, ServerProtocol())
print 'Listening on *:%d' % (port)
reactor.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment