Beispiel #1
0
def getChunksList(file, peerAddr):
    """
    Retrives the chunks list for a file from another active peer.
    :param file: File object
    :param peerAddr: IP address and port of the destination peer
    :return: chunksList (list() of integer, each one represents a chunkID)
    """

    # connect to remote peer
    s = networking.createConnection(peerAddr)
    if s is None:
        return None

    try:
        # send request and get the answer
        message = str(peerCore.peerID) + " " + \
                  "CHUNKS_LIST {} {} {}".format(file.groupName, file.treePath, file.timestamp)
        networking.mySend(s, message)
        data = networking.myRecv(s)
        networking.closeConnection(s, peerCore.peerID)
    except (socket.timeout, RuntimeError, ValueError):
        print("Error while getting chunks list")
        networking.closeConnection(s, peerCore.peerID)
        return None

    if str(data).split()[0] == "ERROR":
        # remote peer answered with an error string
        print('Received from the peer :', data)
        return None
    else:
        # success: return chunksList
        chunksList = eval(str(data))
        return chunksList
Beispiel #2
0
def changeRole(groupName, targetPeerID, action):
    """
    Change the role of a peer in a group (Master peers only)
    :param groupName: is the name of the group on which the change will be applied
    :param targetPeerID: is the peerID of the peer target of the change
    :param action: can be ADD_MASTER, CHANGE_MASTER, TO_RW, TO_RO
    :return: boolean (True for success, False for any error)
    """

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return False

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "ROLE {} {} {}".format(action.upper(), targetPeerID, groupName)
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: role not changed
        print('Received from the tracker :', answer)
        return False
    else:
        # tracker successfully changed role
        if action.upper() == "CHANGE_MASTER":
            # set the peer itself (former master) to RW
            groupsList[groupName]["role"] = "RW"
        return True
Beispiel #3
0
def disconnectGroup(groupName):
    """
    Disconnect the peer from the group (the group becomes restorable).
    Stop eventual running sync threads.
    :param groupName: name of the group from which the peer want to disconnect
    :return: boolean (True for success, False for any error)
    """

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return False

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "DISCONNECT {}".format(groupName)
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: return False
        print('Received from the tracker :', answer)
        return False
    else:
        # stop every synchronization thread working on file of the group
        # and remove group related tasks from the queue
        syncScheduler.stopSyncThreadsByGroup(groupName, syncScheduler.SYNC_STOPPED)
        syncScheduler.removeGroupTasks(groupName)

        groupsList[groupName]["status"] = "RESTORABLE"

        return True
Beispiel #4
0
def retrieveGroups():
    """
    Retrieves groups from the tracker and update local groups list.
    In case of error return immediately without updating local groups.
    :return: boolean (True for success, False for any error)
    """
    global groupsList

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "GROUPS"
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: group not restored
        print('Received from the tracker :', answer)
        return False
    else:
        # set the local groups list equals to the retrieved one
        # split operation in order to skip the initial 'OK -'
        groupsList = eval(answer.split(" ", 2)[2])

    return True
Beispiel #5
0
def startPeer():
    """
    Load previous session information about files.
    Start a server thread on a free port.
    Finally send coordinates to central tracker in order to be
    reachable from other peers.
    :return: tracker object
    """

    # load local file tree with previous session information (if any)
    global localFileTree
    localFileTree = fileSystem.getFileStatus(previousSessionFile)
    if localFileTree is None:
        return None

    # create and start the scheduler thread
    schedulerThread = Thread(target=syncScheduler.scheduler, args=())
    schedulerThread.daemon = True
    schedulerThread.start()

    # join the ZeroTier virtual network
    zeroTierIP = networking.joinNetwork()

    # retrieve ZT IP address of the tracker
    getTrackerZTAddr()

    # create a server thread which will ask on all the IP addresses
    # including the ZeroTier IP address
    # port will be choose among available ones
    server = peerServer.Server()
    server.daemon = True
    server.start()

    # wait for serverStart in order to retrieve the choosen port number
    while not server.serverStart:
        pass

    # get peer server port number
    global myPortNumber
    myPortNumber = server.port

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return None

    # send my IP address and port number to tracker
    # in order to be reachable from other peers
    try:
        message = str(peerID) + " " + "HERE {} {}".format(zeroTierIP, myPortNumber)
        networking.mySend(s, message)
        __ = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return None

    return server
Beispiel #6
0
def createGroup(groupName, groupTokenRW, groupTokenRO):
    """
    Create a new group by sending a request to the tracker with all the necessary information
    :param groupName: name of the group
    :param groupTokenRW: token for Read&Write access
    :param groupTokenRO: token for ReadOnly access
    :return: boolean (True for success, False for any error)
    """

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return False

    # encrypt the two tokens using the md5 algorithm
    encryptedTokenRW = hashlib.md5(groupTokenRW.encode())
    encryptedTokenRO = hashlib.md5(groupTokenRO.encode())

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "CREATE {} {} {}".format(groupName,
                                                               encryptedTokenRW.hexdigest(),
                                                               encryptedTokenRO.hexdigest())
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: group not created
        print('Received from the tracker :', answer)
        return False
    else:
        # group successfully created: add it to my local groups list
        groupsList[groupName] = dict()
        groupsList[groupName]["name"] = groupName
        groupsList[groupName]["status"] = "ACTIVE"
        groupsList[groupName]["total"] = 1
        groupsList[groupName]["active"] = 1
        groupsList[groupName]["role"] = "MASTER"

        localFileTree.addGroup(fileSystem.Node(groupName, True))

        return True
Beispiel #7
0
def peerExit():
    """
    Disconnect peer from all the active groups by sending a request to the tracker.
    Furthermore, stop all the working synchronization thread.
    :return: boolean (True for success, False for any error)
    """

    s = networking.createConnection(trackerZTAddr)

    if s is None:
        return False

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "EXIT"
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: return False
        print('Received from the tracker :', answer)
        return False
    else:

        # stop scheduler
        syncScheduler.stopScheduler()
        syncScheduler.removeAllTasks()

        # stop every working synchronization thread
        syncScheduler.stopAllSyncThreads(syncScheduler.SYNC_STOPPED)

        # leave ZetoTier network
        networking.leaveNetwork()

        # wait for eventual sync threads termination
        time.sleep(3)

        # save session status
        fileSystem.saveFileStatus(localFileTree, previousSessionFile)

        return True
Beispiel #8
0
def sendChunksList(message, thread):
    """
    Sends local chunks list of a file to another peer that requests it.
    :param message: message received
    :param thread: thread handler of the connection
    :return: void
    """

    # get message parameters
    messageFields = message.split()
    groupName = messageFields[1]
    fileTreePath = messageFields[2]
    timestamp = int(messageFields[3])

    # retrieve file information
    fileNode = peerCore.localFileTree.getGroup(groupName).findNode(
        fileTreePath)

    if fileNode is not None:
        # check timestamp in order to ensure local file validity
        if fileNode.file.timestamp == timestamp:
            if fileNode.file.availableChunks is not None:
                if len(fileNode.file.availableChunks) != 0:

                    # send back chunks list
                    answer = str(fileNode.file.availableChunks)

                else:
                    answer = "ERROR - EMPTY LIST"
            else:
                answer = "ERROR - UNITIALIZED LIST"
        else:
            answer = "ERROR - DIFFERENT VERSION"
    else:
        answer = "ERROR - UNRECOGNIZED FILE {} IN GROUP {}".format(
            fileTreePath, groupName)

    try:
        networking.mySend(thread.clientSock, answer)
    except (socket.timeout, RuntimeError, ValueError):
        print("Error while sending: ", answer)
Beispiel #9
0
def joinGroup(groupName, token):
    """
    Join a group by sending a request to the tracker.
    :param groupName: is the name of the group that peer want to join
    :param token: it's the access token (password)
    :return: boolean (True for success, False for any error) (True for success, False for any error)
    """

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return False

    # encrypt the token using the md5 algorithm
    encryptedToken = hashlib.md5(token.encode())

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "JOIN {} {}".format(groupName, encryptedToken.hexdigest())
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: group not joined
        print('Received from the tracker :', answer)
        return False
    else:
        # group successfully joined: set group status to ACTIVE
        groupsList[groupName]["status"] = "ACTIVE"

        if localFileTree.getGroup(groupName) is None:
            localFileTree.addGroup(fileSystem.Node(groupName, True))

        # initialize file list for the group
        startGroupSync(groupName)

        return True
Beispiel #10
0
def startGroupSync(groupName):
    """
    Starts eventual required synchronization in a specific group.
    First of all, it retrieves files information from the tracker.
    Information retrieved are compared to local information
    belonging to a previous session of the group (if any)
    in order to detect added/removed/updated files, reacting
    properly to these events
    :param groupName: selected group
    :return: void
    """

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return

    # retrieves file information from the tracker
    try:
        message = str(peerID) + " " + "GET_FILES {}".format(groupName)
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: return immediately
        print("Received from the tracker: ", answer)
        return
    else:
        # split operation in order to skip the initial 'OK -'
        updatedFileList = eval(answer.split(" ", 2)[2])

    # call the function that evaluates the information retrieved from the tracker
    # comparing them with local information about a previous session (if it exists)
    updateLocalGroupTree(groupName, localFileTree.getGroup(groupName), updatedFileList)
Beispiel #11
0
def retrievePeers(groupName, selectAll):
    """
    Retrieve a list containg all the peers of a group.
    If selectAll = False retrieve only ACTIVE peers
    :param groupName: name of the group
    :param selectAll: boolean (True for success, False for any error) value
    :return: list of peers
    """

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return None

    if selectAll:
        tmp = "ALL"
    else:
        tmp = "ACTIVE"

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "PEERS {} {} ".format(groupName, tmp)
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return None

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: return None
        print('Received from the tracker :', answer)
        peersList = None
    else:
        # split operation in order to skip the initial 'OK -'
        peersList = eval(answer.split(" ", 2)[2])

    return peersList
Beispiel #12
0
def restoreGroup(groupName):
    """
    Restore a group by sending a request to the tracker.
    In case of success update my local groups list setting the group status to ACTIVE.
    :param groupName: is the name of the group that I want to restore
    :return: boolean (True for success, False for any error)
    """

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return False

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "RESTORE {}".format(groupName)
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: group not restored
        print('Received from the tracker :', answer)
        return False
    else:
        # group successfully restored: set group status to ACTIVE
        groupsList[groupName]["status"] = "ACTIVE"

        if localFileTree.getGroup(groupName) is None:
            localFileTree.addGroup(fileSystem.Node(groupName, True))

        # initialize file list for the group
        startGroupSync(groupName)

        return True
Beispiel #13
0
def getTrackerZTAddr():
    """
    Retrives the ZeroTier IP address from the tracker
    and set the associated global variable trackerZTAddr
    :return: void
    """

    global trackerZTAddr

    s = networking.createConnection(trackerAddr)
    if s is None:
        return

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "INFO"
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    trackerZTAddr = eval(answer)
Beispiel #14
0
    def manageRequest(self, message, peerID):
        """
        Manage different incoming requests.
        Call an appropriate handler according to the message content.
        :param message: incoming message
        :param peerID: id of the peer who sent the message
        :return: void
        """

        action = message.split()[0]

        # if action != "BYE":
        #     print('[Thr {}] [Peer: {}] Received {}'.format(self.number, peerID, message))

        if action == "CHUNKS_LIST":
            fileSharing.sendChunksList(message, self)

        elif action == "CHUNK":
            fileSharing.sendChunk(message, self)

        elif action == "ADDED_FILES":
            answer = syncScheduler.addedFiles(message)
            networking.mySend(self.clientSock, answer)

        elif action == "REMOVED_FILES":
            answer = syncScheduler.removedFiles(message)
            networking.mySend(self.clientSock, answer)

        elif action == "UPDATED_FILES":
            answer = syncScheduler.updatedFiles(message)
            networking.mySend(self.clientSock, answer)

        elif action == "BYE":
            answer = "BYE PEER"
            networking.mySend(self.clientSock, answer)
            self.stop()
Beispiel #15
0
def sendChunk(message, thread):
    """
    Send requested chunk to another peer.
    :param message: message received
    :param thread: thread handler of the connection
    :return: void
    """

    # get message parameters
    messageFields = message.split()
    groupName = messageFields[1]
    fileTreePath = messageFields[2]
    timestamp = int(messageFields[3])

    # id of the requested chunk
    chunkID = int(messageFields[4])

    error = True

    # get local file information
    fileNode = peerCore.localFileTree.getGroup(groupName).findNode(
        fileTreePath)

    if fileNode is not None:

        file = fileNode.file

        # check timestamp in order to ensure local file validity
        if file.timestamp == timestamp:
            if chunkID in file.availableChunks:

                # get chunk's size
                if chunkID == file.chunksNumber - 1:
                    chunkSize = file.lastChunkSize
                else:
                    chunkSize = CHUNK_SIZE

                if file.status == "S":
                    # peer has the whole file: open and send it

                    try:
                        f = open(file.filepath, 'rb')
                        offset = chunkID * CHUNK_SIZE
                        f.seek(offset)

                        dataChunk = f.read(chunkSize)

                        try:
                            error = False
                            answer = "OK - I'M SENDING THE CHUNK"
                            networking.mySend(thread.clientSock, answer)
                            networking.sendChunk(thread.clientSock, dataChunk,
                                                 chunkSize)
                        except (socket.timeout, RuntimeError):
                            print(
                                "Error while sending chunk {}".format(chunkID))

                        f.close()
                    except FileNotFoundError:
                        answer = "ERROR - IT WAS NOT POSSIBLE TO OPEN THE FILE"

                if file.status == "D":
                    # peer is still downloading the file -> send chunk from tmp directory

                    try:
                        chunkPath = file.filepath + "_tmp/" + "chunk" + str(
                            chunkID)

                        f = open(chunkPath, 'rb')

                        dataChunk = f.read(chunkSize)

                        try:
                            error = False
                            answer = "OK - I'M SENDING THE CHUNK"
                            networking.mySend(thread.clientSock, answer)
                            networking.sendChunk(thread.clientSock, dataChunk,
                                                 chunkSize)
                        except (socket.timeout, RuntimeError):
                            print(
                                "Error while sending chunk {}".format(chunkID))

                        f.close()
                    except FileNotFoundError:
                        answer = "ERROR - IT WAS NOT POSSIBLE TO OPEN THE FILE"
            else:
                answer = "ERROR - UNAVAILABLE CHUNK"
        else:
            answer = "ERROR - DIFFERENT VERSION"
    else:
        answer = "ERROR - UNRECOGNIZED FILE {} IN GROUP {}".format(
            fileTreePath, groupName)

    if error:
        # send error answer: other peer will not wait for the chunk
        try:
            networking.mySend(thread.clientSock, answer)
        except (socket.timeout, RuntimeError, ValueError):
            print("Error while sending: ", answer)
Beispiel #16
0
def getChunks(dl, file, peer, tmpDirPath):
    """
    This function allows to retrieve chunks from another active peer.
    Chunks are selected from the dl.rarestFirstChunksList and requested.
    The function iterate its behavior until the download is complete.
    :param dl: download information and data
    :param file: File object
    :param peer: peer information, it's a dictionary
    :param tmpDirPath: path of the directory where chunk will be stored
    :return: void
    """

    # get peer address
    peerAddr = peer["address"]

    if len(file.availableChunks) + len(dl.scheduledChunks) >= COMPLETION_RATE * file.chunksNumber \
            or len(file.missingChunks) <= MAX_CHUNKS:
        # don't use random discard if the number of missing chunks is smaller than a certain amount
        threshold = 1

    else:
        # use random discard
        threshold = INITIAL_TRESHOLD

    # connect to remote peer
    s = networking.createConnection(peerAddr)
    if s is None:
        return

    while not dl.complete:

        if file.stopSync:
            break

        # list of chunks that the function will retrieve in a single iteration
        chunksList = list()

        dl.lock.acquire()

        for chunk in dl.rarestFirstChunksList:
            if len(chunksList) >= MAX_CHUNKS:
                # chunksList full
                break
            if len(file.missingChunks) > MAX_CHUNKS \
                    and len(file.availableChunks) + len(dl.scheduledChunks) <= COMPLETION_RATE * file.chunksNumber \
                    and random() > threshold:
                # randomly discard this chunk from the request list
                continue
            if peer in dl.chunksToPeers[chunk]:
                # add chunk to request list and scheduled list
                chunksList.append(chunk)
                dl.scheduledChunks.add(chunk)

        # remove scheduled chunks from main list
        # this avoid that other threads request scheduled chunks
        for chunk in chunksList:
            dl.rarestFirstChunksList.remove(chunk)

        dl.lock.release()

        # decrease discard probability for next round
        threshold += TRESHOLD_INC_STEP

        if len(chunksList) == 0:
            # if no chunks can be request to the peer
            # sleep 5 seconds and then try again to compute chunksList

            for i in range(0, 5):
                if file.stopSync or dl.complete:
                    break
                else:
                    time.sleep(1)

        else:

            errors = 0

            for i in range(0, len(chunksList)):

                chunkID = chunksList[i]

                if errors == MAX_ERRORS:
                    networking.closeConnection(s, peerCore.peerID)
                    # try to re-establish connection
                    s = networking.createConnection(peerAddr)
                    if s is None:
                        # connection broken or peer disconnected
                        for j in range(i, len(chunksList)):
                            # reload in the main list all the scheduled chunks
                            chunk = chunksList[j]
                            errorOnGetChunk(dl, chunk)
                        return

                # check eventual stop forced from main thread
                if file.stopSync:
                    break

                try:
                    # send request and wait for a string response
                    message = str(peerCore.peerID) + " " + \
                              "CHUNK {} {} {} {}".format(file.groupName, file.treePath, file.timestamp, chunkID)
                    networking.mySend(s, message)
                    answer = networking.myRecv(s)
                except (socket.timeout, RuntimeError, ValueError):
                    print("Error receiving message about chunk {}".format(
                        chunkID))
                    errorOnGetChunk(dl, chunkID)
                    errors += 1
                    continue

                if answer.split()[0] == "ERROR":
                    # error: consider next chunks
                    print("Received:", answer)
                    errorOnGetChunk(dl, chunkID)
                    continue

                try:
                    # success: get the chunk

                    # evaluate chunks size
                    if chunkID == file.chunksNumber - 1:
                        chunkSize = file.lastChunkSize
                    else:
                        chunkSize = CHUNK_SIZE

                    data = networking.recvChunk(s, chunkSize)
                except (socket.timeout, RuntimeError):
                    print("Error receiving chunk {}".format(chunkID))
                    errorOnGetChunk(dl, chunkID)
                    errors += 1
                    continue

                try:
                    peerCore.pathCreationLock.acquire()
                    if not os.path.exists(tmpDirPath):
                        # print("Creating the path: " + tmpDirPath)
                        os.makedirs(tmpDirPath)
                    peerCore.pathCreationLock.release()

                    chunkPath = tmpDirPath + "chunk" + str(chunkID)

                    # write chunk in a new file
                    f = open(chunkPath, 'wb')
                    f.write(data)
                    f.close()

                    try:
                        file.missingChunks.remove(chunkID)
                        file.availableChunks.append(chunkID)
                        dl.scheduledChunks.remove(chunkID)
                    except ValueError:
                        pass

                except FileNotFoundError:
                    errorOnGetChunk(dl, chunkID)
                    continue

    networking.closeConnection(s, peerCore.peerID)
Beispiel #17
0
def updateFiles(groupName, files):
    """
    Update a list of file in the synchronization group,
    making them ready to be acknowledged from other peers.
    :param groupName: name of the group from which files will be updated
    :param files: list of tuples (fileObject, timestamp)
    :return: void
    """

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return False

    # collect information required for the update operation
    filesInfo = list()

    for f in files:
        file = f[0]
        fileInfo = dict()
        fileInfo["treePath"] = file.treePath
        fileInfo["filesize"] = file.filesize
        fileInfo["timestamp"] = file.timestamp
        filesInfo.append(fileInfo)

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "UPDATED_FILES {} {}".format(groupName, str(filesInfo))
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: return False
        print('Received from the tracker :', answer)
        return False
    else:

        for f in files:
            file = f[0]
            timestamp = f[1]
            key = file.groupName + "_" + file.treePath
            # stop possible synchronization thread
            syncScheduler.stopSyncThread(key, syncScheduler.FILE_UPDATED)

            # make the peer ready to upload chunks
            if file.syncLock.acquire(blocking=False):
                # file not used by any sinchronization process
                file.status = "S"
                file.initSeed()
                file.syncLock.release()
            else:
                # file is currently in synchronization
                # create a thread which will wait under the end of the synchronization
                # and then it will update file state
                t = Thread(target=waitSyncAndUpdate, args=(file, timestamp))
                t.daemon = True
                t.start()

        # retrieve the list of active peers for the file
        activePeers = retrievePeers(groupName, selectAll=False)

        # notify other active peers
        for peer in activePeers:

            s = networking.createConnection(peer["address"])
            if s is None:
                continue

            try:
                # send request message and wait for the answer, then close the socket
                message = str(peerID) + " " + "UPDATED_FILES {} {}".format(groupName, str(filesInfo))
                networking.mySend(s, message)
                __ = networking.myRecv(s)
                networking.closeConnection(s, peerID)
            except (socket.timeout, RuntimeError, ValueError):
                networking.closeConnection(s, peerID)
                continue

        return True
Beispiel #18
0
def removeFiles(groupName, treePaths):
    """
    Remove a list of file from the synchronization group.
    :param groupName: name of the group from which files will be removed
    :param treePaths: list of treePaths of the files that will be removed
    :return: boolean (True for success, False for any error)
    """

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return False

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "REMOVED_FILES {} {}".format(groupName, str(treePaths))
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: return False
        print('Received from the tracker :', answer)
        return False
    else:
        # remove files from the local file list

        groupTree = localFileTree.getGroup(groupName)

        for treePath in treePaths:

            key = groupName + "_" + treePath
            if key in syncScheduler.syncThreads:
                groupTree.removeNode(treePath, False)
                syncScheduler.stopSyncThread(key, syncScheduler.FILE_REMOVED)
            else:
                groupTree.removeNode(treePath, True)

        # retrieve the list of active peers for the file
        activePeers = retrievePeers(groupName, selectAll=False)

        # notify other active peers
        for peer in activePeers:

            s = networking.createConnection(peer["address"])
            if s is None:
                continue

            try:
                # send request message and wait for the answer, then close the socket
                message = str(peerID) + " " + "REMOVED_FILES {} {}".format(groupName, str(treePaths))
                networking.mySend(s, message)
                __ = networking.myRecv(s)
                networking.closeConnection(s, peerID)
            except (socket.timeout, RuntimeError, ValueError):
                networking.closeConnection(s, peerID)
                continue

        return True
Beispiel #19
0
def addFiles(groupName, filepaths, directory):
    """
    Add a list of files to a synchronization group.
    :param groupName: name of the group in which files will be added
    :param filepaths: filepaths list of the files that will be added
    :param directory: directory path (empty if the file doesn't belong a directory)
    :return: boolean (True for success, False for any error)
    """

    # list of dictionary, where each dict contains all the info required
    # from the tracker to add a file in the group
    filesInfo = list()

    # WP stands for Without FilePath: it's a copy of filesInfo but without filepaths
    # because I don't need to send them to the tracker
    filesInfoWFP = list()

    if directory == "":
        for filepath in filepaths:
            fileInfo = dict()
            # split filepath into directoryPath and filename, saving only the latter
            __, fileInfo["treePath"] = os.path.split(filepath)
            fileInfo["filepath"] = filepath
            fileInfo["filesize"], fileInfo["timestamp"] = fileManagement.getFileStat(filepath)
            filesInfo.append(fileInfo)

            fileInfoWFP = fileInfo.copy()
            del fileInfoWFP["filepath"]
            filesInfoWFP.append(fileInfoWFP)

    else:
        # it's a directory
        for filepath in filepaths:
            fileInfo = dict()
            # remove dirPath from the filename
            # e.g.  filepath:   C://home/Desktop/file.txt
            #       directory:  C://home/Desktop
            #       dirPath:    C://home
            #       filename:   Desktop/file.txt
            dirPath, __ = os.path.split(directory)
            fileInfo["treePath"] = filepath.replace(dirPath, "")[1:]
            fileInfo["filepath"] = filepath
            fileInfo["filesize"], fileInfo["timestamp"] = fileManagement.getFileStat(filepath)
            filesInfo.append(fileInfo)

            fileInfoWFP = fileInfo.copy()
            del fileInfoWFP["filepath"]
            filesInfoWFP.append(fileInfoWFP)

    s = networking.createConnection(trackerZTAddr)
    if s is None:
        return False

    try:
        # send request message and wait for the answer, then close the socket
        message = str(peerID) + " " + "ADDED_FILES {} {}".format(groupName, str(filesInfoWFP))
        networking.mySend(s, message)
        answer = networking.myRecv(s)
        networking.closeConnection(s, peerID)
    except (socket.timeout, RuntimeError, ValueError):
        networking.closeConnection(s, peerID)
        return False

    if answer.split(" ", 1)[0] == "ERROR":
        # tracker replied with an error message: return False
        print("Received from the tracker: ", answer)
        return False
    else:

        groupTree = localFileTree.getGroup(groupName)

        for fileInfo in filesInfo:
            # add file to the personal list of files of the peer

            filename = fileInfo["treePath"].split("/")[-1]
            treePath = fileInfo["treePath"]

            file = fileManagement.File(groupName=groupName, treePath=treePath,
                                       filename=filename, filepath=fileInfo["filepath"],
                                       filesize=fileInfo["filesize"], timestamp=fileInfo["timestamp"],
                                       status="S", previousChunks=list())

            groupTree.addNode(treePath, file)
            file.initSeed()

        # retrieve the list of active peers for the file
        activePeers = retrievePeers(groupName, selectAll=False)

        # notify other active peers
        for peer in activePeers:

            s = networking.createConnection(peer["address"])
            if s is None:
                continue

            try:
                # send request message and wait for the answer, then close the socket
                message = str(peerID) + " " + "ADDED_FILES {} {}".format(groupName, str(filesInfoWFP))
                networking.mySend(s, message)
                __ = networking.myRecv(s)
                networking.closeConnection(s, peerID)
            except (socket.timeout, RuntimeError, ValueError):
                networking.closeConnection(s, peerID)
                continue

        return True
Beispiel #20
0
    def manageRequest(self, request, peerID):
        """
        Serves clients different requests.
        :param request: incoming requested stripped of the peerID
        :param peerID: id of the peer
        :return: void
        """

        # all the requests (stripped of the peerID) are identified using the first word
        # e.g. <action> <parameters>
        action = request.split()[0]

        # don't show common requests in the output of the tracker
        if action != "PEERS" and action != "BYE" and action != "GROUPS":
            print('[Thr {}] [Peer: {}] Received {}'.format(
                self.number, peerID, request))

        if action == "INFO":
            answer = str((zeroTierIP, PORT_NUMBER))
            networking.mySend(self.clientSock, answer)

        if action == "GROUPS":
            answer = reqHandlers.sendGroups(groups, peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "RESTORE":
            answer = reqHandlers.restoreGroup(request, groups, peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "JOIN":
            answer = reqHandlers.joinGroup(request, groups, peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "CREATE":
            answer = reqHandlers.createGroup(request, groups, groupsLock,
                                             peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "ROLE":
            answer = reqHandlers.manageRole(request, groups, groupsLock,
                                            peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "PEERS":
            answer = reqHandlers.retrievePeers(request, groups, peers, peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "ADDED_FILES":
            answer = reqHandlers.addedFiles(request, groups, groupsLock,
                                            peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "UPDATED_FILES":
            answer = reqHandlers.updatedFiles(request, groups, groupsLock,
                                              peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "REMOVED_FILES":
            answer = reqHandlers.removedFiles(request, groups, groupsLock,
                                              peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "GET_FILES":
            answer = reqHandlers.getFiles(request, groups, peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "HERE":
            answer = reqHandlers.imHere(request, peers, peerID,
                                        self.clientAddr)
            networking.mySend(self.clientSock, answer)

        elif action == "LEAVE":
            answer = reqHandlers.leaveGroup(request, groups, groupsLock,
                                            peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "DISCONNECT":
            answer = reqHandlers.disconnectGroup(request, groups, groupsLock,
                                                 peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "EXIT":
            answer = reqHandlers.peerExit(groups, groupsLock, peerID)
            networking.mySend(self.clientSock, answer)

        elif action == "BYE":
            answer = "OK - BYE PEER"
            networking.mySend(self.clientSock, answer)
            self.stop()

        else:
            answer = "ERROR - UNEXPECTED REQUEST"
            networking.mySend(self.clientSock, answer)