def __init__(self, addr=args.addr, port=args.port, givenbootstraplist=args.bootstrap, debugoption=args.debug, objectname=args.objectname, logger=args.logger, writetodisk=args.writetodisk): self.addr = addr if addr else findOwnIP() self.port = port self.debug = debugoption self.durable = writetodisk self.isnameserver = args.domain != '' self.domain = args.domain self.useroute53 = args.route53 if objectname == '': parser.print_help() self._graceexit(1) self.objectname = objectname # initialize receive queue self.receivedmessages_semaphore = Semaphore(0) self.receivedmessages = [] # lock to synchronize message handling self.lock = Lock() # create server socket and bind to a port self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.socket.setblocking(0) if self.port: try: self.socket.bind((self.addr, self.port)) except socket.error as e: print "Cannot bind to port %d" % self.port print "Socket Error: ", e self._graceexit(1) else: for i in range(50): self.port = random.randint(14000, 15000) try: self.socket.bind((self.addr, self.port)) break except socket.error as e: print "Socket Error: ", e self.socket.listen(10) self.connectionpool = ConnectionPool() try: self.connectionpool.epoll = select.epoll() except AttributeError as e: # the os doesn't support epoll self.connectionpool.epoll = None # set the logger if logger: LOGGERNODE = logger else: LOGGERNODE = None # Initialize replicas # Keeps {peer:outofreachcount} self.replicas = {} # Nameserver state if self.isnameserver: self.type = NODE_NAMESERVER try: self.nameserver = Nameserver(self.addr, self.domain, self.useroute53, self.replicas, self.debug) except Exception as e: print "Error:", e print "Could not start Replica as a Nameserver, exiting." self._graceexit(1) else: self.type = NODE_REPLICA self.alive = True self.me = Peer(self.addr, self.port, self.type) # set id self.id = '%s:%d' % (self.addr, self.port) # add self to connectionpool self.connectionpool.add_connection_to_self( self.me, SelfConnection(self.receivedmessages, self.receivedmessages_semaphore)) self.logger = Logger("%s-%s" % (node_names[self.type], self.id), lognode=LOGGERNODE) if self.isnameserver: self.nameserver.add_logger(self.logger) print "%s-%s connected." % (node_names[self.type], self.id) # Keeps the liveness of the nodes self.nodeliveness = {} self.bootstrapset = set() # connect to the bootstrap node if givenbootstraplist: self.discoverbootstrap(givenbootstraplist) self.connecttobootstrap() self.stateuptodate = False
def __init__(self, addr=args.addr, port=args.port, givenbootstraplist=args.bootstrap, debugoption=args.debug, objectname=args.objectname, logger=args.logger, writetodisk=args.writetodisk): self.addr = addr if addr else findOwnIP() self.port = port self.debug = debugoption self.durable = writetodisk self.isnameserver = args.domain != '' self.domain = args.domain self.useroute53 = args.route53 if objectname == '': parser.print_help() self._graceexit(1) self.objectname = objectname # initialize receive queue self.receivedmessages_semaphore = Semaphore(0) self.receivedmessages = [] # lock to synchronize message handling self.lock = Lock() # create server socket and bind to a port self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.socket.setblocking(0) if self.port: try: self.socket.bind((self.addr,self.port)) except socket.error as e: print "Cannot bind to port %d" % self.port print "Socket Error: ", e self._graceexit(1) else: for i in range(50): self.port = random.randint(14000,15000) try: self.socket.bind((self.addr,self.port)) break except socket.error as e: print "Socket Error: ", e self.socket.listen(10) self.connectionpool = ConnectionPool() try: self.connectionpool.epoll = select.epoll() except AttributeError as e: # the os doesn't support epoll self.connectionpool.epoll = None # set the logger if logger: LOGGERNODE = logger else: LOGGERNODE = None # Initialize replicas # Keeps {peer:outofreachcount} self.replicas = {} # Nameserver state if self.isnameserver: self.type = NODE_NAMESERVER try: self.nameserver = Nameserver(self.addr, self.domain, self.useroute53, self.replicas, self.debug) except Exception as e: print "Error:", e print "Could not start Replica as a Nameserver, exiting." self._graceexit(1) else: self.type = NODE_REPLICA self.alive = True self.me = Peer(self.addr,self.port,self.type) # set id self.id = '%s:%d' % (self.addr, self.port) # add self to connectionpool self.connectionpool.add_connection_to_self(self.me, SelfConnection(self.receivedmessages, self.receivedmessages_semaphore)) self.logger = Logger("%s-%s" % (node_names[self.type],self.id), lognode=LOGGERNODE) if self.isnameserver: self.nameserver.add_logger(self.logger) print "%s-%s connected." % (node_names[self.type],self.id) # Keeps the liveness of the nodes self.nodeliveness = {} self.bootstrapset = set() # connect to the bootstrap node if givenbootstraplist: self.discoverbootstrap(givenbootstraplist) self.connecttobootstrap() self.stateuptodate = False
class Node(): """Node encloses the basic Node behaviour and state that are extended by Replicas and Nameservers. """ def __init__(self, addr=args.addr, port=args.port, givenbootstraplist=args.bootstrap, debugoption=args.debug, objectname=args.objectname, logger=args.logger, writetodisk=args.writetodisk): self.addr = addr if addr else findOwnIP() self.port = port self.debug = debugoption self.durable = writetodisk self.isnameserver = args.domain != '' self.domain = args.domain self.useroute53 = args.route53 if objectname == '': parser.print_help() self._graceexit(1) self.objectname = objectname # initialize receive queue self.receivedmessages_semaphore = Semaphore(0) self.receivedmessages = [] # lock to synchronize message handling self.lock = Lock() # create server socket and bind to a port self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.socket.setblocking(0) if self.port: try: self.socket.bind((self.addr, self.port)) except socket.error as e: print "Cannot bind to port %d" % self.port print "Socket Error: ", e self._graceexit(1) else: for i in range(50): self.port = random.randint(14000, 15000) try: self.socket.bind((self.addr, self.port)) break except socket.error as e: print "Socket Error: ", e self.socket.listen(10) self.connectionpool = ConnectionPool() try: self.connectionpool.epoll = select.epoll() except AttributeError as e: # the os doesn't support epoll self.connectionpool.epoll = None # set the logger if logger: LOGGERNODE = logger else: LOGGERNODE = None # Initialize replicas # Keeps {peer:outofreachcount} self.replicas = {} # Nameserver state if self.isnameserver: self.type = NODE_NAMESERVER try: self.nameserver = Nameserver(self.addr, self.domain, self.useroute53, self.replicas, self.debug) except Exception as e: print "Error:", e print "Could not start Replica as a Nameserver, exiting." self._graceexit(1) else: self.type = NODE_REPLICA self.alive = True self.me = Peer(self.addr, self.port, self.type) # set id self.id = '%s:%d' % (self.addr, self.port) # add self to connectionpool self.connectionpool.add_connection_to_self( self.me, SelfConnection(self.receivedmessages, self.receivedmessages_semaphore)) self.logger = Logger("%s-%s" % (node_names[self.type], self.id), lognode=LOGGERNODE) if self.isnameserver: self.nameserver.add_logger(self.logger) print "%s-%s connected." % (node_names[self.type], self.id) # Keeps the liveness of the nodes self.nodeliveness = {} self.bootstrapset = set() # connect to the bootstrap node if givenbootstraplist: self.discoverbootstrap(givenbootstraplist) self.connecttobootstrap() self.stateuptodate = False def _getipportpairs(self, bootaddr, bootport): for node in socket.getaddrinfo(bootaddr, bootport, socket.AF_INET, socket.SOCK_STREAM): yield Peer(node[4][0], bootport, NODE_REPLICA) def discoverbootstrap(self, givenbootstraplist): bootstrapstrlist = givenbootstraplist.split(",") for bootstrap in bootstrapstrlist: #ipaddr:port pair given as bootstrap if bootstrap.find(":") >= 0: bootaddr, bootport = bootstrap.split(":") for peer in self._getipportpairs(bootaddr, int(bootport)): self.bootstrapset.add(peer) #dnsname given as bootstrap else: answers = [] try: answers = dns.resolver.query('_concoord._tcp.' + bootstrap, 'SRV') except (dns.resolver.NXDOMAIN, dns.exception.Timeout): if self.debug: self.logger.write("DNS Error", "Cannot resolve %s" % str(bootstrap)) for rdata in answers: for peer in self._getipportpairs(str(rdata.target), rdata.port): self.bootstrapset.append(peer) def connecttobootstrap(self): tries = 0 keeptrying = True while tries < BOOTSTRAPCONNECTTIMEOUT and keeptrying: for bootpeer in self.bootstrapset: try: if self.debug: self.logger.write( "State", "trying to connect to bootstrap: %s" % str(bootpeer)) helomessage = create_message(MSG_HELO, self.me) successid = self.send(helomessage, peer=bootpeer) if successid < 0: tries += 1 continue keeptrying = False break except socket.error as e: if self.debug: self.logger.write( "Socket Error", "cannot connect to bootstrap: %s" % str(e)) tries += 1 continue time.sleep(1) def startservice(self): # Start a thread that waits for inputs receiver_thread = Thread(target=self.server_loop, name='ReceiverThread') receiver_thread.start() # Start a thread with the server which will start a thread for each request main_thread = Thread(target=self.handle_messages, name='MainThread') main_thread.start() # Start a thread that pings all neighbors ping_thread = Timer(LIVENESSTIMEOUT, self.ping_neighbor) ping_thread.name = 'PingThread' ping_thread.start() # Start a thread that goes through the nascentset and cleans expired ones nascent_thread = Timer(NASCENTTIMEOUT, self.clean_nascent) nascent_thread.name = 'NascentThread' nascent_thread.start() # Start a thread that waits for inputs if self.debug: input_thread = Thread(target=self.get_user_input_from_shell, name='InputThread') input_thread.start() return self def __str__(self): return "%s NODE %s:%d" % (node_names[self.type], self.addr, self.port) def statestr(self): returnstr = "" for peer in self.replicas: returnstr += node_names[peer.type] + " %s:%d\n" % (peer.addr, peer.port) if hasattr(self, 'pendingcommands') and len(self.pendingcommands) > 0: pending = "".join("%d: %s" % (cno, proposal) for cno,proposal \ in self.pendingcommands.iteritems()) returnstr = "%s\nPending:\n%s" % (returnstr, pending) return returnstr def ping_neighbor(self): """used to ping neighbors periodically""" # Only ping neighbors that didn't send a message recently while True: # Check nodeliveness for peer in self.replicas: if peer == self.me: continue if peer in self.nodeliveness: nosound = time.time() - self.nodeliveness[peer] else: nosound = LIVENESSTIMEOUT + 1 if nosound <= LIVENESSTIMEOUT: # Peer is alive self.replicas[peer] = 0 continue if nosound > LIVENESSTIMEOUT: # Send PING to node if self.debug: self.logger.write("State", "Sending PING to %s" % str(peer)) pingmessage = create_message(MSG_PING, self.me) successid = self.send(pingmessage, peer=peer) if successid < 0 or nosound > (2 * LIVENESSTIMEOUT): # Neighbor not responding, mark the neighbor if self.debug: self.logger.write("State", "Neighbor not responding") self.replicas[peer] += 1 time.sleep(LIVENESSTIMEOUT) def clean_nascent(self): lastnascentset = set([]) while True: for sock in lastnascentset.intersection( self.connectionpool.nascentsockets): # expired -- if it's not already in the set, it should be deleted self.connectionpool.activesockets.remove(sock) self.connectionpool.nascentsockets.remove(sock) lastnascentset = self.connectionpool.nascentsockets time.sleep(NASCENTTIMEOUT) def server_loop(self): """Serverloop that listens to multiple connections and accepts new ones. Server State - inputready: sockets that are ready for reading - exceptready: sockets that are ready according to an *exceptional condition* """ self.socket.listen(10) if self.connectionpool.epoll: self.connectionpool.epoll.register(self.socket.fileno(), select.EPOLLIN) self.use_epoll() else: # the OS doesn't support epoll self.connectionpool.activesockets.add(self.socket) self.use_select() self.socket.close() return def use_epoll(self): while self.alive: try: events = self.connectionpool.epoll.poll(1) for fileno, event in events: if fileno == self.socket.fileno(): clientsock, clientaddr = self.socket.accept() clientsock.setblocking(0) self.connectionpool.epoll.register( clientsock.fileno(), select.EPOLLIN) self.connectionpool.epollsockets[ clientsock.fileno()] = clientsock elif event & select.EPOLLIN: success = self.handle_connection( self.connectionpool.epollsockets[fileno]) if not success: self.connectionpool.epoll.unregister(fileno) self.connectionpool.del_connection_by_socket( self.connectionpool.epollsockets[fileno]) self.connectionpool.epollsockets[fileno].close() del self.connectionpool.epollsockets[fileno] elif event & select.EPOLLHUP: self.connectionpool.epoll.unregister(fileno) self.connectionpool.epollsockets[fileno].close() del self.connectionpool.epollsockets[fileno] except KeyboardInterrupt, EOFError: os._exit(0) self.connectionpool.epoll.unregister(self.socket.fileno()) self.connectionpool.epoll.close()
class Node(): """Node encloses the basic Node behaviour and state that are extended by Replicas and Nameservers. """ def __init__(self, addr=args.addr, port=args.port, givenbootstraplist=args.bootstrap, debugoption=args.debug, objectname=args.objectname, logger=args.logger, writetodisk=args.writetodisk): self.addr = addr if addr else findOwnIP() self.port = port self.debug = debugoption self.durable = writetodisk self.isnameserver = args.domain != '' self.domain = args.domain self.useroute53 = args.route53 if objectname == '': parser.print_help() self._graceexit(1) self.objectname = objectname # initialize receive queue self.receivedmessages_semaphore = Semaphore(0) self.receivedmessages = [] # lock to synchronize message handling self.lock = Lock() # create server socket and bind to a port self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.socket.setblocking(0) if self.port: try: self.socket.bind((self.addr,self.port)) except socket.error as e: print "Cannot bind to port %d" % self.port print "Socket Error: ", e self._graceexit(1) else: for i in range(50): self.port = random.randint(14000,15000) try: self.socket.bind((self.addr,self.port)) break except socket.error as e: print "Socket Error: ", e self.socket.listen(10) self.connectionpool = ConnectionPool() try: self.connectionpool.epoll = select.epoll() except AttributeError as e: # the os doesn't support epoll self.connectionpool.epoll = None # set the logger if logger: LOGGERNODE = logger else: LOGGERNODE = None # Initialize replicas # Keeps {peer:outofreachcount} self.replicas = {} # Nameserver state if self.isnameserver: self.type = NODE_NAMESERVER try: self.nameserver = Nameserver(self.addr, self.domain, self.useroute53, self.replicas, self.debug) except Exception as e: print "Error:", e print "Could not start Replica as a Nameserver, exiting." self._graceexit(1) else: self.type = NODE_REPLICA self.alive = True self.me = Peer(self.addr,self.port,self.type) # set id self.id = '%s:%d' % (self.addr, self.port) # add self to connectionpool self.connectionpool.add_connection_to_self(self.me, SelfConnection(self.receivedmessages, self.receivedmessages_semaphore)) self.logger = Logger("%s-%s" % (node_names[self.type],self.id), lognode=LOGGERNODE) if self.isnameserver: self.nameserver.add_logger(self.logger) print "%s-%s connected." % (node_names[self.type],self.id) # Keeps the liveness of the nodes self.nodeliveness = {} self.bootstrapset = set() # connect to the bootstrap node if givenbootstraplist: self.discoverbootstrap(givenbootstraplist) self.connecttobootstrap() self.stateuptodate = False def _getipportpairs(self, bootaddr, bootport): for node in socket.getaddrinfo(bootaddr, bootport, socket.AF_INET, socket.SOCK_STREAM): yield Peer(node[4][0],bootport,NODE_REPLICA) def discoverbootstrap(self, givenbootstraplist): bootstrapstrlist = givenbootstraplist.split(",") for bootstrap in bootstrapstrlist: #ipaddr:port pair given as bootstrap if bootstrap.find(":") >= 0: bootaddr,bootport = bootstrap.split(":") for peer in self._getipportpairs(bootaddr, int(bootport)): self.bootstrapset.add(peer) #dnsname given as bootstrap else: answers = [] try: answers = dns.resolver.query('_concoord._tcp.'+bootstrap, 'SRV') except (dns.resolver.NXDOMAIN, dns.exception.Timeout): if self.debug: self.logger.write("DNS Error", "Cannot resolve %s" % str(bootstrap)) for rdata in answers: for peer in self._getipportpairs(str(rdata.target), rdata.port): self.bootstrapset.append(peer) def connecttobootstrap(self): tries = 0 keeptrying = True while tries < BOOTSTRAPCONNECTTIMEOUT and keeptrying: for bootpeer in self.bootstrapset: try: if self.debug: self.logger.write("State", "trying to connect to bootstrap: %s" % str(bootpeer)) helomessage = create_message(MSG_HELO, self.me) successid = self.send(helomessage, peer=bootpeer) if successid < 0: tries += 1 continue keeptrying = False break except socket.error as e: if self.debug: self.logger.write("Socket Error", "cannot connect to bootstrap: %s" % str(e)) tries += 1 continue time.sleep(1) def startservice(self): # Start a thread that waits for inputs receiver_thread = Thread(target=self.server_loop, name='ReceiverThread') receiver_thread.start() # Start a thread with the server which will start a thread for each request main_thread = Thread(target=self.handle_messages, name='MainThread') main_thread.start() # Start a thread that pings all neighbors ping_thread = Timer(LIVENESSTIMEOUT, self.ping_neighbor) ping_thread.name = 'PingThread' ping_thread.start() # Start a thread that goes through the nascentset and cleans expired ones nascent_thread = Timer(NASCENTTIMEOUT, self.clean_nascent) nascent_thread.name = 'NascentThread' nascent_thread.start() # Start a thread that waits for inputs if self.debug: input_thread = Thread(target=self.get_user_input_from_shell, name='InputThread') input_thread.start() return self def __str__(self): return "%s NODE %s:%d" % (node_names[self.type], self.addr, self.port) def statestr(self): returnstr = "" for peer in self.replicas: returnstr += node_names[peer.type] + " %s:%d\n" % (peer.addr,peer.port) if hasattr(self, 'pendingcommands') and len(self.pendingcommands) > 0: pending = "".join("%d: %s" % (cno, proposal) for cno,proposal \ in self.pendingcommands.iteritems()) returnstr = "%s\nPending:\n%s" % (returnstr, pending) return returnstr def ping_neighbor(self): """used to ping neighbors periodically""" # Only ping neighbors that didn't send a message recently while True: # Check nodeliveness for peer in self.replicas: if peer == self.me: continue if peer in self.nodeliveness: nosound = time.time() - self.nodeliveness[peer] else: nosound = LIVENESSTIMEOUT + 1 if nosound <= LIVENESSTIMEOUT: # Peer is alive self.replicas[peer] = 0 continue if nosound > LIVENESSTIMEOUT: # Send PING to node if self.debug: self.logger.write("State", "Sending PING to %s" % str(peer)) pingmessage = create_message(MSG_PING, self.me) successid = self.send(pingmessage, peer=peer) if successid < 0 or nosound > (2*LIVENESSTIMEOUT): # Neighbor not responding, mark the neighbor if self.debug: self.logger.write("State", "Neighbor not responding") self.replicas[peer] += 1 time.sleep(LIVENESSTIMEOUT) def clean_nascent(self): lastnascentset = set([]) while True: for sock in lastnascentset.intersection(self.connectionpool.nascentsockets): # expired -- if it's not already in the set, it should be deleted self.connectionpool.activesockets.remove(sock) self.connectionpool.nascentsockets.remove(sock) lastnascentset = self.connectionpool.nascentsockets time.sleep(NASCENTTIMEOUT) def server_loop(self): """Serverloop that listens to multiple connections and accepts new ones. Server State - inputready: sockets that are ready for reading - exceptready: sockets that are ready according to an *exceptional condition* """ self.socket.listen(10) if self.connectionpool.epoll: self.connectionpool.epoll.register(self.socket.fileno(), select.EPOLLIN) self.use_epoll() else: # the OS doesn't support epoll self.connectionpool.activesockets.add(self.socket) self.use_select() self.socket.close() return def use_epoll(self): while self.alive: try: events = self.connectionpool.epoll.poll(1) for fileno, event in events: if fileno == self.socket.fileno(): clientsock, clientaddr = self.socket.accept() clientsock.setblocking(0) self.connectionpool.epoll.register(clientsock.fileno(), select.EPOLLIN) self.connectionpool.epollsockets[clientsock.fileno()] = clientsock elif event & select.EPOLLIN: success = self.handle_connection(self.connectionpool.epollsockets[fileno]) if not success: self.connectionpool.epoll.unregister(fileno) self.connectionpool.del_connection_by_socket(self.connectionpool.epollsockets[fileno]) self.connectionpool.epollsockets[fileno].close() del self.connectionpool.epollsockets[fileno] elif event & select.EPOLLHUP: self.connectionpool.epoll.unregister(fileno) self.connectionpool.epollsockets[fileno].close() del self.connectionpool.epollsockets[fileno] except KeyboardInterrupt, EOFError: os._exit(0) self.connectionpool.epoll.unregister(self.socket.fileno()) self.connectionpool.epoll.close()