def __init__(self, nodetype, addr=options.addr, port=options.port, givenbootstraplist=options.bootstrap, debugoption=options.debug, objectfilename=options.objectfilename, objectname=options.objectname, instantiateobj=False, configpath=options.configpath, logger=options.logger): """Node State - addr: hostname for Node, detected automatically - port: port for Node, can be taken from the commandline (-p [port]) or detected automatically by binding. - connectionpool: ConnectionPool that keeps all Connections Node knows about - type: type of the corresponding Node: NODE_ACCEPTOR | NODE_REPLICA | NODE_NAMESERVER - alive: liveness of Node - outstandingmessages: collection of sent but not-yet-acked messages - socket: server socket for Node - me: Peer object that represents Node - id: id for Node (addr:port) - groups: other Peers in the system that Node knows about. Node.groups is indexed by the corresponding node_name (NODE_ACCEPTOR | NODE_REPLICA | NODE_NAMESERVER), which returns a Group """ self.addr = addr if addr else findOwnIP() self.port = port self.connectionpool = ConnectionPool() self.type = nodetype if instantiateobj: if objectfilename == '': parser.print_help() self._graceexit(1) self.objectfilename = objectfilename self.objectname = objectname ## messaging layer information self.receivedmessages_semaphore = Semaphore(0) self.receivedmessages = [] # msgs not acked yet # {msgid: msginfo} self.outstandingmessages_lock =RLock() self.outstandingmessages = {} # last msg timestamp for all peers # {peer: timestamp} self.lastmessages_lock =RLock() self.lastmessages = {} # number of retries for all peers # {peer: retries} self.retries_lock =RLock() self.retries = {} self.lock = Lock() self.done = False self.donecond = Condition() # 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: print "Cannot bind to port %d" % self.port 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: pass self.socket.listen(10) self.alive = True # initialize empty groups self.me = Peer(self.addr,self.port,self.type) self.id = self.me.getid() self.configpath = configpath try: LOGGERNODE = load_configdict(self.configpath)['LOGGERNODE'] except: if logger: LOGGERNODE=logger else: LOGGERNODE = None self.logger = NetworkLogger("%s-%s" % (node_names[self.type],self.id), LOGGERNODE) self.logger.write("State", "Connected.") self.groups = {NODE_ACCEPTOR:Group(self.me), NODE_REPLICA: Group(self.me), NODE_NAMESERVER:Group(self.me)} # connect to the bootstrap node if givenbootstraplist: self.bootstraplist = [] self.discoverbootstrap(givenbootstraplist) self.connecttobootstrap() if self.type == NODE_REPLICA or self.type == NODE_NAMESERVER: self.stateuptodate = False
class Node(): """Node encloses the basic Node behaviour and state that are extended by Leaders, Acceptors or Replicas. """ def __init__(self, nodetype, addr=options.addr, port=options.port, givenbootstraplist=options.bootstrap, debugoption=options.debug, objectfilename=options.objectfilename, objectname=options.objectname, instantiateobj=False, configpath=options.configpath, logger=options.logger): """Node State - addr: hostname for Node, detected automatically - port: port for Node, can be taken from the commandline (-p [port]) or detected automatically by binding. - connectionpool: ConnectionPool that keeps all Connections Node knows about - type: type of the corresponding Node: NODE_ACCEPTOR | NODE_REPLICA | NODE_NAMESERVER - alive: liveness of Node - outstandingmessages: collection of sent but not-yet-acked messages - socket: server socket for Node - me: Peer object that represents Node - id: id for Node (addr:port) - groups: other Peers in the system that Node knows about. Node.groups is indexed by the corresponding node_name (NODE_ACCEPTOR | NODE_REPLICA | NODE_NAMESERVER), which returns a Group """ self.addr = addr if addr else findOwnIP() self.port = port self.connectionpool = ConnectionPool() self.type = nodetype if instantiateobj: if objectfilename == '': parser.print_help() self._graceexit(1) self.objectfilename = objectfilename self.objectname = objectname ## messaging layer information self.receivedmessages_semaphore = Semaphore(0) self.receivedmessages = [] # msgs not acked yet # {msgid: msginfo} self.outstandingmessages_lock =RLock() self.outstandingmessages = {} # last msg timestamp for all peers # {peer: timestamp} self.lastmessages_lock =RLock() self.lastmessages = {} # number of retries for all peers # {peer: retries} self.retries_lock =RLock() self.retries = {} self.lock = Lock() self.done = False self.donecond = Condition() # 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: print "Cannot bind to port %d" % self.port 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: pass self.socket.listen(10) self.alive = True # initialize empty groups self.me = Peer(self.addr,self.port,self.type) self.id = self.me.getid() self.configpath = configpath try: LOGGERNODE = load_configdict(self.configpath)['LOGGERNODE'] except: if logger: LOGGERNODE=logger else: LOGGERNODE = None self.logger = NetworkLogger("%s-%s" % (node_names[self.type],self.id), LOGGERNODE) self.logger.write("State", "Connected.") self.groups = {NODE_ACCEPTOR:Group(self.me), NODE_REPLICA: Group(self.me), NODE_NAMESERVER:Group(self.me)} # connect to the bootstrap node if givenbootstraplist: self.bootstraplist = [] self.discoverbootstrap(givenbootstraplist) self.connecttobootstrap() if self.type == NODE_REPLICA or self.type == NODE_NAMESERVER: self.stateuptodate = False def createinfofile(self): try: infofile = open(self.objectfilename[:-3]+"-descriptor", 'a') infofile.write("%s:%d" %(self.addr,self.port)) infofile.close() except IOError as e: self.logger.write("File Error", "Info file cannot be created.") self._graceexit(1) def _getipportpairs(self, bootaddr, bootport): for node in socket.getaddrinfo(bootaddr, bootport): 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.bootstraplist.append(peer) #dnsname given as bootstrap else: answers = [] try: answers = dns.resolver.query('_concoord._tcp.'+bootstrap, 'SRV') except (dns.resolver.NXDOMAIN, dns.exception.Timeout): self.logger.write("DNS Error", "Cannot resolve %s" % bootstrap) for rdata in answers: for peer in self._getipportpairs(str(rdata.target), rdata.port): self.bootstraplist.append(peer) def connecttobootstrap(self): tries = 0 keeptrying = True while tries < BOOTSTRAPCONNECTTIMEOUT and keeptrying: for bootpeer in self.bootstraplist: try: self.logger.write("State", "trying to connect to bootstrap: %s" % bootpeer) helomessage = HandshakeMessage(MSG_HELO, self.me) success = self.send(helomessage, peer=bootpeer) if success < 0: tries += 1 continue self.groups[NODE_REPLICA].add(bootpeer) self.logger.write("State", "connected to bootstrap: %s:%d" % (bootpeer.addr,bootpeer.port)) keeptrying = False break except socket.error, e: self.logger.write("Connection Error", "cannot connect to bootstrap: %s" % str(e)) print e tries += 1 continue time.sleep(1)