class Trans: # transaction types (i.e., reasons for making DHT requests) FINGER = 0 # finding finger peers for us (index = finger table index) BACKUP = 1 # finding redundant successors in case real one dies PRUNE = 2 # are we still in charge of this file? if not, drop it GET = 10 # finding place for client to get data (client = client socket) PUT = 11 # finding place for client to put data (client = client socket, data = file data)) SHOW = 12 # transaction is asking for peer list (client = client socket, timer = 30sec timer) next = 0 # incrementing count of transactions def __init__(self, type, main, arg1=None, arg2=None): self.type = type self.main = main def make_trans(): num = Trans.next Trans.next += 1 return '%s-%d' % (main.myname, num) self.id = make_trans() if self.type == Trans.FINGER: self.index = arg1 elif self.type == Trans.BACKUP: pass # nothing special to do elif self.type == Trans.PRUNE: pass # nothing special to do elif self.type == Trans.GET: self.client = arg1 elif self.type == Trans.PUT: self.client = arg1 self.data = arg2 elif self.type == Trans.SHOW: self.client = arg1 # create a timer; allow 30 seconds for a show to complete def cb(): self.remove() # close client connection; we won't receive any more peer responses self.client.close_when_done() # we use a timeout to determine the roll call being done because # getting the SHOW message back doesn't mean we've seen all PEER messages self.timer = Timer(10, cb) self.timer.add() def add(self): self.main.trans[self.id] = self def remove(self): if self.type == Trans.SHOW: self.timer.remove() del self.main.trans[self.id]
def __init__(self, host, port, peers): self.host = host self.port = int(port) self.peers = {} # dictionary of Peer objects self.clients = set() # set of client sockets for i in peers: self.peers[i] = Peer(i) self.listen_sock = ListenSocket(self.port, self) self.keepalive_timer = Timer(15, self.keepalive_timer_cb) self.keepalive_timer.add() self.revive_timer = Timer(60, self.revive_timer_cb) self.revive_timer.add()
def __init__(self, type, main, arg1=None, arg2=None): self.type = type self.main = main def make_trans(): num = Trans.next Trans.next += 1 return '%s-%d' % (main.myname, num) self.id = make_trans() if self.type == Trans.FINGER: self.index = arg1 elif self.type == Trans.BACKUP: pass # nothing special to do elif self.type == Trans.PRUNE: pass # nothing special to do elif self.type == Trans.GET: self.client = arg1 elif self.type == Trans.PUT: self.client = arg1 self.data = arg2 elif self.type == Trans.SHOW: self.client = arg1 # create a timer; allow 30 seconds for a show to complete def cb(): self.remove() # close client connection; we won't receive any more peer responses self.client.close_when_done() # we use a timeout to determine the roll call being done because # getting the SHOW message back doesn't mean we've seen all PEER messages self.timer = Timer(10, cb) self.timer.add()
def revive_timer_cb(self): # re-add self.revive_timer = Timer(60, self.revive_timer_cb) self.revive_timer.add() for i in self.peers.values(): if i.state == Peer.DEAD: self.do_spawn(i.host)
def keepalive_timer_cb(self): # re-add self.keepalive_timer = Timer(15, self.keepalive_timer_cb) self.keepalive_timer.add() for i in self.peers.values(): if i.socket: i.socket.write([]) # send keepalive
class Daemon: def __init__(self, host, port, peers): self.host = host self.port = int(port) self.peers = {} # dictionary of Peer objects self.clients = set() # set of client sockets for i in peers: self.peers[i] = Peer(i) self.listen_sock = ListenSocket(self.port, self) self.keepalive_timer = Timer(15, self.keepalive_timer_cb) self.keepalive_timer.add() self.revive_timer = Timer(60, self.revive_timer_cb) self.revive_timer.add() def run(self): Event.dispatch() def on_connect(self, socket): pass def on_error(self, socket): # see if it's a peer; if it's a client, remove socket for p in self.peers.values(): if p.socket == socket: p.disconnected() self.broadcast(p.get_state()) self.clients.discard(socket) # just in case def on_data(self, socket, data): pos = data.find('\n') if pos < 0: # need to wait for new line return 0 elif pos == 0: return 1 # just a keep-alive args = data[0:pos].split(' ') # possible messages (peer) # HELLO host -- peer is now active and ready to be started # STARTED host port -- peer is active and listening on given port # STOPPED host -- peer is stopped if args[0] == 'HELLO' and len(args) == 2: host = args[1] peer = self.peers[host] peer.hello(socket) self.broadcast(peer.get_state()) elif args[0] == 'STARTED' and len(args) == 3: host = args[1] port = args[2] peer = self.peers[host] peer.started(port) self.broadcast(peer.get_state()) elif args[0] == 'STOPPED' and len(args) == 2: host = args[1] peer = self.peers[host] peer.stopped() self.broadcast(peer.get_state()) # possible messages (client) # CHELLO -- client is connected and would like status # CSTART host -- request to start host # CSTOP host -- request to stop host # CKILL host -- request to kill host elif args[0] == 'CHELLO' and len(args) == 1: for i in self.peers.values(): socket.write(i.get_state()) self.clients.add(socket) elif args[0] == 'CSTART' and len(args) == 2: self.do_start(args[1]) elif args[0] == 'CSTOP' and len(args) == 2: self.do_stop(args[1]) elif args[0] == 'CKILL' and len(args) == 2: self.do_kill(args[1]) else: print 'unknown message:', ' '.join(args) return pos + 1 def do_start(self, host): peer = self.peers[host] try: bootstrap = random.choice(['%s:%d' % (i.host,i.port) for i in self.peers.values() if i.state == Peer.STARTED]) except IndexError: bootstrap = 'none' if peer.state == Peer.STOPPED: peer.socket.write(['START', bootstrap]) def do_stop(self, host): peer = self.peers[host] if peer.state == Peer.STARTED: peer.socket.write(['STOP']) def do_kill(self, host): peer = self.peers[host] if peer.state == Peer.STARTED or peer.state == Peer.STOPPED: peer.socket.write(['KILL']) def broadcast(self, msg): for i in self.clients: i.write(msg) # send out a newline sometimes def keepalive_timer_cb(self): # re-add self.keepalive_timer = Timer(15, self.keepalive_timer_cb) self.keepalive_timer.add() for i in self.peers.values(): if i.socket: i.socket.write([]) # send keepalive def revive_timer_cb(self): # re-add self.revive_timer = Timer(60, self.revive_timer_cb) self.revive_timer.add() for i in self.peers.values(): if i.state == Peer.DEAD: self.do_spawn(i.host) def do_spawn(self, host): # spawn shell script that delivers payload Popen(['./deliver.sh', host, '%s:%d' % (self.host, self.port)])