def next(self, input): action = map(RSNAction.RSNAction, [input["action"]])[0] if action == RSNAction.turnOn: # TODO: do something about boot-strap # TODO: ping GSN # Qian: turnOn is called by host, thus, it is not necessary to make a DNS query. # just pass it within input # RSN can be set by: # 1. There is one bus asking for adding but there is no RSN yet (that bus is the first one in its route) # 2. The previous RSN is lost # for situation 1, the driver state machine will be hung up because he needs to wait for the initialization of RSN state machine # In situation 2, the GSN will send a backup group info to the new RSN. (Backup is not necessary for situation 1) # Terry: when a rsn turn on, it means gsn sent a message to bus to indicate it to be a rsn # Terry: the message should include the route and group info #GROUP_MEMBER = input["group_member"] #BUS_TABLE = input["bus_table"] global GSN_ADDR, LOCAL_ADDR, RSN_ID gsnIp = socket.gethostbyname('localhost') gsnPort = 40000 # pre-configured GSN_ADDR = Addr(gsnIp, gsnPort) LOCAL_ADDR = Addr(input["localIP"], input["localPort"]) RSN_ID = input["rsnId"] LOC_REQ_NO = 0 return RSNSM.Idle else: # remain off return RSNSM.Off
def next(self, input): action = map(UserAction.UserAction, [input["action"]])[0] if action == UserAction.turnOn: global LOCAL_ADDR, GSN_ADDR, USER_ID # TODO: do something about boot-strap # TODO: ping DNS LOCAL_ADDR = Addr(input["localIP"], input["localPort"]) gsnIp = socket.gethostbyname('localhost') gsnPort = 40000 # pre-configured GSN_ADDR = Addr(gsnIp, gsnPort) USER_ID = input["userId"] return UserSM.Ready else: # remain off return UserSM.Off
def next(self, input): action = map(DriverAction.DriverAction, [input["action"]])[0] if action == DriverAction.turnOn: global ROUTE_NO, DIRECTION, BUS_ID, LOCAL_ADDR, GSN_ADDR # TODO: do something about boot-strap # TODO: DNS query, need to read this name from config. # gsn_ip = socket.gethostbyname('ece.cmu.edu') gsnIp = socket.gethostbyname('localhost') gsnPort = 40000 # pre-configured GSN_ADDR = Addr(gsnIp, gsnPort) LOCAL_ADDR = Addr(input["localIP"], input["localPort"]) BUS_ID = input["busId"] return DriverSM.Idle else: # remain off return DriverSM.Off
def next(self, input): action = map(GSNAction.GSNAction, [input["action"]])[0] if action == GSNAction.turnOn: global LOCAL_ADDR, GSN_ID, TIMER_OFF, TIMER_ON # do something about boot-strap # Qian: seems we don't need to do anything LOCAL_ADDR = Addr(input["localIP"], input["localPort"]) GSN_ID = input["gsnId"] # unblock the timer thread TIMER_OFF.clear() TIMER_ON.set() return GSNSM.Ready else: # remain off return GSNSM.Off
def next(self, input): action = map(DriverAction.DriverAction, [input["action"]])[0] if action == DriverAction.recvLocReq: # TODO: response the current location # check if the rsn is my RSN, route matched? global ROUTE_NO, DIRECTION, RSN_ADDR, LOCAL_ADDR, BUS_ID, WATCHDOG LOGGER.info("received RSN location request: %s" % input) # pet the watch dog WATCHDOG.petWatchdog() # check if the RSN has changed if RSN_ADDR.ip != input["rsnIP"] or RSN_ADDR.port != input["rsnPort"]: LOGGER.info("RSN has changed") RSN_ADDR = Addr(input["rsnIP"], input["rsnPort"]) loc_message = { "SM" : "RSN_SM", "action" : "recvDriverLoc", "requestNo" : input["requestNo"], "route" : ROUTE_NO, "direction" : DIRECTION, "busId" : BUS_ID, "location" : Location.getLocation(), "busIP" : LOCAL_ADDR.ip, "busPort" : LOCAL_ADDR.port } # TODO: TEST ONLY; rsn should be modified MessagePasser.directSend(RSN_ADDR.ip, RSN_ADDR.port, loc_message) return DriverSM.Ready elif action == DriverAction.restart: # restart global LOCAL_ADDR, RSN_ADDR, ROUTE_NO, DIRECTION, BUS_ID, RESEND_ELECT_NUM LOGGER.info("Receive restart message from GSN. Restart now.") # TODO: ping RSN to add into the group add_message = { "SM" : "GSN_SM", "action" : "recvBusReq", "type" : "add", "route" : ROUTE_NO, "direction" : DIRECTION, "busId" : BUS_ID, "location" : Location.getLocation(), "busIP" : LOCAL_ADDR.ip, "busPort" : LOCAL_ADDR.port } # TODO: should use real gsn MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, add_message) RESEND_ELECT_NUM = 0 # pet the watch dog WATCHDOG.petWatchdog() return DriverSM.Init_Waiting elif action == DriverAction.timeout: # if reaches the limit of re-elect, reboot global RESEND_ELECT_NUM if RESEND_ELECT_NUM >= 3: LOGGER.info("RESEND_ELECT_NUM reaches the limit, reboot now.") RESEND_ELECT_NUM = 0 # restart global LOCAL_ADDR, RSN_ADDR, ROUTE_NO, DIRECTION, BUS_ID add_message = { "SM" : "GSN_SM", "action" : "recvBusReq", "type" : "add", "route" : ROUTE_NO, "direction" : DIRECTION, "busId" : BUS_ID, "location" : Location.getLocation(), "busIP" : LOCAL_ADDR.ip, "busPort" : LOCAL_ADDR.port } # TODO: should use real gsn MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, add_message) # pet the watch dog WATCHDOG.petWatchdog() return DriverSM.Init_Waiting else: # re-send re-elect msg LOGGER.info("send re-elect request to GSN, RESEND_ELECT_NUM: %s" % str(RESEND_ELECT_NUM)) RESEND_ELECT_NUM = RESEND_ELECT_NUM + 1 RSN_elect_message = { "SM" : "GSN_SM", "action" : "recvElecReq", "busId" : BUS_ID, "route" : ROUTE_NO, "direction" : DIRECTION, "location" : Location.getLocation(), "busIP" : LOCAL_ADDR.ip, "busPort" : LOCAL_ADDR.port } MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, RSN_elect_message) # pet the watch dog WATCHDOG.petWatchdog() return DriverSM.Hold elif action == DriverAction.turnOff: # TODO: do something to shut-down RESEND_ELECT_NUM = 0 WATCHDOG.stopWatchdog() return DriverSM.Off else: # for other illegal action # assert 0, "Init_Waiting: invalid action: %s" % str(input) pass
def next(self, input): action = map(DriverAction.DriverAction, [input["action"]])[0] if action == DriverAction.recvRSNAck: global MYSELF_ADDR, RSN_ADDR, ROUTE_NO, DIRECTION, BUS_ID # if the response route number doesn't match if input["route"] != ROUTE_NO: return DriverSM.Init_Waiting RSN_ADDR = Addr(input["rsnIP"], input["rsnPort"]) # pet the watch dog WATCHDOG.petWatchdog() return DriverSM.Ready elif action == DriverAction.timeout: # not receive the reponse from RSN for 15 secs global RESEND_ELECT_NUM if RESEND_ELECT_NUM >= 3: LOGGER.info("RESEND_ELECT_NUM reaches the limit, reboot now.") RESEND_ELECT_NUM = 0 # restart global LOCAL_ADDR, RSN_ADDR, ROUTE_NO, DIRECTION, BUS_ID add_message = { "SM" : "GSN_SM", "action" : "recvBusReq", "type" : "add", "route" : ROUTE_NO, "direction" : DIRECTION, "busId" : BUS_ID, "location" : Location.getLocation(), "busIP" : LOCAL_ADDR.ip, "busPort" : LOCAL_ADDR.port } # TODO: should use real gsn MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, add_message) # pet the watch dog WATCHDOG.petWatchdog() return DriverSM.Init_Waiting else: # re-send re-elect msg LOGGER.info("send re-elect request to GSN, RESEND_ELECT_NUM: %s" % str(RESEND_ELECT_NUM)) RESEND_ELECT_NUM = RESEND_ELECT_NUM + 1 RSN_elect_message = { "SM" : "GSN_SM", "action" : "recvElecReq", "busId" : BUS_ID, "route" : ROUTE_NO, "direction" : DIRECTION, "location" : Location.getLocation(), "busIP" : LOCAL_ADDR.ip, "busPort" : LOCAL_ADDR.port } MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, RSN_elect_message) # pet the watch dog WATCHDOG.petWatchdog() return DriverSM.Init_Waiting return DriverSM.Init_Waiting elif action == DriverAction.turnOff: # TODO: do something to shut-down RESEND_ELECT_NUM = 0 WATCHDOG.stopWatchdog() return DriverSM.Off else: # for other illegal action # assert 0, "Init_Waiting: invalid action: %s" % str(input) pass
def next(self, input): action = map(GSNAction.GSNAction, [input["action"]])[0] if action == GSNAction.recvUserReq: # TODO: forward user request to responding RSN LOGGER.info("receive user request") rsn = getRSNByName(input["route"]) if rsn != None: LOGGER.info("forward user request to RSN") rsnAddr = rsn["rsnAddr"] request_message = { "SM": "RSN_SM", "action": "recvLocReq", "original": input } MessagePasser.directSend(rsnAddr.ip, rsnAddr.port, request_message) else: LOGGER.info("no rsn running") response_message = { "SM": "USER_SM", "action": "recvRes", "location": None, "busId": None, "original": input } MessagePasser.directSend(input["userIP"], input["userPort"], response_message) return GSNSM.Ready elif action == GSNAction.heartBeat: LOGGER.info("send heart beat to each RSN") global HB_NO HB_NO = HB_NO + 1 hb_message = {"SM": "RSN_SM", "action": "recvGSNHB", "HBNo": HB_NO} for route in ROUTE_TABLE: MessagePasser.directSend(ROUTE_TABLE[route]["rsnAddr"].ip, ROUTE_TABLE[route]["rsnAddr"].port, hb_message) return GSNSM.Ready elif action == GSNAction.recvHBRes: LOGGER.info("receive HB response") global ROUTE_TABLE, HB_NO # update ROUTE_TABLE if input["route"] in ROUTE_TABLE: if input["rsnId"] == ROUTE_TABLE[input["route"]]["rsnId"]: ROUTE_TABLE[input["route"]]["rsnAddr"] = Addr( input["rsnIP"], input["rsnPort"]) ROUTE_TABLE[input["route"]]["busTable"] = input["busTable"] ROUTE_TABLE[input["route"]]["last_update"] = input["HBNo"] ROUTE_TABLE[input["route"]]["isElect"] = False else: # TODO: the rsnId is not recorded pass else: # TODO: the route is not recorded. pass return GSNSM.Ready elif action == GSNAction.recvBusReq: # TODO: update route table and forward user request to responding RSN LOGGER.info("receive bus request") rsn = getRSNByName(input["route"]) # if there is no RSN, assign the request bus as the RSN if rsn == None: # Qian: some checks: (1) if there is no rsn but receive a remove req LOGGER.info("assign new RSN") """ routeTableElm = RouteTableElm(input["route"], Addr(input["driverIp"], input["driverPort"]), []) routeTableElm.busTable.append(BusTableElm(Addr(input["driverIp"], input["driverPort"]))) """ route_table_entry = { "rsnId": input["busId"], "rsnAddr": Addr(input["busIP"], input["busPort"]), "busTable": None, "last_update": HB_NO } ROUTE_TABLE[input["route"]] = route_table_entry assign_message = { "SM": "RSN_SM", "action": "recvRSNAssign", "type": "self", "route": input["route"], "original": input, "groupMember": [input["busId"]] } MessagePasser.directSend(input["busIP"], input["busPort"], assign_message) else: # Qian: GSN will just forward it to rsn # may change this design request_message = { "SM": "RSN_SM", "action": "recvBusChange", "type": input["type"], # add or remove "route": input["route"], "direction": input["direction"], "location": input["location"], "busId": input["busId"], "busIP": input["busIP"], "busPort": input["busPort"] } MessagePasser.directSend(rsn["rsnAddr"].ip, rsn["rsnAddr"].port, request_message) return GSNSM.Ready elif action == GSNAction.recvElecReq: # receive election rsn request for a bus LOGGER.info("receive election request") global HB_NO rsn = getRSNByName(input["route"]) # check if the rsn is live by checking the time stamp if rsn["last_update"] + 1 >= HB_NO: # means the RSN is alive, tell the driver to wait or reboot if rsn["isElect"] == True: LOGGER.info( "new RSN has been elected, ignore the elect request") else: LOGGER.info("RSN is alive, ask the driver to reboot") restart_message = {"SM": "DRIVER_SM", "action": "restart"} MessagePasser.directSend(input["busIP"], input["busPort"], restart_message) else: # the RSN is dead, elect a new one, select the bus who sends the request, #with the longest potential running time bus_table = rsn["busTable"] ''' rsn_candidate = None min_dist = -1 min_bus_id = -1 for bus in bus_table: dist = int(bus_table[bus]["location"]) if min_dist < 0 or dist < min_dist: min_dist = dist rsn_candidate = bus_table[bus] min_bus_id = bus ''' LOGGER.info( "RSN is dead, select a new RSN [%s] for route [%s]" % (input["busId"], input["route"])) # explicitly send a message to shut down the previous RSN resign_message = {"SM": "RSN_SM", "action": "recvRSNResign"} MessagePasser.directSend(rsn["rsnAddr"].ip, rsn["rsnAddr"].port, resign_message) # assign a new RSN assign_message = { "SM": "RSN_SM", "action": "recvRSNAssign", "type": "normal", "route": input["route"], "original": None, "busTable": bus_table } ROUTE_TABLE[input["route"]] = { "rsnId": input["busId"], "rsnAddr": Addr(input["busIP"], input["busPort"]), "busTable": bus_table, "last_update": HB_NO, "isElect": True, } MessagePasser.directSend(input["busIP"], input["busPort"], assign_message) # TODO: select a bus from the table to be the new rsn, below code just selects the first driver ''' elm.rsnIP = elm.busTable[0]["rsnAddr"].ip elm.rsnPort = elm.busTable[0]["rsnAddr"].port LOGGER.info("send message to new rsn") assign_message = { "SM" : "RSN_SM", "action" : "recvRSNAssign", "groupMember" : elm.busTable } # TODO: TEST ONLY; gsn should be modified MessagePasser.directSend(elm.rsnIP, elm.rsnPort, request_message) ''' return GSNSM.Ready elif action == GSNAction.turnOff: # TODO: do something to shut-down return GSNSM.Off
def next(self, input): action = map(RSNAction.RSNAction, [input["action"]])[0] if action == RSNAction.recvLocReq: # TODO: lookup the queried bus location and # TODO: response to user directly global BUS_TABLE, LOC_REQ_NO LOGGER.info("received location request: %s" % input) # fetch the nearest bus available # TODO: this function should be polished nearest_bus = None nearest_loc = None nearest_dist = -1 for key in BUS_TABLE: bus = BUS_TABLE[key] if (int(bus["last_update"]) >= int(LOC_REQ_NO) - 1) and (int( bus["last_update"]) <= int(LOC_REQ_NO)): distance = int(input["original"]["location"]) - int( bus["location"]) if (nearest_dist < 0 or distance < nearest_dist) and distance >= 0: nearest_dist = distance nearest_bus = key nearest_loc = bus["location"] response_message = { "SM": "USER_SM", "action": "recvRes", "location": nearest_loc, "busId": nearest_bus, "original": input["original"] } MessagePasser.directSend(input["original"]["userIP"], input["original"]["userPort"], response_message) return RSNSM.Ready elif action == RSNAction.askBusLoc: # periodically ask each buses' location # TODO: triggered by host timer global GROUP_MEMBER, RSN_ID, ROUTE_NO, LOCAL_ADDR, LOC_REQ_NO LOGGER.info("asking each bus' location %s" % BUS_TABLE.keys()) LOC_REQ_NO = LOC_REQ_NO + 1 # maybe overflow!!! req_loc_message = { "SM": "DRIVER_SM", "action": "recvLocReq", "requestNo": LOC_REQ_NO, "rsnId": RSN_ID, "route": ROUTE_NO, "rsnIP": LOCAL_ADDR.ip, "rsnPort": LOCAL_ADDR.port } #MessagePasser.multicast(GROUP_MEMBER, req_loc_message) # TODO: replace the code below with a multicast version for member in BUS_TABLE: MessagePasser.directSend(BUS_TABLE[member]["addr"].ip, BUS_TABLE[member]["addr"].port, req_loc_message) return RSNSM.Ready elif action == RSNAction.recvDriverLoc: # TODO: update local cache global BUS_TABLE, ROUTE_NO if input["route"] == ROUTE_NO \ and input["busId"] in BUS_TABLE \ and input["requestNo"] > BUS_TABLE[input["busId"]]["last_update"]: BUS_TABLE[input["busId"]] = { "direction": input["direction"], "location": input["location"], "addr": Addr(input["busIP"], input["busPort"]), "last_update": input["requestNo"] # TODO: use local time stamp } return RSNSM.Ready elif action == RSNAction.recvBusChange: # TODO: add or remove a bus from current group LOGGER.info("Receive bus change request: %s" % input) global GROUP_MEMBER, BUS_TABLE, ROUTE_NO, RSN_ID, LOCAL_ADDR, LOC_REQ_NO if input["route"] == ROUTE_NO: if input["type"] == "add": #if not input["busId"] in BUS_TABLE: #GROUP_MEMBER.append(input["busId"]) BUS_TABLE[input["busId"]] = { "direction": input["direction"], "location": input["location"], "addr": Addr(input["busIP"], input["busPort"]), "last_update": LOC_REQ_NO # TODO: use local time stamp } # send an ACK to driver rsn_ack = { "SM": "DRIVER_SM", "action": "recvRSNAck", "route": ROUTE_NO, "rsnId": RSN_ID, "rsnIP": LOCAL_ADDR.ip, "rsnPort": LOCAL_ADDR.port } MessagePasser.directSend(input["busIP"], input["busPort"], rsn_ack) elif input["type"] == "remove": if input["busId"] in BUS_TABLE: #GROUP_MEMBER.remove(input["busId"]) BUS_TABLE.pop(input["busId"]) return RSNSM.Ready elif action == RSNAction.recvGSNHB: LOGGER.info("Receive GSN heart beat: %s" % input["HBNo"]) global BUS_TABLE, RSN_ID, ROUTE_NO, LOCAL_ADDR, GSN_ADDR, LOC_REQ_NO # filter out some dead buses remove_list = [] for bus in BUS_TABLE: if int(BUS_TABLE[bus]["last_update"]) + 1 < LOC_REQ_NO: remove_list.append(bus) for bus in remove_list: BUS_TABLE.pop(bus) # send current route table to GSN HB_res_message = { "SM": "GSN_SM", "action": "recvHBRes", "HBNo": input["HBNo"], "rsnId": RSN_ID, "route": ROUTE_NO, "rsnIP": LOCAL_ADDR.ip, "rsnPort": LOCAL_ADDR.port, "busTable": BUS_TABLE } MessagePasser.directSend(GSN_ADDR.ip, GSN_ADDR.port, HB_res_message) return RSNSM.Ready elif action == RSNAction.recvRSNResign: LOGGER.info("Receive GSN resign") TIMER_OFF.set() TIMER_ON.clear() return RSNSM.Idle elif action == RSNAction.turnOff: # TODO: do something to shut-down TIMER_OFF.set() TIMER_ON.clear() return RSNSM.Off else: # for other illegal action # assert 0, "Ready: invalid action: %s" % str(input) pass
def next(self, input): action = map(RSNAction.RSNAction, [input["action"]])[0] if action == RSNAction.recvRSNAssign: # TODO: received the group info from GSN # TODO: store the group info global LOCAL_ADDR, ROUTE_NO, BUS_TABLE, TIMER_ON, TIMER_OFF ROUTE_NO = input["route"] # if the RSN is the Driver itself, send a recvRSNAck to driver role if input["type"] == "self": BUS_TABLE[input["original"]["busId"]] = { "direction": input["original"]["direction"], "location": input["original"]["location"], "addr": Addr(input["original"]["busIP"], input["original"]["busPort"]), "last_update": 0 # TODO: use local time stamp } rsn_ack = { "SM": "DRIVER_SM", "action": "recvRSNAck", "route": ROUTE_NO, "rsnId": RSN_ID, "rsnIP": LOCAL_ADDR.ip, "rsnPort": LOCAL_ADDR.port } MessagePasser.directSend(input["original"]["busIP"], input["original"]["busPort"], rsn_ack) elif input["type"] == "normal": BUS_TABLE = input["busTable"] if BUS_TABLE == None: BUS_TABLE = {} # reset all time stampes for bus in BUS_TABLE: BUS_TABLE[bus]["last_update"] = 0 # notify each bus global GROUP_MEMBER, RSN_ID, ROUTE_NO, LOCAL_ADDR, LOC_REQ_NO LOGGER.info("asking each bus' location %s" % BUS_TABLE.keys()) LOC_REQ_NO = 0 LOC_REQ_NO = LOC_REQ_NO + 1 # maybe overflow!!! req_loc_message = { "SM": "DRIVER_SM", "action": "recvLocReq", "requestNo": LOC_REQ_NO, "rsnId": RSN_ID, "route": ROUTE_NO, "rsnIP": LOCAL_ADDR.ip, "rsnPort": LOCAL_ADDR.port } for member in BUS_TABLE: MessagePasser.directSend(BUS_TABLE[member]["addr"].ip, BUS_TABLE[member]["addr"].port, req_loc_message) # unblock the timer thread TIMER_OFF.clear() TIMER_ON.set() return RSNSM.Ready elif action == RSNAction.timeout: # TODO: re-ping # Terry: seems no need to re-ping gsn return RSNSM.Idle elif action == RSNAction.turnOff: global TIMER_ON, TIMER_OFF # TODO: do something to shut-down TIMER_OFF.set() TIMER_ON.clear() return RSNSM.Off else: # for other illegal action # assert 0, "Idle: invalid action: %s" % str(input) pass