def connectionResponse(self, datagram, packet, host_port):

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(datagram)

        format = '!LB' + str(packet.packet_length - 1) + 's'
        packet.data = [0, 0]
        headerDec, packet.data[0], packet.data[1] = struct.unpack(
            format, datagram)

        userName = packet.data[1].decode("utf-8")

        if self.serverProxy.userExists(userName):

            #num seq a traiter #todo

            self.expected_num_seq[host_port] = 1
            self.num_seq[host_port] = 0
            self.sent_packet_history[host_port] = {}
            self.received_packet_history[host_port] = {}
            self.failed(host_port)

            self.errorDict[host_port] = "userExists"
        elif self.malformed(userName, user_name=True) == True:
            self.expected_num_seq[host_port] = 1
            self.num_seq[host_port] = 0
            self.sent_packet_history[host_port] = {}
            self.received_packet_history[host_port] = {}
            self.failed(host_port)
            self.errorDict[host_port] = "malformed User Name"

        elif len(self.serverProxy.getUserList()) >= 513:

            self.expected_num_seq[host_port] = 1
            self.num_seq[host_port] = 0
            self.sent_packet_history[host_port] = {}
            self.received_packet_history[host_port] = {}
            self.failed(host_port)
            self.errorDict[host_port] = "serverSaturated"

        else:
            self.expected_num_seq[userName] = 1
            self.num_seq[userName] = 0
            self.sent_packet_history[userName] = {}
            self.received_packet_history[userName] = {}

            self.serverProxy.addUser(userName, ROOM_IDS.MAIN_ROOM, None,
                                     host_port)
            self.movieRoom[userName] = ROOM_IDS.MAIN_ROOM
            connectionDone = Packet(1, self.num_seq[userName], 0, '')

            self.sendPacket(connectionDone, host_port)

            #?????
            self.serverProxy.updateUserChatroom(userName, ROOM_IDS.MAIN_ROOM)
Example #2
0
    def errorReceived(self, buf):

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(buf)

        format = '!LB' + str(packet.packet_length - 1) + 's'
        packet.data = [0, 0]
        headerDec, packet.data[0], packet.data[1] = struct.unpack(format, buf)
        print("ERREUR", packet.data[1].decode("utf8"))
        if 'wrongNumSeq:' in packet.data[1].decode('utf8'):
            self.num_seq = int(packet.data[1][12:].decode("utf8"))
            print("new num seq", self.num_seq)
        print("error :", packet.data[1].decode("utf8"))
        return 0
    def errorReceived(self, datagram, user_name):

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(datagram)

        format = '!LB' + str(packet.packet_length - 1) + 's'
        packet.data = [0, 0]
        headerDec, packet.data[0], packet.data[1] = struct.unpack(
            format, datagram)

        if 'wrongNumSeq:' in packet.data[1].decode('utf8'):
            self.num_seq[user_name] = int(packet.data[1][12:].decode("utf8"))
        print("error :", packet.data[1].decode("utf8"))
        return 0
Example #4
0
    def errorReceived(self,datagram):

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(datagram)

        format = '!LB' + str(packet.packet_length - 1) + 's'
        packet.data = [0, 0]
        headerDec, packet.data[0], packet.data[1] = struct.unpack(format, datagram)

        if packet.data[1].decode('utf8') in ["wrongUserName","serverSaturated","userExists"]:
            self.clientProxy.connectionRejectedONE(packet.data[1].decode("utf8"))
        elif 'wrongNumSeq:' in packet.data[1].decode("utf8"):
            self.num_seq=int(packet.data[1][12:].decode("utf8"))
        print("error :",packet.data[1].decode("utf8"))
        return 0
Example #5
0
    def connectionMovieRoom(self, buf):

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(buf)

        format = '!LB' + str(packet.packet_length - 1) + 's'
        packet.data = [0, 0]
        headerDec, packet.data[0], packet.data[1] = struct.unpack(format, buf)
        # the joined room
        if self.existMovie(packet.data[1].decode("utf-8")) == False:
            self.error('Movie Room Does Not Exist')
            print(packet.data[1].decode("utf-8"), 'Movie Room Does Not Exist',
                  self.serverProxy.getMovieList())
        else:
            print('the room does exist ')
            self.movieRoom = (packet.data[1].decode("utf-8"))
            # mettre à jour la liste des utilisateur du movie room dans le serveur
            self.serverProxy.updateUserChatroom(self.user_name, self.movieRoom)
            # self.serverProxy.startStreamingMovie(self.movieRoom)
            self.updateUserList(movie_room=self.movieRoom)
class c2wTcpChatClientProtocol(Protocol):
    def __init__(self, clientProxy, serverAddress, serverPort):
        """
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.
        :param serverAddress: The IP address (or the name) of the c2w server,
            given by the user.
        :param serverPort: The port number used by the c2w server,
            given by the user.

        Class implementing the UDP version of the client protocol.

        .. note::
            You must write the implementation of this class.

        Each instance must have at least the following attribute:

        .. attribute:: clientProxy

            The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number used by the c2w server.

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """

        #: The IP address of the c2w server.
        self.serverAddress = serverAddress
        #: The port number used by the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy

        self.movie_list = []
        self.user_list = []
        self.num_seq = 0
        self.expected_num_seq = 0
        self.user_name = ""
        self.timer = None
        self.room = ''
        self.booleanDict = {}  #dictionnaire de boolean

        self.received_packet_history = {}
        self.sent_packet_history = {}

        self.buf = b''
        self.packet = Packet(-1, 0, 0, [])
        self.datagram = b''
        self.buf_total = b''

        self.sendAndWait = True
        self.queuePacket = []

    def sendLoginRequestOIE(self, userName):
        """
        :param string userName: The user name that the user has typed.

        The client proxy calls this function when the user clicks on
        the login button.
        """
        moduleLogger.debug('loginRequest called with username=%s', userName)

        packet = Packet(0, 0, len(userName) + 1, [len(userName), userName])

        self.sendPacket(packet)
        # dés que j'envoie un data j'incremente mon num seq

        self.user_name = userName

    def sendChatMessageOIE(self, message):
        """
        :param message: The text of the chat message.
        :type message: string

        Called by the client proxy  when the user has decided to send
        a chat message

        .. note::
           This is the only function handling chat messages, irrespective
           of the room where the user is.  Therefore it is up to the
           c2wChatClientProctocol or to the server to make sure that this
           message is handled properly, i.e., it is shown only by the
           client(s) who are in the same room.
        """

        message = ''.join(filter(lambda x: x in printable, message))
        seqNumber = self.num_seq
        message_packet = Packet(64, seqNumber,
                                len(self.user_name) + len(message) + 2, [
                                    len(self.user_name),
                                    self.user_name.encode('utf-8'),
                                    len(message),
                                    message.encode('utf8')
                                ])
        message_packet.packet_format = '!LB' + str(
            message_packet.data[0]) + 's' + 'B' + str(
                message_packet.data[2]) + 's'

        self.sendPacket(message_packet)

    def ack(self, packet, host_port):

        ack = Packet(80, packet.numSeq, 0, None)
        self.transport.write(ack.pack(), host_port)

    def sendJoinRoomRequestOIE(self, roomName):
        """
        :param roomName: The room name (or movie title.)

        Called by the client proxy  when the user
        has clicked on the watch button or the leave button,
        indicating that she/he wants to change room.

        .. warning:
            The controller sets roomName to
            c2w.main.constants.ROOM_IDS.MAIN_ROOM when the user
            wants to go back to the main room.
        """

        self.asked_room = roomName
        # disconnection from a movie room to the main room
        if roomName == ROOM_IDS.MAIN_ROOM:
            main_packet = Packet(49, self.num_seq, 0, None)
            self.sendPacket(main_packet)

        # connection to a movie room:
        else:

            movie_packet = Packet(48, self.num_seq,
                                  len(roomName) + 1, [len(roomName), roomName])
            self.sendPacket(movie_packet)

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        leave_paquet = Packet(3, self.num_seq, 0, "")
        self.sendPacket(leave_paquet)

    def dataReceived(self, data):
        """
        :param string buf: the payload of the UDP packet.
        :param host_port: a touple containing the source IP address and port.

        Called **by Twisted** when the client has received a UDP
        packet.
        """

        time1 = time.time()

        self.buf_total += data
        self.buf += data
        # print("buf tota",self.buf_total)

        while (True):
            #print("packet length", self.packet.packet_length, "len buf", len(self.buf))

            if self.packet.message_type == -1 and len(self.buf) >= 4:

                self.packet.unpackHeader(self.buf[:4])
                print("while packet", self.packet.packet_length)
                print("while self buf", self.buf[:4])
                self.datagram = self.buf[:4]
                self.buf = self.buf[4:]

            elif self.packet.message_type != -1 and self.packet.packet_length <= len(
                    self.buf):

                self.datagram += self.buf[:self.packet.packet_length]
                self.buf = self.buf[self.packet.packet_length:]
                self.datagram_treatment((self.packet, self.datagram))
                self.packet = Packet(-1, 0, 0, [])

            else:
                break
        print(time.time() - time1, "sec")

    def datagram_treatment(self, packbuf):

        print("CLIENT RECEIVED PACKET", packbuf[0])

        packet = packbuf[0]
        buf = packbuf[1]

        # if we receive a message we ack it
        if packet.message_type != 80:
            self.ack(packet)

        # here we have a verified num_seq and and ack message we should cancel our callater
        if (packet.message_type == 80):
            print('Ack received')
            if self.num_seq == packet.num_seq:

                self.num_seq = (self.num_seq + 1) % 2047
                if self.timer is not None:

                    self.timer.cancel()
                    self.timer = None
                self.sendAndWait = True
                self.sendQueue()

                if self.lastPacketSent().message_type in [48, 49]:
                    # if we receive the ack of join room or leave room
                    self.room = self.asked_room
                    self.clientProxy.joinRoomOKONE()
                    pass
                elif self.lastPacketSent().message_type == 3:
                    # if we receive the ack of leave main room
                    self.clientProxy.leaveSystemOKONE()
                else:
                    print("acquittement non pris en comtpe", packet)

        elif packet.num_seq in self.received_packet_history.keys(
        ) and self.received_packet_history[packet.num_seq].isEqual(packet):

            print("paquet ignoré", packet,
                  self.received_packet_history[packet.num_seq])

        elif self.expected_num_seq != packet.num_seq and packet.num_seq in self.received_packet_history.keys(
        ) and not self.received_packet_history[packet.num_seq].isEqual(packet):
            # todo
            self.wrongExpectedNumSeq()

            error = "error " + str(self.expected_num_seq) + " ! = " + str(
                packet.num_seq)
            print(error)

            # dans ce stade on est sur que le num seq est verifié et quil sagit pas dun message d'ack
        elif self.sendAndWait:

            print('')
            self.received_packet_history[packet.num_seq] = packet
            self.expected_num_seq += 1

            if packet.message_type == 1:
                print('connexion etablie')
            elif packet.message_type == 2:
                print('connexion echouée')

            elif packet.message_type == 128:

                self.errorReceived(buf)

            elif packet.message_type == 16:
                self.movieListReceived(packet, buf)

            elif packet.message_type == 19:
                self.updateUserListMainRoom(packet, buf)

            elif packet.message_type == 65:
                self.chatReceived(packet, buf)

            elif packet.message_type == 18:
                self.updateUserListMovieRoom(packet, buf)
        else:
            pass

    def chatReceived(self, packet, buf):

        packet.data = [0, 0, 0, 0]
        # offset=4
        # lenSender=struct.unpack_from('!B',buf,offset)[0]
        # offset+=1
        # sender=struct.unpack_from('!'+str(lenSender)+'s',offset)[0]
        # offset+=lenSender
        # lenMessage=struct.unpack_from('!B',buf,offset)[0]
        # message=struct.unpack_from('!'+str(lenMessage)+'s')

        len_sender = struct.unpack_from('!B', buf, offset=4)[0]

        format = '!LB' + str(len_sender) + 'sB' + str(packet.packet_length -
                                                      2 - len_sender) + 's'

        headerDec, packet.data[0], packet.data[1], packet.data[2], packet.data[
            3] = struct.unpack(format, buf)

        if packet.data[1].decode('utf-8') != self.user_name:
            self.clientProxy.chatMessageReceivedONE(
                packet.data[1].decode('utf8'), packet.data[3].decode('utf8'))

    def wrongExpectedNumSeq(self):
        self.error('wrongNumSeq:' + str(self.expected_num_seq))

    def error(self, errorType):
        error = Packet(128, self.num_seq,
                       len(errorType) + 1, [len(errorType), errorType])
        self.sendPacket(error)

    def errorReceived(self, buf):

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(buf)

        format = '!LB' + str(packet.packet_length - 1) + 's'
        packet.data = [0, 0]
        headerDec, packet.data[0], packet.data[1] = struct.unpack(format, buf)
        print("ERREUR", packet.data[1].decode("utf8"))
        if packet.data[1].decode('utf8') in [
                "wrongUserName", "serverSaturated", "userExists"
        ]:
            self.clientProxy.connectionRejectedONE(
                packet.data[1].decode("utf8"))
        elif 'wrongNumSeq:' in packet.data[1].decode("utf8"):
            self.num_seq = int(packet.data[1][12:].decode("utf8"))
            print("new num seq", self.num_seq)
            pass
        print("error :", packet.data[1].decode("utf8"))
        return 0

    def updateUserListMainRoom(self, packet, buf):
        # here we receive the new list of user in main room

        self.user_list = []

        packet.data = []

        offset = 4
        len_Rooms = struct.unpack_from("!H", buf,
                                       offset)[0]  # number of movie room
        i = 0

        offset += 2
        packet.data.append(len_Rooms)
        for i in range(len_Rooms):

            len_UserList = struct.unpack_from('!H', buf, offset=offset)[0]

            packet.data.append(len_UserList)

            offset += 2

            if len_UserList != 0:
                # if room is not empty
                for j in range(0, len_UserList):

                    len_UserName = struct.unpack_from('!B', buf,
                                                      offset=offset)[0]

                    packet.data.append(len_UserName)

                    offset += 1

                    user = struct.unpack_from("!" + str(len_UserName) + "s",
                                              buf,
                                              offset=offset)[0]

                    packet.data.append(user.decode('utf8'))

                    offset += len_UserName

                    if i == 0:
                        movie_title = ROOM_IDS.MAIN_ROOM
                    elif self.movie_list == []:
                        movie_title = i
                    else:
                        movie_title = self.movie_list[i - 1]

                    user_tuple = (user.decode('utf8'), movie_title
                                  )  # ("alice","batman")

                    self.user_list.append(user_tuple)

        if "initok" in self.booleanDict and self.booleanDict["initok"] == True:
            print("set user ok")
            self.clientProxy.setUserListONE(self.user_list)
        else:
            pass

    def updateUserListMovieRoom(self, packet, buf):

        self.user_list = []
        packet.data = []

        offset = 4
        len_users = struct.unpack_from("!H", buf, offset)[0]  # nombre de users

        offset += 2
        packet.data.append(len_users)

        for j in range(0, len_users):
            len_UserName = struct.unpack_from('!B', buf, offset=offset)[0]

            packet.data.append(len_UserName)

            offset += 1

            user = struct.unpack_from("!" + str(len_UserName) + "s",
                                      buf,
                                      offset=offset)[0]

            packet.data.append(user.decode('utf8'))

            offset += len_UserName

            user_tuple = (user.decode('utf8'), self.room)

            self.user_list.append(user_tuple)

        self.clientProxy.setUserListONE(self.user_list)

    def movieListReceived(self, packet, buf):

        self.movie_list = []
        packet.data = []
        len_movie_list = struct.unpack_from("!H", buf,
                                            offset=4)[0]  # nombre de salon

        packet.data.append(len_movie_list)
        offset = 6
        i = 0
        while i < len_movie_list:

            format = "!B"
            len_movie_title = struct.unpack_from(format, buf, offset=offset)[0]
            packet.data.append(len_movie_title)

            format = "!" + str(len_movie_title) + "s"
            offset += 1
            movie_title = struct.unpack_from(format, buf, offset=offset)[0]
            packet.data.append(movie_title.decode("utf8"))

            ip_movie = []
            format = "!B"

            offset += len_movie_title
            # unpacker l'adresse ip
            for j in range(0, 4):
                ip_movie.append(
                    struct.unpack_from(format, buf, offset=offset)[0])
                offset += 1

            ip_movie = list(map(
                str,
                ip_movie))  # ecrire dans une liste les 4 octet de l'adresse ip

            packet.data.append('.'.join(list(map(str, ip_movie))))

            format = '!H'

            port_movie = struct.unpack_from(format, buf, offset)[0]
            packet.data.append(port_movie)
            offset += 2
            i = i + 1

            movie_tuple = (movie_title.decode("utf8"), ip_movie, port_movie)
            self.movie_list.append(movie_tuple)

        user_list_update = []
        for user in self.user_list:

            if user[1] != ROOM_IDS.MAIN_ROOM:
                movie_title = self.movie_list[user[1] - 1]
            else:
                movie_title = ROOM_IDS.MAIN_ROOM
            user_list_update.append((user[0], movie_title))
        self.user_list = user_list_update

        self.clientProxy.initCompleteONE(self.user_list, self.movie_list)
        self.booleanDict['initok'] = True

    def sendPacket(self, packet, call_count=1):

        if self.sendAndWait and call_count == 1:
            print('CLIENT ' + self.user_name + ' SEND PACKET', packet)
            self.transport.write(packet.pack())

            self.sendAndWait = False
            self.sent_packet_history[packet.num_seq] = packet

            call_count += 1

            if call_count <= 4:
                self.timer = reactor.callLater(5, self.sendPacket, packet,
                                               call_count)

        elif call_count > 1:

            print('CLIENT ' + self.user_name + ' SEND PACKET', packet)
            self.transport.write(packet.pack())

            call_count += 1

            if call_count <= 4:
                self.timer = reactor.callLater(5, self.sendPacket, packet,
                                               call_count)

        else:

            self.queuePacket.append(packet)
            print("packet ajoute a la queupacket", packet)

    def sendQueue(self):

        for packet in self.queuePacket:
            self.sendPacket(packet)
        self.queuePacket = []

    def ack(self, packet):

        ack = Packet(80, packet.num_seq, 0, None)
        self.transport.write(ack.pack())
        print("ack de", packet)

    def lastPacketReceived(self):

        return self.received_packet_history[
            len(self.received_packet_history.keys()) - 1]

    def nlastPacketReceived(self, i):
        return self.received_packet_history[
            len(self.received_packet_history.keys()) - i]

    def lastPacketSent(self):
        return self.sent_packet_history[len(self.sent_packet_history.keys()) -
                                        1]

    def nlastPacketSent(self, i):
        return self.sent_packet_history[len(self.sent_packet_history.keys()) -
                                        i]
Example #7
0
    def datagramReceived(self, datagram, host_port):
        """
        :param string datagram: the payload of the UDP packet.
        :param host_port: a touple containing the source IP address and port.

        Called **by Twisted** when the client has received a UDP
        packet.
        """

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(datagram)
        print("CLIENT RECEIVE A PACKET",packet)

        #if we receive a message we ack it
        if packet.message_type != 80 :

            self.ack(packet,host_port)


        #here we have a verified num_seq and and ack message we should cancel our callater
        if (packet.message_type ==80):
            if self.num_seq==packet.num_seq:

                self.num_seq = (self.num_seq + 1) % 1023
                if self.timer is not None:
                    print("TIMER CANCEL")
                    self.timer.cancel()
                    self.timer=None
                self.sendAndWait = True
                self.sendqueuepacket()
                if self.lastPacketSent().message_type in [48,49]:
                    #if we receive the ack of join room or leave room
                    self.room=self.room_wanted
                    self.clientProxy.joinRoomOKONE()

                elif self.lastPacketSent().message_type==3:
                    #if we receive the ack of leave main room
                    self.clientProxy.leaveSystemOKONE()
                else:
                    return 0



        elif packet.num_seq in self.received_packet_history.keys() and  self.received_packet_history[packet.num_seq].isEqual(packet):
            print("paquet ignoré",packet,self.received_packet_history[packet.num_seq])

        elif self.expected_num_seq != packet.num_seq:
            #todo
            self.wrongExpectedNumSeq(host_port)

            #dans ce stade on est sur que le num seq est verifié et quil sagit pas dun message d'ack
        elif self.sendAndWait:
            print('')
            self.received_packet_history[packet.num_seq] = packet
            self.expected_num_seq = (self.expected_num_seq+1)%1023

            if packet.message_type ==1:
                print('connexion etablie')
            elif packet.message_type ==2:
                print('connexion echouée')

            elif packet.message_type==128:

                self.errorReceived(datagram)


            elif packet.message_type==16:
                self.movieListReceived(packet,datagram)




            elif packet.message_type==19:
                self.updateUserListMainRoom(packet,datagram)


            elif packet.message_type ==65:
                self.chatReceived(packet,datagram)

            elif packet.message_type ==18:
                self.updateUserListMovieRoom(packet,datagram)
Example #8
0
class c2wTcpChatServerProtocol(Protocol):
    def __init__(self, serverProxy, clientAddress, clientPort):
        """
        :param serverProxy: The serverProxy, which the protocol must use
            to interact with the user and movie store (i.e., the list of users
            and movies) in the server.
        :param clientAddress: The IP address (or the name) of the c2w server,
            given by the user.
        :param clientPort: The port number used by the c2w server,
            given by the user.

        Class implementing the TCP version of the client protocol.

        .. note::
            You must write the implementation of this class.

        Each instance must have at least the following attribute:

        .. attribute:: serverProxy

            The serverProxy, which the protocol must use
            to interact with the user and movie store in the server.

        .. attribute:: clientAddress

            The IP address of the client corresponding to this
            protocol instance.

        .. attribute:: clientPort

            The port number used by the client corresponding to this
            protocol instance.

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.

        .. note::
            The IP address and port number of the client are provided
            only for the sake of completeness, you do not need to use
            them, as a TCP connection is already associated with only
            one client.
        """
        #: The IP address of the client corresponding to this
        #: protocol instance.
        self.clientAddress = clientAddress

        #: The port number used by the client corresponding to this
        #: protocol instance.
        self.clientPort = clientPort
        #: The serverProxy, which the protocol must use
        #: to interact with the user and movie store in the server.
        self.serverProxy = serverProxy
        self.client_host_port = (self.clientAddress, self.clientPort)
        self.sent_packet_history = {}
        self.received_packet_history = {}
        self.errorVar = ""
        self.user_name = None

        for movie in self.serverProxy.getMovieList():
            self.serverProxy.startStreamingMovie(movie.movieTitle)

        self.buf = b''
        self.packet = Packet(-1, 0, 0, [])
        self.datagram = b''
        self.buf_total = b''
        self.sendAndWait = True
        self.queuePacket = []

    def dataReceived(self, data):
        """
        :param data: The data received from the client (not necessarily
                     an entire message!)

        Twisted calls this method whenever new data is received on this
        connection.
        """
        # self.buf_total+=data
        self.buf += data
        # print("buf tota",self.buf_total)
        while (True):
            #print("packet length", self.packet.packet_length, "len buf", len(self.buf))

            if self.packet.message_type == -1 and len(self.buf) >= 4:

                self.packet.unpackHeader(self.buf[:4])
                #print("while packet", self.packet.packet_length)
                #print("while self buf", self.buf[:4])
                self.datagram = self.buf[:4]
                self.buf = self.buf[4:]

            elif self.packet.message_type != -1 and self.packet.packet_length <= len(
                    self.buf):

                self.datagram += self.buf[:self.packet.packet_length]
                self.buf = self.buf[self.packet.packet_length:]
                self.datagram_treatment((self.packet, self.datagram))
                self.packet = Packet(-1, 0, 0, [])

            elif self.packet.packet_length > 100:
                self.buf = b''
                self.packet = Packet(-1, 0, 0, [])
                self.datagram = b''

            else:
                break

    def datagram_treatment(self, packbuf):
        packet = packbuf[0]
        buf = packbuf[1]

        user_name_print = "unknown"
        if self.user_name is not None:
            user_name_print = self.user_name
        print("SERVER RECEIVED PACKET" + user_name_print, packet)

        # if the buf received is not an ack then we send an ack
        if packet.message_type != 80:
            self.ack(packet)
            print('Ack sent')

        if packet.message_type == 0:

            self.connectionResponse(buf)

        # if it's and ack of connecion done we send user list then movielist

        elif (packet.message_type == 80):
            if packet.num_seq == self.num_seq:

                if self.num_seq == packet.num_seq:
                    self.num_seq = (self.num_seq + 1) % 2047

                    if self.timer is not None:
                        print("TIMER CANCEL")
                        self.timer.cancel()
                        self.timer = None
                    self.sendAndWait = True
                    self.sendQueue()
                if self.lastPacketSent().message_type == 1:
                    self.updateUserList(ROOM_IDS.MAIN_ROOM)

                elif self.nlastPacketSent(2).message_type == 1:
                    self.sendMovieList()

                elif self.lastPacketSent().message_type == 2:

                    self.error(self.errorVar)
            else:
                return 0  # old ack

        elif packet.num_seq in self.received_packet_history.keys(
        ) and self.received_packet_history[packet.num_seq].isEqual(packet):
            print("paquet ignoré", packet,
                  self.received_packet_history[packet.num_seq])

        elif self.expected_num_seq != packet.num_seq:

            self.wrongExpectedNumSeq()
            error = "error " + str(self.expected_num_seq) + " ! = " + str(
                packet.num_seq)
            print(error)

        # if it's and ack of connecion done we send movie list then userlist
        # here we are sure that the num sq is verified and that i's not an ack
        elif self.sendAndWait:
            self.received_packet_history[packet.num_seq] = packet
            self.expected_num_seq += 1
            if packet.message_type == 64:
                print("MESSAGE BIEN RECU")
                self.forward(packet, buf)
            elif packet.message_type == 48:

                self.connectionMovieRoom(buf)

            elif packet.message_type == 49:

                print("PAQUET DECONNEXION RECU")
                self.deconnectionMovieRoom()
            elif packet.message_type == 3:
                self.leaveSystem()
            elif packet.message_type == 128:

                self.errorReceived(buf)
        else:
            pass

    def forward(self, packet, buf):

        len_sender = struct.unpack_from('!B', buf, offset=4)[0]

        format = '!LB' + str(len_sender) + 'sB' + str(packet.packet_length -
                                                      2 - len_sender) + 's'

        packet.data = [0, 0, 0, 0]
        headerDec, packet.data[0], packet.data[1], packet.data[2], packet.data[
            3] = struct.unpack(format, buf)

        if self.malformed(packet.data[3].decode('utf8')):

            self.error("malformed message")
        else:
            user_chat_room_dict = self.getUserChatRoomDict()

            if self.movieRoom == ROOM_IDS.MAIN_ROOM:
                sender_chat_room = "main_room"
            else:
                sender_chat_room = self.movieRoom

            i = 0
            while i < len(user_chat_room_dict[sender_chat_room]):
                receiver = user_chat_room_dict[sender_chat_room][i]
                print("FORWARD5")
                messagePacket = Packet(65, -1, packet.packet_length,
                                       packet.data, format)
                self.serverProxy.getUserByName(
                    receiver).userChatInstance.sendPacket(messagePacket)
                print("FORWARD6")
                i += 1

    def connectionMovieRoom(self, buf):

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(buf)

        format = '!LB' + str(packet.packet_length - 1) + 's'
        packet.data = [0, 0]
        headerDec, packet.data[0], packet.data[1] = struct.unpack(format, buf)
        # the joined room
        if self.existMovie(packet.data[1].decode("utf-8")) == False:
            self.error('Movie Room Does Not Exist')
            print(packet.data[1].decode("utf-8"), 'Movie Room Does Not Exist',
                  self.serverProxy.getMovieList())
        else:
            print('the room does exist ')
            self.movieRoom = (packet.data[1].decode("utf-8"))
            # mettre à jour la liste des utilisateur du movie room dans le serveur
            self.serverProxy.updateUserChatroom(self.user_name, self.movieRoom)
            # self.serverProxy.startStreamingMovie(self.movieRoom)
            self.updateUserList(movie_room=self.movieRoom)

    def existMovie(self, movieRoom):
        Exist = False
        for movie in self.serverProxy.getMovieList():
            if movieRoom == movie.movieTitle:
                Exist = True
        return (Exist)

    def leaveSystem(self):

        old_movie_room = self.movieRoom
        self.serverProxy.removeUser(self.user_name)
        self.updateUserList(movie_room=old_movie_room)

    def deconnectionMovieRoom(self):

        old_movie_room = self.movieRoom
        self.movieRoom = ROOM_IDS.MAIN_ROOM
        self.serverProxy.updateUserChatroom(self.user_name, self.movieRoom)

        self.updateUserList(movie_room=old_movie_room)
        print("DECONNECTION OK")

    def connectionResponse(self, buf):

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(buf)

        format = '!LB' + str(packet.packet_length - 1) + 's'
        packet.data = [0, 0]
        headerDec, packet.data[0], packet.data[1] = struct.unpack(format, buf)

        userName = packet.data[1].decode("utf-8")
        self.user_name = userName
        if self.serverProxy.userExists(userName):

            # num seq a traiter #todo

            self.expected_num_seq = 1
            self.num_seq = 0
            self.sent_packet_history = {}
            self.received_packet_history = {}
            self.failed()

            self.errorVar = "userExists"
        elif self.malformed(userName, user_name=True) == True:
            self.expected_num_seq = 1
            self.num_seq = 0
            self.sent_packet_history = {}
            self.received_packet_history = {}
            self.failed()
            self.errorVar = "malformed User Name"

        elif len(self.serverProxy.getUserList()) >= 513:

            self.expected_num_seq = 1
            self.num_seq = 0
            self.sent_packet_history = {}
            self.received_packet_history = {}
            self.failed()
            self.errorVar = "serverSaturated"

        else:
            self.expected_num_seq = 1
            self.num_seq = 0
            self.sent_packet_history = {}
            self.received_packet_history = {}

            self.serverProxy.addUser(userName, ROOM_IDS.MAIN_ROOM, self,
                                     self.client_host_port)
            self.movieRoom = ROOM_IDS.MAIN_ROOM
            connectionDone = Packet(1, self.num_seq, 0, '')

            self.sendPacket(connectionDone)

            # ?????
            self.serverProxy.updateUserChatroom(userName, ROOM_IDS.MAIN_ROOM)

    def malformed(self, message, user_name=False):

        if not user_name:
            message = message[:-1]

            return False

        elif len(message) == 0 or (
                len(message) <= 255 and message[0].isalpha() and
            (len(message) == 1 or message[1:].isalnum())):
            return False

        return True

    def ack(self, packet):

        ack = Packet(80, packet.num_seq, 0, None)
        self.transport.write(ack.pack())
        user_name = 'unknown'
        if self.user_name is not None:
            user_name = self.user_name
        print('ACK', packet.num_seq, user_name)

    def error(self, errorType):
        error = Packet(128, self.num_seq,
                       len(errorType) + 1, [len(errorType), errorType])
        self.sendPacket(error)

    def errorReceived(self, buf):

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(buf)

        format = '!LB' + str(packet.packet_length - 1) + 's'
        packet.data = [0, 0]
        headerDec, packet.data[0], packet.data[1] = struct.unpack(format, buf)
        print("ERREUR", packet.data[1].decode("utf8"))
        if 'wrongNumSeq:' in packet.data[1].decode('utf8'):
            self.num_seq = int(packet.data[1][12:].decode("utf8"))
            print("new num seq", self.num_seq)
        print("error :", packet.data[1].decode("utf8"))
        return 0

    def wrongExpectedNumSeq(self):
        self.error('wrongNumSeq:' + str(self.expected_num_seq))

    def failed(self):

        failed = Packet(2, self.num_seq, 0, '')
        self.sendPacket(failed)

    def sendMovieList(self):
        # we send list of movie sorted

        movie_list = self.serverProxy.getMovieList()
        movie_list = sorted(movie_list, key=lambda x: x.movieTitle)

        data = []
        length = 2
        format = "!LH"
        data.append(len(movie_list))

        for movie in movie_list:
            format += "B" + str(len(movie.movieTitle)) + "sBBBBH"
            data.append(len(movie.movieTitle))

            data.append(movie.movieTitle.encode("utf-8"))
            print('movie.movieIpAddress', movie.movieIpAddress)
            data = data + list(map(int, movie.movieIpAddress.split(".")))
            data.append(movie.moviePort)
            # 1 byte -> lenghtmovie title, 4 bytes -> length ipv4 , 2 bytes -> port
            length = length + 1 + len(movie.movieTitle) + 4 + 2

        movie_list_packet = Packet(16, self.num_seq, length, data, format)

        self.sendPacket(movie_list_packet)

    def updateUserList(self, movie_room):
        # if user joined a main room: WE SEND TO EACH USER IN MAIN ROOM (EVEN THE USER HIMSELF) "UserListMainRoom"
        # if user joined a movie room: WE SEND TO EACH USER IN THAT MOVIE ROOM "UserListMovieRoom":
        #
        #                               WE SEND TO EACH USER IN THE MAIN ROOM "UserListMainRoom"

        user_list = self.serverProxy.getUserList(
        )  # list of all users connected to the server

        # update user list in the case of joining the system
        if movie_room == ROOM_IDS.MAIN_ROOM:
            # I look for users in that main room and I send them the appropriate list
            for user in user_list:

                if user.userChatRoom == ROOM_IDS.MAIN_ROOM:
                    user.userChatInstance.sendUserListMainRoom()
        # update user list
        else:

            for user in user_list:

                if user.userChatRoom == movie_room:
                    user.userChatInstance.sendUserListMovieRoom(
                        user.userChatRoom)
                elif user.userChatRoom == ROOM_IDS.MAIN_ROOM:
                    user.userChatInstance.sendUserListMainRoom()

    def sendUserListMovieRoom(self, movie_room):
        # send the Packet of usersList in a movie room  to the user

        user_chat_room_dict = self.getUserChatRoomDict()
        update_user_list_packet = Packet(18, -1, 0, [])

        update_user_list_packet.data.append(
            len(user_chat_room_dict[movie_room]))

        update_user_list_packet.packet_format = "!LH"
        update_user_list_packet.packet_length = 2
        for user_chat_room in user_chat_room_dict[movie_room]:
            update_user_list_packet.packet_format += "B" + str(
                len(user_chat_room)) + "s"
            update_user_list_packet.packet_length += 1 + len(user_chat_room)
            update_user_list_packet.data.append(len(user_chat_room))
            update_user_list_packet.data.append(user_chat_room.encode("utf8"))

        print("user list movie", update_user_list_packet)
        self.sendPacket(update_user_list_packet)

    def sendUserListMainRoom(self):
        user_list_packet = Packet(19, -1, 2, [], "!LH")

        user_chat_room_dict = {}
        user_chat_room_dict["main_room"] = []
        for movie in self.serverProxy.getMovieList():
            user_chat_room_dict[movie.movieTitle] = []
        # user_chat_room_dict={"main_room":[5,alice,3,bob];"batmann":[5,mario]...

        user_list = self.serverProxy.getUserList()
        for user in user_list:
            if user.userChatRoom == ROOM_IDS.MAIN_ROOM:
                user_chat_room_dict["main_room"].append(len(user.userName))
                user_chat_room_dict["main_room"].append(
                    user.userName.encode('utf8'))

            else:
                user_chat_room_dict[user.userChatRoom].append(
                    len(user.userName))
                user_chat_room_dict[user.userChatRoom].append(
                    user.userName.encode('utf8'))

            user_list_packet.packet_length += 1 + len(user.userName)

        data = []
        # data= [Nombre de room,NombreUtilisateurMainRoom,5,alice,3,bob]

        user_list_packet.packet_format += "H"
        data.append(len(user_chat_room_dict.keys()))
        data.append(int(len(user_chat_room_dict["main_room"]) / 2))
        data += user_chat_room_dict["main_room"]
        user_list_packet.packet_length += 2
        i = 0
        while i < len(user_chat_room_dict["main_room"]):
            user_list_packet.packet_format += "B" + str(
                user_chat_room_dict["main_room"][i]) + "s"

            i += 2
        del user_chat_room_dict["main_room"]

        for movie in sorted(user_chat_room_dict.keys()):

            user_list_packet.packet_length += 2
            user_list_packet.packet_format += "H"

            data.append(int(len(user_chat_room_dict[movie]) / 2))
            data += user_chat_room_dict[movie]
            i = 0

            while i < len(user_chat_room_dict[movie]):
                user_list_packet.packet_format += "B" + str(
                    user_chat_room_dict[movie][i]) + "s"

                i += 2

        user_list_packet.data = data

        self.sendPacket(user_list_packet)

    def sendPacket(self, packet, call_count=1):

        if self.sendAndWait and call_count == 1:
            if (packet.message_type in [65, 18, 19]):
                packet.num_seq = self.num_seq

            self.sendAndWait = False
            print('SERVER SEND PACKET TO ' + self.user_name, packet)
            self.transport.write(packet.pack())

            self.sent_packet_history[packet.num_seq] = packet
            print("callcount", call_count)
            call_count += 1

            if call_count <= 4:
                self.timer = reactor.callLater(5, self.sendPacket, packet,
                                               call_count)

        elif call_count > 1:
            print('SERVER SEND PACKET TO ' + self.user_name, packet)
            self.transport.write(packet.pack())
            call_count += 1

            if call_count <= 4:
                self.timer = reactor.callLater(5, self.sendPacket, packet,
                                               call_count)

        else:
            self.queuePacket.append(packet)
            print("packet stocke", packet)

    def sendQueue(self):

        for packet in self.queuePacket:
            self.sendPacket(packet)
        self.queuePacket = []

        #                   UTILS

    def lastPacketReceived(self):

        return self.received_packet_history[
            len(self.received_packet_history.keys()) - 1]

    def nlastPacketReceived(self, i):
        return self.received_packet_history[
            len(self.received_packet_history.keys()) - i]

    def lastPacketSent(self):

        return self.sent_packet_history[len(self.sent_packet_history.keys()) -
                                        1]

    def nlastPacketSent(self, i):
        if len(self.sent_packet_history) > (
                len(self.sent_packet_history.keys()) -
                i) and (len(self.sent_packet_history.keys()) - i) >= 0:
            return self.sent_packet_history[
                len(self.sent_packet_history.keys()) - i]
        else:
            return Packet(None, None, None, None)

    def getUserChatRoomDict(self):
        """
        this method return a dict with dict[movie_room]= [list of user of the movie room]
        :return:
        """

        user_chat_room_dict = {}
        user_chat_room_dict["main_room"] = []
        for movie in self.serverProxy.getMovieList():
            user_chat_room_dict[movie.movieTitle] = []
        user_list = self.serverProxy.getUserList()
        for user in user_list:
            if user.userChatRoom == ROOM_IDS.MAIN_ROOM:

                user_chat_room_dict["main_room"].append(user.userName)

            else:

                user_chat_room_dict[user.userChatRoom].append(user.userName)

        return user_chat_room_dict
    def datagramReceived(self, datagram, host_port):
        """
        :param string datagram: the payload of the UDP packet.
        :param host_port: a touple containing the source IP address and port.

        Twisted calls this method when the server has received a UDP
        packet.  You cannot change the signature of this method.
        """

        packet = Packet(0, 0, 0, 0)
        packet.unpackHeader(datagram)
        print("SERVER RECEIVING PACKET", packet)

        if self.serverProxy.getUserByAddress(host_port) is not None:
            user_name = self.serverProxy.getUserByAddress(host_port).userName

        elif host_port in self.num_seq.keys():
            user_name = host_port

        else:
            user_name = None
        print('host_port', host_port)

        #if the datagram received is not an ack then we send an ack
        if packet.message_type != 80:
            self.ack(packet, host_port)

        if packet.message_type == 0:

            self.connectionResponse(datagram, packet, host_port)

        #if it's and ack of connecion done we send user list then movielist

        elif (packet.message_type == 80):
            if packet.num_seq == self.num_seq[user_name]:

                self.num_seq[user_name] = (self.num_seq[user_name] + 1) % 1023

                if self.timer[user_name] != None:
                    self.timer[user_name].cancel()
                    self.timer[user_name] = None
                self.sendAndWait = True
                self.sendqueuepacket()

                if self.lastPacketSent(user_name).message_type == 1:
                    self.updateUserList(ROOM_IDS.MAIN_ROOM)

                elif self.nlastPacketSent(user_name, 2).message_type == 1:
                    self.sendMovieList(user_name, host_port)

                elif self.lastPacketSent(user_name).message_type == 2:

                    self.error(self.errorDict[user_name], host_port, user_name)

            else:
                return 0  #old ack

        elif packet.num_seq in self.received_packet_history.keys(
        ) and self.received_packet_history[packet.num_seq].isEqual(packet):
            print("paquet ignoré", packet,
                  self.received_packet_history[packet.num_seq])

        elif self.expected_num_seq[user_name] != packet.num_seq:

            self.wrongExpectedNumSeq(host_port, user_name)
            print("ERROR")

        #if it's and ack of connecion done we send movie list then userlist
        #here we are sure that the num sq is verified and that i's not an ack
        else:
            self.received_packet_history[user_name][packet.num_seq] = packet
            self.expected_num_seq[user_name] = (
                self.expected_num_seq[user_name] + 1) % 1023
            if packet.message_type == 64:
                print("MESSAGE BIEN RECU")
                self.forward(packet, datagram, host_port, user_name)
            elif packet.message_type == 48:

                self.connectionMovieRoom(datagram, packet, host_port,
                                         user_name)

            elif packet.message_type == 49:
                self.deconnectionMovieRoom(datagram, packet, host_port,
                                           user_name)
            elif packet.message_type == 3:
                self.leaveSystem(user_name)
            elif packet.message == 128:
                self.errorReceived(datagram, user_name)