예제 #1
0
class EvalClient():

    POSITIONS = ['1 2 3', '3 2 1', '2 3 1', '3 1 2', '1 3 2', '2 1 3']
    ACTIONS = ['gun', 'sidepump', 'hair']

    def __init__(self, host: str, port: int, controlMain):
        self.controlMain = controlMain
        self.server = (host, port)
        self.encryptionHandler = EncryptionHandler(b'Sixteen byte key')
        pass

    def sendToEval(self,
                   positions=None,
                   action=None,
                   sync_delay=None,
                   quit=False):
        if quit:
            message = '# |logout| '
        else:
            message = '#' + self.POSITIONS[positions] + '|' + self.ACTIONS[
                action] + '|' + '0.005'

        message = self.encryptionHandler.encrypt_msg(message)
        self.evalSocket.send(message)

        if quit:
            return

        data = self.evalSocket.recv(1024).decode()
        print('Received from server: ' + data)

    def connectToEval(self):
        self.evalSocket = socket.socket()
        print(self.server)
        self.evalSocket.connect(self.server)
예제 #2
0
from Util.encryption import EncryptionHandler

h = EncryptionHandler(b'Sixteen Byte Key')

message = "caleb"
em = h.encrypt_msg(message)
print(h.decrypt_message(em))
print(b"R\x9e\xc6!\x01\x05\xcf\xa6&\xac\x9dQ\xc8\x92\xe5\xb4".decode('utf8'))
예제 #3
0
class Ultra96Server:
    # Tuple containing "host" and "port" values for ultra96 server
    connection = ()

    # Holds socket address and port for each dancer, tied to dancer id as key
    clients = {}

    # Class for handling AES encryption
    encryptionhandler = None 

    # Holds last timestamps from the 3 dancers/laptops
    currTimeStamps = {}

    # Holds the last 10 recorded offsets from the 3 dancers
    # 2d array containing 10 lists of 3 offsets from each dancer 
    last10Offsets = {}

    # Used to iterate offset list from the back in order to update offsets
    currIndexClockOffset = {}

    # Holds average offsets for 3 dancers, calculated from last10Offsets
    currAvgOffsets = {}

    # Booleans to check if current moves have been received for each dancer
    currentMoveReceived = {}

    # Count to keep track of number of clock sync updates sent from each client
    # in current rotation (1-10)
    clocksyncCount = {}

    offsetLock = threading.Lock()
    timestampLock = threading.Lock()
    moveRcvLock = threading.Lock()

    # Initialize encryption handler and socket data + misc setup
    def __init__(self, host:str, port:int, key:bytes):
        self.connection = (host,port)
        self.encryptionhandler = EncryptionHandler(key.encode())

        # for _ in range(10):
        #     self.last10Offsets.append([None,None,None])
        return

    def updateTimeStamp(self, message : str, dancerID):
        print("Evaluating move...")
        print(f"time recorded by bluno:", {message})

        #calculate relative time using offset
        timestamp = float(message)
        relativeTS = timestamp - self.currAvgOffsets[dancerID]

        self.timestampLock.acquire()
        self.currTimeStamps[dancerID] = relativeTS
        self.timestampLock.release()

        return

    def broadcastMessage(self, message):
        message = self.encryptionhandler.encrypt_msg(message)
        for conn, addr in self.clients.values():
            print("BROADCAST: ",conn)
            conn.send(message)

    def respondClockSync(self, message : str, dancerID, timerecv):
        print(f"Received clock sync request from dancer, {dancerID}")
        timestamp = message
        print(f"t1 =",{timestamp})
        conn, addr = self.clients[dancerID]

        # response = str(timerecv) + "|" + str(time.time())
        response = json.dumps({'command' : 'CS', 'message': str(timerecv) + '|' + str(time.time())})
        conn.send(response.encode())

    # Must be called after acquiring offsetlock
    def updateAvgOffset(self):
        for dancerID, offsetList in self.last10Offsets.items():
            currSum = 0
            numOffsets = 10
            for offset in offsetList:
                if offset is None:
                    numOffsets -= 1
                    continue
                currSum += offset
            if numOffsets == 0:
                continue
            self.currAvgOffsets[dancerID] = currSum/numOffsets
        
    # Check if variance between 10 offsets in dancerID is too high.
    # If so, force another 10 updates with the specific dancerID
    def checkOffsetVar(self, dancerID):
        conn,addr = self.clients[dancerID]
        prevOffset = self.currAvgOffsets[dancerID]
        self.updateAvgOffset()

        clockDriftDetected = False
        offsetDiff = 0
        if not prevOffset is None:
            offsetDiff = abs(self.currAvgOffsets[dancerID] - prevOffset)
            clockDriftDetected = (offsetDiff > 5e-05)

        varLast10 = variance(self.last10Offsets[dancerID])
        print("VARIANCE FOR DANCER: ", dancerID, varLast10)
        if varLast10 > 1e-05 or clockDriftDetected:
            print("Offset variance too high: ",varLast10," or clock drift too high:",
                offsetDiff, "Resyncing for Dancer: ", dancerID)
            conn.send(self.encryptionhandler.encrypt_msg("sync"))
        
        return
            
    def updateOffset(self, message: str, dancerID):
        self.offsetLock.acquire()
        print(f"{dancerID} has received offsetlock")
        self.last10Offsets[dancerID][self.currIndexClockOffset[dancerID]] = float(message)
        self.currIndexClockOffset[dancerID] = (self.currIndexClockOffset[dancerID] - 1) % 10
        print(f"{dancerID} is releasing offsetlock")
        self.offsetLock.release()

        if self.clocksyncCount[dancerID] != 10:
            self.clocksyncCount[dancerID] += 1

        if self.clocksyncCount[dancerID] == 10:
            self.checkOffsetVar(dancerID)
            self.clocksyncCount[dancerID] = 0
            
        print("Updating dancer " + str(dancerID) + " offset to: " + message + "\n")
        return
    
    def calculateSyncDelay(self):
        sortedTimestamps = sorted(self.currTimeStamps.values())
        return (sortedTimestamps[2] - sortedTimestamps[0])

    def handleServerInput(self):
        command = input("The rest of this test script will be controlled via " +
            "server side input. Type 'sync' to perform clock synchronization " +
            "protocol and 'start' to broadcast start signal to all laptops/dancers\n")


        while command != "quit":
            if command == "sync":
                self.broadcastMessage("sync")
            if command == "start":
                self.broadcastMessage("start")
            command = input("Enter 'sync' to start clock sync and 'start' "+
                "to send start signal for move eval")
        self.broadcastMessage("quit")

    def handleClient(self, dancerID : str):
        conn,addr = self.clients[dancerID]
        try:
            while True:
                data = conn.recv(1024)
                timerecv = time.time()
                data = self.encryptionhandler.decrypt_message(data)
                data = json.loads(data)
                print("Received data:" + json.dumps(data) + "\n")
                # print(data.decode("utf8"))

                if data['command'] == "shutdown":
                    print(dancerID, ' Received shutdown signal\n')
                    break
                elif data['command'] == "clocksync":
                    print("cLoCkSyNc")
                    self.respondClockSync(data['message'], dancerID, timerecv)
                elif data['command'] == "offset":
                    self.updateOffset(data['message'], dancerID)
                elif data['command'] == "evaluateMove":
                    self.updateTimeStamp(data['message'], dancerID)

                    self.moveRcvLock.acquire()
                    self.currentMoveReceived[dancerID] = True
                    if all(value == True for value in self.currentMoveReceived.values()):
                        print(f"Sync delay calculated:", {self.calculateSyncDelay()})
                        self.currentMoveReceived = {key: False for key in self.currentMoveReceived.keys()}
                    self.moveRcvLock.release()

                # decrypted_msg = encryptionHandler.decrypt_message(data)
            print(dancerID, " RETURNING\n")
        except:
            print("[ERROR][", dancerID, "] -> ", sys.exc_info())

    # Initialize connections with 3 dancers prior to start of evaluation
    def initializeConnections(self, numDancers = 3):
        mySocket = socket.socket()
        # host,port = self.connection
        mySocket.bind((self.connection))
        mySocket.listen(5)

        try:
            for _ in range(numDancers):
                conn,addr = mySocket.accept()
                data = self.encryptionhandler.decrypt_message(conn.recv(4096))
                print("Dancer ID: ", data)
                self.clients[data] = (conn,addr)
                print(addr, '\n')

                self.currIndexClockOffset[data] = 9 # initialize index counter to 9 for each dancer
                self.last10Offsets[data] = [None for _ in range(10)] # initialize last 10 offsets for dancer id to None
                self.currAvgOffsets[data] = None
                self.currentMoveReceived[data] = False
                self.clocksyncCount[data] = 0
            return 
        except:
            print(sys.exc_info()[0], "\n")
            return
예제 #4
0
class Dancer():
    def __init__(self, dancerID: int, conn: socket.socket):
        self.dancerID = dancerID
        self.conn = conn
        self.clockSyncResponseLock = threading.Event(
        )  # To handle client-server synchronization for clock sync protocol
        self.encryptionHandler = EncryptionHandler(b'Sixteen byte key')

        self.currIndexClockOffset = 9
        self.last10Offsets = [None for _ in range(10)]
        self.currAvgOffset = None
        self.clockSyncCount = 0
        self.dataQueue = Queue()

    def handleClient(self, dataQueue, dataQueueLock: threading.Event,
                     positionChange: list):
        self.dataQueue = dataQueue
        self.dataQueueLock = dataQueueLock
        conn = self.conn
        while True:
            try:
                receivedFromBuffer = self.recvall(conn)
                timerecv = time.time()
                packets = receivedFromBuffer.decode('utf8').split(
                    ",")  # Split into b64encoded packets by ',' delimiter
                packets.pop(-1)  # Pop last empty "packet"
                for packet in packets:
                    data = self.encryptionHandler.decrypt_message(packet)
                    if not data:
                        continue
                    data = json.loads(data)
                    # print("Received data:" + json.dumps(data) + "\n")
                    # print(data.decode("utf8"))

                    if data['command'] == "shutdown":
                        print(self.dancerID, ' Received shutdown signal\n')
                        return

                    elif data['command'] == "clocksync":
                        self.respondClockSync(data['message'], conn, timerecv,
                                              self.dancerID)

                    elif data['command'] == "offset":
                        self.updateOffset(data['message'])
                        self.clockSyncResponseLock.set()

                    elif data['command'] == "timestamp":
                        # unlock data queue to store data
                        self.dataQueueLock.clear()
                        self.updateTimeStamp(data['message'])

                    elif data['command'] == "data":
                        data.pop('command')
                        data.pop('PosChangeFlag')
                        self.addData(data)

                    elif data['command'] == "poschange":
                        self.updatePosition(data['message'], positionChange)

            except Exception as e:
                print("[ERROR][HANDLECLIENT]:", self.dancerID, e)
                return

    def updatePosition(self, data, positionChange: list):
        change = int(data)
        positionChange[self.dancerID] += change
        print("Dancer", self.dancerID, "Received position change data", data,
              "\nNewData: ", positionChange)
        return

    def updateTimeStamp(self, data):
        timestamp = float(data)
        relativeTimeStamp = timestamp - self.currAvgOffset
        self.currTimeStamp = relativeTimeStamp
        print("Dancer: ", self.dancerID, "bluno recorded TS: ", timestamp,
              "adjusted TS: ", self.currTimeStamp)

    def addData(self, data):
        if not self.dataQueueLock.is_set():
            self.dataQueue.put(data)
        else:
            while not self.dataQueue.empty():
                self.dataQueue.get()

    def recvall(self, conn: socket.socket):
        fullMessageReceived = False
        data = b''
        while not fullMessageReceived:
            data += conn.recv(1024)
            if data[-1] == 44:  # 44 corresponds to ',' which is delimiter for end of b64 encoded msg
                fullMessageReceived = True
        return data

    def respondClockSync(self, message: str, conn: socket.socket,
                         timerecv: float, dancerID):
        # print(f"Received clock sync request from dancer, {dancerID}")
        timestamp = message
        # print(f"t1 =",{timestamp})

        response = json.dumps({
            'command': 'clocksync',
            'message': str(timerecv) + '|' + str(time.time())
        })
        conn.send(self.encryptionHandler.encrypt_msg(response))

    def sendMessage(self, message: str):
        message = self.encryptionHandler.encrypt_msg(message)
        self.conn.send(message)

    def handleClockSync(self, doClockSync: threading.Event,
                        clockSyncHandlerCount, clockSyncCountLock):
        while True:
            try:
                doClockSync.wait()
                for _ in range(10):
                    self.sendMessage('sync')
                    self.clockSyncResponseLock.clear()
                    time.sleep(0.05)
                    self.clockSyncResponseLock.wait()
                clockSyncCountLock.acquire()
                if clockSyncHandlerCount[0] > 1:
                    # clockSyncCountLock.acquire()
                    clockSyncHandlerCount[0] -= 1
                    # print(self.dancerID, "done", clockSyncHandlerCount)
                    clockSyncCountLock.release()
                    while clockSyncHandlerCount[0] != 3:
                        pass
                        # print(self.dancerID, "PASS", clockSyncHandlerCount)
                elif clockSyncHandlerCount[0] == 1:
                    doClockSync.clear()
                    clockSyncHandlerCount[0] = 3
                    clockSyncCountLock.release()

                # doClockSync.clear()
            except Exception as e:
                print(e)
                return

    def updateOffset(self, message: str):
        self.last10Offsets[self.currIndexClockOffset] = float(message)
        self.currIndexClockOffset = (self.currIndexClockOffset - 1) % 10

        if self.clockSyncCount != 10:
            self.clockSyncCount += 1

        if self.clockSyncCount == 10:
            self.updateAvgOffset()
            self.clockSyncCount = 0

        # print("Updating dancer " + str(self.dancerID) + " offset to: " + message + "\n")
        return

    def updateAvgOffset(self):
        offsetSum = 0
        numOffsets = 10
        for offset in self.last10Offsets:
            offsetSum += offset
        self.currAvgOffset = offsetSum / numOffsets
        print("Dancer: ", str(self.dancerID), "average offset: ",
              self.currAvgOffset)
예제 #5
0
class Ultra96Server():
    def __init__(self, host: str, port: int, key: str):
        # each value in list holds dancer class
        self.addr = (host, port)
        self.dancers = [Dancer(0, None), Dancer(0, None), Dancer(0, None)]
        self.encryptionHandler = EncryptionHandler(key.encode('utf8'))
        self.globalShutDown = threading.Event()

    def initializeConnections(self, numDancers=NUM_DANCERS):
        socket96 = socket.socket()
        # host,port = self.connection
        socket96.bind((self.addr))
        socket96.listen(3)

        try:
            for _ in range(numDancers):
                conn, addr = socket96.accept()
                messageRecv = self.recvall(conn)
                dancerID = self.encryptionHandler.decrypt_message(messageRecv)
                print("Accepted connection from:", addr, "Dancer ID: ",
                      dancerID)

                dancerID = int(dancerID)
                if dancerID not in [0, 1, 2]:
                    raise Exception(
                        "Dancer ID invalid, must be integer value 0,1 or 2")
                self.dancers[dancerID] = Dancer(dancerID, conn)

        except Exception as e:
            print("[ERROR][initializeConnections]", e)

    def executeClientHandlers(self, executor, dataQueues, dataQueueLock,
                              positionChange):
        dancerID = 0
        for dancer in self.dancers:
            executor.submit(dancer.handleClient, dataQueues[dancerID],
                            dataQueueLock, positionChange)
            dancerID += 1

    def executeClockSyncHandlers(self, executor, doClockSync: threading.Event):
        self.clockSyncHandlerCount = [3]
        self.clockSyncCountLock = threading.Lock()
        for dancer in self.dancers:
            executor.submit(dancer.handleClockSync, doClockSync,
                            self.clockSyncHandlerCount,
                            self.clockSyncCountLock)

    def recvall(self, conn: socket.socket):
        fullMessageReceived = False
        data = b''
        while not fullMessageReceived:
            data += conn.recv(1024)
            if data[-1] == 44:  # 44 corresponds to ',' which is delimiter for end of b64 encoded msg
                fullMessageReceived = True
        return data

    def broadcastMessage(self, message):
        print("BROADCASTING: ", message)
        message = self.encryptionHandler.encrypt_msg(message)
        for dancer in self.dancers:
            dancer.conn.send(message)

    def getSyncDelay(self) -> float:
        timeStampList = []
        for dancer in self.dancers:
            timeStampList.append(dancer.currTimeStamp)
        sortedTimeStamps = sorted(timeStampList)
        return sortedTimeStamps[NUM_DANCERS - 1] - sortedTimeStamps[0]
예제 #6
0
class LaptopClient():
    def __init__(self, host, port, dancerID):
        self.moveStarted = Event()
        self.evalStarted = Event()
        self.socketLock = Lock()
        self.host = host
        self.port = port
        self.encryptionHandler = EncryptionHandler(b'Sixteen byte key')
        self.dancerID = dancerID

    def sendMessage(self, message):
        print("SENDING: ", message)
        encrypted_message = self.encryptionHandler.encrypt_msg(
            message
        ) + b','  #Send b64encoded bytes with ',' delimiter as ',' is not valid b64encoded char
        self.mySocket.send(encrypted_message)

    def handleBlunoData(self, inputQueue):
        try:
            packet = None
            while True:
                packet = None
                packet = inputQueue.get()
                if packet is not None:
                    if not self.evalStarted.is_set():
                        # print("Eval not yet started, ignoring data")
                        # print(packet)
                        continue
                    if packet['PosChangeFlag'] != 0:
                        self.sendMessage(
                            json.dumps({
                                "command": "poschange",
                                "message": packet['PosChangeFlag']
                            }))
                    if packet['moveFlag'] == 1:
                        if not self.moveStarted.is_set():
                            # if move hasn't started, set flag and send timestamp
                            self.moveStarted.set()
                            self.sendMessage(
                                json.dumps({
                                    "command": "timestamp",
                                    "message": packet['time']
                                }))
                        packet['command'] = 'data'
                        self.sendMessage(json.dumps(packet))
                        # print(packet)
                else:
                    print("No packet found...")
                time.sleep(0.04)
        except Exception as e:
            print("HANDLEBLUNO:", e)
            sys.exit()

    def startClockSync(self):
        self.timeSend = time.time()
        messagedict = {"command": "clocksync", "message": str(self.timeSend)}
        print("SENDING", messagedict)
        self.sendMessage(json.dumps(messagedict))

    def respondClockSync(self, timestamps, timeRecv):
        timestamps = json.loads(timestamps)['message'].split('|')
        print(f"t1:", {self.timeSend}, "t2:", \
            {timestamps[0]}, "t3:", {timestamps[1]}, "t4:", {timeRecv})
        t = [
            self.timeSend,
            float(timestamps[0]),
            float(timestamps[1]), timeRecv
        ]

        roundTripTime = (t[3] - t[0]) - (t[2] - t[1])
        print("RTT:", {roundTripTime})

        clockOffset = ((t[2] - t[3] - roundTripTime / 2) +
                       (t[1] - t[0] - roundTripTime / 2)) / 2
        messagedict = {"command": "offset", "message": str(clockOffset)}
        self.sendMessage(json.dumps(messagedict))
        print("Clock offset:", {clockOffset})
        print("\n")

    def handleServerCommands(self):
        command = self.mySocket.recv(4096)
        timeRecv = time.time()
        command = self.encryptionHandler.decrypt_message(command)
        print("COMMAND RECEIVED:", command)
        while command != "quit":
            if command == "sync":
                self.startClockSync()
            elif command == "start":
                self.evalStarted.set()
            elif command == 'moveComplete':
                self.moveStarted.clear()
            elif "clocksync" in command:
                self.respondClockSync(command, timeRecv)

            command = self.mySocket.recv(4096)
            timeRecv = time.time()
            command = self.encryptionHandler.decrypt_message(command)
            print("COMMAND RECEIVED:", command)
        print("Shutting down dancer number " + self.dancerID)
        self.sendMessage(json.dumps(SHUTDOWNCOMMAND))
        self.mySocket.close()
        print("Quitting now")
        sys.exit()

    def connectAndIdentify(self, host, port, dancerID):
        self.mySocket = socket.socket()
        self.mySocket.connect((host, port))
        print(dancerID, ": Connection established with ", (host, port))
        self.sendMessage(dancerID)

    def start(self, remote=False):
        if remote:
            REMOTE_SERVER_IP = 'sunfire.comp.nus.edu.sg'
            PRIVATE_SERVER_IP = '137.132.86.228'

            username = input("Enter ssh username: "******"Enter ssh password: ")
            key = 'Sixteen byte key'  #remember to hide
            tunnel1 = sshtunnel.open_tunnel(
                (REMOTE_SERVER_IP, 22),
                remote_bind_address=(PRIVATE_SERVER_IP, 22),
                ssh_username=username,
                ssh_password=password,
                # local_bind_address=('127.0.0.1', 8081),
                block_on_close=False)
            tunnel1.start()
            print('[Tunnel Opened] Tunnel into Sunfire opened ' +
                  str(tunnel1.local_bind_port))
            tunnel2 = sshtunnel.open_tunnel(
                ssh_address_or_host=(
                    'localhost', tunnel1.local_bind_port),  # ssh into xilinx
                remote_bind_address=('127.0.0.1', 10022),  # binds xilinx host
                ssh_username='******',
                ssh_password='******',
                local_bind_address=('127.0.0.1',
                                    10022),  # localhost to bind it to
                block_on_close=False)
            tunnel2.start()
            self.connectAndIdentify('127.0.0.1', 10022, self.dancerID)
        else:
            self.connectAndIdentify('127.0.0.1', 10022, self.dancerID)
    print('Address: ' + str(tunnel1.local_bind_address))
    print('Port no: ' + str(tunnel1.local_bind_port))
    with SSHTunnelForwarder(('localhost', 10022),
                            ssh_username='******',
                            ssh_password='******',
                            remote_bind_address=('localhost', 10022),
                            local_bind_address=('localhost', 8080)) as tunnel2:
        print('Tunnel opened to ultra96 board with...')
        print('Address: ' + str(tunnel2.local_bind_address))
        print('Port no: ' + str(tunnel2.local_bind_port))
        host = '127.0.0.1'
        port = 8080

        mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        mySocket.connect((host, port))

        message = input(" -> ")

        while message != 'q':
            encryptionHandler = EncryptionHandler(key.encode())
            encrypted_msg = encryptionHandler.encrypt_msg(message)
            mySocket.send(encrypted_msg)
            data = mySocket.recv(1024).decode()

            print('Received from server: ' + data)

            message = input(" -> ")

        mySocket.close()

print('Closing connection')
class EvalClient():
    def __init__(self, host: str, port: int, controlMain):
        self.moveCounter = 0
        self.controlMain = controlMain
        self.server = (host, port)
        self.encryptionHandler = EncryptionHandler(b'Sixteen byte key')
        pass

    def sendToEval(self,
                   positions=randint(0, 5),
                   action=None,
                   sync_delay=0,
                   quit=False):
        if self.moveCounter == 24:
            quit = True
        if quit:
            message = '# |logout| '
        else:
            if positions == None:
                positions = randint(0, 5)
            message = '#' + POSITIONS[positions] + '|' + ACTIONS[
                action] + '|' + str(sync_delay)

        message = self.encryptionHandler.encrypt_msg(message)
        self.evalSocket.send(message)

        if quit:
            return

        data = self.evalSocket.recv(1024).decode()
        print('Received from server: ' + data)
        self.moveCounter += 1
        return data

    def updateDancerPositions(self, dancerPositions, positionChange):
        middleDancerIndex = int(dancerPositions[1]) - 1
        leftDancerIndex = int(dancerPositions[0]) - 1
        rightDancerIndex = int(dancerPositions[2]) - 1

        # middle dancer doesn't move
        if positionChange[middleDancerIndex] == 0:
            # all dancers don't move
            if positionChange[rightDancerIndex] == 0 and positionChange[
                    leftDancerIndex] == 0:
                print("[UPDATE DANCER POSITIONS][NO CHANGE]", dancerPositions)
                positionChange = [0, 0, 0]
                return

            elif positionChange[rightDancerIndex] < 0 and positionChange[
                    leftDancerIndex] > 0:
                temp = dancerPositions[0]
                dancerPositions[0] = dancerPositions[2]
                dancerPositions[2] = temp
                print(
                    "[UPDATE DANCER POSITIONS][RIGHT AND LEFT SWAP POSITIONS]",
                    dancerPositions)

            else:
                print("[UPDATE DANCER POSITIONS][INVALID CHANGE]",
                      dancerPositions)

        # middle dancer moves right
        elif positionChange[middleDancerIndex] > 0:
            if positionChange[leftDancerIndex] > 0 and positionChange[
                    rightDancerIndex] < 0:
                dancerPositions[2] = middleDancerIndex + 1
                dancerPositions[0] = rightDancerIndex + 1
                dancerPositions[1] = leftDancerIndex + 1
                print(
                    "[UPDATE DANCER POSITIONS][MIDDLE & LEFT DANCERS MOVE RIGHT, RIGHT DANCER MOVES LEFT",
                    dancerPositions)

            elif positionChange[leftDancerIndex] == 0 and positionChange[
                    rightDancerIndex] < 0:
                dancerPositions[2] = middleDancerIndex + 1
                dancerPositions[1] = rightDancerIndex + 1
                print(
                    "[UPDATE DANCER POSITIONS][LEFT DANCER STAYS, MIDDLE DANCER MOVES RIGHT, RIGHT DANCER MOVES LEFT",
                    dancerPositions)

            else:
                print("[UPDATE DANCER POSITIONS][INVALID CHANGE]",
                      dancerPositions)

        #middle dancer moves left
        else:
            if positionChange[leftDancerIndex] > 0 and positionChange[
                    rightDancerIndex] < 0:
                dancerPositions[0] = middleDancerIndex + 1
                dancerPositions[1] = rightDancerIndex + 1
                dancerPositions[2] = leftDancerIndex + 1
                print(
                    "[UPDATE DANCER POSITIONS][MIDDLE & RIGHT DANCERS MOVE LEFT, LEFT DANCER MOVES RIGHT",
                    dancerPositions)

            elif positionChange[rightDancerIndex] == 0 and positionChange[
                    leftDancerIndex] > 0:
                dancerPositions[0] = middleDancerIndex + 1
                dancerPositions[1] = leftDancerIndex + 1
                print(
                    "[UPDATE DANCER POSITIONS][RIGHT DANCER STAYS, MIDDLE DANCER MOVES LEFT, LEFT DANCER MOVES RIGHT",
                    dancerPositions)

            else:
                print("[UPDATE DANCER POSITIONS][INVALID CHANGE]",
                      dancerPositions)

        print("Positions updated, resetting position change")
        for x in range(len(positionChange)):
            positionChange[x] = 0

    def handleEval(self, outputForEval, rdyForEval: threading.Event,
                   server: Ultra96Server, globalShutDown: threading.Event,
                   dancerPositions: list, positionChange: list,
                   doClockSync: threading.Event):

        while True:
            if globalShutDown.is_set():
                return
            try:
                rdyForEval.wait()
                self.updateDancerPositions(dancerPositions, positionChange)
                outputForEval['delay'] = server.getSyncDelay()
                positionsStr = ''
                for dancerPosition in dancerPositions:
                    positionsStr += str(dancerPosition) + ' '
                positionsStr = positionsStr.strip()

                outputForEval['positions'] = POSITIONS_DICT[positionsStr]
                print("SENDING TO EVAL SERVER: ", outputForEval)
                servResponse = self.sendToEval(outputForEval['positions'],
                                               outputForEval['action'],
                                               outputForEval['delay'])
                servResponse = servResponse.replace(',', '')
                servResponse = servResponse.replace('[', '')
                servResponse = servResponse.replace(']', '')
                servResponse = servResponse.replace('\'', '')
                servResponse = servResponse.replace(' ', '')
                dancerPositions[0] = int(servResponse[0])
                dancerPositions[1] = int(servResponse[1])
                dancerPositions[2] = int(servResponse[2])
                print("Server updated values:", dancerPositions)
                rdyForEval.clear()
                # doClockSync.set()
                server.broadcastMessage("moveComplete")
            except Exception as e:
                print("[ERROR][EVALCLIENT]", e)
                return

    def connectToEval(self):
        self.evalSocket = socket.socket()
        print(self.server)
        self.evalSocket.connect(self.server)
예제 #9
0
class Ultra96Server():
    # Tuple containing "host" and "port" values for ultra96 server
    connection = ()

    # Holds socket address and port for each dancer, tied to dancer id as key
    clients = {}

    # Class for handling AES encryption
    encryptionHandler = None

    # Holds last timestamps from the 3 dancers/laptops
    currTimeStamps = {}

    # Holds the last 10 recorded offsets from the 3 dancers
    # 2d array containing 10 lists of 3 offsets from each dancer
    last10Offsets = {}

    # Used to iterate offset list from the back in order to update offsets
    currIndexClockOffset = {}

    # Holds average offsets for 3 dancers, calculated from last10Offsets
    currAvgOffsets = {}

    # Booleans to check if current moves have been received for each dancer
    currentMoveReceived = {}

    # Count to keep track of number of clock sync updates sent from each client
    # in current rotation (1-10)
    clocksyncCount = {}

    # To synchronize clock sync broadcasts and offset receiving
    clockSyncResponseLock = {}

    def __init__(self, host: str, port: int, key: str, controlMain):
        self.controlMain = controlMain
        self.connection = (host, port)
        self.encryptionHandler = EncryptionHandler(key.encode())
        self.lockDataQueue = controlMain.lockDataQueue
        self.doClockSync = controlMain.doClockSync
        self.dancerDataDict = controlMain.dancerDataDict
        self.moveCompletedFlag = controlMain.moveCompletedFlag
        self.globalShutDown = controlMain.globalShutDown

        return

    def recvall(self, conn: socket.socket):
        fullMessageReceived = False
        data = b''
        while not fullMessageReceived:
            data += conn.recv(1024)
            if data[-1] == 44:  # 44 corresponds to ',' which is delimiter for end of b64 encoded msg
                fullMessageReceived = True
        return data

    def initializeConnections(self, numDancers=NUM_DANCERS):
        mySocket = socket.socket()
        # host,port = self.connection
        mySocket.bind((self.connection))
        mySocket.listen(5)

        try:
            for _ in range(numDancers):
                conn, addr = mySocket.accept()
                print(conn, addr)
                # data = conn.recv(4096)
                data = self.recvall(conn)
                print(data)
                data = self.encryptionHandler.decrypt_message(data)
                print("Dancer ID: ", data)
                self.clients[data] = (conn, addr)
                print(addr, '\n')

                self.currIndexClockOffset[
                    data] = 9  # initialize index counter to 9 for each dancer
                self.last10Offsets[data] = [
                    None for _ in range(10)
                ]  # initialize last 10 offsets for dancer id to None
                self.currAvgOffsets[data] = None
                self.currentMoveReceived[data] = False
                self.clocksyncCount[data] = 0
                self.dancerDataDict[data] = Queue()
                self.clockSyncResponseLock[data] = threading.Event()
            return
        except:
            print(sys.exc_info(), "\n")
            return

    def calculateSyncDelay(self):
        sortedTimestamps = sorted(self.currTimeStamps.values())
        return (sortedTimestamps[-1] - sortedTimestamps[0])

    def addData(self, dancerID, data):
        with self.lockDataQueue:
            if not self.moveCompletedFlag.is_set():
                self.dancerDataDict[dancerID].put(data)
            else:
                while not self.dancerDataDict[dancerID].empty():
                    self.dancerDataDict[dancerID].get()

    def updateTimeStamp(self, message: str, dancerID):
        print("Evaluating move...")
        print(f"time recorded by bluno:", {message})

        #calculate relative time using offset
        timestamp = float(message)
        relativeTS = timestamp - self.currAvgOffsets[dancerID]
        self.currTimeStamps[dancerID] = relativeTS
        print(dancerID, "adjusted timestamp: ", relativeTS)

    def handleClient(self, dancerID: str):
        conn, addr = self.clients[dancerID]
        while True:
            if self.globalShutDown.is_set():
                return
            try:
                # receivedFromBuffer = conn.recv(4096)
                receivedFromBuffer = self.recvall(conn)
                timerecv = time.time()
                packets = receivedFromBuffer.decode('utf8').split(
                    ",")  #Split into b64encoded packets by ',' delimiter
                packets.pop(-1)
                # print("data received at ", timerecv, data)
                for packet in packets:
                    data = self.encryptionHandler.decrypt_message(packet)
                    if not data:
                        continue
                    data = json.loads(data)
                    # print("Received data:" + json.dumps(data) + "\n")
                    # print(data.decode("utf8"))

                    if data['command'] == "shutdown":
                        print(dancerID, ' Received shutdown signal\n')
                        break
                    elif data['command'] == "clocksync":
                        self.respondClockSync(data['message'], dancerID,
                                              timerecv)
                    elif data['command'] == "offset":
                        self.clockSyncResponseLock[dancerID].set()
                        self.updateOffset(data['message'], dancerID)
                    elif data['command'] == "timestamp":
                        self.moveCompletedFlag.clear()
                        self.updateTimeStamp(data['message'], dancerID)
                        self.currentMoveReceived[dancerID] = True
                        # if all(value == True for value in self.currentMoveReceived.values()):
                        #     print(f"Sync delay calculated:", {self.calculateSyncDelay()})
                        #     self.currentMoveReceived = {key: False for key in self.currentMoveReceived.keys()}
                    elif data['command'] == "data":
                        data.pop('command')
                        self.addData(dancerID, data)
                    elif data['command'] == "moveComplete":
                        pass
                        # self.moveCompletedFlag.clear()
            except UnicodeDecodeError:

                print("Packet incorrectly received")
                pass
            except Exception as e:
                print("[ERROR][", dancerID, "] -> ", e)
                print(self.dancerDataDict[dancerID].qsize())
                pass

            # decrypted_msg = encryptionHandler.decrypt_message(data)
        print(dancerID, " RETURNING\n")
        return

    def handleClockSync(self, dancerID):
        while True:
            if self.globalShutDown.is_set():
                return
            self.doClockSync.wait()
            for _ in range(10):
                self.broadcastMessage('sync')
                self.clockSyncResponseLock[dancerID].clear()
                self.clockSyncResponseLock[dancerID].wait()
            self.doClockSync.clear()

    # Check if variance between 10 offsets in dancerID is too high.
    # If so, force another 10 updates with the specific dancerID
    def checkOffsetVar(self, dancerID):
        conn, addr = self.clients[dancerID]
        self.updateAvgOffset()

        varLast10 = variance(self.last10Offsets[dancerID])
        print("VARIANCE FOR DANCER: ", dancerID, varLast10)
        if varLast10 > 1e-05:
            print("Offset variance too high: ", "varLast10",
                  "Resyncing for Dancer: ", dancerID)
            conn.send(self.encryptionHandler.encrypt_msg("sync"))

        return

    def updateOffset(self, message: str, dancerID):
        # self.offsetLock.acquire()
        # print(f"{dancerID} has received offsetlock")
        self.last10Offsets[dancerID][
            self.currIndexClockOffset[dancerID]] = float(message)
        self.currIndexClockOffset[dancerID] = (
            self.currIndexClockOffset[dancerID] - 1) % 10
        # print(f"{dancerID} is releasing offsetlock")
        # self.offsetLock.release()

        if self.clocksyncCount[dancerID] != 10:
            self.clocksyncCount[dancerID] += 1

        if self.clocksyncCount[dancerID] == 10:
            self.checkOffsetVar(dancerID)
            self.clocksyncCount[dancerID] = 0

        print("Updating dancer " + str(dancerID) + " offset to: " + message +
              "\n")
        return

    def broadcastMessage(self, message):
        print("BROADCASTING: ", message)
        message = self.encryptionHandler.encrypt_msg(message)
        for conn, addr in self.clients.values():
            conn.send(message)

    def respondClockSync(self, message: str, dancerID, timerecv):
        print(f"Received clock sync request from dancer, {dancerID}")
        timestamp = message
        print(f"t1 =", {timestamp})
        conn, addr = self.clients[dancerID]

        # response = str(timerecv) + "|" + str(time.time())
        response = json.dumps({
            'command': 'clocksync',
            'message': str(timerecv) + '|' + str(time.time())
        })
        conn.send(self.encryptionHandler.encrypt_msg(response))

    def updateAvgOffset(self):
        for dancerID, offsetList in self.last10Offsets.items():
            currSum = 0
            numOffsets = 10
            for offset in offsetList:
                if offset is None:
                    numOffsets -= 1
                    continue
                currSum += offset
            if numOffsets == 0:
                continue
            self.currAvgOffsets[dancerID] = currSum / numOffsets
예제 #10
0
import socket
from base64 import b64decode, b64encode
from Cryptodome.Cipher import AES
import time
from Util.encryption import EncryptionHandler
import json

eH = EncryptionHandler(b'Sixteen byte key')

host, port = ('127.0.0.1', 10022)
mySocket = socket.socket()
mySocket.bind((host, port))
mySocket.listen()
conn, addr = mySocket.accept()

conn.send(eH.encrypt_msg("sync"))
data = conn.recv(4096)
timeRecv = time.time()
time.sleep(1)
response = json.dumps({
    'command': 'clocksync',
    'message': str(timeRecv) + '|' + str(time.time())
})
conn.send(eH.encrypt_msg(response))
data = conn.recv(4096)
timeRecv = time.time()
print(eH.decrypt_message(data))

time.sleep(10)
conn.send(eH.encrypt_msg("start"))