Beispiel #1
0
    def startProtocol(self):
        """one_user_full_login_udp_server_test
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.packet_stor
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport
    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport
        nomMovie = 0

        for m in self.serverProxy.getMovieList():
            nomMovie += 1
            print("Movie title: ", m.movieTitle, m.movieId)
            print('ip port',
                  self.serverProxy.getMovieAddrPort(m.movieTitle)[0])
        print(nomMovie)
Beispiel #3
0
	def startProtocol(self):
		"""
		DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

		If in doubt, do not add anything to this method.  Just ignore it.
		It is used to randomly drop outgoing packets if the -l
		command line option is used.
		"""
		self.transport = LossyTransport(self.transport, self.lossPr)
		DatagramProtocol.transport = self.transport
Beispiel #4
0
class c2wUdpChatClientProtocol(DatagramProtocol):

    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address (or the name) of the c2w server.

        .. attribute:: serverPort

            The port number used by the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

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

        self.serverAddress = serverAddress
        self.serverPort = serverPort
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        self.seqNum = 0  # sequence number for the next packet to be sent
        self.dHandler = DatagramHandler(self)
        self.userId = 0
        self.userName = ""
        self.packReceived = False
        self.movieList = []
        self.users = []  # userId: user
        self.state = state_code["disconnected"]
        self.movieRoomId = -1  # not in movie room
        self.currentMovieRoom = None

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    def sendPacket(self, packet, callCount=0):
        """
        param packet: Packet object
        param callCount: only used for the timeout mechanism.
        """
        # the packet is received
        if packet.ack == 1:
            print "###sending ACK packet###:", packet
            buf = util.packMsg(packet)
            self.transport.write(buf.raw, (self.serverAddress, self.serverPort))
            return

        if packet.seqNum != self.seqNum:
            return

        print "###sending packet###:", packet
        buf = util.packMsg(packet)
        self.transport.write(buf.raw, (self.serverAddress, self.serverPort))
        callCount += 1
        if callCount < attempt_num:
            reactor.callLater(timeout, self.sendPacket, packet, callCount)
        else:
            print "too many tries, packet:", packet," aborted"
            return

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

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

        self.roomType = 3
        self.seqNum = 0  # reset seqNum
        self.userId = 0  # use reserved userId when login
        self.userName = userName

        loginRequest = Packet(frg=0, ack=0, msgType=0,
                    roomType=self.roomType, seqNum=self.seqNum,
                    userId=self.userId, destId=0, length=len(userName),
                    data=userName)
        self.sendPacket(loginRequest)
        self.state = state_code["loginWaitForAck"]


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

        Called **by the controller**  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.
        """
        # This method is called when user clicks "send" button of any room
        destId = 0
        if self.state == state_code["inMainRoom"]:
            roomType = room_type["mainRoom"]
            destId = 0  # for main room
        elif self.state == state_code["inMovieRoom"]:
            roomType = room_type["movieRoom"]
            destId = self.movieRoomId
        else:
            print "State error!"
            return

        messagePack = Packet(frg=0, ack=0, msgType=type_code["message"],
                            roomType=roomType, seqNum=self.seqNum,
                            userId=self.userId, destId=destId,
                            length=len(message), data=message)
        self.sendPacket(messagePack)

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

        Called **by the controller**  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.
        """
        if roomName == ROOM_IDS.MAIN_ROOM:
            joinRoomRequest = Packet(frg=0, ack=0,
                                    msgType=type_code["roomRequest"],
                                    roomType=room_type["mainRoom"],
                                    seqNum=self.seqNum, userId=self.userId,
                                    destId=0, length=0, data=None)
            self.sendPacket(joinRoomRequest)
            self.state = state_code["waitForMainRoomAck"]
            self.movieRoomId = -1
        else:
            roomId = [movie.roomId for movie in self.movieList
                                            if movie.movieName==roomName][0]
            joinRoomRequest = Packet(frg=0, ack=0,
                                    msgType=type_code["roomRequest"],
                                    roomType=room_type["movieRoom"],
                                    seqNum=self.seqNum, userId=self.userId,
                                    destId=roomId, length=0, data=None)
            self.sendPacket(joinRoomRequest)
            self.state = state_code["waitForMovieRoomAck"]
            self.currentMovieRoom = roomName
            self.movieRoomId = roomId

    def sendLeaveSystemRequestOIE(self):
        """
        Called **by the controller**  when the user
        has clicked on the leave button in the main room.
        """

        LeaveSystemRequest=Packet(frg=0, ack=0, msgType=type_code["disconnectRequest"],
                                roomType=room_type["notApplicable"],
                                seqNum=self.seqNum, userId=self.userId,
                                destId=0, length=0, data="")
        self.sendPacket(LeaveSystemRequest)

    def messageReceived(self, pack):
        # different action for different room type
        # find userName by id
        userName = [user.name for user in self.users if user.userId==pack.destId][0]
        if (pack.roomType == room_type["mainRoom"] or
                pack.roomType == room_type["movieRoom"]):
            self.clientProxy.chatMessageReceivedONE(userName, pack.data)

    def showMainRoom(self):
        """init the main room"""
        userList = util.adaptUserList(self.users)
        movieList = util.adaptMovieList(self.movieList)
        self.clientProxy.initCompleteONE(userList, movieList)

    def changeRoom(self):
        self.clientProxy.joinRoomOKONE()

    def updateUserList(self, movieName=None):
        """refresh the userList in the room"""
        userList = util.adaptUserList(self.users, movieName=movieName)
        self.clientProxy.setUserListONE(userList)

    def datagramReceived(self, datagram, (host, port)):
        """
        :param string datagram: the payload of the UDP packet.
        :param host: the IP address of the source.
        :param port: the source port.

        Called **by Twisted** when the client has received a UDP
        packet.
        """
        pack = self.dHandler.unpackMsg(datagram)
        if pack == None:
            return
        print "####packet received:", pack

        # the previous packet is received
        if pack.ack == 1 and pack.seqNum == self.seqNum:
            self.seqNum += 1
            if pack.msgType == type_code["errorMessage"]:  # error handling
                print "error message received:", error_decode[pack.data]
                print "state:", state_decode[self.state]
                if self.state == state_code["loginWaitForAck"]:  # loginFailed
                    self.clientProxy.connectionRejectedONE(
                                            error_decode[pack.data])  # back to login window
                else:
                    print "unexpected error code"
            elif pack.msgType == type_code["loginRequest"]:  # wait for movieList
                self.state = state_code["loginWaitForMovieList"]
                self.userId = pack.userId  # get userId from server
            elif pack.msgType == type_code["roomRequest"]:
                if (pack.roomType == room_type["movieRoom"] and
                        self.state == state_code["waitForMovieRoomAck"]):
                    # This packet contains the ip and the port of the movie requested
                    self.state = state_code["waitForMovieRoomUserList"]
                    self.clientProxy.updateMovieAddressPort(self.currentMovieRoom,
                            pack.data["ip"], pack.data["port"])
                elif (pack.roomType == room_type["mainRoom"] and
                        self.state == state_code["waitForMainRoomAck"]):
                    self.state = state_code["waitForMainRoomUserList"]
                else:
                    print "unexpected roomrequest ACK"
            elif pack.msgType == type_code["disconnectRequest"]:
                self.clientProxy.leaveSystemOKONE()
                self.clientProxy.applicationQuit()
            elif pack.msgType == type_code["message"]:
                pass
            else:
                print "Unexpected type of ACK packet"
            return

        if pack.msgType == type_code["movieList"]:
            # save movieList
            self.movieList = pack.data
            self.state = state_code["loginWaitForUserList"]
        elif pack.msgType == type_code["userList"]:
            # save userList
            self.users = pack.data
            if self.state == state_code["loginWaitForUserList"]:
                self.state = state_code["inMainRoom"]
                self.showMainRoom()
            elif self.state == state_code["inMainRoom"]:
                self.updateUserList()
            elif self.state == state_code["inMovieRoom"]:
                self.updateUserList(movieName=self.currentMovieRoom)
            elif self.state == state_code["waitForMovieRoomUserList"]:
                self.state = state_code["inMovieRoom"]
                self.changeRoom()
                self.updateUserList(movieName=self.currentMovieRoom)
            elif self.state == state_code["waitForMainRoomUserList"]:
                self.state = state_code["inMainRoom"]
                self.changeRoom()
                self.updateUserList()
            else:
                print "unexpected userList"
        elif pack.msgType == type_code["messageForward"]:
            self.messageReceived(pack)
        else:  # type not defined
            print "type not defined on client side"
Beispiel #5
0
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :param serverAddress: The IP address (or the name) of the c2w server,
            given by the user.
            given by the user.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr

        self.seq_number = 0  #This variable contains the sequence number used to track packet loss
        self.userID = 0  #This vatiable contains the id of the client that was set by the server (initially set to 0)
        self.lastEventID = 0  #This variable contains the id of the last event the client is currently aware of.
        self.userRoomID = 0  #This variable contains the room the client is currently in.
        self.futureRoomID = 0  #This variable contains the room the client want to switch to
        self.entry_number_awaited = 0  #This variable contains the number of entry the client is expecting from the next multi-entry response

        self.packet_stored = 0  #This variable contains a packet to be resent if its answer is not received. When it is equals to 0 there is no packet to resend.
        self.packet_awaited = 16  #This variable contains the type of the next packet to be received. When it is equals to 16 there is no packet to be received.

        self.store = c2wClientModel(
        )  #The c2wClientModel is a class used to store all data about users and movies

        self.delay = 0.5  #The length of the timer that is armed whenever the client send a request. When it runs out the client resend the message if no answer was given.
        self.pingTimer = 1  #The time to wait before sending a ping after having received last pong
        self.resendTries = 0  #The number of times the resend function has resent the message
        self.store.addMovie(ROOM_IDS.MAIN_ROOM, '0.0.0.0', '0', 0)

    def startProtocol(self):
        """one_user_full_login_udp_server_test
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.packet_stor
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    def incrementSeqNumber(self):
        if self.seq_number >= 65536:
            self.seq_number = 0
        else:
            self.seq_number = self.seq_number + 1

########### The function that resends packets whenever the timer runs out.
#OK

    def resend_packet(self, seq_number):
        if self.packet_awaited != 16 and self.packet_stored != 0 and self.seq_number == seq_number:  #Check if there is a packet to be resent
            if self.resendTries < 10:
                print('resending :')
                print(self.packet_stored)
                self.transport.write(self.packet_stored,
                                     (self.serverAddress, self.serverPort))
                self.resendTries += 1
                reactor.callLater(self.delay, self.resend_packet, seq_number)
            else:
                self.clientProxy.applicationQuit()

########### PUT_LOGIN
#OK

    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 = packing.PUT_LOGIN(self.seq_number, userName)
        print('login :'******'Message request called with content=%s', message)
        packet = packing.PUT_NEW_MESSAGE(self.seq_number, self.userID,
                                         self.userRoomID, message)
        print('new message :')
        print(packet)
        self.transport.write(packet, (self.serverAddress, self.serverPort))

        self.packet_stored = packet
        self.packet_awaited = 15
        reactor.callLater(self.delay, self.resend_packet, self.seq_number)

########### PUT_SWITCH_ROOM
#OK

    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.
        """

        moduleLogger.debug('Join Room request called with room name = %s',
                           roomName)

        self.futureRoomID = self.store.getMovieByTitle(roomName).movieId
        packet = packing.PUT_SWITCH_ROOM(self.seq_number, self.userID,
                                         self.futureRoomID)
        print('put switch room :')
        print(packet)
        self.transport.write(packet, (self.serverAddress, self.serverPort))

        self.packet_stored = packet
        self.packet_awaited = 13
        reactor.callLater(self.delay, self.resend_packet, self.seq_number)

########### PUT_LOGOUT
#OK

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """

        moduleLogger.debug('Leave system request called')

        packet = packing.PUT_LOGOUT(self.seq_number, self.userID)
        print('logout :')
        print(packet)
        self.transport.write(packet, (self.serverAddress, self.serverPort))

        self.packet_stored = packet
        self.packet_awaited = 3
        reactor.callLater(self.delay, self.resend_packet, self.seq_number)

########### GET_PING
#OK

    def sendGetPingRequestOIE(self):
        """
        This function is used by the chatClientProtocol to get ping from the server
        """

        if self.packet_awaited == 16:  #Check if there is an awaited response first, if not start the ping
            moduleLogger.debug('Get ping request called')
            packet = packing.GET_PING(self.seq_number, self.userID,
                                      self.lastEventID, self.userRoomID)
            print('get_ping :')
            print(packet)
            self.transport.write(packet, (self.serverAddress, self.serverPort))

            self.packet_stored = packet
            self.packet_awaited = 5
            reactor.callLater(self.delay, self.resend_packet, self.seq_number)
        else:  #If there is, report the ping at a later date (to make sure there is never two requests sent by the client and not answered at once)
            reactor.callLater(self.pingTimer, self.sendGetPingRequestOIE)

########### GET_EVENTS
#OK

    def sendGetEventsRequestOIE(self, nbr_events):
        """
        This function is used by the chatClientProtocol when a ping from the server has revealed that the client is not synchronized yet
        """

        moduleLogger.debug('Get events request called')
        packet = packing.GET_EVENTS(self.seq_number, self.userID,
                                    self.lastEventID, nbr_events, 0)
        print('get events :')
        print(packet)
        self.transport.write(packet, (self.serverAddress, self.serverPort))

        self.packet_stored = packet
        self.packet_awaited = 7
        reactor.callLater(self.delay, self.resend_packet, self.seq_number)

########### GET_ROOMS
#OK

    def sendGetRoomsRequestOIE(self, first_room_id, nbr_rooms):
        """
        This fuction is used by the chatClientProtocol to get a list of current rooms
        """

        moduleLogger.debug('Get rooms request called')
        packet = packing.GET_ROOMS(self.seq_number, self.userID, first_room_id,
                                   nbr_rooms)
        print('get rooms :')
        print(packet)
        self.transport.write(packet, (self.serverAddress, self.serverPort))

        self.packet_stored = packet
        self.packet_awaited = 9
        reactor.callLater(self.delay, self.resend_packet, self.seq_number)

########### GET_USERS
#OK

    def sendGetUsersRequestOIE(self, first_user_id, nbr_users):
        """
        This function is used by the chatClientProtocol to get a list of current users
        """

        moduleLogger.debug('Get users request called')
        packet = packing.GET_USERS(self.seq_number, self.userID, first_user_id,
                                   nbr_users, self.userRoomID)
        print('get_users :')
        print(packet)
        self.transport.write(packet, (self.serverAddress, self.serverPort))

        self.packet_stored = packet
        self.packet_awaited = 11
        reactor.callLater(self.delay, self.resend_packet, self.seq_number)

###########

    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.
        """

        fieldsList = unpacking.decode(datagram)

        if fieldsList[0][0] == self.packet_awaited and fieldsList[0][
                1] == self.seq_number:
            #Check if the message received is the one that is awaited (type and sequence number check)
            print('Correct packet received...')
            print(fieldsList)
            self.packet_stored = 0
            self.packet_awaited = 16
            self.resendTries = 0
            self.incrementSeqNumber()

            ########### RESPONSE_LOGIN OK
            if fieldsList[0][0] == 1:
                print('Received the login response...')
                if fieldsList[1][0] == 0:
                    print('Login status : Done')
                    self.userID = fieldsList[1][1]
                    self.lastEventID = fieldsList[1][2]
                    self.sendGetUsersRequestOIE(1, 255)
                elif fieldsList[1][0] == 1:
                    self.clientProxy.connectionRejectedONE('Unknow error')
                    print('Login status : Unknown error')
                elif fieldsList[1][0] == 2:
                    self.clientProxy.connectionRejectedONE('Too many users')
                    print('Login status : Too many users')
                elif fieldsList[1][0] == 3:
                    self.clientProxy.connectionRejectedONE('Invalid username')
                    print('Login status : Invalid username')
                elif fieldsList[1][0] == 4:
                    self.clientProxy.connectionRejectedONE(
                        'Username not available')
                    print('Login status : Username not available')

            ########### RESPONSE_LOGOUT
            if fieldsList[0][0] == 3:
                print('Received the logout response...')
                self.userID = 0
                self.lastEventID = 0
                self.seq_number = 0
                self.packet_stored = 0
                self.packet_awaited = 16
                self.store.removeAllMovies()
                self.store.removeAllUsers()
                self.clientProxy.leaveSystemOKONE()
                moduleLogger.debug('Logout status : Done')

            ########### RESPONSE_PING
            elif fieldsList[0][0] == 5:
                print('Received the ping response...')
                lastServerEventID = fieldsList[1][0]
                if self.lastEventID != lastServerEventID:
                    print(
                        'Ping status : Not up-to-date, getting events required'
                    )
                    self.sendGetEventsRequestOIE(lastServerEventID -
                                                 self.lastEventID)

                else:
                    print('Ping status : up-to-date, preparing next ping')
                    reactor.callLater(self.pingTimer,
                                      self.sendGetPingRequestOIE)

            ########### RESPONSE_EVENTS
            elif fieldsList[0][0] == 7:
                print('Received the get_events response...')
                for i in range(len(fieldsList[1])):
                    if fieldsList[1][i][1] == 1:  #Message event
                        print('Message event received !')
                        self.lastEventID = fieldsList[1][i][0]

                        user = self.store.getUserById(fieldsList[1][i][3])
                        print(user)
                        if user.userChatRoom == self.userRoomID and user.userId != self.userID:
                            self.clientProxy.chatMessageReceivedONE(
                                user.userName, fieldsList[1][i][4])
                            print(fieldsList[1][i][4])

                    elif fieldsList[1][i][1] == 2:  #New user event
                        print('A new user has been added !')
                        self.lastEventID = fieldsList[1][i][0]

                        room = self.store.getMovieById(fieldsList[1][i][2])
                        self.store.addUser(fieldsList[1][i][4],
                                           fieldsList[1][i][3], room.movieId)
                        self.clientProxy.userUpdateReceivedONE(
                            fieldsList[1][i][4], room.movieTitle)
                        moduleLogger.debug('GetEvents status : New user')

                    elif fieldsList[1][i][1] == 3:  #Switch room event
                        print('A user switched room')
                        self.lastEventID = fieldsList[1][i][0]

                        name = self.store.getUserById(
                            fieldsList[1][i][3]).userName
                        room = self.store.getMovieById(
                            fieldsList[1][i][4]).movieTitle
                        self.store.updateUserChatroom(name,
                                                      fieldsList[1][i][4])
                        self.clientProxy.userUpdateReceivedONE(name, room)
                        moduleLogger.debug(
                            'GetEvent status : User switched room')

                    elif fieldsList[1][i][1] == 4:  #Logout event
                        print('A user disconnected !')
                        self.lastEventID = fieldsList[1][i][0]

                        name = self.store.getUserById(
                            fieldsList[1][i][3]).userName
                        self.store.removeUser(name)
                        self.clientProxy.userUpdateReceivedONE(
                            name, ROOM_IDS.OUT_OF_THE_SYSTEM_ROOM)
                        moduleLogger.debug('GetEvent status : User logged out')

                print('GetEvent status : up-to-date, preparing next ping')
                reactor.callLater(self.pingTimer, self.sendGetPingRequestOIE)

            ########### RESPONSE_ROOMS
            elif fieldsList[0][0] == 9:
                print('Received the get_room response...')
                #FieldsList returns the data in the following form : Room_id, IP, Port, Room_name, Nbr_users
                #AddMovie accepts it in the following form : Title, IP, Port, ID
                moduleLogger.debug('Room status : Rooms list received')
                for i in range(len(fieldsList[1])):
                    if self.store.getMovieById(fieldsList[1][i][0]) is None:
                        self.store.addMovie(fieldsList[1][i][3],
                                            fieldsList[1][i][1],
                                            fieldsList[1][i][2],
                                            fieldsList[1][i][0])

                c2wMovies = self.store.getMovieList(
                )  #get the movie list in the appropriate format
                movieList = []
                for i in range(len(c2wMovies)):
                    if c2wMovies[i].movieTitle != ROOM_IDS.MAIN_ROOM:
                        movieList.append((c2wMovies[i].movieTitle,
                                          c2wMovies[i].movieIpAddress,
                                          c2wMovies[i].moviePort))
                c2wUsers = self.store.getUserList(
                )  #get the user list in the appropriate format
                print(c2wUsers)
                userList = []
                for i in range(len(c2wUsers)):
                    userList.append((c2wUsers[i].userName,
                                     self.store.getMovieById(
                                         c2wUsers[i].userChatRoom).movieTitle))
                print(userList)
                self.clientProxy.initCompleteONE(
                    userList, movieList)  #send both to the UI
                print('Room status : UI has been updated')

                print('Room status : UI is ready, starting ping cycle')
                reactor.callLater(
                    self.pingTimer, self.sendGetPingRequestOIE
                )  #Then starts the Ping - Pong - GetEvents - ResponseEvents - Ping cycle

            ########### RESPONSE_USERS
            elif fieldsList[0][0] == 11:
                print('Received the get_user response...')
                #FieldsList returns the data in the following form : user_id, user_name, room_id
                #AddUser accepts it in the following form : Name, ID, Chatroom
                moduleLogger.debug('Users status : Users list received')
                print(fieldsList)
                for i in range(len(fieldsList[1])):
                    print("AAA")
                    if not self.store.userExists(fieldsList[1][i][1]):
                        self.store.addUser(fieldsList[1][i][1],
                                           fieldsList[1][i][0],
                                           fieldsList[1][i][2])

                print(
                    'Users status : Users list fully updated, asking for rooms'
                )
                self.sendGetRoomsRequestOIE(1, 255)

            ########### RESPONSE_SWITCH_ROOM
            elif fieldsList[0][0] == 13:
                print('Received the switch room response...')
                if fieldsList[1][0] == 0:
                    self.clientProxy.joinRoomOKONE()
                    self.userRoomID = self.futureRoomID
                    print('Switch room status : Done')
                elif fieldsList[1][0] == 1:
                    print('Switch room status : Unknow error')

            ########### RESPONSE_NEW_MESSAGE
            elif fieldsList[0][0] == 15:
                print('Received the put_new_message response')
                if fieldsList[1][0] == 0:
                    print('Message status : transmitted')
                elif fieldsList[1][0] == 1:
                    print('Message status : Unknown error')
                    self.clientProxy.chatMessageReceivedONE(
                        'Server', 'Message status : Unknown error')
                elif fieldsList[1][0] == 2:
                    print('Message status : Invalid room')
                    self.clientProxy.chatMessageReceivedONE(
                        'Server', 'Message status : Invalid room')
                elif fieldsList[1][0] == 3:
                    print(
                        'Message status : Incorrect room (You must send a message only into your current room)'
                    )
                    self.clientProxy.chatMessageReceivedONE(
                        'Server',
                        'Message status : Incorrect room (You must send a message only into your current room)'
                    )
Beispiel #6
0
class c2wUdpChatServerProtocol(DatagramProtocol):
    lastMessage = {}  #Id du dernier message envoyé à un Host Port
    tempUsernames = {}
    seqUsers = {}  #list des seq de chaque utilsateur
    attenteUsers = {
    }  #dico permettant de stocker une variable indiquant le nombre de fois que l'on a envoyé un message sans réponse
    ACKUsers = {
    }  #Chaque valeur vaut 1 ou 0 pour un host_port donné. Si 1 : on vient de recevoir un ACK (on arrete le reacteur de l'utilisateur), tant valeur = 0 on continue le bouclage
    waitForACK = {}  #Dico stockant les reacteurs
    seq = 1  #Seq du serveur

    def __init__(self, serverProxy, lossPr):
        """
        :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 lossPr: The packet loss probability for outgoing packets.  Do
            not modify this value!

        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:: serverProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """
        #: The serverProxy, which the protocol must use
        #: to interact with the server (to access the movie list and to
        #: access and modify the user list).
        self.serverProxy = serverProxy
        self.lossPr = lossPr

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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.
        """

        msg = struct.unpack_from('!hh' + str(len(datagram) - 4) + 's',
                                 datagram)
        taille = msg[0]
        st = msg[1]  #Seq + Type
        data = datagram
        if taille == len(
                datagram):  #vérification que la taille du message est conforme
            seqType = self.getSeqType(
                st)  #Tupple contenant la Sequence et le Type
            (nseq, tTrame) = seqType
            if tTrame != 63:
                print('ack sent respons to ' + str(seqType[1]))
                self.sendAck(seqType[0], host_port)

            if tTrame == 1:  #Le message reçu est une inscription
                user = (data.decode('utf-8'))[4:]
                print("inscription received from " + user)
                check = self.checkInscription(user)
                if check != 0:
                    print("inscription refused for " + user)
                    msg = bytearray(1)
                    struct.pack_into('b', msg, 0, check)
                    self.lastMessage[host_port] = 8
                    self.sender(
                        1, 8, msg, host_port
                    )  #Envoie de l'erreur d'inscription avec le code d'erreur associé (check = 1, 2 ou 3)
                else:
                    print("inscription accepted for " + user)
                    self.lastMessage[
                        host_port] = 7  #On initie le dernier message de l'utilisateur à 7 (Inscription OK)
                    self.tempUsernames[host_port] = user
                    self.ACKUsers[host_port] = 0
                    self.attenteUsers[host_port] = 0
                    self.inscriptionAccepted(
                        host_port
                    )  #Envoie du msg 7 : inscription acceptée. Doit se faire APRES l'ajout de l'user

            if tTrame == 5:  #MESSAGE RECU
                print('msg received from ' +
                      (self.serverProxy.getUserByAddress(host_port).userName) +
                      ' and relayed')
                self.lastMessage[
                    host_port] = 5  #Le dernier message reçu de l'utilisateur est "l'envoie d'un msg instantanné
                self.redirchat(msg[2], host_port)  #On redirige le message

            if tTrame == 6:  #JOINDRE UN SALON
                print('user ' +
                      (self.serverProxy.getUserByAddress(host_port).userName) +
                      ' trying to join room')
                self.lastMessage[host_port] = 6
                self.join_room_response(datagram, host_port)

            if tTrame == 9:  #LEAVING
                print('user ' +
                      (self.serverProxy.getUserByAddress(host_port).userName) +
                      ' leaving')
                self.lastMessage[host_port] = 5
                self.userUpdate(
                    self.serverProxy.getUserByAddress(host_port).userName, 127,
                    host_port)
                self.serverProxy.removeUser(
                    self.serverProxy.getUserByAddress(host_port).userName)
                print(self.serverProxy.getUserList())

            if tTrame == 63:  #ACK RECU
                print('ack received')
                if self.lastMessage[host_port] == 7:

                    if (nseq + 1 == self.seq):
                        if (
                                self.ACKUsers[host_port] == 0
                        ):  #Si on attendait un ACK de l'utilisateur, on cancel le bouclage du racteur
                            self.waitForACK[host_port].cancel(
                            )  #On cancel le bouclage du Send&Wait
                            self.ACKUsers[host_port] = 1

                        self.seqUsers[
                            host_port] = 2  #On initie la sequence de l'utilisateur à 1
                        self.serverProxy.addUser(
                            self.tempUsernames[host_port], 0, None, host_port
                        )  #Ajout de l'utilisateur dans la base de donnée
                        #self.userUpdate((self.serverProxy.getUserByAddress(host_port).userName), 0, host_port)              #Envoie la mise a jour aux autres utilisateurs
                        self.lastMessage[
                            host_port] = 2  #On indique que le dernier message envoyé est la liste des firlm
                        print('sending list of films to ' +
                              (self.serverProxy.getUserByAddress(
                                  host_port).userName))
                        self.ACKUsers[
                            host_port] = 0  #Comme on envoie un message, on initie la valeur de l'ACK de l'utilisateur à 0 (on n'a pas reçu d'acquittements)
                        self.attenteUsers[
                            host_port] = 0  #Pareil que l'ACK mais pour le nombre de tentative.
                        self.sendListFilm(host_port)  #On envoie les films.

                elif self.lastMessage[host_port] != 8:
                    if (nseq + 1 == self.seqUsers[host_port]):
                        if (
                                self.ACKUsers[host_port] == 0
                        ):  #Si on attendait un ACK de l'utilisateur, on cancel le bouclage du racteur
                            self.waitForACK[host_port].cancel()
                            self.ACKUsers[host_port] = 1

                        if self.lastMessage[
                                host_port] == 2:  #Si le dernier message est l'envoie de film
                            self.lastMessage[
                                host_port] = 3  #On envoie la liste des utilisateurs
                            print('sending list of users to ' +
                                  (self.serverProxy.getUserByAddress(
                                      host_port).userName))
                            self.ACKUsers[host_port] = 0
                            self.attenteUsers[host_port] = 0
                            self.sendListUsers(host_port)
                            self.userUpdate((self.serverProxy.getUserByAddress(
                                host_port).userName), 0, host_port)
            print("uizef")

    #ENVOIE DE L'INSCRIPTION ACCEPTEE
    def inscriptionAccepted(self, host_port):
        if ((self.attenteUsers[host_port] < 10)
                and (self.ACKUsers[host_port] == 0)):
            if self.attenteUsers[host_port] != 0: self.seq += -1
            self.sender(0, 7, None,
                        host_port)  #Envoie du message Inscription OK
            self.waitForACK[host_port] = reactor.callLater(
                1, self.inscriptionAccepted, host_port)
            self.attenteUsers[host_port] += 1

        elif self.attenteUsers[host_port] == 10:
            print("The new user did not send any answer")

    #ENVOIE LA LISTE DE FILM
    def sendListFilm(self, host_port):
        if ((self.attenteUsers[host_port] < 10)
                and (self.ACKUsers[host_port] == 0)):
            taille = 0
            LF = self.serverProxy.getMovieList()
            for i in LF:
                taille += len(i.movieTitle) + 8
            buffer = bytearray(taille)
            n = 0
            for i in LF:
                title, port, ip, ide = i.movieTitle, i.moviePort, i.movieIpAddress, i.movieId
                title = title.encode('utf-8')
                struct.pack_into(
                    '!b', buffer, n,
                    len(title) +
                    8)  #taille dans le buffer 8 = taille,ip ,port,id
                ipe = ip.split('.')
                for i in range(4):
                    struct.pack_into('b', buffer, n + 1 + i, int(ipe[i]))
                form = '!hb' + str(len(title)) + 's'
                struct.pack_into(form, buffer, n + 5, port, ide, title)
                n += 8 + len(title)
            self.sender(taille, 2, buffer, host_port)
            self.waitForACK[host_port] = reactor.callLater(
                1, self.sendListFilm, host_port)
            self.attenteUsers[host_port] += 1

        elif self.attenteUsers[host_port] == 10:
            print('user ' +
                  (self.serverProxy.getUserByAddress(host_port).userName) +
                  ' has been removed from database')
            self.serverProxy.removeUser(
                self.serverProxy.getUserByAddress(host_port).userName)

    #ENVOIE LA LISTE DES USERS
    def sendListUsers(self, host_port):
        if ((self.attenteUsers[host_port] < 10)
                and (self.ACKUsers[host_port] == 0)):
            taille = 0
            for i in self.serverProxy.getUserList():
                taille += len(i.userName) + 2
            buffer = bytearray(taille)
            n = 0
            for i in self.serverProxy.getUserList():
                user, idroom = i.userName, i.userChatRoom
                if idroom != 0:
                    idroom = self.serverProxy.getMovieById(
                        i.userChatRoom).movieId
                    print(idroom)
                user = user.encode('utf8')
                form = '!bb' + str(len(user)) + 's'
                struct.pack_into(
                    form, buffer, n,
                    len(user) + 1 + 1, idroom, user
                )  #taille données=longueur titre + 1 octet de taille + 2 + 4 + 1) suivie par ip, port etc..
                n += len(user) + 2
            self.sender(taille, 3, buffer, host_port)
            self.waitForACK[host_port] = reactor.callLater(
                1, self.sendListUsers, host_port)
            self.attenteUsers[host_port] += 1

        elif self.attenteUsers[host_port] == 10:
            print('user ' +
                  (self.serverProxy.getUserByAddress(host_port).userName) +
                  ' has been removed from database')
            self.serverProxy.removeUser(
                self.serverProxy.getUserByAddress(host_port).userName)

    #METTRE A JOUR UN USER
    def userUpdate(self, userName, idSalon, host_port):
        userName = userName.encode('utf-8')
        buffer = bytearray(len(userName) + 1)
        struct.pack_into('b' + str(len(userName)) + 's', buffer, 0, idSalon,
                         userName)
        for i in self.serverProxy.getUserList():
            hp = i.userAddress
            #if host_port!=hp:
            print('sending update')
            self.ACKUsers[hp] = 0
            self.attenteUsers[hp] = 0
            self.sendUserUpdate((len(userName) + 1, buffer, hp))

    def sendUserUpdate(self, touple):
        taille = touple[0]
        buffer = touple[1]
        host_port = touple[2]
        if ((self.attenteUsers[host_port] < 10)
                and (self.ACKUsers[host_port] == 0)):
            self.sender(taille, 4, buffer, host_port)
            self.waitForACK[host_port] = reactor.callLater(
                1, self.sendUserUpdate, touple)
            self.attenteUsers[host_port] += 1

        elif self.attenteUsers[host_port] == 10:
            print('user ' +
                  (self.serverProxy.getUserByAddress(host_port).userName) +
                  ' has been removed from database')
            self.serverProxy.removeUser(
                self.serverProxy.getUserByAddress(host_port).userName)

    def sendRedirChat(self, taille, buffer, host_port):
        if ((self.attenteUsers[host_port] < 10)
                and (self.ACKUsers[host_port] == 0)):
            self.sender(taille, 10, buffer, host_port)
            self.waitForACK[host_port] = reactor.callLater(
                1, self.sendRedirChat, (taille, buffer, host_port))
            self.attenteUsers[host_port] += 1

        elif self.attenteUsers[host_port] == 10:
            print('user ' +
                  (self.serverProxy.getUserByAddress(host_port).userName) +
                  ' has been removed from database')
            self.serverProxy.removeUser(
                self.serverProxy.getUserByAddress(host_port).userName)

    #REDIRIGE CHAT
    def redirchat(self, message, host_port):

        user = self.serverProxy.getUserByAddress(host_port).userName
        taille_user = len(user)
        user = user.encode('utf-8')
        taille_msg = len(message)
        taille_data = taille_user + taille_msg + 1  #+1 car taille de l'utilisateur est sur 1 octet
        msg = bytearray(taille_data)
        form = '!b' + str(taille_user) + 's' + str(taille_msg) + 's'
        struct.pack_into(form, msg, 0, taille_user, user, message)
        for i in self.serverProxy.getUserList():
            if i.userChatRoom == self.serverProxy.getUserByAddress(
                    host_port).userChatRoom:
                hp = i.userAddress
                #if host_port!=hp:
                self.ACKUsers[hp] = 0
                self.attenteUsers[hp] = 0
                self.sendRedirChat(taille_data, msg, hp)

    #REPONSE A UNE DEMANDE D'ACCES A UNE ROOM
    def join_room_response(self, datagram, host_port):

        form = '!hhb'
        data = struct.unpack_from(form, datagram)
        id_movie = data[2]
        user = self.serverProxy.getUserByAddress(host_port).userName
        if id_movie == 0:
            self.sender(0, 11, None, host_port)
            self.serverProxy.updateUserChatroom(user, ROOM_IDS.MAIN_ROOM)
            self.userUpdate(user, 0, host_port)
        else:
            m = self.serverProxy.getMovieById(id_movie)
            if m == None:
                self.sender(0, 12, None, host_port)
            else:
                self.sender(0, 11, None, host_port)
                self.serverProxy.updateUserChatroom(user, m.movieId)
                self.userUpdate(user, m.movieId, host_port)
                n = 0
                for i in self.serverProxy.getUserList():
                    if i.userChatRoom != ROOM_IDS.MAIN_ROOM and self.serverProxy.getMovieById(
                            i.userChatRoom
                    ) != None and self.serverProxy.getMovieById(
                            i.userChatRoom).movieId == m.movieId:
                        n += 1
                if n == 1:
                    self.serverProxy.startStreamingMovie(m.movieTitle)

    #def leave_system_response(self,datagram,host_port):

    #ENVOIE D'UN ACK
    def sendAck(self, seq, host_port):

        typeM = self.dec2bin(63, 6)
        seqM = self.dec2bin(seq, 10)
        st = seqM + typeM
        msg = bytearray(4)
        struct.pack_into('!hh', msg, 0, 4, int(st, 2))
        self.transport.write(msg, host_port)

    #METHODE ASSEMBLANT LE MESSAGE ET L'ENTETE
    def sender(self, taille, typeM, data, host_port):

        if (
            (typeM != 8) and (typeM != 7)
        ):  #7 ou 8 = Inscription acceptée/Refusée ===> User n'est pas encore dans la base de donnée du serveur
            user = self.serverProxy.getUserByAddress(
                host_port
            ).userName  #on trouve l'utilisateur à qui on envoie le message
            seqM = self.dec2bin(self.seqUsers[host_port], 10)
            self.seqUsers[host_port] += 1
        else:
            user = None
            seqM = self.dec2bin(
                self.seq, 10
            )  #Si l'utilisateur n'existe pas, on envoie avec la séquence du serveur
            self.seq += 1
        typeM = self.dec2bin(typeM, 6)  #conversion du type sur 6 bit

        st = seqM + typeM  #on concatene sequence et type
        buf = bytearray(4)
        struct.pack_into('!hh', buf, 0, taille + 4, int(st, 2))

        if data != None:
            buf = buf + data
        self.transport.write(buf, host_port)

    #VERIFICATION DE L'INSCRIPTION
    def checkInscription(self, data):

        check = 0
        if (data.find(" ") != -1):
            check = 3
        if len(data) > 127:  #Username > 254 caractere = 254 octets
            check = 2
        if self.serverProxy.userExists(data): check = 1
        return check

        #CONVERTISSEUR BINAIRE
    def dec2bin(self, decimal,
                nbbits):  #Le convertisseur fait une division euclidienne

        if decimal == 0:
            return "0".zfill(nbbits)
        result = ""
        while decimal != 0:
            decimal, rest = divmod(decimal, 2)
            result = "01"[rest] + result
        return result.zfill(nbbits)

    #RETOURNE lE NUM DE SEQ ET LE TYPE DE TRAME
    def getSeqType(self, st):

        st = str(self.dec2bin(st, 16))
        seq = st[:-6]
        types = st[-6:]
        return int(seq, 2), int(types,
                                2)  #tupple[0] = sequence, tupple[1] = type
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """
        #initializing the sequence number to zero
        self.seql = 0
        #initializing the resend counter to zero
        self.count = 0
        self.repeat = None
        self.movielist = []
        self.userlist = []
        self.ackcm = None
        self.ackleave = None
        self.username = None

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

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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.
        """
        #total length of the loginrequest packet
        length = len(userName) + 4
        self.username = userName

        #combined sequence number and type number
        sequ_type = (self.seql << 4) | (types["Envoi du Pseudo"])

        buf = struct.pack('!HH%is' % len(userName), length, sequ_type,
                          userName.encode('utf-8'))
        self.transport.write(buf, (self.serverAddress, self.serverPort))

        #retransmit the loginrequest if lost.
        if (self.count < 7):
            self.repeat = reactor.callLater(1, self.sendLoginRequestOIE,
                                            userName)
            self.count += 1

        moduleLogger.debug('loginRequest called with username=%s', 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.
        """

        lenuser = len(self.username.encode('utf-8'))
        length = 4 + 1 + lenuser + len(message.encode('utf-8'))
        buf = bytearray(length)
        offset = 4
        sequ_type = (self.seql << 4) | (types["Message Chat"])

        struct.pack_into('!HH', buf, 0, length, sequ_type)
        struct.pack_into('!B%is' % len(self.username.encode('utf-8')), buf,
                         offset, lenuser, self.username.encode('utf-8'))
        offset += 1 + lenuser
        struct.pack_into('!%is' % len(message.encode('utf-8')), buf, offset,
                         message.encode('utf-8'))

        self.transport.write(buf, (self.serverAddress, self.serverPort))

        #retransmit the chatmessage if lost.
        if (self.count < 7):
            self.repeat = reactor.callLater(1, self.sendChatMessageOIE,
                                            message)
            self.count += 1
        pass

    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.
        """
        if (roomName is ROOM_IDS.MAIN_ROOM):
            #total length of the Quitter salle film packet
            length = 4

            #combined sequence number and type number
            sequ_type = (self.seql << 4) | (types["Quitter salle film"])
            self.ackcm = self.seql

            #Packing and sending the Quitter salle film packet
            buf = struct.pack('!HH', length, sequ_type)
            self.transport.write(buf, (self.serverAddress, self.serverPort))

        else:
            #total length of the Choix d’un film packet
            length = len(roomName) + 4

            #combined sequence number and type number
            sequ_type = (self.seql << 4) | (types["Choix d’un film"])
            self.ackcm = self.seql

            #Packing and sending the Choix d’un film packet
            buf = struct.pack('!HH%is' % len(roomName), length, sequ_type,
                              roomName.encode('utf-8'))
            self.transport.write(buf, (self.serverAddress, self.serverPort))

        #retransmit the Choix d’un film or Quitter salle film if lost.
        if (self.count < 7):
            self.repeat = reactor.callLater(1, self.sendJoinRoomRequestOIE,
                                            roomName)
            self.count += 1

        pass

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        #total length of the leaveSystemRequest packet
        length = 4

        #combined sequence number and type number
        sequ_type = (self.seql << 4) | (types["Quitter application"])
        self.ackleave = self.seql

        #Packing and transmitting the leaveSystemRequest packet.
        buf = struct.pack('!HH', length, sequ_type)
        self.transport.write(buf, (self.serverAddress, self.serverPort))

        #retransmit the leaveSystemRequest packet if lost.
        if (self.count < 7):
            self.repeat = reactor.callLater(1, self.sendLeaveSystemRequestOIE)
            self.count += 1

        pass

    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.
        """
        #unpacking and extracting the length, sequence number and type from the received data.
        lenght, seq_type, data = struct.unpack('!HH%is' % (len(datagram) - 4),
                                               datagram)
        seql = seq_type >> 4
        typ = seq_type & 15
        offset = 4

        #if type of the received data is not an ACK, then it has to send an ACK for the received data.
        if (typ != types["Acquittement"]):
            sequ_type = (seql << 4) | (types["Acquittement"])
            buf = struct.pack('!HH', 4, sequ_type)
            self.transport.write(buf, host_port)
            print("send ack {}".format(buf))
            self.seql += 1

        #retransmission cancelled if ACK is received
        elif (typ == types["Acquittement"]):
            if self.repeat != None:
                self.repeat.cancel()
                self.repeat = None
            self.count = 0
            self.seql += 1

        if (typ == types["Refus connexion"]):
            self.clientProxy.connectionRejectedONE("user name already exists")

        #if received data is movielist then unpack and store it in the variable as defined.
        if (typ == types["Envoi liste films"]):

            while offset < lenght:
                print(offset, lenght)
                cip, port, lenmovie, iid = struct.unpack_from(
                    '!IHHB', datagram, offset)
                offset += 9
                movietitle = struct.unpack_from('!%is' % (lenmovie - 9),
                                                datagram,
                                                offset)[0].decode('utf-8')
                offset += lenmovie - 9
                aip = str(ipaddress.IPv4Address(cip))
                stport = str(port)
                stiid = str(iid)
                self.movielist.append((movietitle, aip, stport, stiid))

        #if received data is userlist then unpack and store it in the variable as defined.
        if (typ == types["Envoi liste users"]):
            userList = []
            while offset < lenght:
                lenuser, userstatus = struct.unpack_from(
                    '!BB', datagram, offset)
                offset += 2
                use = struct.unpack_from('!%is' % lenuser, datagram,
                                         offset)[0].decode('utf-8')
                offset += lenuser
                #stuserstatus=str(userstatus)
                if (userstatus == 0):
                    auserstatus = ROOM_IDS.MAIN_ROOM
                else:

                    for movie in self.movielist:
                        if movie[3] == str(userstatus):
                            auserstatus = movie[0]
                userList.append((use, auserstatus))

            if self.userlist == []:
                self.userlist = userList
                self.clientProxy.initCompleteONE(self.userlist, self.movielist)
            else:
                self.userlist = userList
                self.clientProxy.setUserListONE(self.userlist)

        if (typ == types["Acquittement"]):
            if (seql == self.ackcm):
                self.clientProxy.joinRoomOKONE()
            if (seql == self.ackleave):
                self.clientProxy.leaveSystemOKONE()

        if (typ == types["Message Chat"]):
            lenuser = struct.unpack_from('!B', datagram, 4)[0]
            username = struct.unpack_from('!%is' % lenuser, datagram,
                                          5)[0].decode('utf-8')
            lengthmsg = lenght - 4 - 1 - lenuser
            msg = struct.unpack_from('!%is' % lengthmsg, datagram,
                                     5 + lenuser)[0].decode('utf-8')
            if (self.username != username):
                self.clientProxy.chatMessageReceivedONE(username, msg)
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        #dictionaire pour les id des films
        self.dictmoovie = dict()
        self.seqnum = 0
        self.Token = 0
        self.seqgtr = 0
        self.deconnexion = 4
        self.nombre_envoie = 0
        self.reception_ack = {}

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    #
    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def numseq(self, seq):
        #on genere un numero de sequence pour chaque paquet envoyé
        # en augmentant la valeur recue pour le prochain paquet
        # une fois le numero de sequence a 65536 on le reinitialise
        if seq == 65536:
            seq = 0
        else:
            seq += 1
        return seq
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #si le paquet recu est de type login reponse on teste la valeur de coderep
    def Preparepaquet(self, Version, Type, Token, Sequencenumber, payload):
        payloadsize = len(payload)
        header1 = (Version << 28) + (Type << 24) + Token
        header2 = (Sequencenumber << 16) + payloadsize
        packet = struct.pack('>II' + str(len(payload)) + 's', header1, header2,
                             payload.encode('utf−8'))
        return (packet)

        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #si le paquet recu est de type login reponse on teste la valeur de coderep
    def PaquetLRQ(self, Version, Type, Token, Sequencenumber, iduser,
                  username):
        usernamepack = struct.pack(
            '>HH' + str(len(username.encode('utf−8'))) + 's', iduser,
            len(username.encode('utf−8')), username.encode('utf−8'))
        userdatasize = len(usernamepack)
        header1 = (Version << 28) + (Type << 24) + Token
        header2 = (Sequencenumber << 16) + userdatasize
        packet = struct.pack('>II', header1, header2) + usernamepack
        return (packet)

        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #si le paquet recu est de type login reponse on teste la valeur de coderep

    # pour recevoir les paquets simples avec payload non decodé
    def paquetsimple(self, datagram):
        (header1, header2,
         payload) = struct.unpack('>II' + str(len(datagram) - 8) + 's',
                                  datagram)
        token = header1 & int('111111111111111111111111', 2)
        header1 = header1 >> 24
        Type = header1 & int('1111', 2)
        header1 = header1 >> 4
        version = header1
        payloadsize = header2 & int('1111111111111111', 2)
        header2 = header2 >> 16
        seqnum = header2 & int('1111111111111111', 2)
        return (version, Type, token, seqnum, payloadsize, payload)
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #si le paquet recu est de type login reponse on teste la valeur de coderep

    def paquetrecuLRP(self, datagram):
        (header1, header2, coderp, userid,
         username) = struct.unpack('>IIBH' + str(len(datagram) - 11) + 's',
                                   datagram)
        token = header1 & int('111111111111111111111111', 2)
        header1 = header1 >> 24
        Type = header1 & int('1111', 2)
        header1 = header1 >> 4
        version = header1
        payloadsize = header2 & int('1111111111111111', 2)
        header2 = header2 >> 16
        seqnum = header2 & int('1111111111111111', 2)
        return (version, Type, token, seqnum, payloadsize, coderp, userid,
                username)
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #si le paquet recu est de type login reponse on teste la valeur de coderep
    def constructack(self, Version, Type, Token, Sequencenumber, payload):
        payloadsize = len(payload)
        header1 = (Version << 28) + (Type << 24) + Token
        header2 = (Sequencenumber << 16) + payloadsize
        packet = struct.pack('>II' + str(len(payload)) + 's', header1, header2,
                             payload.encode('utf−8'))
        return (packet)
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def paquetGTR(self, Token, Seqnumber, moovie_id):
        header1 = (1 << 28) + (5 << 24) + Token
        payload = struct.pack('>H', moovie_id)
        gtrdatasize = len(payload)
        header2 = (Seqnumber << 16) + gtrdatasize
        packet = struct.pack('>II', header1, header2) + payload
        return (packet)
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #fonnction de depaquetage lors de la reception de RST
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    def depaquetageRST(self, datagram):
        # affiche le rst recu
        print(" ".join("{:02x}".format(c) for c in datagram))

        # liste contenant la liste des utilisateurs dans la mainroom
        userList = list()
        # liste contenant le nom, port et l'ip du film
        movieList = list()
        # dictionnaire contenant les id de chaque film en fonction de leur nom
        user_moovielist = dict()
        # liste contenant l'id, port et l'ip du film
        userdata = list()
        datagram = datagram[8:]
        print(datagram)
        id_mainroom = struct.unpack('>H', datagram[0:2])[0]

        datagram = datagram[2:]
        taille = struct.unpack('>H', datagram[0:2])[0]

        datagram = datagram[2:]
        mainroom = struct.unpack(str(taille) + 's', datagram[0:taille])
        mainroom = mainroom[0].decode('utf-8')
        mainroom = ROOM_IDS.MAIN_ROOM
        datagram = datagram[taille:]
        # récupere l'adresse ip et le port de la main room
        ip = struct.unpack('>I', datagram[0:4])[0]
        ip3 = ip & 255
        ip = ip >> 8
        ip2 = ip & 255
        ip = ip >> 8
        ip1 = ip & 255
        ip = ip >> 8
        ip0 = ip
        ip_adress = str.join(".", (str(ip0), str(ip1), str(ip2), str(ip3)))

        datagram = datagram[4:]
        Port = struct.unpack('>H', datagram[0:2])[0]

        datagram = datagram[2:]
        nombre_usermainroom = struct.unpack('>H', datagram[0:2])[0]

        datagram = datagram[2:]

        user_moovielist[mainroom] = id_mainroom

        #parcours des utilisateurs dans la main room
        for i in range(nombre_usermainroom):
            userId = struct.unpack('>H', datagram[0:2])[0]

            datagram = datagram[2:]
            userNameLength = struct.unpack('>H', datagram[0:2])[0]

            datagram = datagram[2:]
            userName = struct.unpack(
                str(userNameLength) + 's', datagram[0:userNameLength])[0]

            userName = userName.decode('utf-8')
            datagram = datagram[userNameLength:]
            userList.append((userName, mainroom))
            userdata.append((userId, userName))

        nbre_film = struct.unpack('>H', datagram[0:2])[0]

        datagram = datagram[2:]
        # parcours de la liste des films pour recuperer les utilisateurs regardant un film
        for j in range(nbre_film):

            id_moovieroom = struct.unpack('>H', datagram[0:2])[0]

            datagram = datagram[2:]
            taille = struct.unpack('>H', datagram[0:2])[0]
            print('taille du nom de film:' + str(taille))
            datagram = datagram[2:]

            moovie_name = struct.unpack(str(taille) + 's',
                                        datagram[0:taille])[0]

            moovie_name = moovie_name.decode('utf-8')
            datagram = datagram[taille:]

            # récuperer l'adresse ip et le port de chaque film
            ip = struct.unpack('>I', datagram[0:4])[0]
            ip3 = ip & 255
            ip = ip >> 8
            ip2 = ip & 255
            ip = ip >> 8
            ip1 = ip & 255
            ip = ip >> 8
            ip0 = ip
            ip_adress = str.join(".", (str(ip0), str(ip1), str(ip2), str(ip3)))

            datagram = datagram[4:]
            Port = struct.unpack('>H', datagram[0:2])[0]

            datagram = datagram[2:]
            nmbre_usermoovieroom = struct.unpack('>H', datagram[0:2])[0]

            datagram = datagram[2:]

            # recupere la liste des utilisateurs regardant un film donné
            for i in range(nmbre_usermoovieroom):
                userId = struct.unpack('>H', datagram[0:2])[0]

                datagram = datagram[2:]
                taille = struct.unpack('>H', datagram[0:2])[0]

                datagram = datagram[2:]
                userName = struct.unpack(
                    str(taille) + 's', datagram[0:taille])[0]

                userName = userName.decode('utf-8')
                print(' user pour cette room:' + userName)
                datagram = datagram[taille:]
                userList.append((userName, moovie_name))
                userdata.append((userId, userName))

            liste_vide = struct.unpack('>H', datagram[0:2])[0]
            datagram = datagram[2:]
            # liste contenant le nom, port et l'ip du film
            movieList.append((moovie_name, ip, Port))
            # dictionnaire contenant les id de chaque film en fonction de leur nom
            user_moovielist[moovie_name] = id_moovieroom

        return (userList, movieList, user_moovielist, userdata)

    def message(self, Token, Seqnumber, id_user, message):
        id_user = struct.pack('>H', id_user)
        message = struct.pack('>H' + str(len(message.encode('utf−8'))) + 's',
                              len(message.encode('utf−8')),
                              message.encode('utf−8'))
        payload = id_user + message
        msgdatasize = len(payload)
        header1 = (1 << 28) + (6 << 24) + Token
        header2 = (Seqnumber << 16) + msgdatasize
        packet = struct.pack('>II', header1, header2) + payload
        return (packet)

    def leaveroom(self, Token, Sequencenumber):

        header1 = (1 << 28) + (7 << 24) + Token
        header2 = (Sequencenumber << 16) + 0
        packet = struct.pack('>II', header1, header2)
        return (packet)

    def sendAndWait(self, paquet, numseq, host_port):

        #on verifie si le nombre d'envoie est inferieur a 3 et si on a recu un ack du client
        #si non on incremente le nombre d'envoie et si oui le paquet est aquité sinon
        #apres trois tentative on arrete d'envoyer le LRP
        if self.nombre_envoie <= 2 and self.reception_ack[numseq] == False:
            self.transport.write(paquet, host_port)
            self.nombre_envoie += 1
            print('nmbre envoielrp:' + str(self.nombre_envoie))
            reactor.callLater(1, self.sendAndWait, paquet, numseq, host_port)
        elif (self.reception_ack[numseq] == True):

            print('paquet aquitte')
        else:
            print('nmbre envoie:' + str(self.nombre_envoie))
            if (self.nombre_envoie > 2):
                print('paquet perdu')

    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)
        print(userName)

        datagram = self.PaquetLRQ(1, 1, 0, 0, 0, userName)
        print(datagram)
        print(" ".join("{:02x}".format(c) for c in datagram))
        server = (self.serverAddress, self.serverPort)
        self.username = userName
        self.transport.write(datagram, server)
        self.reception_ack[self.seqnum] = False
        reactor.callLater(1, self.sendAndWait, datagram, self.seqnum, server)

    def sendChatMessageOIE(self, message):

        server = (self.serverAddress, self.serverPort)

        print('personne envoyant le message:' + str(self.userid))
        seqnumber = self.numseq(int(self.seqnum))

        datagram = self.message(self.Token, self.seqnum, self.userid, message)
        print(datagram)
        self.transport.write(datagram, server)
        self.reception_ack[self.seqnum] = False
        reactor.callLater(1, self.sendAndWait, datagram, self.seqnum, server)
        """
        :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.
        """

        pass

    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.
        """

        server = (self.serverAddress, self.serverPort)

        seqnumber = self.numseq(int(self.seqnum))
        self.seqgtr = self.seqnum
        print('seqgtr envoyé au serveur:' + str(self.seqgtr))

        datagram = self.paquetGTR(self.Token, self.seqnum,
                                  self.dictmoovie[roomName])
        print(datagram)
        self.transport.write(datagram, server)
        self.nombre_envoie = 0
        self.reception_ack[self.seqnum] = False
        reactor.callLater(1, self.sendAndWait, datagram, self.seqnum, server)
        pass

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        server = (self.serverAddress, self.serverPort)

        seqnumber = self.numseq(int(self.seqnum))
        self.deconnexion = seqnumber + 1
        print('seqgtr envoyé au serveur:' + str(self.seqgtr))

        datagram = self.leaveroom(self.Token, seqnumber + 1)
        print(datagram)
        self.transport.write(datagram, server)
        self.reception_ack[self.seqnum] = False
        reactor.callLater(1, self.sendAndWait, datagram, self.seqnum, server)
        pass

    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.
        """

        print('roomdata rst:' + str(datagram))
        print(" ".join("{:02x}".format(c) for c in datagram))
        #on decode le paquet recu du serveur
        (version, Type, Token, numseq, payloadsize,
         payload) = self.paquetsimple(datagram)
        #on numero de sequence courant recu
        self.seqnum = numseq
        self.Token = Token
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #si le paquet recu est ack on l'affiche
        if (Type == 0):
            self.reception_ack[numseq] = True
            print('ack serveur:' + str(version) + ',' + str(Type) + ',' +
                  str(self.Token) + ',' + str(self.seqnum) + ',' +
                  str(payloadsize) + ',' + str(payload))
            if (self.seqgtr == self.seqnum):
                print('joinRoomOKONE')
                self.clientProxy.joinRoomOKONE()
                self.seqgtr = 0
            elif (self.deconnexion == self.seqnum):
                self.clientProxy.leaveSystemOKONE()
                #(userList,moovieList,dictmovie)=self.depaquetageRST(datagram)

        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #si le paquet recu est de type login reponse on teste la valeur de coderep
        #si le paquet recu n'est pas un ack on envoie un ack au serveur
        #a revoir pour le cas ou type=2 on envoie rien
        if (Type != 0):
            print('seqnum venant du serveur:' + str(self.seqnum))
            print('le message recu est pas un ack')
            ack = self.constructack(1, 0, self.Token, self.seqnum, '')
            self.transport.write(ack, host_port)
            print('ack bien envoyé au serveur')
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #
        #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #si le paquet recu est de type login reponse on teste la valeur de coderep
        if (Type == 2):
            #(coderep,userid,username)=struct.unpack('>BH'+str((payload)-3)+'s',payload)
            (version, Type, self.Token, self.seqnum, payloadsize, coderp,
             self.userid, username) = self.paquetrecuLRP(datagram)
            print('coderep:' + str(coderp))
            if (coderp == 1):
                erreur = 'username non conforme'
                self.clientProxy.connectionRejectedONE(erreur)

            elif (coderp == 2):

                erreur = 'username too long'
                self.clientProxy.connectionRejectedONE(erreur)
            elif (coderp == 3):

                erreur = 'username deja utilise'
                self.clientProxy.connectionRejectedONE(erreur)
            elif (coderp == 255):
                erreur = 'unknow error'
                self.clientProxy.connectionRejectedONE(erreur)
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        #depaquetage de la userlist et de la moovielist
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        if Type == 4:
            if self.seqnum == 1:
                (self.userList, self.moovieList, self.dictmoovie,
                 self.userdata) = self.depaquetageRST(datagram)

                self.clientProxy.initCompleteONE(self.userList,
                                                 self.moovieList)
            elif self.seqnum > 1:
                (self.userList, self.moovieList, self.dictmoovie,
                 self.userdata) = self.depaquetageRST(datagram)

                self.clientProxy.setUserListONE(self.userList)

    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    #   pour mettre a jour la liste des utilisateurs quand une nouvelle personne
    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        if (Type == 6):
            (header1, header2, id_user, usernamesize,
             message) = struct.unpack('>IIHH' + str(len(datagram) - 12) + 's',
                                      datagram)
            for user in self.userdata:
                if (user[0] == id_user):
                    print('user envoyant le message trouvé avec id:',
                          str(user[0]), str(user[1]))

                    self.clientProxy.chatMessageReceivedONE(
                        user[1], message.decode('utf-8'))
        pass
Beispiel #9
0
class c2wUdpChatClientProtocol(DatagramProtocol):

    seq = 1
    lastMessage = ''
    attenteServer = 0  #Initié à 0 pour le premier envoie de login
    ACKServer = 0
    waitForACK = ''

    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort

        self.serverHost = serverAddress, serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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)
        userName = userName.encode('utf8')
        self.attenteServer = 0
        self.ACKServer = 0
        self.sendLogin(userName)

    def sendLogin(self, userName):
        if ((self.attenteServer < 10) and (self.ACKServer == 0)):
            if self.attenteServer != 0: self.seq = 1
            self.sender(len(userName), 1, userName, self.serverHost)
            self.waitForACK = reactor.callLater(1, self.sendLogin, userName)

            self.attenteServer += 1
        elif self.attenteServer == 10:
            print("The server do not answer")

    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.
        """

        taille = len(message)
        if taille * 2 < 65000:
            message = message.encode('utf-8')
            self.attenteServer = 0
            self.ACKServer = 0
            self.sendChatMessage(message)

    def sendChatMessage(self, message):
        if ((self.attenteServer < 10) and (self.ACKServer == 0)):
            self.sender(len(message), 5, message, self.serverHost)
            self.waitForACK = reactor.callLater(1, self.sendChatMessage,
                                                message)
            self.attenteServer += 1

        elif self.attenteServer == 10:
            print("The server do not answer")

    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.
        """

        if not isinstance(roomName, str): idm = 0
        else: idm = movieIds[roomName]
        msg = bytearray(1)
        struct.pack_into('!b', msg, 0, idm)
        self.attenteServer = 0
        self.ACKServer = 0
        self.sendJoinRoom(msg)

    def sendJoinRoom(self, msg):
        if ((self.attenteServer < 10) and (self.ACKServer == 0)):
            self.sender(1, 6, msg, self.serverHost)
            self.waitForACK = reactor.callLater(1, self.sendJoinRoom, msg)
            self.attenteServer += 1
        elif self.attenteServer == 10:
            print("The server does not answer")

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        self.attenteServer = 0
        self.ACKServer = 0
        self.sendLeaveSystem()

    def sendLeaveSystem(self):
        if ((self.attenteServer < 10) and (self.ACKServer == 0)):
            self.lastMessage = 'quit'
            self.sender(0, 9, None, self.serverHost)
            self.waitForACK = reactor.callLater(1, self.sendLeaveSystem)
            self.attenteServer += 1
        elif self.attenteServer == 10:
            print("The server does not answer")

    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.
        """
        global movieList
        global userList
        global movieIds

        msg = struct.unpack_from('!hh' + str(len(datagram) - 4) + 's',
                                 datagram)
        taille = msg[0]
        st = msg[1]  #Seq + Type
        if taille == len(datagram):
            seqType = self.getSeqType(
                st)  #Tupple contenant la Sequence et le Type
            (nseq, tTrame) = seqType

            if seqType[
                    1] != 63:  #Si le message reçu n'est pas un ACK, on envoie un ACK
                print('msg received -- ack sent response to ' +
                      str(seqType[1]))
                self.sendAck(seqType[0], host_port)

            if seqType[1] == 8:  #REFUSEE
                print('inscription refused')
                datagram = datagram[4:]
                check = struct.unpack_from('b', datagram)
                self.clientProxy.connectionRejectedONE(str(check[0]))

            if seqType[1] == 11: self.clientProxy.joinRoomOKONE()

            if seqType[1] == 2:  #MOVIES
                print('movie list received')
                movieList = []
                movieIds = {}
                datagram = datagram[4:]
                while len(datagram) != 0:
                    tp = struct.unpack_from('b', datagram)  #on recup la taille
                    form = 'bbbbb'
                    t = struct.unpack_from(form, datagram)
                    ipl = t[1:5]  #recuperation de l ip
                    ip = ''
                    for i in range(4):  #boucle de reconcatenation de l ip
                        ip += str(ipl[i]) + '.'
                    ip = ip[:-1]  # enlever le dernier point
                    datagram = datagram[5:]
                    te = struct.unpack_from('!hb' + str(tp[0] - 8) + 's',
                                            datagram)
                    movieList += [(te[2].decode('utf-8'), ip, te[0])]
                    movieIds[te[2].decode('utf-8')] = te[1]
                    datagram = datagram[tp[0] - 5:]

            if seqType[1] == 3:  #USERS
                print('user list received')
                userList = []
                datagram = datagram[4:]
                while len(datagram) != 0:
                    tp = struct.unpack_from('b', datagram)  #on recup la taille
                    form = 'bb' + str(tp[0] - 2) + 's'
                    t = struct.unpack_from(form, datagram)
                    user = t[2].decode('utf-8')
                    #user=user[4:]
                    if t[1] == 0: userList += [(user, ROOM_IDS.MAIN_ROOM)]
                    else: userList += [(user, t[1])]
                    datagram = datagram[tp[0]:]
                self.clientProxy.initCompleteONE(userList, movieList)

            if seqType[1] == 10:  #Message reçu
                print('message received')
                tailleUser = struct.unpack_from('!b', msg[2])
                form = '!b' + str(tailleUser[0]) + 's' + str(
                    len(msg[2]) - 1 - tailleUser[0]) + 's'
                umsg = struct.unpack_from(form, msg[2])
                usr = umsg[1].decode('utf-8')
                msg = umsg[2].decode('utf-8')
                self.clientProxy.chatMessageReceivedONE(usr, msg)

            if seqType[1] == 63:  #ACK
                print('ack received')
                print(nseq, self.seq)
                if (nseq + 1 == self.seq):
                    if (
                            self.ACKServer == 0
                    ):  #Si on attendait un ACK de l'utilisateur, on cancel le bouclage du racteur
                        self.waitForACK.cancel(
                        )  #On cancel le bouclage du Send&Wait
                        self.ACKServer = 1
                    if self.lastMessage == 'quit':
                        print('user left')
                        self.clientProxy.leaveSystemOKONE()
                #else:

            if seqType[1] == 8:  #REFUS INSCRIPTION
                print('Inscription refused')
                print(datagram)

            if seqType[1] == 4:  #MISE A JOUR UTILISATEUR
                datagram = datagram[4:]
                [idSalon, userName
                 ] = struct.unpack_from('b' + str(len(datagram) - 1) + 's',
                                        datagram)
                userName = userName.decode('utf8')
                print('user updated')
                if idSalon == 127:
                    self.clientProxy.userUpdateReceivedONE(
                        userName, ROOM_IDS.OUT_OF_THE_SYSTEM_ROOM)
                elif idSalon == 0:
                    self.clientProxy.userUpdateReceivedONE(
                        userName, ROOM_IDS.MAIN_ROOM)
                else:
                    roomName = list(movieIds.keys())[list(
                        movieIds.values()).index(idSalon)]
                    print(roomName)
                    self.clientProxy.userUpdateReceivedONE(userName, roomName)

    def sendAck(self, seq, host_port):
        typeM = self.dec2bin(63, 6)
        seqM = self.dec2bin(seq, 10)
        st = seqM + typeM
        msg = bytearray(4)
        struct.pack_into('!hh', msg, 0, 4, int(st, 2))
        self.transport.write(msg, host_port)

    def dec2bin(self, decimal, nbbits):
        if decimal == 0:
            return "0".zfill(nbbits)
        result = ""
        while decimal != 0:
            decimal, rest = divmod(decimal, 2)
            result = "01"[rest] + result
        return result.zfill(nbbits)

    #RETOURNE lE NUM DE SEQ ET LE TYPE DE TRAME
    def getSeqType(self, st):
        st = self.dec2bin(st, 16)
        seq = st[:10]
        types = st[10:16]
        return int(seq, 2), int(types,
                                2)  #tupple[0] = sequence, tupple[1] = type

    def sender(self, taille, typeM, data, host_port):

        typeM = self.dec2bin(typeM, 6)  #conversion du type sur 6 bit
        seqM = self.dec2bin(self.seq, 10)  #conversion seq sur 6 bit
        self.seq += 1

        st = seqM + typeM  #on concatene sequence et type

        buf = bytearray(4)
        struct.pack_into('!hh', buf, 0, taille + 4, int(st, 2))

        if data != None:
            buf = buf + data

        self.transport.write(buf, host_port)
class c2wUdpChatServerProtocol(DatagramProtocol):
    def __init__(self, serverProxy, lossPr):
        print('begin the initilization of this class')
        """
        :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 lossPr: The packet loss probability for outgoing packets.  Do
            not modify this value!

        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:: serverProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """
        #: The serverProxy, which the protocol must use
        #: to interact with the server (to access the movie list and to
        #: access and modify the user list).
        self.serverProxy = serverProxy
        self.lossPr = lossPr
        self.ackReceived = {}
        self.num = 0
        #iniitilization of sequence number is 0

        self.online = 0
        #self.online: the number of users in the server, to ensure if the server is sature

        #test correct:self.resend = None
        self.tryTime = {}
        self.numAttendu = {}
        self.resend = None

        self.isSend = {}
        self.wasReceived = True

        print('firstly show the movie list', self.serverProxy.getMovieList)
        self.movieList = {}

        for m in self.serverProxy.getMovieList():

            print("Movie title: ", m.movieTitle, m.movieId)
            print('ip', self.serverProxy.getMovieAddrPort(m.movieTitle)[0])
            print('port', self.serverProxy.getMovieAddrPort(m.movieTitle)[1])
            self.serverProxy.startStreamingMovie(m.movieTitle)

            #begin the streaming in all movie rooms
            #heer can be better: if this movie room is no person, we can stop the streaming
            self.movieList[m.movieTitle] = [0, []]
        print('movie list is ', self.movieList)

        print('test user list in server', self.serverProxy.getUserList())
        print('write a fonction which starts when the procedure is lanced')
        self.list = {}
        ticks = time.time()
        print('for thesfdfdsd present time is:', ticks)

    def numConstruct(self):
        #each time before we send a datagram need to generate a number sequence
        # and agument self.num which means the next number seq ready to be sent
        # ensure the number returns to 0 when it arrives at 2047
        numSequence = self.num
        if self.num == 2047:
            self.num = 0
        else:
            self.num += 1
        return numSequence

        #okay

    def testUsername(self, username):
        #param: username  in format string
        #in spec we know that the format of username need to be:
        #1. the length is not over 255 caracteres
        #2. it begin by a alphabet and maybe some alphabet/numbers
        if (len(username) > 256):
            print('the length of username is too long so that no valid')
            return false
        else:
            if not (username[0].isalpha()):
                print('the beginning of username is not an alphabet')
                return False
            else:
                if not (username[1:].isalnum()):
                    print('the following string of username isnot num/alpha ')
                    return False
                else:
                    return True

    def sendMovieRoom(self, host_port):
        NumSalonP = 0
        salonP = []
        salonList = {}

        corps0 = b''

        for u in self.serverProxy.getUserList():
            print(u)
            if (u.userChatRoom == ROOM_IDS.MAIN_ROOM):
                print('this user is in the main room')
                NumSalonP += 1
                salonP.append(u.userName)
            else:
                print('gergze', u.userChatRoom)
                print(self.movieList)
                if u.userChatRoom in self.movieList:
                    self.movieList[u.userChatRoom][0] += 1
                    self.movieList[u.userChatRoom][1].append(u.userName)

        corps0 += struct.pack('>H', NumSalonP)
        print('exam for movie list: slef', self.movieList)
        for i in salonP:
            i = i.encode("utf-8")
            corps0 += struct.pack('b%ds' % len(i), len(i), i)
        for i in self.movieList:
            corps0 += struct.pack('>H', self.movieList[i][0])
            if not (self.movieList[i][1] == 0):
                print('this moivie room is not empty')
                for i in self.movieList[i][1]:
                    i = i.encode("utf-8")
                    corps0 += struct.pack('b%ds' % len(i), len(i), i)

        print(corps0, 'corps0 check itself')

        TypeBin = bin(19)
        Type0 = TypeBin[2:].rjust(8, "0")

        numSequence = self.num
        self.num += 1
        NumSeqBin = bin(numSequence)
        NumSeqUserList = NumSeqBin[2:].rjust(10, "0")

        LongueurInt = 1 + len(corps0) + 1
        LongueurBin = bin(LongueurInt)
        Longueur0 = LongueurBin[2:].rjust(14, "0")

        #datagram_UserList=struct.pack('>IH',int(Type0+NumSeqUserList+Longueur0,2),numSalon)+corps0
        datagram_UserList = struct.pack(
            '>IH', int(Type0 + NumSeqUserList + Longueur0, 2), 2) + corps0

        self.transport.write(datagram_UserList, host_port)
        print('datagram of user list', datagram_UserList)

        movieListDatagram = self.movieListDatagram()

        self.sendDatagram(1, len(movieListDatagram), movieListDatagram,
                          host_port)

    def sendAndWait(self, datagram, numSeq, host_port):
        print('12')
        print(numSeq, datagram, host_port)
        if (self.wasReceived):
            reactor.callLater(5, self.sendAndWait, datagram, numSeq, host_port)
        else:

            if self.tryTime[numSeq] <= 4 and self.ackReceived[numSeq] == False:
                print('send agaim')
                self.transport.write(datagram, host_port)
                print('resend the datagram', datagram)
                self.tryTime[numSeq] += 1
                self.resend[numSeq] = reactor.callLater(
                    5, self.sendAgain, datagram, numSeq, host_port)
            else:
                if (self.ackReceived[numSeq] == True):
                    self.wasReceived = True
                    print('this datagram has been responded', datagram)
                elif (self.tryTime[numSeq] > 4):
                    print('time our for the datagram\'s ack', datagram)
                    userToDelete = self.serverProxy.getUserByAddress(host_port)

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport
        nomMovie = 0

        for m in self.serverProxy.getMovieList():
            nomMovie += 1
            print("Movie title: ", m.movieTitle, m.movieId)
            print('ip port',
                  self.serverProxy.getMovieAddrPort(m.movieTitle)[0])
        print(nomMovie)

    def checkAck(self, host_port):
        print('now we are testing the ack')
        delay(1000)
        print('the ack is not received within 1000')
        return 0

    '''
    def numConstruct(self):
        numSequence=self.num
        self.num+=1
        return numSequence 
        '''

    def getTypeFromDatagram(self, datagram):
        #typeDatagram: int
        typeDatagram = struct.unpack('b', datagram[0:1])[0]
        return typeDatagram

    def getNumSeqFromDatagram(self, datagram):
        #numSequence: int
        unpack = struct.unpack('>I', datagram[0:4])
        print('unpack', bin(unpack[0])[2:].rjust(32, '0')[-24:-14])
        numSeq = int(bin(unpack[0])[2:].rjust(32, '0')[-24:-14], 2)
        return numSeq

    def ackConstructor(self, datagram):
        typeAck = 80
        dataHead = struct.unpack('>I', datagram[0:4])
        #split the number of sequence in this datagram

        numSeq = bin(dataHead[0])[2:].rjust(32, '0')[-24:-14]
        print(numSeq, 'number of seq')
        lengthAck = bin(0)[2:].rjust(14, "0")
        print(bin(typeAck)[2:].rjust(8, "0"), numSeq, lengthAck, 'check ack')
        ackInt = int(bin(typeAck)[2:].rjust(8, "0") + numSeq + lengthAck, 2)
        ack = struct.pack('>I', ackInt)
        return ack

    def getNumSeqFromAck(self, ack):
        #split the number of sequence from ack datagram
        unpack = struct.unpack('>I', ack)
        numSeq = int(bin(unpack[0])[-24:-14], 2)
        return numSeq

    def connFailedConstr(self):
        typeBin = bin(2)[2:].rjust(8, "0")
        numSequence = self.numConstruct()

        numSeqBin = bin(numSequence)[2:].rjust(10, "0")
        lengthBin = bin(0)[2:].rjust(14, "0")

        datagram = struct.pack('>I', int(typeBin + numSeqBin + lengthBin, 2))
        numSeq = int(numSeqBin, 2)
        return numSeq, datagram

    def errorConstr(self, error):
        typeBin = bin(128)[2:].rjust(8, "0")
        numSequence = self.numConstruct()

        numSeqBin = bin(numSequence)[2:].rjust(10, "0")

        lengthBin = bin(len(error) + 1)[2:].rjust(14, "0")
        head = typeBin + numSeqBin + lengthBin

        datagram = struct.pack('>Ib%ds' % len(error), int(head, 2), len(error),
                               error.encode('utf-8'))

        numSeq = int(numSeqBin, 2)
        return numSeq, datagram

    def movieListDatagram(self):
        self.numMovie = 0
        corpsMovie = b''
        for m in self.serverProxy.getMovieList():
            ip = self.serverProxy.getMovieAddrPort(m.movieTitle)[0]
            ip = re.findall(r"\d+", ip)
            print('show me the ip after process', ip)
            port = self.serverProxy.getMovieAddrPort(m.movieTitle)[1]
            print('show me the port number ', port)
            port = bin(port)
            port = port[2:].rjust(14, "0")

            movieName = m.movieTitle
            movieName = movieName.encode("utf-8")
            print('shoe me the length of movie name', len(movieName),
                  type(len(movieName)))
            #corps+=struct.pack('b',len(movieName))

            corpsMovie += struct.pack('b%ds4b' % len(movieName),
                                      len(movieName), movieName, int(ip[0]),
                                      int(ip[1]), int(ip[2]), int(ip[3]))
            corpsMovie += struct.pack('>H', int(port, 2))
            self.numMovie += 1

        movieListDatagram = struct.pack('>H', self.numMovie) + corpsMovie
        return movieListDatagram

    def sendAgain(self, datagram, numSeq, host_port):
        print('12')
        print(numSeq, datagram, host_port)

        if self.tryTime[numSeq] <= 4 and self.ackReceived[numSeq] == False:
            print('send agaim')
            self.transport.write(datagram, host_port)
            print('resend the datagram', datagram)
            self.tryTime[numSeq] += 1
            reactor.callLater(5, self.sendAgain, datagram, numSeq, host_port)
        else:
            if (self.ackReceived[numSeq] == True):
                print('this datagram has been responded', datagram)
            elif (self.tryTime[numSeq] > 4):
                print('time our for the datagram\'s ack', datagram)

    def sendDatagram(self, typeDatagram, longueur, Corps, host_port):
        typeDatagramBin = bin(typeDatagram)[2:].rjust(8, "0")
        numSeqInt = self.numConstruct()
        numSeqBin = bin(numSeqInt)[2:].rjust(14, '0')
        longueurBin = bin(longueur)[2:].rjust(10, "0")
        print(typeDatagramBin + numSeqBin + longueurBin,
              'test in senddatagram')
        datagram = struct.pack(
            '>I', int(typeDatagramBin + numSeqBin + longueurBin, 2)) + Corps
        self.transport.write(datagram, host_port)

    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.
        """
        print('receice a datagram from', datagram, host_port)
        #here if need a test for mal format message
        typeDatagram = self.getTypeFromDatagram(datagram)
        print('receice a datagram from', datagram, host_port,
              'at the type of:', typeDatagram)

        #except we receive an acquitement, we must send back a message of acquitement
        numReceived = self.getNumSeqFromDatagram(datagram)

        if (typeDatagram == 80):
            print('now the server receive an ack from client:', datagram)
            numSeqAck = self.getNumSeqFromAck(datagram)
            print('the number of sequence ack is:', numSeqAck)
            self.ackReceived[numSeqAck] = True

        if not host_port in self.isSend:
            self.isSend[host_port] = True
            self.numAttendu[host_port] = 0

        if (typeDatagram != 80):
            '''    
                if not (numReceived==self.numAttendu[host_port]):
                
                print(numReceived,self.numAttendu)
                print('the number sequence received is not the num seq wait')
                numSeq,errorDatagram=self.errorConstr('Numero de sequence inattendu')
                print('send tht datagram of error:',errorDatagram)
                self.ackReceived[numSeq]=False
                self.transport.write(errorDatagram,host_port)
                return 
                #if the number of sequence is not correct, ignore this message
                '''
            self.numAttendu[host_port] += 1
            ack = self.ackConstructor(datagram)
            print('send an ack:', ack, 'to be a response of datagram:',
                  datagram)
            self.transport.write(ack, host_port)

            if (typeDatagram == 0):

                print('this is a request of connection to server')
                print(datagram[5:])
                print(len(datagram[5:]))
                userName = struct.unpack('%ds' % len(datagram[5:]),
                                         datagram[5:])[0].decode("utf-8")

                userNameLength = len(userName)
                userNameComplete = str(userNameLength) + userName
                print('THE INPUT USERNAME IS :', userName, 'username complete',
                      userNameComplete)

                if (self.online >= 512):

                    print(
                        'now the server is sature and no longer resource for a new user'
                    )

                    numSeq, datagram = self.connFailedConstr()
                    self.transport.write(datagram, host_port)
                    self.ackReceived[numSeq] = False
                    print('send a datagtam refuse', datagram)
                    print('set self.ackReceived:', numSeq, 'to false')
                    numSeq, errorDatagram = self.errorConstr('Serveur sature')
                    print('send tht datagram of error:', errorDatagram)
                    self.ackReceived[numSeq] = False
                    self.transport.write(errorDatagram, host_port)
                    print('set self.ackReceived:', numSeq, 'to false')
                elif (self.testUsername(userName) == False):
                    print('this username is not in the correct format')
                    numSeq, datagram = self.connFailedConstr()
                    self.transport.write(datagram, host_port)
                    self.ackReceived[numSeq] = False
                    print('send a datagtam refuse', datagram)
                    print('set self.ackReceived:', numSeq, 'to false')
                    numSeq, errorDatagram = self.errorConstr(
                        'Mauvais nom d’utilisateurur')
                    print('send tht datagram of error:', errorDatagram)
                    self.ackReceived[numSeq] = False
                    self.transport.write(errorDatagram, host_port)
                    typeDatagram = struct.unpack('>b', errorDatagram[0:1])
                    print(typeDatagram[0], 'typeDatagram errror',
                          errorDatagram)
                    print('set self.ackReceived:', numSeq, 'to false')
                elif (self.serverProxy.userExists(userName)):
                    print(
                        'this username is already in use and existing user list:',
                        self.serverProxy.getUserList())
                    numSeq, datagram = self.connFailedConstr()
                    self.transport.write(datagram, host_port)
                    self.ackReceived[numSeq] = False
                    print('send a datagtam refuse', datagram)
                    print('set self.ackReceived:', numSeq, 'to false')

                    numSeq, errorDatagram = self.errorConstr(
                        'Utilisateur deja existant')
                    print('send tht datagram of error:', errorDatagram)
                    self.ackReceived[numSeq] = False
                    self.transport.write(errorDatagram, host_port)
                    print('set self.ackReceived:', numSeq, 'to false')
                else:
                    print('this user can be allowed in')
                    print('test the user list:',
                          self.serverProxy.getUserList())
                    self.online += 1
                    #this username is admitted
                    print('username valid')
                    TypeBin = bin(1)
                    Type = TypeBin[2:].rjust(8, "0")
                    numSequence = self.numConstruct()
                    NumSeqBin = bin(numSequence)
                    NumSeq = NumSeqBin[2:].rjust(10, "0")

                    LongueurInt = 0
                    LongueurBin = bin(LongueurInt)
                    Longueur = LongueurBin[2:].rjust(14, "0")
                    print(Type + NumSeq + Longueur, 'datagram beform packing')

                    datagram = struct.pack('>I',
                                           int(Type + NumSeq + Longueur, 2))

                    self.transport.write(datagram, host_port)
                    self.tryTime[numSequence] = 0
                    self.ackReceived[numSequence] = False
                    #CORRECT:self.resend = reactor.callLater(5,self.sendAndWait,datagram,numSequence,host_port) $
                    print('check resend', self.resend)
                    self.resend = {}
                    self.resend[numSequence] = None
                    self.resend[numSequence] = reactor.callLater(
                        5, self.sendAgain, datagram, numSequence, host_port)
                    print(self.tryTime, self.resend)
                    for i in self.serverProxy.getUserList():
                        print(i, 'test all user in the list 1420')
                    print('final test for user list',
                          self.serverProxy.getUserList())
                    self.serverProxy.addUser(userName, ROOM_IDS.MAIN_ROOM,
                                             None, host_port)

                    #self.serverProxy.addUser('linue', 'Great Guy')
                    print('check if user is add to the list',
                          self.serverProxy.getUserList())
                    #now we send a datagram of movie list to client

                    #numSalon initial 1 cause we must have a main room

                    NumSalonP = 0
                    salonP = []
                    salonList = {}

                    corps0 = b''
                    print('test for user list change while a new user',
                          self.serverProxy.getUserList())
                    '''
                                [<Instance of c2wUser; userName=alice, userChatRoom=<class 'c2w.main.constants.ROOM_IDS.MAIN_ROOM'>, 
                                userChatInstance=None, userAddress=('127.0.0.1', 46602)>, <Instance of c2wUser; 
                                userName=aliceff, userChatRoom=<class 'c2w.main.constants.ROOM_IDS.MAIN_ROOM'>, userChatInstance=None, userAddress=('127.0.0.1', 36153)>]
                                '''
                    self.movieList0 = {}

                    for m in self.serverProxy.getMovieList():
                        self.movieList0[m.movieTitle] = [0, []]

                    for u in self.serverProxy.getUserList():
                        print(u)
                        if (u.userChatRoom == ROOM_IDS.MAIN_ROOM):
                            print('this user is in the main room')
                            NumSalonP += 1
                            salonP.append(u.userName)
                        else:
                            if u.userChatRoom in self.movieList:
                                self.movieList0[u.userChatRoom][0] += 1
                                self.movieList0[u.userChatRoom][1].append(
                                    u.userName)
                    self.movieList = self.movieList0
                    corps0 += struct.pack('>H', NumSalonP)
                    print('test salonP', salonP)
                    print('exam for movie list: slef', self.movieList)
                    for i in salonP:
                        i = i.encode("utf-8")
                        corps0 += struct.pack('b%ds' % len(i), len(i), i)
                    for i in self.movieList:
                        corps0 += struct.pack('>H', self.movieList[i][0])
                        if not (self.movieList[i][1] == 0):
                            print('this moivie room is not empty')
                            for i in self.movieList[i][1]:
                                i = i.encode("utf-8")
                                corps0 += struct.pack('b%ds' % len(i), len(i),
                                                      i)

                    print(corps0, 'corps0 check itself')

                    TypeBin = bin(19)
                    Type0 = TypeBin[2:].rjust(8, "0")
                    Type0 = TypeBin[2:].rjust(8, "0")

                    numSequence = self.num
                    self.num += 1
                    NumSeqBin = bin(numSequence)
                    NumSeqUserList = NumSeqBin[2:].rjust(10, "0")

                    LongueurInt = 1 + len(corps0) + 1
                    LongueurBin = bin(LongueurInt)
                    Longueur0 = LongueurBin[2:].rjust(14, "0")

                    #datagram_UserList=struct.pack('>IH',int(Type0+NumSeqUserList+Longueur0,2),numSalon)+corps0
                    datagram_UserList = struct.pack(
                        '>IH', int(Type0 + NumSeqUserList + Longueur0, 2),
                        len(self.movieList) + 1) + corps0

                    #self.transport.write(datagram_UserList,host_port)
                    sendList = []
                    for u in self.serverProxy.getUserList():
                        print(u.userChatRoom)

                        if (u.userChatRoom == ROOM_IDS.MAIN_ROOM):
                            sendList.append(u.userAddress)
                    print('send list check', sendList)
                    if (len(sendList) > 0):
                        for i in sendList:
                            self.transport.write(datagram_UserList, i)

                    print('datagram of user list', datagram_UserList)

                    movieListDatagram = self.movieListDatagram()

                    self.sendDatagram(16, len(movieListDatagram),
                                      movieListDatagram, host_port)

                    #corps+=struct.pack('b%ds4b>H'%len(movieName),len(movieName),movieName,ip[0],ip[1],ip[2],ip[3],int(port,2))
                    #movieList.apppend((m.movieTitle,self.serverProxy.getMovieAddrPort(m.movieTitle)[0],self.serverProxy.getMovieAddrPort(m.movieTitle)[1]))
                '''
                        
                        
                        print('add a user in the list of user')
                        
                        start_end[numSequence]=timeit.timeit()
                        print('test the start time of waiting an ack',start_end[numSequence], start_end)
                        
                        print('room ids ',ROOM_IDS.MAIN_ROOM)
                        
                        #now we need to send a datagram about movie list to client
                        
                        self.transport.write(movieList,host_port)
                        
                        
                        for m in self.serverProxy.getMovieList():
                                print('get movie list',m.movieId)
                        for u in self.serverProxy.getUserList():
                                print('user name: ', u.userName,u.userChatRoom)
                                if(u.userChatRoom==ROOM_IDS.MAIN_ROOM):
                                        print('okay')
                                if not(u.userChatRoom==ROOM_IDS.MOVIE_ROOM):
                                        print(' not okay')
                        
                        #if this datagram for connection is not received by our client
                        #this means the ack from client is not received here'''

            elif (typeDatagram == 48 or typeDatagram == 49):
                print(
                    'now the server receives an request of entring/quitting the video room',
                    typeDatagram)

                typeAck = 80
                # numSeq=datagramSplit(datagram)
                dataHead = struct.unpack('>I', datagram[0:4])
                #print(dataHead,'datahead')
                numSequenceBin = (bin(dataHead[0])[2:].rjust(32, '0')[8:18])

                numSeq = numSequenceBin

                longueur = bin(0)
                longueurAck = longueur[2:].rjust(14, "0")
                ack0bin = bin(typeAck)[2:].rjust(8, "0") + numSeq + longueurAck
                ack0 = int(ack0bin, 2)

                ack = struct.pack('>I', ack0)
                self.transport.write(ack, host_port)
                print('send an ack for entring the video room', ack)
                if (typeDatagram == 48):

                    lenroomName = datagram[4]
                    roomName = struct.unpack('%ds' % lenroomName,
                                             datagram[5:])[0].decode('utf-8')
                    #self.serverProxy.addUser(userName,ROOM_IDS.MOVIE_ROOM,None,host_port)

                    print('now the user is in the room', roomName)
                    print('show me the user List now',
                          self.serverProxy.getUserList())
                    print(
                        'username to change its position',
                        self.serverProxy.getUserByAddress(host_port).userName)

                    self.serverProxy.updateUserChatroom(
                        self.serverProxy.getUserByAddress(host_port).userName,
                        roomName)
                    print('show me the user List now WHEN I ENTER MOVIE ROOM',
                          self.serverProxy.getUserList())
                else:
                    roomBefore = self.serverProxy.getUserByAddress(
                        host_port).userChatRoom
                    self.serverProxy.updateUserChatroom(
                        self.serverProxy.getUserByAddress(host_port).userName,
                        ROOM_IDS.MAIN_ROOM)
                    print('show me the user List now WHEN I QUIT MOVIE ROOM',
                          self.serverProxy.getUserList())
                    Type0 = bin(18)[2:].rjust(8, "0")
                    numSequence = self.num
                    self.num += 1
                    NumSeqBin = bin(numSequence)
                    NumSeqUserList = NumSeqBin[2:].rjust(10, "0")

                    corps = b''

                    sendListRoom = []
                    peopleRoom = []
                    for u in self.serverProxy.getUserList():
                        print(u.userChatRoom, roomBefore)
                        if (u.userChatRoom == roomBefore):
                            print('hi a friend in this movie room')

                            sendListRoom.append(u.userAddress)
                            peopleRoom.append(u.userName)

                    if (len(peopleRoom) > 0):

                        corps += struct.pack('>H', len(peopleRoom))
                        for i in peopleRoom:
                            corps += struct.pack('b%ds' % len(i), len(i),
                                                 i.encode('utf-8'))
                        print('send list check', sendListRoom)

                    LongueurInt = len(corps)
                    LongueurBin = bin(LongueurInt)
                    Longueur0 = LongueurBin[2:].rjust(14, "0")
                    head = Type0 + NumSeqUserList + Longueur0
                    datagram = struct.pack('>I', int(head, 2)) + corps
                    if (len(sendListRoom) > 0):
                        print('send list to users in salon', datagram)
                        for i in sendListRoom:
                            self.transport.write(datagram, i)

                NumSalonP = 0
                salonP = []
                salonList = {}

                corps0 = b''
                print('test for user list change while a new user',
                      self.serverProxy.getUserList())
                '''
                        [<Instance of c2wUser; userName=alice, userChatRoom=<class 'c2w.main.constants.ROOM_IDS.MAIN_ROOM'>, 
                        userChatInstance=None, userAddress=('127.0.0.1', 46602)>, <Instance of c2wUser; 
                        userName=aliceff, userChatRoom=<class 'c2w.main.constants.ROOM_IDS.MAIN_ROOM'>, userChatInstance=None, userAddress=('127.0.0.1', 36153)>]
                        '''

                self.movieList0 = {}
                for u in self.serverProxy.getUserList():
                    print(u)
                    if (u.userChatRoom == ROOM_IDS.MAIN_ROOM):
                        print('this user is in the main room')
                        NumSalonP += 1
                        salonP.append(u.userName)
                    else:

                        for m in self.serverProxy.getMovieList():
                            self.movieList0[m.movieTitle] = [0, []]
                        print('test userchatroom and movie list',
                              u.userChatRoom, self.movieList)
                        if u.userChatRoom in self.movieList:
                            print('yes fina a user in movie room')
                            self.movieList0[u.userChatRoom][0] += 1
                            self.movieList0[u.userChatRoom][1].append(
                                u.userName)

                self.movieList = self.movieList0
                corps0 += struct.pack('>H', NumSalonP)
                print('test salonP', salonP)
                print('exam for movie list: self', self.movieList)
                for i in salonP:
                    i = i.encode("utf-8")
                    corps0 += struct.pack('b%ds' % len(i), len(i), i)
                for i in self.movieList:
                    corps0 += struct.pack('>H', self.movieList[i][0])
                    if not (self.movieList[i][1] == []):
                        print('this moivie room is not empty')
                        for i in self.movieList[i][1]:
                            i = i.encode("utf-8")
                            corps0 += struct.pack('b%ds' % len(i), len(i), i)
                print(corps0, 'corps0 check itself')

                TypeBin = bin(19)
                Type0 = TypeBin[2:].rjust(8, "0")

                numSequence = self.num
                self.num += 1
                NumSeqBin = bin(numSequence)
                NumSeqUserList = NumSeqBin[2:].rjust(10, "0")

                LongueurInt = 1 + len(corps0) + 1
                LongueurBin = bin(LongueurInt)
                Longueur0 = LongueurBin[2:].rjust(14, "0")

                #datagram_UserList=struct.pack('>IH',int(Type0+NumSeqUserList+Longueur0,2),numSalon)+corps0
                datagram_UserList = struct.pack(
                    '>IH', int(Type0 + NumSeqUserList + Longueur0, 2),
                    len(self.movieList) + 1) + corps0

                #self.transport.write(datagram_UserList,host_port)
                sendList = []
                for u in self.serverProxy.getUserList():
                    print(u.userChatRoom)
                    if (u.userChatRoom == ROOM_IDS.MAIN_ROOM):
                        sendList.append(u.userAddress)

                print('send list check', sendList)
                if (len(sendList) > 0):
                    for i in sendList:
                        self.transport.write(datagram_UserList, i)

                print('datagram of user list for type 48 / 49',
                      datagram_UserList)

                if (typeDatagram == 48):

                    Type0 = bin(18)[2:].rjust(8, "0")
                    numSequence = self.num
                    self.num += 1
                    NumSeqBin = bin(numSequence)
                    NumSeqUserList = NumSeqBin[2:].rjust(10, "0")

                    corps = b''

                    sendListRoom = []
                    peopleRoom = []
                    for u in self.serverProxy.getUserList():
                        print(u.userChatRoom, roomName)
                        if (u.userChatRoom == roomName):
                            print('hi a friend in this movie room')

                            sendListRoom.append(u.userAddress)
                            peopleRoom.append(u.userName)

                    if (len(peopleRoom) > 0):

                        corps += struct.pack('>H', len(peopleRoom))
                        for i in peopleRoom:
                            corps += struct.pack('b%ds' % len(i), len(i),
                                                 i.encode('utf-8'))
                        print('send list check', sendListRoom)

                    LongueurInt = len(corps)
                    LongueurBin = bin(LongueurInt)
                    Longueur0 = LongueurBin[2:].rjust(14, "0")
                    head = Type0 + NumSeqUserList + Longueur0
                    datagram = struct.pack('>I', int(head, 2)) + corps
                    if (len(sendListRoom) > 0):
                        print('send list to users in salon', datagram)
                        for i in sendListRoom:
                            self.transport.write(datagram, i)

            elif (typeDatagram == 3):
                print('now there is a user who wanna quit the system',
                      host_port)
                #del self.numAttendu[host_port]
                self.serverProxy.removeUser(
                    self.serverProxy.getUserByAddress(host_port).userName)
                #self.serverProxy.updateUserChatroom(self.serverProxy.getUserByAddress(host_port).userName,ROOM_IDS.OUT_OF_THE_SYSTEM_ROOM)

                self.online -= 1
                print('self.online', self.online)
                print('show me the user List when someOne LEAVE',
                      self.serverProxy.getUserList())

                NumSalonP = 0
                salonP = []
                salonList = {}

                corps0 = b''
                print('test for user list change while a new user',
                      self.serverProxy.getUserList())
                '''
                        [<Instance of c2wUser; userName=alice, userChatRoom=<class 'c2w.main.constants.ROOM_IDS.MAIN_ROOM'>, 
                        userChatInstance=None, userAddress=('127.0.0.1', 46602)>, <Instance of c2wUser; 
                        userName=aliceff, userChatRoom=<class 'c2w.main.constants.ROOM_IDS.MAIN_ROOM'>, userChatInstance=None, userAddress=('127.0.0.1', 36153)>]
                        '''
                self.movieList0 = {}

                for m in self.serverProxy.getMovieList():
                    self.movieList0[m.movieTitle] = [0, []]
                for u in self.serverProxy.getUserList():
                    print(u)
                    if (u.userChatRoom == ROOM_IDS.MAIN_ROOM):
                        print('this user is in the main room')
                        NumSalonP += 1
                        salonP.append(u.userName)
                    else:
                        if u.userChatRoom in self.movieList:
                            self.movieList0[u.userChatRoom][0] += 1
                            self.movieList0[u.userChatRoom][1].append(
                                u.userName)
                self.movieList = self.movieList0
                corps0 += struct.pack('>H', NumSalonP)
                print('test salonP', salonP)
                print('exam for movie list: slef', self.movieList)
                for i in salonP:
                    i = i.encode("utf-8")
                    corps0 += struct.pack('b%ds' % len(i), len(i), i)
                for i in self.movieList:
                    corps0 += struct.pack('>H', self.movieList[i][0])
                    if not (self.movieList[i][1] == 0):
                        print('this moivie room is not empty')
                        for i in self.movieList[i][1]:
                            i = i.encode("utf-8")
                            corps0 += struct.pack('b%ds' % len(i), len(i), i)

                print(corps0, 'corps0 check itself')

                TypeBin = bin(19)
                Type0 = TypeBin[2:].rjust(8, "0")
                Type0 = TypeBin[2:].rjust(8, "0")

                numSequence = self.num
                self.num += 1
                NumSeqBin = bin(numSequence)
                NumSeqUserList = NumSeqBin[2:].rjust(10, "0")

                LongueurInt = 1 + len(corps0) + 1
                LongueurBin = bin(LongueurInt)
                Longueur0 = LongueurBin[2:].rjust(14, "0")

                #datagram_UserList=struct.pack('>IH',int(Type0+NumSeqUserList+Longueur0,2),numSalon)+corps0
                datagram_UserList = struct.pack(
                    '>IH', int(Type0 + NumSeqUserList + Longueur0, 2),
                    len(self.movieList) + 1) + corps0

                #self.transport.write(datagram_UserList,host_port)
                sendList = []
                for u in self.serverProxy.getUserList():
                    print(u.userChatRoom)

                    if (u.userChatRoom == ROOM_IDS.MAIN_ROOM):
                        sendList.append(u.userAddress)
                print('send list check', sendList)
                if (len(sendList) > 0):
                    for i in sendList:
                        self.transport.write(datagram_UserList, i)

                print('boss int quit 3 test: datagram of user list',
                      datagram_UserList)

            elif (typeDatagram == 64):
                print('there is a user speaking')

                datagram = struct.pack('b', 65) + datagram[1:]

                lenUsername = datagram[4]

                userName = struct.unpack('%ds' % lenUsername,
                                         datagram[5:5 + lenUsername])[0]
                userName = userName.decode('utf-8')
                print('test userbnal talking', userName, len(userName))
                uSend = self.serverProxy.getUserByName(userName)
                print('user name in 64', userName)
                sendList = []
                for u in self.serverProxy.getUserList():

                    if (not u == uSend
                            and u.userChatRoom == uSend.userChatRoom):
                        sendList.append(u.userAddress)
                print('test send list', sendList)
                if (len(sendList) > 0):
                    for i in sendList:
                        self.transport.write(datagram, i)
class c2wUdpChatServerProtocol(DatagramProtocol):
    def __init__(self, serverProxy, lossPr):
        """
        :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 lossPr: The packet loss probability for outgoing packets.  Do
            not modify this value!

        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:: serverProxy
            The serverProxy, which the protocol must use
            to interact with the user and movie store in the server.

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """
        #: The serverProxy, which the protocol must use
        #: to interact with the server (to access the movie list and to
        #: access and modify the user list).
        self.serverProxy = serverProxy
        self.lossPr = lossPr
        self.num_seq = {}
        self.user_adress = {}
        self.received_packet_history = {}
        self.sent_packet_history = {}
        self.expected_num_seq = {}
        self.errorList = [
            "nonExpectedNumSeq", "wrongUserName", "serverSaturated",
            "userExists"
        ]
        self.timer = {}
        self.movieRoom = {}
        self.errorDict = {}

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

        self.sendAndWait = True

        self.queuepacket = []

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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)

    def forward(self, packet, datagram, host_port, user_name):

        len_sender = struct.unpack_from('!B', datagram, 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, datagram)

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

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

            if self.movieRoom[packet.data[1].decode(
                    'utf8')] == ROOM_IDS.MAIN_ROOM:
                sender_chat_room = "main_room"
            else:
                sender_chat_room = self.movieRoom[packet.data[1].decode(
                    'utf8')]

            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, self.num_seq[receiver],
                                       packet.packet_length, packet.data,
                                       format)
                #messagePacket.packet_format="!LB" + str(self.data[0]) + 's' + "B" + str(self.data[2]) + 's'
                self.sendPacket(
                    messagePacket,
                    self.serverProxy.getUserByName(receiver).userAddress)
                print("FORWARD6")
                i += 1

    def connectionMovieRoom(self, datagram, packet, host_port, 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)
        # the joined room
        if self.existMovie(packet.data[1].decode("utf-8")) == False:
            self.error('Movie Room Does Not Exist', host_port, user_name)
            print(packet.data[1].decode("utf-8"), 'Movie Room Does Not Exist',
                  self.serverProxy.getMovieList())
        else:
            print('the room does exist ')
            self.movieRoom[user_name] = (packet.data[1].decode("utf-8"))
            # mettre à jour la liste des utilisateur du movie room dans le serveur
            self.serverProxy.updateUserChatroom(user_name,
                                                self.movieRoom[user_name])
            # self.serverProxy.startStreamingMovie(self.movieRoom[user_name])
            self.updateUserList(movie_room=self.movieRoom[user_name])

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

    def leaveSystem(self, user_name):

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

    def deconnectionMovieRoom(self, datagram, packet, host_port, user_name):

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

        self.updateUserList(movie_room=old_movie_room)
        print('sent_packet_history', self.sent_packet_history)
        print('received_packet_history', self.received_packet_history)

    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)

    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, host_port):

        ack = Packet(80, packet.num_seq, 0, None)
        self.transport.write(ack.pack(), host_port)
        print('ACKACKACK')

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

    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

    def wrongExpectedNumSeq(self, host_port, user_name):
        self.error('wrongNumSeq:' + str(self.expected_num_seq[user_name]),
                   host_port)

    def failed(self, host_port):

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

    def sendMovieList(self, user_name, host_port):
        # 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[user_name], length, data,
                                   format)

        self.sendPacket(movie_list_packet, host_port)

    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:
                    self.sendUserListMainRoom(user.userName, user.userAddress)
        #update user list
        else:

            for user in user_list:

                if user.userChatRoom == movie_room:
                    self.sendUserListMovieRoom(user, user.userChatRoom)
                elif user.userChatRoom == ROOM_IDS.MAIN_ROOM:
                    self.sendUserListMainRoom(user.userName, user.userAddress)

    def sendUserListMovieRoom(self, user, 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, self.num_seq[user.userName], 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"))

        self.sendPacket(update_user_list_packet, user.userAddress)

    def sendUserListMainRoom(self, user_name, host_port):
        user_list_packet = Packet(19, self.num_seq[user_name], 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, host_port)

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

        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

        if self.sendAndWait == True and call_count == 1:

            print('SERVER SEND PACKET', packet)
            self.transport.write(packet.pack(), host_port)

            self.sent_packet_history[user_name][packet.num_seq] = packet

            self.sendAndWait = False

            call_count += 1

            if call_count <= 4:
                self.timer[user_name] = reactor.callLater(
                    5, self.sendPacket, packet, host_port, call_count)
        elif call_count > 1:

            print('SERVER SEND PACKET', packet)
            self.transport.write(packet.pack(), host_port)

            call_count += 1

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

        else:

            self.queuepacket.append((packet, host_port))

    def sendqueuepacket(self):
        print("SEND AND WAIIIIIT")
        for packethost in self.queuepacket:
            self.sendPacket(*packethost)

        self.queuepacket = []

#                   UTILS

    def lastPacketReceived(self, user_name):

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

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

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

    def nlastPacketSent(self, user_name, i):
        if len(self.sent_packet_history[user_name]) > (
                len(self.sent_packet_history[user_name].keys()) - i) and (
                    len(self.sent_packet_history[user_name].keys()) - i) >= 0:
            return self.sent_packet_history[user_name][
                len(self.sent_packet_history[user_name].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
class c2wUdpChatClientProtocol(DatagramProtocol):
    
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        Class implementing the UDP version of the client protocol.
            You must write the implementation of this class.

        Each instance must have at least the following attributes:

        .. attribute:: serverAddress

            The IP address (or the name) of the c2w server.

        .. attribute:: serverPort

            The port number used by the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

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

        self.serverAddress = serverAddress
        self.serverPort = serverPort
        self.clientProxy = clientProxy
        self.lossPr = lossPr

        self.client = clientClass.client(self.clientProxy, self, 
                                         (self.serverAddress,self.serverPort))
        
    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport
    

    def sendMessage(self, message):
        self.transport.write(message.raw,(self.serverAddress,self.serverPort))
    

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

        The controller calls this function as soon as the user clicks on
        the login button.
        """
        
        self.client.sendLoginRequest(userName)
        moduleLogger.debug('loginRequest called with username=%s', userName)

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

        Called **by the controller**  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.
        """
        self.client.sendChatMessageOIE(message)

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

        Called **by the controller**  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.client.sendJoinRoomRequest(roomName)
        print "-------------------launching timer------------------------------"
        moduleLogger.debug('RoomRequest called with roomName=%s', roomName)
        
    def sendLeaveSystemRequestOIE(self):
        """
        Called **by the controller**  when the user
        has clicked on the leave button in the main room.
        """
        self.client.sendLeaveRoomMessage()

    def datagramReceived(self, datagram, (host, port)):
        """
        :param string datagram: the payload of the UDP packet.
        :param host: the IP address of the source.
        :param port: the source port.

        Called **by Twisted** when the client has received a UDP
        packet.
        """
        print "-------------------Receiving message---------------------------"
        self.client.testingFragmentation(datagram)
Beispiel #13
0
 def startProtocol(self):
     self.transport = LossyTransport(self.transport, self.lossPr)
     DatagramProtocol.transport = self.transport
Beispiel #14
0
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        Class implementing the UDP version of the client protocol.
        
        Parameters
        ----------
        serverAddress : The IP address (or the name) of the c2w server, given 
        by the user.
            
        serverPort : The port number used by the c2w server, given by the user.
            
        clientProxy : The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.


        Attributes
        ----------
        serverAddress : The IP address of the c2w server.

        serverPort : The port number of the c2w server.

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

        lossPr : The packet loss probability for outgoing packets. Do not 
        modify this value!  (It is used by startProtocol.)            
        """

        #: The IP address of the c2w server.
        self.serverAddress = serverAddress
        #: The port number of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        self.seqNumSent = 0
        self.sessionToken = 0
        self.timer = 0
        self.userID = 0
        self.roomRequested = []
        self.roomStructure = {}

    def startProtocol(self):
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    def sendMsg(self, msg, host_port):
        print(msg)
        self.transport.write(msg, host_port)

    def sendLoginRequestOIE(self, userName):
        """
        The client proxy calls this function when the user clicks on the login
        button.
        
        Parameters
        ----------
        userName: string
            The user name that the user has typed.
        """
        moduleLogger.debug('loginRequest called with username=%s', userName)

        #connection request
        version = 0b1 << 28
        typ1 = 0b1 << 24
        self.sessionToken = 0
        hybrid = version + typ1 + self.sessionToken
        payloadS = len(userName.encode('utf-8')) + 4
        USER = userName.encode('utf-8')
        header = struct.pack('!IHH', hybrid, self.seqNumSent, payloadS)
        payload = struct.pack('!HH' + str(len(USER)) + 's', self.userID,
                              len(USER), USER)
        packet = header + payload
        self.sendMsg(packet, (self.serverAddress, self.serverPort))
        self.timer = reactor.callLater(1.0, self.sendMsg, packet,
                                       (self.serverAddress, self.serverPort))
        self.seqNumSent += 1

    def roomStateRequest(self):
        #request for rooms
        version = 0b1 << 28
        typ = 0b11 << 24
        self.type_sent = 3
        hybrid = version + typ + self.sessionToken
        payloadS = 0
        header = struct.pack('!IHH', hybrid, self.seqNumSent, payloadS)
        packet = header
        self.sendMsg(packet, (self.serverAddress, self.serverPort))
        self.timer = reactor.callLater(1.0, self.sendMsg, packet,
                                       (self.serverAddress, self.serverPort))
        self.seqNumSent += 1

    def sendChatMessageOIE(self, message):
        """
        Called by the client proxy  when the user has decided to send a chat
        message

        Parameters
        ----------
        message : string
            The text of the 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.
        """
        self.message_sent.append(message)
        version = 0b1 << 28
        typ = 0b110 << 24
        self.type_sent = 6
        hybrid = version + typ + self.sessionToken
        payloadS = len(message) + 2
        header = struct.pack('!IHH', hybrid, self.seqNumSent, payloadS)
        MSG = message.encode('utf-8')
        payload = struct.pack('!HH' + str(len(MSG)) + 's', self.userID,
                              len(MSG), MSG)
        packet = header + payload
        self.sendMsg(packet, (self.serverAddress, self.serverPort))
        self.timer = reactor.callLater(1.0, self.sendMsg, packet,
                                       (self.serverAddress, self.serverPort))
        self.seqNumSent += 1

    def sendJoinRoomRequestOIE(self, roomName):
        """
        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.
        
        Parameters
        ----------
        roomName: string
            The room name (or movie title.)

        Note
        -----
        The controller sets roomName to
        c2w.main.constants.ROOM_IDS.MAIN_ROOM when the user
        wants to go back to the main room.
        """
        self.roomRequested.append(roomName)
        version = 0b1 << 28
        typ = 0b101 << 24
        self.type_sent = 5
        hybrid = version + typ + self.sessionToken
        payloadS = 2
        idRoom = self.roomStructures[roomName]
        header = struct.pack('!IHH', hybrid, self.seqNumSent, payloadS)
        payload = struct.pack('H', idRoom)
        packet = header + payload
        self.sendMsg(packet, (self.serverAddress, self.serverPort))
        self.timer = reactor.callLater(1.0, self.sendMsg, packet,
                                       (self.serverAddress, self.serverPort))
        self.seqNumSent += 1

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user has clicked on the leave 
        button in the main room.
        """
        version = 0b1 << 28
        typ = 0b111 << 24
        self.type_sent = 7
        hybrid = version + typ + self.sessionToken
        payloadS = 0
        header = struct.pack('!IHH', hybrid, self.seqNumSent, payloadS)
        packet = header
        self.sendMsg(packet, (self.serverAddress, self.serverPort))
        self.timer = reactor.callLater(1.0, self.sendMsg, packet,
                                       (self.serverAddress, self.serverPort))
        self.seqNumSent += 1

    def datagramReceived(self, datagram, host_port):
        """
        Called by Twisted when the client has received a UDP packet.
        
        Parameters
        ----------
        datagram : string
            the payload of the UDP packet.
            
        host_port: tuple
            a tuple containing the source IP address and port.
        """
        hybrid, seqNum, payloadS = struct.unpack_from('!IHH', datagram, 0)
        datagram_typ = (hybrid & 0b1111 << 24) >> 24
        datagram_sessionToken = hybrid & 0b111111111111111111111111
        self.sessionToken = datagram_sessionToken
        if datagram_typ == 0:
            if seqNum == self.seqNumSent - 1:
                self.timer.cancel()
        elif datagram_typ == 2:
            self.acquittement(seqNum, host_port)

    def acquittement(self, seqNum, host_port):
        version = 0b1 << 28
        typ = 0b0 << 24
        hybrid = version + typ + self.sessionToken
        packet = struct.pack('!IHH', hybrid, seqNum, 0)
        self.sendMsg(packet, host_port)
Beispiel #15
0
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        self.HEADER_LENGTH = 4

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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.
        """
        packet_length = self.HEADER_LENGTH + len(userName)
        seq_num = 0  #always begins connection with a 0
        packet_type = 1
        seq_num_and_packet_type = seq_num + packet_type
        encoded_userName = userName.encode('ascii', 'replace')
        packet_bin = struct.pack("hh" + str(len(userName)) + "s",
                                 packet_length, seq_num_and_packet_type,
                                 encoded_userName)
        self.transport.write(packet_bin, (self.serverAddress, self.serverPort))
        moduleLogger.debug('loginRequest called with username=%s', 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.
        """
        pass

    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.
        """
        pass

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        pass

    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_length, seq_num_and_type) = struct.unpack_from("hh",
                                                               datagram,
                                                               offset=0)
        packet_type = seq_num_and_type % 16  #We take the last 4 bits
        seq_num = int(seq_num_and_type / 16)  #We cut the last 4 bits

        print(packet_length)
        print(packet_type)
        print(seq_num)

        # (self.msg,) = struct.unpack_from(str(self.packet_length-self.HEADER_LENGTH)+"s", datagram, offset=self.HEADER_LENGTH)

        # (timestamp, package_length) = struct.unpack_from("hh", datagram, offset=0)
        # (msg,) = struct.unpack_from(str(package_length-self.header_length)+"s", datagram, offset=self.header_length)
        # response = msg.decode('ascii')
        # self.clientProxy.responseReceived(response)

        pass
Beispiel #16
0
class c2wUdpChatServerProtocol(DatagramProtocol):
    def __init__(self, serverProxy, lossPr):
        """
        Class implementing the UDP version of the client protocol.
        
        Parameters
        ----------
        serverProxy : The serverProxy the protocol must use
            to interact with the user and movie store (i.e., the list of users
            and movies) in the server.
            
        lossPr : The packet loss probability for outgoing packets.  Do
            not modify this value!
        """
        self.serverProxy = serverProxy
        self.lossPr = lossPr
        self.timer = 0
        self.roomTitleID = {}
        self.user_room = {}
        self.sessionTokens = {}
        self.sessionTokens[0] = 0
        self.seqNumSent = {}
        self.seqNumSent[0] = 0

    def startProtocol(self):
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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.
        """
        hybrid, seqNum, payloadS = struct.unpack_from('!IHH', datagram, 0)
        datagram_typ = (hybrid & 0b1111 << 24) >> 24
        datagram_sessionToken = hybrid & 0b111111111111111111111111
        if not (self.serverProxy.getUserByAddress(host_port)):
            ID = 0
        else:
            if self.serverProxy.getUserByAddress(host_port).userId == None:
                ID = 0
            else:
                ID = self.serverProxy.getUserByAddress(host_port).userId

        if datagram_typ == 0:
            if seqNum == self.seqNumSent[ID] - 1:
                self.timer.cancel()
                reactor.run()
                if seqNum == 0:
                    if datagram_sessionToken != 0:
                        self.roomState(ID, host_port)

        elif datagram_typ == 1:
            self.acquittement(seqNum, ID, host_port)
            self.loginResponse(datagram, host_port)

    def sendMsg(self, msg, host_port):
        print(msg)
        self.transport.write(msg, host_port)

    def loginResponse(self, datagram, host_port):
        version = 0b1 << 28
        typ = 0b10 << 24
        seqNum = 0
        payloadS_datagram = struct.unpack_from('!IHH', datagram, 0)[2]
        l = payloadS_datagram - 4
        uid, userNameLen, userNameBin = struct.unpack_from(
            '!HH' + str(l) + 's', datagram, 8)
        userName = userNameBin.decode('utf-8')
        print("username :"******"Main Room"
            seToken = random.getrandbits(24)
            self.sessionTokens[ID] = seToken
            self.seqNumSent[ID] = 0
            self.sessionTokens[seToken] = ID
            hybrid1 = version + typ + self.sessionTokens[ID]
            payloadS1 = l + 5
        else:
            sessionToken = 0
            response = 3
            hybrid1 = version + typ + sessionToken
            ID = 0
            payloadS1 = l + 12
        header = struct.pack('!IHH', hybrid1, seqNum, payloadS1)
        payload = struct.pack(
            '!BHH' + str(len(userName.encode('utf-8'))) + 's', response, ID,
            len(userName.encode('utf-8')), userName.encode('utf-8'))
        packet = header + payload
        self.sendMsg(packet, host_port)
        self.timer = reactor.callLater(1.0, self.sendMsg, packet, host_port)
        reactor.run()
        self.seqNumSent[ID] += 1

    def roomState(self, ID, host_port):
        """
        Send the current state of the room
        """
        version = 0b1 << 28
        typ = 0b100 << 24
        sessionToken = self.sessionTokens[ID]
        hybrid = version + typ + sessionToken
        payloadS = 0
        userName = self.serverProxy.getUserById(ID).userName
        #we recover the position of the user in the dict
        roomName = self.user_room[userName]
        #list of all the users
        userListAll = self.serverProxy.getUserList()
        #if the user is in the main room
        if roomName == "Main Room":
            roomId = 1
            movieIp = 0
            moviePort = 0
            payloadS += 8
            payloadS += (len(roomName.encode('utf-8')) + 2)
            payload = struct.pack(
                '!HH' + str(len(roomName.encode('utf-8'))) + 'sIH', roomId,
                len(roomName.encode('utf-8')), roomName.encode('utf-8'),
                movieIp, moviePort)
            userList = []
            for u in userListAll:
                print("mec al :", u.userName)
                print("userchatRoom", u.userChatRoom)
                if self.user_room[u.userName] == roomName:
                    userList.append(u)
                print("tout user :"******"userRoom = ", self.user_room)
                print("userList :", userList)
            if len(userList) == 0:
                payloadS += 2
                payload += struct.pack('!H', 0)
            else:
                payloadS += 2
                payload += struct.pack('!H', len(userList))
                for u in userList:
                    payloadS += 2
                    payload += struct.pack('!H', u.userId)
                    l = len(u.userName.encode('utf-8'))
                    payloadS += l + 2
                    payload += struct.pack('!H' + str(l) + 's', l,
                                           u.userName.encode('utf-8'))
            roomList = self.serverProxy.getMovieList()
            lenght_r = len(roomList)
            payloadS += 2
            payload += struct.pack('!H', lenght_r)
            for room in roomList:
                payloadS += 2
                payload += struct.pack('!H', room.movieId)
                print('Movie id: ', room.movieId)
                l = len(room.movieTitle.encode('utf-8'))
                payloadS += l + 2
                payload += struct.pack('!H' + str(l) + 's', l,
                                       room.movieTitle.encode('utf-8'))
                payloadS += 4
                IP = room.movieIpAddress
                ip = int(ipaddress.ip_address(IP))
                print("IP :", ip)
                payload += struct.pack('!I', ip)
                payloadS += 2
                payload += struct.pack('!H', room.moviePort)
                userList = []
                for u in userListAll:
                    if u.userChatRoom == roomName:
                        userList.append(u)
                if len(userList) == 0:
                    payloadS += 2
                    payload += struct.pack('!H', len(userList))
                else:
                    for u in userList:
                        payloadS += 2
                        payload += struct.pack('!H', u.userID)
                        l = len(userList.userName.encode('utf-8'))
                        payloadS += l + 2
                        payload += struct.pack('!H' + str(l) + 's', l,
                                               u.userName.encode('utf-8'))
                payloadS += 2
                payload += struct.pack('!H', 0)
        else:
            roomList = self.serverProxy.getMovieList()
            lenght_r = len(roomList)
            payloadS += 2
            payload += struct.pack('!H', lenght_r)
            for room in roomList:
                payloadS += 2
                payload += struct.pack('!H', room.movieID)
                l = len(room.movieTitle.encode('utf-8'))
                payloadS += l + 2
                payload += struct.pack('!H' + str(l) + 's', l,
                                       room.movieTitle.encode('utf-8'))
                payloadS += 4

                IP = room.movieIpAddress
                ip = int(ipaddress.ip_address(IP))
                payload += struct.pack('!I', ip)
                payloadS += 2
                payload += struct.pack('!H', room.moviePort)
                userList = []
                for u in userListAll:
                    if u.userChatRoom == roomName:
                        userList.append(u)
                if len(userList) == 0:
                    payloadS += 2
                    payload += struct.pack('!H', len(userList))
                else:
                    for u in userList:
                        payloadS += 2
                        payload += struct.pack('!H', u.userID)
                        l = len(userList.userName.encode('utf-8'))
                        payloadS += l + 2
                        payload += struct.pack('!H' + str(l) + 's', l,
                                               u.userName.encode('utf-8'))
                payloadS += 2
                payload += struct.pack('!H', 0)

        header = struct.pack('!IHH', hybrid, self.seqNumSent[ID], payloadS)
        packet = header + payload
        self.sendMsg(packet, host_port)
        self.timer = reactor.callLater(1.0, self.sendMsg, packet, host_port)
        self.seqNumSent[ID] += 1

    def acquittement(self, seqNum, ID, host_port):
        version = 0b1 << 28
        typ = 0b0 << 24
        sessionToken = self.sessionTokens[ID]
        hybrid = version + typ + sessionToken
        packet = struct.pack('!IHH', hybrid, seqNum, 0)
        self.sendMsg(packet, host_port)
Beispiel #17
0
class c2wUdpChatServerProtocol(DatagramProtocol):

    def __init__(self, serverProxy, lossPr):
        """
        :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 lossPr: The packet loss probability for outgoing packets.  Do
            not modify this value!

        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:: serverProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """
          
        self.managecount={}
        self.managerepeat = {}
        self.usserName=""
        self.manageackul={}
        self.manageuserseq={}       
        self.rejseq=0
 
        #: The serverProxy, which the protocol must use
        #: to interact with the server (to access the movie list and to 
        #: access and modify the user list).
        self.serverProxy = serverProxy
        self.lossPr = lossPr

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

        #verify username with the existing data
    def verifyName(self, userName):
        if self.serverProxy.userExists(userName):
            status=0
        else:
            status=1
        return status

        #function to send the login acceptance msg.
    def loginAcpMsg(self, host_port):
        sequ_type=(self.manageuserseq[host_port]<<4) | (types["Acceptation connexion"])
        buf=struct.pack('!HH',4,sequ_type)
        self.transport.write(buf,host_port)
        
        #retransmit the login acceptance msg if lost.
        if(self.managecount[host_port]<7):
            self.managerepeat[host_port] = reactor.callLater(1,self.loginAcpMsg,host_port)
            self.managecount[host_port]+=1

        #send login Refuse msg if username already exist.
    def sendLoginRefuse(self, host_port):
        sequ_type=(self.rejseq<<4) | (types["Refus connexion"])
        buf=struct.pack('!HH',4,sequ_type)
        self.transport.write(buf,host_port)
        
        #retransmit the login Refuse msg if lost.
        if(self.managecount[host_port]<7):
            self.managerepeat[host_port] = reactor.callLater(1,self.sendLoginRefuse,host_port)
            self.managecount[host_port]+=1
        

        #function to send movies list
    def sendMovieList(self, host_port):
        length = 4
        for f in self.serverProxy.getMovieList():
            length += 9 + len(f.movieTitle.encode('utf-8'))

        buf=bytearray(length)
        offset=4
        sequ_type=(self.manageuserseq[host_port]<<4) | (types["Envoi liste films"])
        struct.pack_into('!HH',buf,0,length,sequ_type)

        for f in self.serverProxy.getMovieList():
                aip=f.movieIpAddress
                port=f.moviePort
                iid=f.movieId
                title=f.movieTitle
                cip=int(ipaddress.IPv4Address(aip))
                lenmovie=9+len(title)
                
                struct.pack_into('!IHHB%is'%len(title.encode('utf-8')),buf,offset,cip,port,lenmovie,iid,title.encode('utf-8'))
                offset += 9+len(title.encode('utf-8'))  
   
        self.transport.write(buf,host_port)

        #retransmit the movies list msg if lost.
        if(self.managecount[host_port]<7):
            self.managerepeat[host_port] = reactor.callLater(1,self.sendMovieList,host_port)
            self.managecount[host_port]+=1

        #function to send users list
    def sendUserList(self, host_port):
        length = 4
        for f in self.serverProxy.getUserList():
            length += 2 + len(f.userName.encode('utf-8'))

        buf=bytearray(length)
        offset=4
        sequ_type=(self.manageuserseq[host_port]<<4) | (types["Envoi liste users"])
        struct.pack_into('!HH',buf,0,length,sequ_type)

        for f in self.serverProxy.getUserList():        
            use=f.userName
            us=f.userChatRoom
            print(use,us)
            if (us==ROOM_IDS.MAIN_ROOM):
                userstatus=0
            else:
                print(us)
                userstatus=self.serverProxy.getMovieByTitle(f.userChatRoom).movieId
            ip_port=f.userAddress
                
            lenuser=len(use)
            print(use,userstatus,ip_port)
                
            struct.pack_into('!BB%is'%len(use.encode('utf-8')),buf,offset,lenuser,userstatus,use.encode('utf-8'))
            offset += 2+len(use.encode('utf-8'))  
   
        self.transport.write(buf,host_port)

        #retransmit the users list msg if lost.
        if(self.managecount[host_port]<7):
            self.managerepeat[host_port] = reactor.callLater(1,self.sendUserList,host_port)
            self.managecount[host_port]+=1
        
        #condition to send users list
    def sendUserListAll(self):
        print(self.serverProxy.getUserList())
        for f in self.serverProxy.getUserList():
            self.sendUserList(f.userAddress)

        #function to forward the chat msg
    def sendChatMsg(self,username,msg,host_port):
        lenuser=len(username.encode('utf-8'))
        length=4+1+lenuser+len(msg.encode('utf-8'))
        buf=bytearray(length)
        offset=4
        sequ_type=(self.manageuserseq[host_port]<<4) | (types["Message Chat"])
        struct.pack_into('!HH',buf,0,length,sequ_type)
        
        struct.pack_into('!B%is'%len(username.encode('utf-8')),buf,offset,lenuser,username.encode('utf-8'))
        offset+=1+lenuser
        struct.pack_into('!%is'%len(msg.encode('utf-8')),buf,offset,msg.encode('utf-8'))
        self.transport.write(buf,host_port)

        if(self.managecount[host_port]<7):
            self.managerepeat[host_port] = reactor.callLater(1,self.sendChatMsg,username,msg,host_port)
            self.managecount[host_port]+=1
        
        #condition to send chat msg
    def sendChatMsgAll(self,username,msg):
        user=self.serverProxy.getUserByName(username)
        print(self.serverProxy.getUserList())
        for f in self.serverProxy.getUserList():
            if f.userChatRoom == user.userChatRoom:
                self.sendChatMsg(username,msg,f.userAddress)
        

    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.
        """
        #unpacking and extracting the length, sequence number, type and data  from the received msg.   
        lenght, seq_type, data = struct.unpack('!HH%is'%(len(datagram)-4), datagram)  
        seql=seq_type>>4
        typ=seq_type & 15

        #if type of the received msg is not an ACK, then it will send an ACK for the received msg.
        if(typ!=types["Acquittement"]):
            sequ_type=(seql<<4) | (types["Acquittement"])
            buf=struct.pack('!HH',4,sequ_type)
            self.transport.write(buf,host_port)

        #if Ack is received it will cancel the retransmission of the msg. 
        elif (typ==types["Acquittement"]):
            self.managerepeat[host_port].cancel()
            self.manageuserseq[host_port] += 1
            self.managecount[host_port] = 0

            #once received the ack for acceptance msg with its seql no, add the user to the server and send the movie list
            if(seql==0):
                self.serverProxy.addUser(self.usserName,ROOM_IDS.MAIN_ROOM,userChatInstance=None,userAddress=host_port)
                self.sendMovieList(host_port)
           
            elif(seql==1):
                self.sendUserList(host_port)

            elif(seql==2):
                self.sendUserListAll()                               

        if(typ==types["Envoi du Pseudo"]):
            self.usserName=data.decode('utf-8')
            stat = self.verifyName(self.usserName)  
          
            if(stat==1):
                self.manageuserseq[host_port]=0
                self.managecount[host_port]=0
                self.managerepeat[host_port]=None
                self.loginAcpMsg(host_port)
            else:
                self.sendLoginRefuse(host_port)            
        
        if(typ==types["Choix d’un film"]):
            roomName=data.decode('utf-8')
            self.serverProxy.updateUserChatroom((self.serverProxy.getUserByAddress(host_port)).userName, roomName)
            self.serverProxy.startStreamingMovie(roomName)
            self.sendUserListAll()      
         
        if(typ==types["Quitter salle film"]):
            self.serverProxy.updateUserChatroom((self.serverProxy.getUserByAddress(host_port)).userName, ROOM_IDS.MAIN_ROOM)
            self.sendUserListAll()  
                      
        if(typ==types["Quitter application"]):
            self.serverProxy.removeUser(self.serverProxy.getUserByAddress(host_port).userName)
            self.sendUserListAll()
            
        if(typ==types["Message Chat"]):
            lenuser=struct.unpack_from('!B',datagram,4)[0]
            username=struct.unpack_from('!%is'%lenuser,datagram,5)[0].decode('utf-8')
            lengthmsg=lenght-4-1-lenuser
            msg=struct.unpack_from('!%is'%lengthmsg,datagram,5+lenuser)[0].decode('utf-8')
            self.sendChatMsgAll(username,msg)
                
        pass
class c2wUdpChatClientProtocol(DatagramProtocol):


	def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
		"""
		: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.
		:param clientProxy: The clientProxy, which the protocol must use
		to interact with the Graphical User Interface.

		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 attributes:

		.. attribute:: serverAddress

		The IP address of the c2w server.

		.. attribute:: serverPort

		The port number of the c2w server.

		.. attribute:: clientProxy

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

		.. attribute:: lossPr

		The packet loss probability for outgoing packets.  Do
		not modify this value!  (It is used by startProtocol.)

		.. 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 of the c2w server.
		self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
		self.clientProxy = clientProxy
		self.c2wClientModel = c2wClientModel()
		self.lossPr = lossPr
		self.last_event_id =0
		self.seq = 0
		self.userID = 0
		self.roomID = 0
		self.dstRoomID = 0
		self.init = False
		self.messageType = 0x00
		self.movieList = []
		self.userList = []
		self.logged = False
		self.responses = []
		self.lastDGTreated = None
		self.logged = False
		
	def incrementSeq(self) :
		if (self.seq > 65535) :
			self.seq = 0
		else :
			self.seq += 1
        
	def startProtocol(self):
		"""
		DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

		If in doubt, do not add anything to this method.  Just ignore it.
		It is used to randomly drop outgoing packets if the -l
		command line option is used.
		"""
		self.transport = LossyTransport(self.transport, self.lossPr)
		DatagramProtocol.transport = self.transport

			
	#--------this function verifies every 60s if the user is connected. If he's not, the application is closed--------------				
	def verifyConnexion(self):
		if(self.connected == False):
			self.clientProxy.applicationQuit()
		else:
			self.connected = False
			reactor.callLater(60, self.verifyConnexion)
	
	#GET_PING send a message to the server asking for the last event of the room where the user is
	def getPing(self, initial):
		self.messageType = 0x4
		msgLength = 4
		buf = bytearray(10)
		last_event_id_2fb = (self.last_event_id & int('111111111111111100000000',2)) >> 8 #retrieve two first bytes in event_id
		last_event_id_lb = (self.last_event_id) & 255 #retrieve last byte in event_id
		struct.pack_into('!BHBHHBB', buf, 0, self.messageType, self.seq, self.userID, msgLength, last_event_id_2fb, last_event_id_lb, self.roomID)
		
		if self.logged == True :
			self.transport.write(buf, (self.serverAddress, self.serverPort))
			seq = self.seq
			msgType = self.messageType
			self.incrementSeq()
			reactor.callLater(0.5, self.verifyResponse, buf, seq, msgType) # if we don't receive response after 500ms, the GET_PING request is resent
			if initial == True:
				reactor.callLater(1, self.getPing, True)# this method is called every second, True means it's not a message retry, so it can call a new get ping after a second
			else:
				pass
		else :
			pass
	
	#split in groups of 254 the number of events to be asked to the server
	def getEvents(self, numberOfEvents): 
		nbIterations = math.ceil(numberOfEvents/254) #we calculate the number of times it will be necessary to ask for events eg: 300/254 = 1.18 -> 2 times 
		while(nbIterations != 0):
			if(numberOfEvents/254 >= 1):
				nbDemande = 254
				numberOfEvents -= 254
			else:
				nbDemande = numberOfEvents
			self.events(nbDemande)
			nbIterations -= 1
	
	#pack and send to the server the GET_EVENTS request
	def events(self, nbDemande) :
		self.messageType = 0x6
		msgLength = 5
		buf = bytearray(11)
		last_event_id_2fb = (self.last_event_id & int('111111111111111100000000',2)) >> 8
		last_event_id_lb = (self.last_event_id) & 255
		struct.pack_into('!BHBHHBBB', buf, 0, self.messageType, self.seq, self.userID, msgLength, last_event_id_2fb, last_event_id_lb, nbDemande, self.roomID)
		self.transport.write(buf, (self.serverAddress, self.serverPort))
		seq = self.seq
		msgType = self.messageType
		self.incrementSeq()
		reactor.callLater(0.5, self.verifyResponse, nbDemande, seq, msgType) #after a half second, we call a function that checks if the response was received 
	
	#PUT_LOGIN send a message to the server to inform it of the user's wish to enter the server	
	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)
		self.messageType = 0x00
		usernameLength = len(userName.encode('utf-8')) #len returns the number of characters 
		msgLength = usernameLength + 1 # 1 for UL field
		buf = bytearray(7+usernameLength) #2 bytes for seq, 1 for userID,...
		struct.pack_into('!BHBHB'+str(usernameLength)+'s', buf, 0, self.messageType, self.seq, self.userID, msgLength, usernameLength, userName.encode('utf-8')) 
		self.transport.write(buf, (self.serverAddress, self.serverPort))
		seq = self.seq
		msgType = self.messageType
		self.incrementSeq()
		reactor.callLater(0.5, self.verifyResponse, userName, seq, msgType) #after a half second, we call a function that checks if the response was received

	#PUT_NEW_MESSAGE send a message to the server with the text the user has typed in the chatroom wether it is in the MAIN_ROOM or a MOVIE_ROOM
	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.
		"""
		self.messageType = 0x0E
		msgLength = 1 + 2 + len(message) #1 byte for room_id, 2 for text length...
		buf = bytearray(9+len(message)) #2 bytes for seq, 1 pour userID,...
		struct.pack_into('!BHBHBH'+str(len(message))+'s', buf, 0, self.messageType, self.seq, self.userID, msgLength, self.roomID, len(message), message.encode('utf-8'))
																																			 #the result is saved in buf
		self.transport.write(buf, (self.serverAddress, self.serverPort))
		seq = self.seq
		msgType = self.messageType
		self.incrementSeq()
		reactor.callLater(0.5, self.verifyResponse, message, seq, msgType) #after a half second, we call a function that checks if the response was received
	
	#PUT_SWITCH_ROOM send a message to the server to inform it of the user's wish to change rooms
	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
			ROOM_IDS.MAIN_ROOM when the user
			wants to go back to the main room.
		"""
		if (roomName == ROOM_IDS.MAIN_ROOM) :
			self.dstRoomID = 0
		else :
			room = self.c2wClientModel.getMovieByTitle(roomName) 
			self.dstRoomID = room.movieId
		self.messageType = 0x0C
		msgLength = 1 #1 for ROOM_ID
		buf = bytearray(7)
		struct.pack_into('!BHBHB', buf, 0, self.messageType, self.seq, self.userID, msgLength, self.dstRoomID)
		self.transport.write(buf, (self.serverAddress, self.serverPort))
		seq = self.seq
		msgType = self.messageType
		self.incrementSeq()
		reactor.callLater(0.5, self.verifyResponse, roomName, seq, msgType) #after a half second, we call a function that checks if the response was received

	#PUT_LOGOUT send a message to the server to inform it of the user's wish to leave the server
	def sendLeaveSystemRequestOIE(self):
		"""
		Called by the client proxy  when the user
		has clicked on the leave button in the main room.
		"""
		self.messageType = 0x02
		msgLength = 0
		buf = bytearray(6) 
		struct.pack_into('!BHBH', buf, 0, self.messageType, self.seq, self.userID, msgLength)
		self.transport.write(buf, (self.serverAddress, self.serverPort))
		seq = self.seq
		msgType = self.messageType
		self.incrementSeq()
		reactor.callLater(0.5, self.verifyResponse, buf, seq, msgType) #after a half second, we call a function that checks if the response was received

	# GET_ROOMS send a message to the server to ask for the list of movies	
	def getRooms(self) :
		self.messageType = 0x08
		msgLength = 2 #1 for FIRST_ROOM_ID 1 for NBR_ROOMS
		buf = bytearray(8) 
		struct.pack_into('!BHBHBB', buf, 0, self.messageType, self.seq, self.userID, msgLength, 1, 255)
		self.transport.write(buf, (self.serverAddress, self.serverPort))
		seq = self.seq
		msgType = self.messageType
		self.incrementSeq()
		reactor.callLater(0.5, self.verifyResponse, buf, seq, msgType) #after a half second, we call a function that checks if the response was received
	
	#GET_USERS send a message to the user to ask for the list of users in the server (MAIN_ROOM) or in the room (MOVIE_ROOM)
	def getUsers(self, roomID) :
		self.messageType = 0x0A
		msgLength = 3 
		buf = bytearray(9) 
		struct.pack_into('!BHBHBBB', buf, 0, self.messageType, self.seq, self.userID, msgLength, 1, 255, self.roomID)
		self.transport.write(buf, (self.serverAddress, self.serverPort))
		seq = self.seq
		msgType = self.messageType
		self.incrementSeq()
		reactor.callLater(0.5, self.verifyResponse, roomID, seq, msgType) #after a half second, we call a function that checks if the response was received
	
	#unpack the RESPONSE_USERS datagram and return the list of users received (userName, userRoom)
	def unpackUsersList(self, datagram) :
		usersPack = struct.unpack('!BHBHB'+str(len(datagram)-7)+'s', datagram)
		nbUsers = usersPack[4]
		users = usersPack[5] #USERS list (variable length)
		listUsers = users
		userTuples=[]
		while (nbUsers != 0) :
			user1 = struct.unpack('!BB'+str(len(listUsers)-2)+'s', listUsers) #separate USER_ID, UL and the rest
			user11 = struct.unpack('!'+str(user1[1])+'sB'+str(len(user1[2])-user1[1]-1)+'s', user1[2]) #separate USERNAME, ROOM_ID and the rest
			userID = user1[0]
			userName = user11[0].decode('utf-8')
			roomID = user11[1]
			if (roomID == 0) :
				userRoom = ROOM_IDS.MAIN_ROOM
				movieName = userRoom
			else :
				userRoom = ROOM_IDS.MOVIE_ROOM
				if self.init == True : #for loggin initialisation, we just need to know if the user is in the main room or in the movie room
					movieName = userRoom
				else :
					movie = self.c2wClientModel.getMovieById(roomID)
					movieName = movie.movieTitle
			userTuples.append((userName, userRoom)) #add USERNAME and ROOM_ID to the list of pair
			user=self.c2wClientModel.getUserByName(userName)
			if user != None :
				pass
			else :
				self.c2wClientModel.addUser(userName, userID, movieName) #store user informations
			nbUsers-=1
			listUsers = user11[2] #make the initial packet equal to the rest, in order to retrieve the other users through further iterations
			self.c2wClientModel.updateUserChatroom(userName, userRoom)
			if (self.init == False) : 
				self.clientProxy.userUpdateReceivedONE(userName, movieName) #won't be execute for the initial response user
			else :
				pass
		return userTuples
	
	#unpack the RESPONSE_ROOMS datagram and return the list of movies received (movieTitle, movieIP, moviePort)
	def unpackRoomsList(self, datagram) :
		moviesPack = struct.unpack('!BHBHB'+str(len(datagram)-7)+'s', datagram)
		nbMovies = moviesPack[4]
		movies = moviesPack[5]
		listMovies = movies	
		moviesTriplets=[]
		while (nbMovies != 0) :
			movie1 = struct.unpack('!B4BHB'+str(len(listMovies)-8)+'s', listMovies) #separate ROOM_ID, IP, PORT_NUMBER, RNL and the rest
			movieID = movie1[0]
			moviePort = movie1[5]
			movieIP = str(movie1[1])+"."+str(movie1[2])+"."+str(movie1[3])+"."+str(movie1[4])
			movie11 = struct.unpack('!'+str(movie1[6])+'sB'+str(len(movie1[7])-movie1[6]-1)+'s', movie1[7]) #separate ROOM_NAME, NBR_USERS and the rest
			movieTitle = movie11[0].decode('utf-8')
			moviesTriplets.append((movieTitle, movieIP, moviePort)) #add ROOM_NAME, IP and PORT_NUMBER to the list of triplets
			self.c2wClientModel.addMovie(movieTitle, movieIP, moviePort, movieID) #store movie informations
			nbMovies-=1
			listMovies = movie11[2] #make the initial packet equal to the rest, in order to retrieve the other videos through further iterations
		print (moviesTriplets)
		return moviesTriplets
	
	#unpack the RESPONSE_EVENTS datagram and execute the necessary updates
	def unpackEvents(self, datagram) :
		eventsPack = struct.unpack('!BHBHB'+str(len(datagram)-7)+'s', datagram) #separate MESSAGE_TYPE, SEQ_NUMBER, USER_ID, MESSAGE_LENGTH (header), NBR_EVENTS and the events
		nbEvents = eventsPack[4]
		events = eventsPack[5]
		while(nbEvents != 0) :
			event1 = struct.unpack('!HBBBB'+str(len(events)-6)+'s', events) #separate EVENT_ID, EVENT_TYPE, ROOM_ID, USER_ID, and the rest
			self.last_event_id = (event1[0]<<8)|event1[1]
			roomID = event1[3]
			userID = event1[4]
			eventType = event1[2]
			
			#MESSAGE event: MESSAGE_LENGTH, MESSAGE
			if (eventType==0x1) :
				event11 = struct.unpack('!H'+str(len(event1[5])-2)+'s', event1[5]) #separate MESSAGE_LENGTH (chat) and the rest
				event111 = struct.unpack('!'+str(event11[0])+'s'+str(len(event11[1])-event11[0])+'s', event11[1]) #separate MESSAGE and the rest
				message = event111[0].decode('utf-8')
				user = self.c2wClientModel.getUserById(userID) #retrieve the user using USER_ID
				userName = user.userName
				if userID != self.userID and self.roomID == roomID : #print the msg only if the message is from another user in the same room. (care of duplication)
					self.clientProxy.chatMessageReceivedONE(userName, message)
				else :
					pass
				events = event111[1]
				
			#NEW_USER event: USERNAME_LENGTH, USERNAME
			elif (eventType==0x2) :
				event11 = struct.unpack('!B'+str(len(event1[5])-1)+'s', event1[5]) #separate UL and the rest
				event111 = struct.unpack('!'+str(event11[0])+'s'+str(len(event11[1])-event11[0])+'s', event11[1]) #separate USERNAME and the rest
				if (roomID == 0) :
					userRoom = ROOM_IDS.MAIN_ROOM
					movieName= userRoom
				else :
					userRoom = ROOM_IDS.MOVIE_ROOM
					movie = self.c2wClientModel.getMovieById(roomID)
					movieName = movie.movieTitle
				userName = event111[0].decode('utf-8')
				user=self.c2wClientModel.getUserByName(userName)
				if user != None : #prevent to add user if he exists, because we add user after response user.
					pass
				else :
					self.c2wClientModel.addUser(userName, userID, movieName) #store user informations
				self.c2wClientModel.updateUserChatroom(userName, userRoom)
				self.clientProxy.userUpdateReceivedONE(userName, movieName)
				events = event111[1]
			
			#SWITCH_ROOM event: NEW_ROOM_ID
			elif (eventType==0x3) :
				event11 = struct.unpack('!B'+str(len(event1[5])-1)+'s', event1[5]) #separate NEW_ROOM_ID and the rest
				newRoomID = event11[0]
				if (newRoomID == 0) :
					room = ROOM_IDS.MAIN_ROOM
					movieName = room
				else :
					room = ROOM_IDS.MOVIE_ROOM
					movie = self.c2wClientModel.getMovieById(newRoomID)
					movieName = movie.movieTitle
				user = self.c2wClientModel.getUserById(userID) #retrieve the user using USER_ID	
				userName = user.userName
				self.c2wClientModel.updateUserChatroom(userName, room)
				self.clientProxy.userUpdateReceivedONE(userName, movieName)
				events = event11[1]
			
			#LOGOUT event:
			elif (eventType==0x4) :
				user = self.c2wClientModel.getUserById(userID) #retrieve the user using USER_ID
				userName = user.userName
				self.clientProxy.userUpdateReceivedONE(userName, ROOM_IDS.OUT_OF_THE_SYSTEM_ROOM)
				self.c2wClientModel.removeUser(userName)
				events = event1[5]
			else :
				pass
			nbEvents-=1
			
	def leaveApplication(self):
		self.clientProxy.connectionRejectedONE("Connexion lost")
		reactor.callLater(2, self.clientProxy.applicationQuit)
		self.logged = False

	#identify the response message type and execute the necessary actions
	def treatDatagram(self, datagram) :
		received = struct.unpack('!BH'+str(len(datagram)-3)+'s', datagram)
		msgType = received[0]

		#RESPONSE_LOGIN
		if (msgType == 0x01) :
			received = struct.unpack('!BHBHBBHB', datagram) #unpack the received data
			status_code = received[4]
			#successful login
			if (status_code==0x00) :
				self.init = True
				self.logged = True
				self.last_event_id = (received[6]<<8)|received[7] #shift the 2 first bytes of the last_event_id to the left and apply a bitwise OR with the last byte
				self.userID = received[5]
				self.getUsers(self.roomID)
				self.connectedTimer = reactor.callLater(60, self.leaveApplication) #if no data received every 60s, we conclude that the connexion is lost
																					# connectedTimer is reinitialised after each data reception
			#unsuccessful login
			elif (status_code==0x01) :
				self.clientProxy.connectionRejectedONE("unknown error")
			elif (status_code==0x02) :
				self.clientProxy.connectionRejectedONE("too many users")
			elif (status_code==0x03) :
				self.clientProxy.connectionRejectedONE("invalid username")
			elif (status_code==0x04) :
				self.clientProxy.connectionRejectedONE("username not available")
			else :
				self.clientProxy.connectionRejectedONE("error")
			
		#RESPONSE_LOGOUT
		elif (msgType == 0x03) :
			received = struct.unpack('!BHBHB', datagram) #unpack the received data
			status_code = received[4]
			if (status_code == 0) :
				self.clientProxy.leaveSystemOKONE()
				self.logged = False
				self.connectedTimer.cancel() #stop timmer
			else :	
				pass
			
		#RESPONSE_PING get the difference betwen server's and user's last event id's
		elif (msgType == 0x05) :
			received = struct.unpack('!BHBHHB', datagram) #unpack the received data containing last event id
			last_event_id = (received[4]<<8)|received[5] 
			if (last_event_id>self.last_event_id): #if server last_event_id is greater than the client
				diff = last_event_id - self.last_event_id
				self.getEvents(diff) #client asks for the remaining events
			elif (last_event_id<self.last_event_id): #if client last_event_id is greater than the server's, it means the server has reached the max seq and then reinitialised it
				diff = last_event_id + (math.pow(2,24) - self.last_event_id) #(math.pow(2,24) - self.last_event_id) : events that took place in the server before reinitialisation
				self.getEvents(diff) #client asks for the events before and after seq reinitialisation
			else:
				pass
			
		#RESPONSE_EVENTS
		elif (msgType == 0x07) :
			self.unpackEvents(datagram)
			
		#RESPONSE_USERS
		elif (msgType == 0x0B) :			
			self.userList = self.unpackUsersList(datagram) #get the list of users in the list of pairs format (USERNAME, ROOM_ID)
			if self.init == True : #self.init set to True when successful loggin and to false when we got response rooms. we call getRooms after response user only for loggin 
				self.getRooms()
			else :
				pass

			
		#RESPONSE_ROOMS
		elif (msgType == 0x09) :
			self.movieList = self.unpackRoomsList(datagram) #get the list of triplets with movies' info	
			self.clientProxy.initCompleteONE(self.userList, self.movieList) #when init is true, it means we have just logged in, and so initialisation is complete
			reactor.callLater(1, self.getPing, True) #call getPing 1s after complete login
			self.init = False


		#RESPONSE_SWITCH_ROOM
		elif (msgType == 0x0D) :
			received = struct.unpack('!BHBHB', datagram) #unpack the received data
			status_code = received[4]
			if (status_code==0x0) :
				self.roomID = self.dstRoomID
				self.getUsers(self.roomID)
				user = self.c2wClientModel.getUserById(self.userID)
				userName = user.userName
				if (self.roomID == 0) :
					userRoom = ROOM_IDS.MAIN_ROOM
					movieName = userRoom
				else :
					userRoom = ROOM_IDS.MOVIE_ROOM
					movie = self.c2wClientModel.getMovieById(self.roomID)
					movieName = movie.movieTitle
				self.c2wClientModel.updateUserChatroom(userName, userRoom)
				self.clientProxy.userUpdateReceivedONE(userName, movieName)
				self.clientProxy.joinRoomOKONE()
			else :
				pass

		#RESPONSE_NEW_MESSAGE
		elif (msgType == 0x0F) :
			received = struct.unpack('!BHBHB', datagram) #unpack the received data
			status_code = received[4]
			if (status_code==0x0) :
				pass
			else :
				pass

		else:
			pass

	
	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.
		"""
		if self.logged == True :
			self.connectedTimer.reset(60)
		else :
			pass
		received = struct.unpack('!BH'+str(len(datagram)-3)+'s', datagram)
		msgType = received[0]
		seq = received[1]
		#the case in which we receive the login message (it's always the first message, so we can execute it whitout checking if there are others with an inferior sequence number)
		if self.lastDGTreated == None and seq == 0 :
			self.treatDatagram(datagram)
			self.lastDGTreated = 0
		#the case in which the message is the expected, we can execute it without worries, and after that we check the list of responses received for ensuing messages
		elif seq == self.lastDGTreated + 1 :
			self.treatDatagram(datagram)
			self.lastDGTreated = self.lastDGTreated + 1
			quit = False
			while quit == False : 
				i = 0
				quit = True
				for item in self.responses :
					if (item[1] == self.lastDGTreated + 1):
						self.treatDatagram(item[2])
						self.lastDGTreated = self.lastDGTreated + 1
						del self.responses[i] #remove the treated data in self.responses
						quit = False
						break
					else :
						i += 1
		#the case in which there's a gap in the sequence number, it means that one or more packets weren't received. We store the datagram in a list 
		elif seq > self.lastDGTreated + 1 :
			self.responses.append((msgType, seq, datagram))
		else :
			pass

	#check if the response was received, called in general 500ms after sending the message
	def verifyResponse(self, parameter, respSeq, messageType): #respSeq is used to be sure that the received response is the expected 
		#the case in which the lastDGTreated is still uninitialized, that means the login response wasn't received. We then resend the request
		if respSeq == 0 and self.lastDGTreated == None :
			self.seq -= 1
			self.sendLoginRequestOIE(parameter)
		#the case in which the lastDGTreated already surpassed the seq number we are checking. It means the datagram was already received and executed, so we don't have to do anything
		elif respSeq <= self.lastDGTreated :
			return
		#the case in which the lastDGTreated is inferior to the seq number we are checking. It means the datagram wasn't executed yet, so we have to search it in the list
		elif respSeq > self.lastDGTreated :
			i = 0
			for item in self.responses :
				#the case in which the response datagram was already received, but wasn't executed, we have to wait for the messages with an inferior seq number to be executed 
				if (item[1] == respSeq):
					return
				else :
					i += 1
			#the case in which the response datagram wasn't received yet (it's not in the list), we have to resend the request 
			tempSeq = self.seq
			self.seq = respSeq #if we didn't receive the expected seq response, we resend the request with the expected seq (respSeq)
			print(self.seq)
			if(messageType == 0x02):
				self.sendLeaveSystemRequestOIE()
			elif(messageType == 0x04):
				self.getPing(False) #false parameter means it is a retry, so we don't call a new get ping after a second
			elif(messageType == 0x06):
				self.getEvents(parameter)
			elif(messageType == 0x08):
				self.getRooms()
			elif(messageType == 0x0A):
				self.getUsers(self.roomID)
			elif(messageType == 0x0C):
				self.sendJoinRoomRequestOIE(parameter)
			elif(messageType == 0x0E):
				self.sendChatMessageOIE(parameter)
			else:
				pass
			self.seq = tempSeq #continue the code with our current seq
		else :
			pass
class c2wUdpChatClientProtocol(DatagramProtocol):   
    
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        
        self.filattente=[]
        self.host_port= (self.serverAddress,self.serverPort)
        
        self.listeFilms=[] #la liste des films envoyée par le serveur
        
        self.listeUsers=[] #la liste des utilisateurs envoyée par le serveur(Main et Movies Rooms)
        
        self.listeUsersMovie=[] #la liste des utilisateurs qui sont dans les movie room
        
        self.monNumeroSequence=0 # numero de sequence du client qui sera incrémenté au fur et à mesure
   
        self.room= " " #il s'agit de la room dans laquelle se trouve l utilisateur à un instant t
        
        self.numeroSequenceWhenGoingMovie=0 # le numero de sequence lorsque l'utilisateur fait la demande pour une movie
   
        self.numeroSequenceWhenGoingMain=0 # le numero de sequence lorsque l'utilisateur fait la demande pour revenir dans la main 
        
        self.numeroSequenceWhenOutMain=0 # le numero de sequence lorsque l'utilisateur fait la demande de deconnexion
        
        self.OnlyTitleAndIdOfMovie=[] # liste contenant les films et leur ID
        
        self.nomUtilisateur="" #contient le username de l'utilisateur
        
        self.connectivite=0
        
        
        
    #Fonction qui envoie un acuittement au serveur 
    def envoieAcquittement(self,numeroSequence):
        TypeAcq = 0
        decalage= numeroSequence << 4
        seqTypAcq= decalage | TypeAcq
        buff= struct.pack('!hh',4,seqTypAcq)
        self.transport.write(buff,(self.serverAddress,self.serverPort))
    
    #Fonction qui permet d'incrementer le numero de sequence jusqu'à 4095
    def incrementerNumeroSequence(self,numSequence):
        if (numSequence==4095): #4095= (2 exposant 12)-1
            numSequence=0
        else: 
            numSequence+=1
        return numSequence
        
    
    # fonction pour verifier si on a recu un ack
    def traiterAcquittement(self,numSeq):
       
        for p in self.filattente:
            if (p[0]==numSeq):
                p[2]=1
                print(p)
                print(self.filattente)
                print("Acquittement bien recu")
                         
    #fonction pour envoyer le paquet si jamais on a toujours pas recu d ack
    def send_And_Wait(self,hostPort):
        for j in self.filattente:
            if (j[4]==hostPort):  
                if (j[1] <= 7): # 7 correspond au nombre maximum de fois qu'on doit ramener un paquet
                    if (j[2] == 0):
                        self.transport.write(j[3],hostPort)
                        j[1]+=1
                        reactor.callLater(1,self.send_And_Wait,hostPort)
                    elif(j[2] == 1):
                        print("Confirmation acquittement bien recu")  
                        self.filattente.remove(j)        
                else:
                    print("le paquet a djaaaaaaa")
                    self.filattente.remove(j)
                    self.clientProxy.applicationQuit()   
    
    #Fonction pour dépaqueter la liste des films envoyée par le serveur
    def paquetListFilms(self,monpaquet):
        
        while(len(monpaquet)>0):
            #longueurMonPaquet=len(monpaquet)
            longueurFilm=int((struct.unpack('!h',monpaquet[6:8]))[0])
            print("longueur de film est :",longueurFilm," et de type :", type(longueurFilm))
            longeurTitreFilm=longueurFilm-9
            portFilm= int((struct.unpack('!h',monpaquet[4:6]))[0])
            adresseIpAConvertir=(struct.unpack('!I',monpaquet[0:4]))[0]
            adresseIp= str(ipaddress.IPv4Address(adresseIpAConvertir))
            IdMovie=int((struct.unpack('!b',monpaquet[8:9]))[0])
            titreFilm=(struct.unpack('!%is'%longeurTitreFilm,monpaquet[9:longueurFilm]))[0].decode('utf-8')
            print("film: ", titreFilm) 
            print("port :",portFilm)
            print("adresse IP : ",adresseIp,"de type", type(adresseIp))
            self.listeFilms.append((titreFilm,adresseIp,portFilm))
            self.OnlyTitleAndIdOfMovie.append([titreFilm,IdMovie])
            #print("la liste des films recu est",self.listeFilms)
            monpaquet=monpaquet[longueurFilm:]
        print("la liste des films est:", self.listeFilms)
     
    #Fonction pour dépaqueter la liste des utilisateurs envoyée par le serveur
    def paquetListUser(self,monpaquet):
        
        self.listeUsers=[]
        self.listeUsersMovie=[]
        
        while(len(monpaquet)>0):
            longueurUserName=int((struct.unpack('!b',monpaquet[0:1]))[0])
            print("longueur USERNAME est :",longueurUserName," et de type :", type(longueurUserName))
            #print("longueur USERNAME est :%i et de type : %s"%(longueurUserName, type(longueurUserName)))
            #longeurTitreFilm=longueurFilm-9
            statut= int((struct.unpack('!b',monpaquet[1:2]))[0])
            print("statut :", statut)
            nomUtilisateur= (struct.unpack('!%is'%longueurUserName,monpaquet[2:(longueurUserName+2)]))[0].decode('utf-8')
            print("USER: "******"on a deux listes qui sont:",self.listeUsers,"\n",self.listeUsersMovie)
            
            monpaquet=monpaquet[(longueurUserName+2):]
    
    
    #Fonction permettant de former le paquet pour rejoindre une movie particulière
    def paquetForParticularMovie(self,numSequence,movieName):
        print(movieName)
        a=4+len(movieName)
        print(a)
        Type = 3
        #decalage= NumSeq << 4
        decalage= numSequence << 4
        
        seqTyp= decalage | Type
        print(seqTyp)
        buf= struct.pack('!hh%is'%len(movieName),a,seqTyp,movieName.encode('utf-8'))
        print("le paquet pour la movie room est :",buf)
        
        return buf

    #Fonction permettant de former le paquet pour retourner dans la main room
    def retourMainRoom(self,numSequence):
        Type = 4
        decalage= numSequence << 4    
        seqTyp= decalage | Type
        print(seqTyp)
        buf= struct.pack('!hh',4,seqTyp)
        print("le paquet pour la main room est :",buf)
       
        return buf
    
    #Fonction pour depaqueter un message de chat recu
    def msgChatRecu(self,monpaquet):
        longueurPseudo=int((struct.unpack('!b',monpaquet[0:1]))[0])
        pseudo=(struct.unpack('!%is'%longueurPseudo,monpaquet[1:(longueurPseudo+1)]))[0].decode('utf-8')
        sms=(struct.unpack('!%is'%(len(monpaquet)-longueurPseudo-1),monpaquet[(longueurPseudo+1):]))[0].decode('utf-8')
        print("emetteur :",pseudo, "message :", sms)
    
        return (pseudo,sms)    
    
    #Fonction permettant de former le paquet pour quitter la main room
    def quitterMainRoom(self,numSequence):
        Type = 2
        decalage= numSequence << 4    
        seqTyp= decalage | Type
        print(seqTyp)
        buf= struct.pack('!hh',4,seqTyp)
        print("le paquet pour la main room est :",buf)
       
        return buf    
    
    
    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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)
        
        #self.transport.connect(self.serverAddress,self.serverPort) #connection au serveur
        self.nomUtilisateur=userName      
        print(userName)
        a=4+len(userName)
        print(a)
        #NumSeq=0
        Type = 1
  
        decalage= self.monNumeroSequence << 4
        
        seqTyp= decalage | Type
        print(seqTyp)
        buf= struct.pack('!hh%is'%len(userName),a,seqTyp,userName.encode('utf-8'))
        print(buf)
        self.transport.write(buf,(self.serverAddress,self.serverPort))
        #self.filattente.append([0,1,0,buf,server])
        self.filattente.append([self.monNumeroSequence,1,0,buf,(self.serverAddress,self.serverPort)])
     
        self.monNumeroSequence=self.incrementerNumeroSequence(self.monNumeroSequence)        
        
        reactor.callLater(1,self.send_And_Wait,(self.serverAddress,self.serverPort))
        
        pass
            
        
    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.
        """
        a=4+1+len(self.nomUtilisateur)+len(message)
        Type = 9
        decalage= self.monNumeroSequence << 4  
        seqTyp= decalage | Type
        print(seqTyp)
        buf= struct.pack('!hhb'+str(len(self.nomUtilisateur))+'s%is'%len(message),a,seqTyp,len(self.nomUtilisateur),self.nomUtilisateur.encode('utf-8'),message.encode('utf-8'))
        print("message de chat",buf)
        self.transport.write(buf,(self.serverAddress,self.serverPort))      
        
        self.filattente.append([self.monNumeroSequence,1,0,buf,(self.serverAddress,self.serverPort)])
        self.monNumeroSequence=self.incrementerNumeroSequence(self.monNumeroSequence)                
        reactor.callLater(1,self.send_And_Wait,(self.serverAddress,self.serverPort))
        
        pass

    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.
        """
        #pour aller dans une movie room
        if (self.room== "MainRoom"):
            buf=self.paquetForParticularMovie(self.monNumeroSequence,roomName)
            self.numeroSequenceWhenGoingMovie= self.monNumeroSequence
            
            print("J'ai fait un paquet pour acceder à une movie room")

            self.transport.write(buf,(self.serverAddress,self.serverPort))
            
            self.filattente.append([self.monNumeroSequence,1,0,buf,(self.serverAddress,self.serverPort)])
            self.monNumeroSequence=self.incrementerNumeroSequence(self.monNumeroSequence)             
            reactor.callLater(1,self.send_And_Wait,(self.serverAddress,self.serverPort))
            self.room="MovieRoom" 
             
        #pour quitter une movie room      
        elif (self.room=="MovieRoom"):
            print("zizaggggggggggggggggggggggggggggggggggggggggggggggg")
            buf=self.retourMainRoom(self.monNumeroSequence)
            self.numeroSequenceWhenGoingMain=self.monNumeroSequence
            self.transport.write(buf,(self.serverAddress,self.serverPort)) 
            
            self.filattente.append([self.monNumeroSequence,1,0,buf,(self.serverAddress,self.serverPort)])
            self.monNumeroSequence=self.incrementerNumeroSequence(self.monNumeroSequence)
            reactor.callLater(1,self.send_And_Wait,(self.serverAddress,self.serverPort))
            self.room="MainRoom" 
        
        pass

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        
        buf=self.quitterMainRoom(self.monNumeroSequence)
        self.numeroSequenceWhenOutMain=self.monNumeroSequence       
        self.transport.write(buf,(self.serverAddress,self.serverPort))
        self.filattente.append([self.monNumeroSequence,1,0,buf,(self.serverAddress,self.serverPort)])
        self.monNumeroSequence=self.incrementerNumeroSequence(self.monNumeroSequence)
        reactor.callLater(1,self.send_And_Wait,(self.serverAddress,self.serverPort))

        
        pass

    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.
        """

        reception=struct.unpack('!hh%is'%(len(datagram)-4),datagram)
        print(reception)
        seqType= int(str(reception[1]))
        corpsMessage=reception[2]
        print("le cors du msg est :",corpsMessage)

        Type= seqType & 15
        NumSeq=seqType >> 4 
       
        if (Type==0):
            self.traiterAcquittement(NumSeq)
            
            # après reception d'un acquittement pour rejoindre la movie room, on y va

            if(NumSeq>0 and self.numeroSequenceWhenGoingMovie==NumSeq):
                print("l'utilisateur est dans la movie room")
                self.clientProxy.joinRoomOKONE()
                self.numeroSequenceWhenGoingMovie=0
                #self.room="MovieRoom" 
                #print("******************************************",self.room)
            
            # après reception d'un acquittement pour quitter la movie room, on retourne donc la main room
            if(self.numeroSequenceWhenGoingMain==NumSeq and NumSeq>0):
                print("on retourne dans la Main Room")
                self.clientProxy.joinRoomOKONE()
                self.numeroSequenceWhenGoingMain=0
                #self.room="MainRoom"
                #   print("******************************************",self.room)

            
            # Acquittement pour demande de départ du système
            if (self.numeroSequenceWhenOutMain==NumSeq and self.numeroSequenceWhenOutMain!=0 ):
                self.clientProxy.leaveSystemOKONE()
                print("BYEBYEBYEBYEBYEBYEBYEBYE")
       
       
       #acquittement de l'acceptation de connexion  
        if (self.connectivite==0 and Type==7):
            """TypeAcq = 0
            decalage= NumSeq << 4
            seqTypAcq= decalage | TypeAcq
            print("sequence et type concaténé pour le 1er acquittement est", seqTypAcq)
            buff= struct.pack('!hh',4,seqTypAcq)
            self.transport.write(buff,(host_port[0],host_port[1]))"""
            
            self.envoieAcquittement(NumSeq) # envoie de l'acquittement au serveur
            self.room= "MainRoom"
            self.connectivite=1
            print("l'utilisateur est dans la ",self.room )
        #Fin acquittement de l'acceptation de connexion 
        
            
        # On recoit la liste des films
        if(Type==5):
            self.envoieAcquittement(NumSeq) # envoie de l'acquittement au serveur
            self.paquetListFilms(corpsMessage)
            
        
        #On recoit la liste des utilisateurs
        if(Type==6):
            
            if(NumSeq==2):
                self.envoieAcquittement(NumSeq) # envoie de l'acquittement au serveur
                self.paquetListUser(corpsMessage)
                print("************************************",self.listeUsers) 
                print("************************************",self.listeFilms)
                self.clientProxy.initCompleteONE(self.listeUsers,self.listeFilms) #permet d'afficher la Main Room
                
            
            #cela signifie qu'il s'agit d'une mise à jour de la liste des users recue, par le serveur
            if(NumSeq>2):
                print("LE PAQUET DE MISE A JOUR DES UITILISATEUS EST ARRIVE")
                self.envoieAcquittement(NumSeq)
                self.paquetListUser(corpsMessage)
                if (self.room=="MainRoom"): 
                    print("MISE A JOUR DE LA LISTE DES UTILISATEURS DE LA MAIN ROOM")
                    print(self.listeUsers)
                    self.clientProxy.setUserListONE(self.listeUsers)
                    print("FIN MISE A JOUR DE LA LISTE DES UTILISATEURS DE LA MAIN ROOM")
                elif (self.room=="MovieRoom"):
                    print("MISE A JOUR DE LA LISTE DES UTILISATEURS DE LA MOVIE ROOM")
                    print(self.listeUsers)
                    self.clientProxy.setUserListONE(self.listeUsersMovie)            
                    print("FIN MISE A JOUR DE LA LISTE DES UTILISATEURS DE LA MOVIE ROOM")

        
        #refus de connexion
        if(Type==8):
            print("Vous n'avez pas été autorisé à vous connecter")
            self.envoieAcquittement(NumSeq)
            if(self.connectivite==0):
                self.clientProxy.connectionRejectedONE("Pseudo trop long ou déja utilisé")
                self.connectivite=1
        
        #Lorsqu'on recoit un message de chat
        if(Type==9):
            self.envoieAcquittement(NumSeq)
            pseudo,sms=self.msgChatRecu(corpsMessage)
            if(self.nomUtilisateur!=pseudo):
                self.clientProxy.chatMessageReceivedONE(pseudo, sms)
            print("Un nouveau message")
        pass
Beispiel #20
0
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        self.seq = 1
        self.tailleHeader = 4
        self.dicoFilm = {
        }  # dictionnaire {Id:titreFilm,.....} ex:{"5":"Big Bunny",....}
        self.compteurSAW = 0  #Useful for the programming of the send & wait policy
        self.user = ""  # le nom d utilisateur que le client va utiliser: ca ne changera pas
        self.deco = -1  #pour savoir si le dernier message envoyé est une déconnexion totale du système

    def incrementeSeq(self):
        if (self.seq < 1023):
            self.seq += 1
        else:
            self.seq = 1

    def sendAndWait(self, message):
        """
        Takes in parameter :
            - the binary message (datagram) ready to be sent
            
        Sets the SendAndWait functionality : it is called by 
        different send-methods (apart from sendAcknowledgeOIE) to send a 
        non-ack datagram to the server
        
        """
        if (self.compteurSAW < 10):

            print("compteur = {0}".format(self.compteurSAW))
            print("{0} envoie: {1}".format(self.user, decoder(message)))
            self.transport.write(message,
                                 (self.serverAddress, self.serverPort))
            self.compteurSAW += 1
            self.RerunFunction = reactor.callLater(1, self.sendAndWait,
                                                   message)
            #reactor.run()
        else:
            print(
                "la valeur max du compteur est atteinte, message non transmis")
            #self.RerunFunction.cancel()
            self.compteurSAW = 0

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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)
        dico = {}
        dico["taille"] = self.tailleHeader + len(userName.encode('utf-8'))
        dico["Type"] = 1
        dico["seq"] = self.seq
        dico["user"] = userName
        print(userName)
        self.user = userName
        connexionRq = encoder(dico)
        self.sendAndWait(connexionRq)

    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.
        """
        #on prépare le message pour l'envoie au serveur
        dicoMessage = {}
        dicoMessage["taille"] = self.tailleHeader + len(
            message.encode('utf-8'))
        dicoMessage["Type"] = 5
        dicoMessage["seq"] = self.seq
        dicoMessage["message"] = message
        msgchat = encoder(dicoMessage)
        self.sendAndWait(msgchat)

        pass

    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.
        """
        #on prépare le message pour l'envoie au serveur

        dicoRequete = {}
        dicoRequete["taille"] = self.tailleHeader + 1
        dicoRequete["Type"] = 6
        dicoRequete["seq"] = self.seq
        if roomName == ROOM_IDS.MAIN_ROOM:  #if the user wants to go to the main room, the room ID is set to 0
            dicoRequete["Id"] = 0
        else:  #we have to find the room ID which corresponds to the given roomName.
            for Id, nom in self.dicoFilm.items(
            ):  # in order to do this, we can use the attibute "dicoFilm", a dictionnary with (str(roomID), roomName) as items
                if nom == roomName:
                    dicoRequete["Id"] = int(Id)
        joindreRq = encoder(dicoRequete)
        self.sendAndWait(joindreRq)

        pass

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        logoutDico = {}
        logoutDico["taille"] = self.tailleHeader
        logoutDico["Type"] = 9
        logoutDico["seq"] = self.seq
        paquet = encoder(logoutDico)
        self.deco = self.seq
        self.sendAndWait(paquet)

        pass

    def sendAcknowledgeOIE(
            self, ackSeq
    ):  #ackSeq est la sequence contenue dans le message à acquitter
        """
        Send an aknowledgment message
        """
        ackDico = {}
        ackDico["taille"] = self.tailleHeader
        ackDico["Type"] = 63
        ackDico["seq"] = ackSeq
        ackDatagram = encoder(ackDico)
        print("{0} envoie un ack de sequence: {1}".format(self.user, ackSeq))
        self.transport.write(ackDatagram,
                             (self.serverAddress, self.serverPort))

    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.
        """
        messageDico = decoder(
            datagram
        )  #The datagram's fields are decoded in a dictionnary (messageDico)
        print("{0} recoit: {1}".format(self.user, messageDico))
        Type = messageDico.get("Type")

        if Type == 2:  #le datagram contient la liste des films

            self.movieList = [
            ]  #list of 3-elements-Tuples [(filmName,filmIpAdresse,filmPort)...]. used by the client Proxy (initCompleteONE()) to display the available movies
            i = 0
            while "taille{0}".format(
                    i
            ) in messageDico:  #to fill in the movieList and the dicoFilm dictionnary
                #print(messageDico)
                tupleTemporaire = (str(messageDico["nom{}".format(i)]),
                                   str(messageDico["ip{}".format(i)]),
                                   str(messageDico["port{}".format(i)]))
                self.movieList.append(tupleTemporaire)
                self.dicoFilm["{0}".format(messageDico["Id{}".format(
                    i)])] = messageDico["nom{0}".format(
                        i)]  #ex: dicoFilm={"5":'Big Buck Bunny',..... }
                #print(self.dicoFilm)
                i += 1
            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

        if Type == 3:  #Le datagram contient la liste des utilisateurs
            self.userList = [
            ]  #list of 2-elements-Tuples [(userName,movieTitle)...]. used by the client Proxy (initCompleteONE()) to display the online users
            i = 0
            while "taille{0}".format(
                    i) in messageDico:  #to fill in the userList
                if messageDico["Id{0}".format(i)] == 0:
                    roomName = ROOM_IDS.MAIN_ROOM
                else:  #find the movieTitle which matches the room ID of each client
                    roomId = messageDico["Id{0}".format(
                        i)]  #roomId est un str contenant un decimal: ex  "5"
                    roomName = self.dicoFilm["{0}".format(roomId)]
                tupleTemporaire = (str(messageDico["user{0}".format(i)]),
                                   roomName)
                #print("tupletemporaire={0}".format(tupleTemporaire))
                self.userList.append(tupleTemporaire)
                i += 1
            #print(self.userList)
            #print(self.movieList)
            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

            self.clientProxy.initCompleteONE(
                self.userList, self.movieList
            )  #affiche les listes des films disponibles et des utilisateurs connectes

        if Type == 4:  # le datagram est une MAJ utilisateur

            roomId = messageDico["Id"]
            userName = messageDico["user"]

            if roomId == 0:  #l'utilisateur veualler dans la salle principale
                roomName = ROOM_IDS.MAIN_ROOM
            elif roomId == 255:  #deconnexion totale du systeme
                roomName = ROOM_IDS.OUT_OF_THE_SYSTEM_ROOM
            else:  # l' utilisateur veut aller dans une movieRoom spécifique
                for Id, nom in self.dicoFilm.items(
                ):  #chercher le titre du Film associé à cet Id (et pas le nom générique ROOM_IDS.MOVIE_ROOM)
                    if int(Id) == roomId:
                        roomName = nom
            self.clientProxy.userUpdateReceivedONE(
                userName, roomName
            )  #MAJ la list des utilisateurs dans le systeme et la modifier sur l'interface graphique

            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

        if Type == 7:  #  inscription acceptee
            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

        if Type == 8:  # error: inscription refusee
            errorCode = messageDico[
                "erreur"]  # recuperer le code erreur contenu dans le message et informer le client selon la valeur du code
            if errorCode == 1:
                self.clientProxy.connectionRejectedONE(
                    "nom d'utilisateur déjà utilisé")
            elif errorCode == 2:
                self.clientProxy.connectionRejectedONE(
                    "nom d'utilisateur dépassant 254 octets")
            elif errorCode == 3:
                self.clientProxy.connectionRejectedONE(
                    "nom d'utilisateur contenant un ou plusieurs espaces")

            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

        if Type == 10:  #recevoir un message de chat des autres utilisateurs
            if not messageDico[
                    "user"] == self.user:  #Pour ne pas afficher un message dont le client est l'auteur
                rUserName = messageDico["user"]
                message = messageDico["message"]
                self.clientProxy.chatMessageReceivedONE(
                    rUserName, message
                )  #afficher le message sur l'interface graphique avec son auteur

            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

        if Type == 11:  #demande de connexion a une salle acceptee par le serveur
            self.clientProxy.joinRoomOKONE(
            )  #commander la connection de l'interface graphique à la salle de film que j'ai demandée

            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

        if Type == 12:  #demande de connexion a une salle rejetee par le serveur
            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

            self.clientProxy.connectionRejectedONE(
                "Echec: veuillez vous reconnecter"
            )  #message erreur + reouverture de l interface pour une nouvelle tentative

        if Type == 63:
            if messageDico[
                    "seq"] == self.seq:  #le message recu est bien un ack à mon dernier message
                self.RerunFunction.cancel(
                )  # arreter le renvoi programmé dans la methode sendAndWait
                if self.deco == self.seq:  # si mon dernier message était une deconnexion totale
                    self.clientProxy.leaveSystemOKONE(
                    )  #fermer l interface graphique
                #on incrémente le numéro de séquence
                self.incrementeSeq(
                )  # N incrementer la sequence que si j'ai recu le bon acquittement
                self.compteurSAW = 0  #Reinitialise le compteur du sensAndWait

        return messageDico
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """

        :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.

        :param clientProxy: The clientProxy, which the protocol must use

            to interact with the Graphical User Interface.


        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 attributes:


        .. attribute:: serverAddress


            The IP address of the c2w server.


        .. attribute:: serverPort


            The port number of the c2w server.


        .. attribute:: clientProxy


            The clientProxy, which the protocol must use

            to interact with the Graphical User Interface.


        .. attribute:: lossPr


            The packet loss probability for outgoing packets.  Do

            not modify this value!  (It is used by startProtocol.)


        .. 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 of the c2w server.

        self.serverPort = serverPort

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

        self.clientProxy = clientProxy

        self.lossPr = lossPr

        # numero de sequence du paquet courant
        self.numeroSeq_courant = 0

        # numero de sequence du paquet qu'on a envoyé en dernière position
        self.numeroSeq_Prec = 0

        #on garde dans cette liste tous les paquets envoyés jusqu'a obtention de leur ack
        self.paquet_memoire = []

        #liste des utilisateurs
        self.users = []

        #numero de sequence du paquet envoyé lorsqu'on veut acceder a une movie room
        self.numeroSeq_GoToMovie = 0

        #numero de sequence du paquet envoyé lorsqu'on veut se deconnecter du système
        self.deconnexion = 0

        #numero de l utilisateur
        self.username = ''

        #room dans laquelle l utilisateur se trouve
        self.room = ''

        #numero de sequence du paquet envoyé lorqu on veut quitter la movie room
        self.main_rome = 0

        #variable pour recuperer le nom du film de l utilisateur lorqu il accede a la movie room
        self.roomName = ''

    #--------------------------------------------------------------------------
    # Fonction pour gerer les numeros de sequence
    #--------------------------------------------------------------------------

    def NumSeq(self, numSeq):
        #on genere un numero de sequence pour chaque paquet envoyé
        #il est initialisé à 0 et incremente de 1 a chaque nouvel envoi
        #jusqu'a 8191 où il revient à 0
        if (numSeq == 4095):
            numSeq = 0
        else:
            numSeq += 1
        return numSeq

    #--------------------------------------------------------------------------
    # Fonction pour definir les formats de paquet
    #--------------------------------------------------------------------------

    def FormatPaquet(self, Type, numSeq, longueur, messageTotal):
        longueur = len(messageTotal)
        entete = (Type << 12) + (numSeq << 16) + longueur
        paquet = struct.pack('!II' + str(len(messageTotal)) + 's', entete,
                             messageTotal.encode('utf−8'))
        return (paquet)

    #--------------------------------------------------------------------------
    # Fonction pour definir le format de qu paquet de login
    #--------------------------------------------------------------------------

    def PaquetLogin(self, Type, numSeq, userName):
        self.numeroSeq_courant = numSeq
        userNamepack = struct.pack(
            str(len(userName.encode('utf−8'))) + 's', userName.encode('utf−8'))
        longueur = len(userNamepack) + 4
        entete = (Type << 28) + (numSeq << 16) + longueur
        paquet = struct.pack('!I', entete) + userNamepack
        return (paquet)

    #--------------------------------------------------------------------------
    # Fonction pour recuperer les inforamtions des paquets recu
    #--------------------------------------------------------------------------

    def PaquetRecu(self, datagram):
        print(datagram)
        (entete,
         messageTotal) = struct.unpack('!I' + str(len(datagram) - 4) + 's',
                                       datagram)
        entete1 = entete >> 28
        Type = entete1 & int('1111', 2)
        entete2 = entete >> 16
        numSeq = entete2 & int('0000111111111111', 2)
        longueur = entete & int('1111111111111111', 2)
        return (Type, numSeq, longueur, messageTotal)

    #--------------------------------------------------------------------------
    # Fonction pour definir le foramts des paquets d'Ack
    #--------------------------------------------------------------------------

    def FormatAck(self, Type, numSeq):
        longueur = 4
        entete = (Type << 28) + (numSeq << 16) + longueur
        paquet = struct.pack('!I', entete)
        return (paquet)

    #--------------------------------------------------------------------------
    # Fonction pour recuperer la liste des utilisateurs de la Main Room
    #--------------------------------------------------------------------------
    def PaquetUser(self, datagram):
        # on affiche le paquet recu
        print(" ".join("{:02x}".format(donnee) for donnee in datagram))

        # liste des utilisateurs du systeme
        userList = list()
        # liste des utilisateurs se trouvant dans la meme movie room que l utilisateur
        users_movie = list()

        #on separe l entete du message utile
        (entete,
         messageTotal) = struct.unpack('!I' + str(len(datagram) - 4) + 's',
                                       datagram)
        print(entete)
        entete1 = entete >> 28
        Type = entete1 & int('1111', 2)
        entete2 = entete >> 16
        numSeq = entete2 & int('0000111111111111', 2)
        longueur = entete & int('1111111111111111', 2)

        datagram = datagram[4:]
        print('le datagram est:' + str(datagram))
        longueurMes = len(messageTotal)
        #on recupere les informations recu jusqu a ce qu il n y a plus rien dans le paquet
        while (longueurMes != 0):
            longName = struct.unpack('!B', datagram[0:1])[0]
            print(longName)
            datagram = datagram[1:]
            print('taille du nom :' + str(longName))
            user_name = struct.unpack(
                str(longName) + 's', datagram[0:longName])[0]
            user_name = user_name.decode('utf-8')
            datagram = datagram[longName:]
            statut = struct.unpack('B', datagram[0:1])[0]
            if (statut == 0):
                statutUser = ROOM_IDS.MAIN_ROOM
            else:
                statutUser = ROOM_IDS.MOVIE_ROOM
                users_movie.append((user_name, self.roomName))
            userList.append((user_name, statutUser))
            datagram = datagram[1:]
            longueurMes = longueurMes - (longName + len(str(statut)) +
                                         len(str(longName)))
        print('Toute la liste est', userList)
        return (userList, users_movie)

    #----------------------------------------------------------------
    # Fonction pour la liste des videos disponibles
    #----------------------------------------------------------------

    def PaquetMovie(self, datagram):
        # liste contenant la longueur, le nom, l adresse IP et le port des films
        movieList = list()
        #on separe l'entete du message en lui meme
        (entete,
         messageTotal) = struct.unpack('!I' + str(len(datagram) - 4) + 's',
                                       datagram)
        entete1 = entete >> 28
        Type = entete1 & int('1111', 2)
        entete2 = entete >> 16
        numSeq = entete2 & int('0000111111111111', 2)
        longueur = entete & int('1111111111111111', 2)
        datagram = datagram[4:]
        longueurMes = len(messageTotal)

        #on recupere les informations recu jusqu a ce qu il n y a plus rien dans le paquet
        while (longueurMes > 0):

            longMovie = struct.unpack('!B', datagram[0:1])[0]
            datagram = datagram[1:]
            movie_name = struct.unpack(
                str(longMovie) + 's', datagram[0:longMovie])[0]
            movie_name = movie_name.decode('utf-8')
            datagram = datagram[longMovie:]

            # on recupere l adresse IP et le port de chaque film
            adr_ip = struct.unpack('!I', datagram[0:4])[0]
            adr_ip3 = adr_ip & 255
            adr_ip = adr_ip >> 8
            adr_ip2 = adr_ip & 255
            adr_ip = adr_ip >> 8
            adr_ip1 = adr_ip & 255
            adr_ip = adr_ip >> 8
            adr_ip0 = adr_ip
            ip_adress = str.join(
                ".", (str(adr_ip0), str(adr_ip1), str(adr_ip2), str(adr_ip3)))
            datagram = datagram[4:]
            port = struct.unpack('!H', datagram[0:2])[0]

            #on ajoute chaque film dans la movieList
            movieList.append((movie_name, ip_adress, port))

            datagram = datagram[2:]
            longueurMes = longueurMes - (longMovie +
                                         (len(str(ip_adress)) - 3) +
                                         len(str(port)) + len(str(longMovie)))
        print('les films disponibles sont', movieList)
        return (movieList)

    #--------------------------------------------------------------------------
    # Fonction pour aller dans une movie room
    #--------------------------------------------------------------------------

    def FormatSelectMovie(self, Type, numSeq, movieName):
        self.numeroSeq_courant = numSeq
        longueur = len(movieName) + 4
        entete = (Type << 28) + (numSeq << 16) + longueur
        paquet = struct.pack('!I' + str(len(movieName.encode('utf-8'))) + 's',
                             entete, movieName.encode('utf−8'))
        return (paquet)

    #--------------------------------------------------------------------------
    # Fonction pour quitter la salle de video
    #--------------------------------------------------------------------------
    def FormatLeaveRoom(self, Type, numSeq):
        self.numeroSeq_courant = numSeq
        longueur = 4
        entete = (Type << 28) + (numSeq << 16) + longueur
        paquet = struct.pack('!I', entete)
        return (paquet)

    #--------------------------------------------------------------------------
    # Fonction pour les messages
    #--------------------------------------------------------------------------

# fonction pour envoyer un message

    def EnvoiMsg(self, Type, numSeq, username, message):
        paquetMes = struct.pack(
            '!B' + str(len(username.encode('utf−8'))) + 's' +
            str(len(message.encode('utf−8'))) + 's',
            len(username.encode('utf−8')), username.encode('utf−8'),
            message.encode('utf−8'))
        longSpeudo = len(self.username.encode('utf−8'))
        longMsg = len(message.encode('utf−8'))
        self.numeroSeq_courant = numSeq
        longueur = longSpeudo + longMsg + 1 + 4
        entete = (Type << 28) + (numSeq << 16) + longueur
        paquet = struct.pack('!I', entete) + paquetMes
        print('la paquet est:' + str(paquet))
        return (paquet)

# fonction pour recuperer les informations lorqu on recoit un message

    def MsgRecu(self, datagram):
        (entete,
         messageTotal) = struct.unpack('!I' + str(len(datagram) - 4) + 's',
                                       datagram)
        print(entete)
        entete1 = entete >> 28
        Type = entete1 & int('1111', 2)
        entete2 = entete >> 16
        numSeq = entete2 & int('0000111111111111', 2)
        longueur = entete & int('1111111111111111', 2)
        datagram = datagram[4:]
        longMes = longueur - 4
        longName = struct.unpack('!B', datagram[0:1])[0]
        datagram = datagram[1:]
        user_name = struct.unpack(str(longName) + 's', datagram[0:longName])[0]
        user_name = user_name.decode('utf-8')
        datagram = datagram[longName:]
        longMessage = longMes - 1 - longName
        message = struct.unpack(
            str(longMessage) + 's', datagram[0:longMessage])[0]
        message = message.decode('utf-8')
        return (user_name, message)

    #----------------------------------------------------------------
    # Fonction pour send & wait
    #----------------------------------------------------------------

# fonction pour verifier si on a recu un ack

    def traitementAck(self, numSeq):

        for p in self.paquet_memoire:
            if (p[0] == numSeq):
                p[2] = 1
                print('ack envoye par le serveur')

    #fonction pour envoyer le paquet si jamais on a toujours pas recu d ack
    def sendAndWait(self, host_port):
        for p in self.paquet_memoire:
            if (p[4] == host_port):
                if (p[1] <= 7):
                    if (p[2] == 0):
                        self.transport.write(p[3], host_port)
                        p[1] += 1
                        print('nombre de message envoye:' + str(p[1]))
                        reactor.callLater(1, self.sendAndWait, host_port)
                    elif (p[2] == 1):
                        print('Le paquet a ete aquitte')
                        self.paquet_memoire.remove(p)
                else:
                    print('Le paquet envoye est perdu')
                    self.paquet_memoire.remove(p)

    def startProtocol(self):
        """

        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!
        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.

        """
        self.transport = LossyTransport(self.transport, self.lossPr)

        DatagramProtocol.transport = self.transport

    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)
        print(userName)
        # on forme le paquet pour le requete de connexion
        paquet = self.PaquetLogin(1, 0, userName)
        print(paquet)
        print(" ".join("{:02x}".format(donnee) for donnee in paquet))
        #on sauvegarde le nom de l utilisateur lorsqu il fait une requete de connexion
        self.username = userName

        # on envoie le paquet au serveur
        server = (self.serverAddress, self.serverPort)
        self.transport.write(paquet, server)

        #on sauvegarde le paquet envoyé
        self.paquet_memoire.append([0, 1, 0, paquet, server])
        self.numeroSeq_Prec = self.numeroSeq_courant
        self.numeroSeq_courant = self.NumSeq(self.numeroSeq_courant)

        #on attend 1s, si on n a toujours pas recu d ack on renvoit le paquet au serveur
        reactor.callLater(1, self.sendAndWait, server)

    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.

        """

        paquet = self.EnvoiMsg(7, self.numeroSeq_courant, self.username,
                               message)
        print(paquet)
        print(" ".join("{:02x}".format(donnee) for donnee in paquet))
        # on envoie le paquet au serveur
        server = (self.serverAddress, self.serverPort)
        self.transport.write(paquet, server)
        self.paquet_memoire.append(
            [self.numeroSeq_courant, 1, 0, paquet, server])
        self.numeroSeq_Prec = self.numeroSeq_courant
        self.numeroSeq_courant = self.NumSeq(self.numeroSeq_courant)
        reactor.callLater(1, self.sendAndWait, server)

        pass

    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.

        """
        server = (self.serverAddress, self.serverPort)
        #pour acceder a une movie room
        if (self.room == 'main_room'):
            paquet = self.FormatSelectMovie(2, self.numeroSeq_courant,
                                            roomName)
            self.numeroSeq_GoToMovie = self.numeroSeq_courant
            self.roomName = roomName
            self.transport.write(paquet, server)
            self.paquet_memoire.append(
                [self.numeroSeq_courant, 1, 0, paquet, server])
            self.numeroSeq_Prec = self.numeroSeq_courant
            self.numeroSeq_courant = self.NumSeq(self.numeroSeq_courant)
            reactor.callLater(1, self.sendAndWait, server)

        #pour sortir de la movie room
        elif (self.room == 'movie_room'):
            paquet = self.FormatLeaveRoom(3, self.numeroSeq_courant)
            self.main_rome = self.numeroSeq_courant
            self.transport.write(paquet, server)
            self.paquet_memoire.append(
                [self.numeroSeq_courant, 1, 0, paquet, server])
            self.numeroSeq_Prec = self.numeroSeq_courant
            self.numeroSeq_courant = self.NumSeq(self.numeroSeq_courant)
            reactor.callLater(1, self.sendAndWait, server)

        pass

    def sendLeaveSystemRequestOIE(self):
        """

        Called by the client proxy  when the user

        has clicked on the leave button in the main room.

        """

        server = (self.serverAddress, self.serverPort)
        paquet = self.FormatLeaveRoom(4, self.numeroSeq_courant)
        self.deconnexion = self.numeroSeq_courant
        self.transport.write(paquet, server)
        self.paquet_memoire.append(
            [self.numeroSeq_courant, 1, 0, paquet, server])
        self.numeroSeq_Prec = self.numeroSeq_courant
        self.numeroSeq_courant = self.NumSeq(self.numeroSeq_courant)

        reactor.callLater(1, self.sendAndWait, server)

        pass

    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.

        """

        #on recupere les informations du paquet recu

        print(" ".join("{:02x}".format(donnee) for donnee in datagram))

        (Type, numSeq, longueur, messageTotal) = self.PaquetRecu(datagram)

        #-------------------------------------------------------------------------
        #on a recu un ack

        if (Type == 0):
            self.traitementAck(numSeq)
            print('ackkk')
            # on a recu un ack apres une requete pour acceder a la movie room
            # on rejoint donc cette movie room
            if (self.numeroSeq_GoToMovie == numSeq and numSeq > 0):
                print('rejoint la movie room')
                self.clientProxy.joinRoomOKONE()
                self.numeroSeq_GoToMovie = 0
                self.room = 'movie_room'

            # on a recu un ack apres un requete pour quitter la movie room
            #on rejoint donc la main room
            if (self.main_rome == numSeq and numSeq > 0):
                print('sortie movie room')
                self.clientProxy.joinRoomOKONE()
                self.main_rome = 0
                self.room = 'main_room'

            # on a recu un ack apres une requete pour quitter le système
            # on sort donc de l application
            if (self.deconnexion == numSeq):
                if (self.deconnexion != 0):
                    self.clientProxy.leaveSystemOKONE()
                    print('l utilisateur a été suprimé')

    #-------------------------------------------------------------------------
    # on envoie un ack au serveur

        if (Type != 0):
            print('message recu')
            ack = self.FormatAck(0, numSeq)
            print('ack envoyé au serveur:' + str(ack))
            self.transport.write(ack, host_port)
            print('ack bien envoyé au serveur avec seqnum:' + str(numSeq))
    #-------------------------------------------------------------------------
    # on a recu la liste des utilisateurs

        if (Type == 6):
            if (numSeq == 1):
                (userList, usersMovie) = self.PaquetUser(datagram)
                self.users = userList
                print('la liste :' + str(self.users))

            elif (numSeq > 1):
                (userList, usersMovie) = self.PaquetUser(datagram)
                if (self.room == 'main_room'):
                    self.clientProxy.setUserListONE(userList)
                elif (self.room == 'movie_room'):
                    self.clientProxy.setUserListONE(usersMovie)

    #-------------------------------------------------------------------------
    # on a recu la liste des videos disponibles

        if (Type == 5):
            movieList = self.PaquetMovie(datagram)
            print('la liste des videos est:' + str(movieList))
            print('la liste est:' + str(self.users))
            self.clientProxy.initCompleteONE(self.users, movieList)

            self.room = 'main_room'
            print(movieList)
    #-------------------------------------------------------------------------
    # on a recu un message

        if (Type == 7):
            (userNom, message) = self.MsgRecu(datagram)
            self.clientProxy.chatMessageReceivedONE(userNom, message)
            print('le message qu on a recu est:' + str(message))

    #-------------------------------------------------------------------------
    #  on a recu un message d erreur apres notre requete de connexion

        if (Type == 9):
            erreur = 'errreur'
            self.clientProxy.connectionRejectedONE(erreur)
        pass
Beispiel #22
0
class c2wUdpChatClientProtocol(DatagramProtocol):
    UserIdDict = {}

    def __init__(self,
                 serverAddress,
                 serverPort,
                 clientProxy,
                 lossPr,
                 lastSequenceNumberSentJR=None,
                 lastSequenceNumberSentLS=None,
                 lastSequenceNumberSentLR=None,
                 lastSequenceNumberSentSM=None,
                 lastSequenceNber=0):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        self.SequenceNumber = 0
        self.UserId = 0
        self.SessionToken = 0
        self.movieList = []
        self.lastSequenceNumberSentJR = lastSequenceNumberSentJR
        self.lastSequenceNumberSentLS = lastSequenceNumberSentLS
        self.lastSequenceNumberSentSM = lastSequenceNumberSentSM
        self.ACKLR = False
        self.counterLR = 0
        self.ACKJR = False
        self.counterJR = 0
        self.counterSM = 0
        self.ACKSM = False
        self.lastSequenceNumberSentLR = lastSequenceNumberSentLR
        self.lastSequenceNber = lastSequenceNber

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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.
        """
        if self.counterLR == 4 and self.ACKLR == False:
            self.clientProxy.applicationQuit()
        Version = 1
        Type = 1
        self.counterLR += 1
        usName = userName.encode('utf-8')

        uName = struct.pack('>H' + str(len(usName)) + 's', len(usName), usName)
        Payload = struct.pack('>H' + str(len(uName)) + 's', 0, uName)
        Psize = len(Payload)
        self.lastSequenceNumberSentLR = self.SequenceNumber
        """not important"""
        LoginRequest = struct.pack(
            '>BBHHH' + str(Psize) + 's', Version * 2**4 + Type,
            self.SessionToken // (2**16),
            self.SessionToken - (2**16) * (self.SessionToken // (2**16)),
            self.SequenceNumber, Psize, Payload)

        ##if self.SequenceNumber==self.lastSequenceNber:
        if self.ACKLR == False:
            self.transport.write(LoginRequest,
                                 (self.serverAddress, self.serverPort))
            self.lastSequenceNber = self.lastSequenceNumberSentLR

        if self.ACKLR == False and self.counterLR <= 3:
            reactor.callLater(1, self.sendLoginRequestOIE, userName)

        #Version=1
        #Type=1
        #SessionToken=0
        #SequenceNumber=0
        #userName=userName.encode('utf-8')
        #UserName=struct.pack('>H'+str(len(userName))+'s',len(userName),userName)
        #Payload=struct.pack('>H'+str(len(UserName))+'s',0,UserName)
        #PayloadSize=len(Payload)
        #LRQ=struct.pack('>BBHHH'+str(PayloadSize)+'s',Version*2**4+Type,SessionToken//(2**16),SessionToken-(2**16)*SessionToken//(2**16),SequenceNumber,PayloadSize,Payload)
        #self.transport.write(LRQ,(self.serverAddress,self.serverPort))

    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.
        """

        if self.counterSM == 3 and self.ACKSM == False:
            self.clientProxy.applicationQuit()
        Version = 1
        Type = 6
        self.counterSM += 1
        self.lastSequenceNumberSentSM = self.SequenceNumber
        Message = message.encode('utf-8')

        Pld = struct.pack('>HH' + str(len(Message)) + 's', self.UserId,
                          len(Message), Message)
        PldSize = len(Pld)

        ChatMessage = struct.pack(
            '>BBHHH' + str(PldSize) + 's', Version * 2**4 + Type,
            self.SessionToken // (2**16),
            self.SessionToken - (2**16) * (self.SessionToken // (2**16)),
            self.SequenceNumber, PldSize, Pld)
        print(self.ACKSM)
        if self.ACKSM == False:
            self.transport.write(ChatMessage,
                                 (self.serverAddress, self.serverPort))
            self.lastSequenceNber = self.SequenceNumber
        if self.ACKSM == False and self.counterSM <= 3:
            self.SequenceNumber = self.SequenceNumber - 1
            reactor.callLater(1, self.sendChatMessageOIE, message)
        self.SequenceNumber += 1
        if self.counterSM == 1:
            self.ACKSM = False
        pass

    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.
        """

        if roomName == ROOM_IDS.MAIN_ROOM:
            roomID = 1
        else:
            for i in self.movieList:
                if i[0] == roomName:
                    roomID = i[3]

        if self.counterJR == 3:
            self.clientProxy.applicationQuit()
        Version = 1
        Type = 5

        self.counterJR += 1
        self.lastSequenceNumberSentJR = self.SequenceNumber

        GTR = struct.pack(
            '>BBHHHH', Version * 2**4 + Type, self.SessionToken // (2**16),
            self.SessionToken - (2**16) * (self.SessionToken // (2**16)),
            self.SequenceNumber, 2, roomID)
        print(self.ACKJR)
        if self.ACKJR == False:
            self.transport.write(GTR, (self.serverAddress, self.serverPort))
            self.lastSequenceNber = self.lastSequenceNumberSentJR
        if self.ACKJR == False and self.counterJR <= 3:
            self.SequenceNumber = self.SequenceNumber - 1
            reactor.callLater(1, self.sendJoinRoomRequestOIE, roomName)
        self.SequenceNumber += 1
        if self.counterJR == 1:
            self.ACKJR = False

        pass

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        Version = 1
        Type = 7
        self.lastSequenceNumberSentLS = self.SequenceNumber
        LOR = struct.pack(
            '>BBHHH', Version * 2**4 + Type, self.SessionToken // (2**16),
            self.SessionToken - (2**16) * (self.SessionToken // (2**16)),
            self.SequenceNumber, 0)
        self.transport.write(LOR, (self.serverAddress, self.serverPort))

        pass

    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 = struct.unpack('>BBHHH' + str(len(datagram) - 8) + 's',
                               datagram)
        Version = Packet[0] // (2**4)
        Type = Packet[0] - (2**4) * (Packet[0] // (2**4))
        self.SessionToken = Packet[1] * (2**16) + Packet[2]
        self.SequenceNumber = Packet[3]

        PayloadSize = Packet[4]
        Payload = Packet[5]

        if Type == 0:
            if self.SequenceNumber == self.lastSequenceNumberSentLR:
                self.ACKLR = True
            if self.SequenceNumber == self.lastSequenceNumberSentJR:
                self.ACKJR = True
                self.counterJR = 0
                #print('me here' + str(self.SessionToken))
                self.clientProxy.joinRoomOKONE()
                self.RRS()
            if self.SequenceNumber == self.lastSequenceNumberSentLS:
                self.clientProxy.leaveSystemOKONE()
                #self.RRS()

            if self.SequenceNumber == self.lastSequenceNumberSentSM:
                self.ACKSM = True
                self.counterSM = 0

        if Type != 0:  ## if the datagram isn't an ACK we have to send one to the server
            Ack = struct.pack(
                '>BBHHH', 16, self.SessionToken // (2**16),
                self.SessionToken - (2**16) * (self.SessionToken // (2**16)),
                self.SequenceNumber, 0)
            self.transport.write(Ack, host_port)
        if Type == 2:
            #print(self.SessionToken)
            self.UserId = struct.unpack('>BH' + str(len(Payload) - 3) + 's',
                                        Payload)[1]
            ResponseCode = struct.unpack('>B' + str(len(Payload) - 1) + 's',
                                         Payload)[0]

            if ResponseCode == 2:
                self.clientProxy.connectionRejectedONE(
                    'Connection failed : Username too long!')
            if ResponseCode == 1:
                self.clientProxy.connectionRejectedONE(
                    'Connection failed : invalid Username!')
            if ResponseCode == 3:
                self.clientProxy.connectionRejectedONE(
                    'Connection failed : Username already taken!')
            if ResponseCode == 4:
                self.clientProxy.connectionRejectedONE(
                    'Connection failed : Service not available!')
        if Type == 4 and self.SequenceNumber == 1:
            c2wUdpChatClientProtocol.UserIdDict = decodeRSTPayload(Payload)[2]
            (userList, self.movieList) = decodeRSTPayload(Payload)[0:2]

            self.clientProxy.initCompleteONE(userList, self.movieList)
        if Type == 4 and self.SequenceNumber != 1:
            c2wUdpChatClientProtocol.UserIdDict = decodeRSTPayload(Payload)[2]
            userList = decodeRSTPayload(Payload)[0]
            #print(userList)
            self.clientProxy.setUserListONE(userList)
            #print(self.SessionToken)
        if Type == 6:

            MessageandId = struct.unpack('>HH' + str(len(Payload) - 4) + 's',
                                         Payload)
            Message = MessageandId[2].decode('utf-8')
            Id = MessageandId[0]
            username = c2wUdpChatClientProtocol.UserIdDict[Id]
            print('me' + str(username))
            self.clientProxy.chatMessageReceivedONE(username, Message)
        if Type == 3:
            userList = decodeRSTPayload(Payload)[0]
            c2wUdpChatClientProtocol.UserIdDict = decodeRSTPayload(Payload)[2]
            for user in userList:
                self.clientProxy.userUpdateReceivedONE(user[0], user[1])

    def RRS(self):
        Version = 1
        Type = 3
        self.SequenceNumber += 1
        #print('RRS    :',self.SequenceNumber)
        RRS = struct.pack(
            '>BBHHH', Version * 2**4 + Type, self.SessionToken // (2**16),
            self.SessionToken - (2**16) * (self.SessionToken // (2**16)),
            self.SequenceNumber, 0)
        self.transport.write(RRS, (self.serverAddress, self.serverPort))
        self.lastSequenceNber = self.SequenceNumber

        pass
Beispiel #23
0
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
		: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.
		:param clientProxy: The clientProxy, which the protocol must use
			to interact with the Graphical User Interface.

		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 attributes:

		.. attribute:: serverAddress

			The IP address (or the name) of the c2w server.

		.. attribute:: serverPort

			The port number used by the c2w server.

		.. attribute:: clientProxy

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

		.. attribute:: lossPr

			The packet loss probability for outgoing packets.  Do
			not modify this value!  (It is used by startProtocol.)

		.. note::
			You must add attributes and methods to this class in order
			to have a working and complete implementation of the c2w
			protocol.
		"""
        self.serverAddress = serverAddress
        self.serverPort = serverPort
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        self.idcall = None
        self.status = None
        self.userID = None
        self.seq_num = 0
        self.expected_seq_num = 0
        self.listOfUserName = []
        self.listOfUserId = ()
        self.userNames = []
        self.listOfTitles = []
        self.listOfMovieId = []
        self.usernamesUpdated = 0
        self.listOfMovies = []
        self.NbrMovie = None
        self.NbrUser = None
        self.current_movie_room_id = None
        self.requested_movie_room_id = None
        self.type_last_message = None
        self.connected = False
        self.requestMovieName = None
        self.MovieName = None

    def startProtocol(self):
        """
		DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

		If in doubt, do not add anything to this method.  Just ignore it.
		It is used to randomly drop outgoing packets if the -l
		command line option is used.
		"""
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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.
		"""
        if type(userName) == str:
            moduleLogger.debug('loginRequest called with username=%s',
                               userName)
            TYPE = '0001'
            self.type_last_message = int(TYPE, 2)
            A = '0'
            R = '0'
            ACK_NUM = 0
            DATA = userName
            buffer_length = 6 + len(DATA)
            buf = ctypes.create_string_buffer(buffer_length)
            fourbyte = (int(TYPE, 2) << 28) + (int(A, 2) << 27) + (
                int(R, 2) << 26) + (int(str(ACK_NUM), 2) << 13) + (
                    int(str(self.seq_num), 2) << 0)
            struct.pack_into('>IH' + str(len(DATA)) + 's', buf, 0, fourbyte,
                             buffer_length, DATA)
            self.transport.write(buf.raw,
                                 (self.serverAddress, self.serverPort))
            self.idcall = reactor.callLater(3.0, self.sendLoginRequestOIE,
                                            [userName])

        else:
            if type(userName) == list:
                if not (userName == []):
                    first_username = userName[0]
                    self.sendLoginRequestOIE(first_username)
                    userName.pop(0)
                    self.sendLoginRequestOIE(userName)
                else:
                    return

    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.
		"""
        ACK_NUM = 0

        self.send_Public_Message(ACK_NUM, self.seq_num, self.userID, message)
        self.idcall = reactor.callLater(3.0, self.sendChatMessageOIE,
                                        [message])

    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.
		"""
        ACK_NUM = 0

        if (roomName == ROOM_IDS.MAIN_ROOM):
            self.requested_movie_room_id = 0
            self.status = 1
            self.MovieName = ROOM_IDS.MAIN_ROOM
            self.send_MainRoom_Request(ACK_NUM, self.seq_num, self.userID)
        else:
            indexOfRoom = self.listOfTitles.index(roomName)
            self.MovieName = roomName
            self.status = 0
            movieId = self.listOfMovieId[indexOfRoom]
            self.send_MovieRoom_Request(ACK_NUM, self.seq_num, self.userID,
                                        movieId)
        self.idcall = reactor.callLater(3.0, self.sendJoinRoomRequestOIE,
                                        [roomName])

    def sendLeaveSystemRequestOIE(self):
        """
		Called by the client proxy  when the user
		has clicked on the leave button in the main room.
		"""
        ACK_NUM = 0
        self.disconnect(ACK_NUM, self.seq_num, self.userID)
        self.clientProxy.applicationQuit()
        self.idcall = reactor.callLater(3.0, self.sendLeaveSystemRequestOIE)

    def datagramReceived(self, data, (host, port)):
        """
		:param data: The message received from the server
		:type data: A string of indeterminate length

		Twisted calls this method whenever new data is received on this
		connection.
		"""
        j = struct.unpack_from('!I', data[0:])[0]
        if (j == 12):
            l = data[4:].split('.')
            for item in l:
                if not (item == ''):
                    self.listOfMovieId.append(int(item))
        else:
            dataParsed = core.parseReceivedData(data)
            TYPE = dataParsed[0]
            data_extracted = dataParsed[6]
            if (TYPE == 2 and self.connected == False):
                self.AnalyseUserMessage(data_extracted)
                self.clientProxy.initCompleteONE(self.listOfUserName,
                                                 self.listOfMovies)
                self.sendAck(dataParsed[5])
                self.connected = True
            elif (TYPE == 2 and self.connected == True and self.status == 1):
                self.AnalyseUserMessage(data_extracted)
                self.clientProxy.setUserListONE(self.listOfUserName)
            elif (TYPE == 2 and self.connected == True and self.status == 0):
                self.AnalyseUserMessageForMovieRoom(self.MovieName,
                                                    data_extracted)
                self.clientProxy.setUserListONE(self.listOfUserName)
            elif (TYPE == 3):
                self.AnalyseMovieMessage(data_extracted)
                self.sendAck(dataParsed[5])
            elif (TYPE == 4):
                PublicMessage_infos = core.extract_public_message(
                    data_extracted)
                userId = PublicMessage_infos[0]
                indiceUser = self.listOfUserId.index(userId)
                username = self.listOfUserName[indiceUser][0]
                self.clientProxy.chatMessageReceivedONE(
                    username, PublicMessage_infos[2])
                self.sendAck(dataParsed[5])
            elif (TYPE == 5):
                PrivateMessage_infos = core.extract_private_message(
                    data_extracted)
                userId = PrivateMessage_infos[0]
                indiceUser = self.listOfUserId.index(userId)
                username = self.listOfUserName[indiceUser][0]
                self.clientProxy.chatMessageReceivedONE(
                    username, PrivateMessage_infos[2])
                self.sendAck(dataParsed[5])
            elif (TYPE == 14):
                self.idcall.cancel()
                self.ReceiveLoginResponse(data_extracted)
                self.sendAck(dataParsed[5])
            elif (TYPE == 15):
                self.idcall.cancel()
                self.seq_num += 1
                if self.type_last_message == 8:
                    self.clientProxy.leaveSystemOKONE()
                elif (self.type_last_message == 6):
                    self.current_movie_room_id = self.requested_movie_room_id
                    self.clientProxy.joinRoomOKONE()
                elif (self.type_last_message == 7):
                    self.current_movie_room_id = self.requested_movie_room_id
                    self.clientProxy.joinRoomOKONE()
            elif (TYPE == 0):
                self.extract_error(data_extracted)
Beispiel #24
0
class c2wUdpChatServerProtocol(DatagramProtocol):
    def __init__(self, serverProxy, lossPr):
        """ 
        :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 lossPr: The packet loss probability for outgoing packets.  Do
            not modify this value!

        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:: serverProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """
        #: The serverProxy, which the protocol must use
        #: to interact with the server (to access the movie list and to
        #: access and modify the user list).

        self.serverProxy = serverProxy
        self.lossPr = lossPr
        self.List_User = []
        # Initialisation de l'event Id
        self.Last_event_Id = -1

        # Liste des films
        self.MovieList = self.serverProxy.getMovieList()
        self.Nbr_Movie = 0

        # Liste des identifiants des movies rooms
        self.listeIdRoom = []

        # Initialisation des buffers qu'on va utiliser pour le Response Event
        self.buf_switch = bytearray(0)
        self.buf_new_msg = bytearray(0)
        self.buf_logout = bytearray(0)
        self.buf_new_user = bytearray(0)

        # Liste des timers
        self.timer = []
        # Dernier paquet reçu
        self.datagram = bytearray(0)
        # Derniière réponse envoyée
        self.response = bytearray(0)
        # L'adresse et le port du dernier utilisateur qui envoyé un paquet
        self.host_port = (0, 0)

        self.bool = False

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    # Méthode qui incrémente l'event Id
    def increment_Event_Id(self):
        if (self.Last_event_Id > 65536):
            self.Last_event_Id = 0
        else:
            self.Last_event_Id += 1

    # Méthode à exécuter si on ne reçoit pas de ping après 60s

    def verifyResponse(self, parameter):

        user_id_list = []
        for i in self.serverProxy.getUserList():
            user_id_list.append(i.userId)
        if parameter in user_id_list:
            increment_Event_Id(self)
            # Formation du paquet à envoyer dans le response event (evenement: suppression d'un utilisateur)

            # Determination de l'identifiant du room dans laquelle l'utilisateur se trouve
            Room_Name = self.serverProxy.getUserById(parameter).userChatRoom
            if Room_Name == ROOM_IDS.MAIN_ROOM:
                RoomId = 0
            else:
                RoomId = self.serverProxy.getMovieByTitle(Room_Name).movieId
            # Last_Event_Id
            a = (self.Last_event_Id & int('111111111111111100000000', 2)) >> 8
            b = (self.Last_event_Id) & 255

            # Message_data
            buf = struct.pack('!HBBBB', a, b, 0x4, RoomId, parameter)
            # Supression de l'utilisateur'
            self.serverProxy.removeUser(
                self.serverProxy.getUserById(parameter).userName)
            self.buf_logout += buf  # Formation petit à petit du buf à envoyer dans le response event pour l'event logout

    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.
        """

        # Récupération de l'entete
        (Message_Type, Seq_Number, User_ID,
         Message_Length) = struct.unpack('!BHBH', datagram[:6])

        # Si on reçoit le meme paquet une deuxième fois
        if self.datagram == datagram:
            if host_port == self.host_port:
                self.transport.write(self.response, host_port)

        else:
            self.datagram = datagram
            self.host_port = host_port

            #----------------------------- RESPONSE-LOGIN -----------------------------------------------

            if Message_Type == 0x00:

                # Recupération du data
                (UL, Username) = struct.unpack(
                    '!B' + str(Message_Length - 1) + 's', datagram[6:])

                # Récupération de la liste des utilisateurs
                self.List_User = self.serverProxy.getUserList()

                # Détermination du status_Code

                i = 0
                for n in self.List_User:
                    if n.userName == Username.decode(
                            'utf-8'
                    ):  # Si le nom d'utilisateur existe déjà dans la liste
                        i = 1
                        User_Id = 0
                if i == 1:
                    Status_Code = 4  # USERNAME-NOT_AVIALABLE
                else:
                    Status_Code = 0  # SUCCESS
                    self.List_User.append(Username)

                    # Ajout de l'utilisateur à la liste et génération de User_ID
                    User_Id = self.serverProxy.addUser(
                        Username.decode('utf-8'),
                        ROOM_IDS.MAIN_ROOM,
                        userAddress=host_port[0])

                    # Incrémentation de l'event Id
                    increment_Event_Id(self)
                    a = (self.Last_event_Id
                         & int('111111111111111100000000', 2)) >> 8
                    b = (self.Last_event_Id) & 255
                    # Message_data
                    buf = struct.pack('!HBBBBB' + str(UL) + 's', a, b, 0x2,
                                      0x0, User_Id, UL, Username)
                    self.buf_new_user += buf  # Formation petit a petit du buf a envoyer dans le response event pour l'event new user

                if User_Id > 255:
                    Status_Code = 2  # TOO_MANY_USERS

                # Construction et envoi de la réponse
                a = (self.Last_event_Id
                     & int('111111111111111100000000', 2)) >> 8
                b = (self.Last_event_Id) & 255
                Response_Login = struct.pack('!BHBHBBHB', 0x01, Seq_Number, 0,
                                             5, Status_Code, User_Id, a, b)
                self.transport.write(Response_Login, host_port)
                self.response = Response_Login
                # Lancement du Timer
                self.timer.append(
                    reactor.callLater(60, self.verifyResponse, User_Id))

    #----------------------------- RESPONSE-ROOMS -----------------------------------------------

            if Message_Type == 0x08:

                # Récupération du data
                (First_Room_Id, Nbr_Rooms) = struct.unpack('!BB', datagram[6:])
                NbrMovie = 0
                # Calcul du Message Length
                Msg_Length = 0
                for i in self.MovieList:
                    if (i.movieId >= First_Room_Id) and (
                            i.movieId <= First_Room_Id + Nbr_Rooms):
                        Msg_Length += len(i.movieTitle) + 9
                        NbrMovie += 1

                # Formation de l'entete
                UserList = self.serverProxy.getUserList()
                buf = bytearray(0)
                buf += struct.pack('!BHBHB', 9, Seq_Number, 0, Msg_Length + 1,
                                   NbrMovie)

                # Formation du message
                self.MovieList = self.serverProxy.getMovieList()

                for i in self.MovieList:
                    # Parcours de la liste des videos disponibles
                    if (i.movieId >= First_Room_Id) and (
                            i.movieId <= First_Room_Id + Nbr_Rooms):
                        (addr_IP,
                         Movie_Port) = self.serverProxy.getMovieAddrPort(
                             i.movieTitle)
                        Video_Name = i.movieTitle
                        Nbr = 0
                        for j in UserList:
                            if Video_Name == j.userChatRoom:
                                Nbr += 1
                        ip = addr_IP.split('.')
                        RNL = len(i.movieTitle)
                        # Construction de la réponse
                        buf += struct.pack('!B4B', i.movieId, int(ip[0]),
                                           int(ip[1]), int(ip[2]), int(ip[3]))
                        buf += struct.pack('!HB' + str(RNL) + 'sB', Movie_Port,
                                           RNL, (i.movieTitle).encode('utf-8'),
                                           Nbr)
                self.transport.write(buf, host_port)
                self.response = buf

    #----------------------------- RESPONSE_USERS -----------------------------------------------

            if Message_Type == 0x0A:

                # Récupération du data
                (First_User_Id, Nbr_Users,
                 Room_Id) = struct.unpack('!BBB', datagram[6:])

                # Récupération de la liste des utilisateurs
                UserList = self.serverProxy.getUserList()
                LenUserList = len(self.serverProxy.getUserList())

                self.Nbr_Movie = len(self.MovieList)
                n = 0

                # Si l'utilisateur demande la liste d'une room précise
                if Room_Id != 0x00:
                    # calcul de la longueur du message
                    Msg_Length = 0
                    Nbr = 0  # Nombre d'utlisateurs dans le movie room
                    e = 0
                    Video_Name = self.serverProxy.getMovieById(
                        Room_Id).movieTitle
                    for i in UserList:
                        if Video_Name == i.userChatRoom:
                            Msg_Length += len(i.userName) + 3
                            Nbr += 1

                    # construction de l'entete
                    buf = bytearray(0)
                    buf = struct.pack('!BHBHB', 11, Seq_Number, 0,
                                      Msg_Length + 1, Nbr)

                    for i in UserList:
                        if Video_Name == i.userChatRoom:
                            if (i.userId >= First_User_Id) and (
                                    i.userId < First_User_Id + Nbr_Users):
                                UL = len(i.userName)
                                buf += struct.pack(
                                    '!BB' + str(UL) + 'sB', i.userId, UL,
                                    (i.userName).encode('utf-8'), Room_Id)

                # si l'utilisateur demande le liste des utilisateurs dans toutes les rooms
                if Room_Id == 0x00:
                    # calcul de la longueur du message
                    Msg_Length = 0
                    buf = bytearray(0)
                    for i in UserList:
                        Msg_Length += len(i.userName) + 3

                    # Entete
                    buf = struct.pack('!BHBHB', 11, Seq_Number, 0,
                                      Msg_Length + 1, len(UserList))

                    e = 0
                    # Récupération des listes des clients pour chaque movie room
                    for i in self.MovieList:
                        if i.movieId not in self.listeIdRoom:
                            self.listeIdRoom.append(i.movieId)
                    listeIdRoom = self.listeIdRoom
                    listeIdRoom.append(0)
                    for RoomId in listeIdRoom:
                        if RoomId != 0:
                            Video_Name = self.serverProxy.getMovieById(
                                RoomId).movieTitle
                            for i in UserList:
                                if (Video_Name == i.userChatRoom):
                                    if (i.userId >= First_User_Id) and (
                                            i.userId <
                                            First_User_Id + Nbr_Users):
                                        UL = len(i.userName)
                                        buf += struct.pack(
                                            '!BB' + str(UL) + 'sB', i.userId,
                                            UL, (i.userName).encode('utf-8'),
                                            RoomId)
                        elif e == 0:
                            e += 1
                            for i in UserList:
                                if (i.userChatRoom == ROOM_IDS.MAIN_ROOM):
                                    if (i.userId >= First_User_Id) and (
                                            i.userId <
                                            First_User_Id + Nbr_Users):
                                        UL = len(i.userName)
                                        #                                       struct.pack_into('!BB'+str(UL)+'sB',buf,7+n,i.userId,UL,(i.userName).encode('utf-8'),0)
                                        #                                       n += 3 + UL
                                        buf += struct.pack(
                                            '!BB' + str(UL) + 'sB', i.userId,
                                            UL, (i.userName).encode('utf-8'),
                                            RoomId)

                self.transport.write(buf, host_port)
                self.response = buf

    #----------------------------- RESPONSE_MESSAGE -----------------------------------------------

            if Message_Type == 0x0E:

                # Récupération du data
                (Room_Id, Msg_Length, Message_Content) = struct.unpack(
                    '!BH' + str(Message_Length - 3) + 's', datagram[6:])

                # Détermination de roomID du client
                Room_Name = (
                    self.serverProxy.getUserById(User_ID)).userChatRoom
                if Room_Name == ROOM_IDS.MAIN_ROOM:
                    RoomId = 0
                else:
                    RoomId = self.serverProxy.getMovieByTitle(
                        Room_Name).movieId
                # Détermination du Status_Code
                if int(Room_Id) == RoomId:
                    Status_Code = 0
                    increment_Event_Id(self)
                    a = (self.Last_event_Id
                         & int('111111111111111100000000', 2)) >> 8
                    b = (self.Last_event_Id) & 255
                    # Construction de la réponse
                    buf = bytearray(0)
                    buf = struct.pack('!HBBBBH' + str(Msg_Length) + 's', a, b,
                                      0x1, Room_Id, User_ID, Msg_Length,
                                      Message_Content)

                    self.buf_new_msg += buf  # Formation petit a petit du buf a envoyer dabs le response event pour l'event new message
                elif int(Room_Id) != RoomId:
                    if RoomId in self.listeIdRoom:
                        Status_Code = 3
                    else:
                        Status_Code = 2
                else:
                    Status_Code = 1
                Response_Message = struct.pack('!BHBHB', 0x0F, Seq_Number, 0,
                                               1, Status_Code)

                self.transport.write(Response_Message, host_port)
                self.response = Response_Message

    #----------------------------- RESPONSE_PING -----------------------------------------------

            if Message_Type == 0x04:

                self.timer[User_ID - 1].reset(60)

                # Récupération du data
                (LastEventId_a, LastEventId_b,
                 Room_Id) = struct.unpack('!HBB', datagram[6:])
                a = (self.Last_event_Id
                     & int('111111111111111100000000', 2)) >> 8
                b = (self.Last_event_Id) & 255
                # Construction et envoi de la réponse
                Response_Ping = struct.pack('!BHBHHB', 0x05, Seq_Number, 0, 3,
                                            a, b)

                self.transport.write(Response_Ping, host_port)
                self.response = Response_Ping

    #----------------------------- RESPONSE_SWITCH_ROOM -----------------------------------------

            if Message_Type == 0x0C:
                # Récupération du data
                (Room_Id) = struct.unpack('!B', datagram[6:])
                userlist = self.serverProxy.getUserList()

                # Détermination du room ID du client =RoomId
                Room_Name = self.serverProxy.getUserById(User_ID).userChatRoom
                if Room_Name == ROOM_IDS.MAIN_ROOM:
                    RoomId = 0
                else:
                    RoomId = self.serverProxy.getMovieByTitle(
                        Room_Name).movieId
                # Détermination du Status_Code
                if Room_Id[0] == RoomId:
                    Status_Code = 1
                elif (RoomId != 0) and (Room_Id[0] != 0):
                    Status_Code = 1
                elif (Room_Id[0] not in self.listeIdRoom):
                    Status_Code = 1

                else:

                    Status_Code = 0
                    if (Room_Id[0] != 0):
                        for i in userlist:  #on verifie si il y a encore des clients dans la room
                            if self.serverProxy.getMovieById(
                                    Room_Id[0]).movieTitle == i.userChatRoom:
                                p = 1
                            else:
                                p = 0
                        if p == 0:
                            #si il n' y a plus personne dans la room:  Start streaming lorsque le client quitte le main room vers un movie room
                            self.serverProxy.startStreamingMovie(
                                self.serverProxy.getMovieById(int(
                                    Room_Id[0])).movieTitle)
                    else:
                        for i in userlist:  #on verifie si il y a encore des clients dans la room
                            if self.serverProxy.getMovieById(
                                    RoomId).movieTitle == i.userChatRoom:
                                p = 1
                            else:
                                p = 0
                        if p == 0:
                            # si il n' y a plus personne dans la room: Stop streaming lorsque le client quitte un movie room
                            self.serverProxy.stopStreamingMovie(
                                self.serverProxy.getMovieById(
                                    int(RoomId)).movieTitle)
                    if Room_Id[0] == 0:
                        self.serverProxy.updateUserChatroom(
                            self.serverProxy.getUserById(User_ID).userName,
                            ROOM_IDS.MAIN_ROOM)
                    else:
                        self.serverProxy.updateUserChatroom(
                            self.serverProxy.getUserById(User_ID).userName,
                            self.serverProxy.getMovieById(int(
                                Room_Id[0])).movieTitle)
                    increment_Event_Id(self)
                    a = (self.Last_event_Id
                         & int('111111111111111100000000', 2)) >> 8
                    b = (self.Last_event_Id) & 255
                    #buf = struct.pack('!HBBBBB',a,b,0x3,Room_Id[0],User_ID,int(Room_Id[0]))
                    buf = struct.pack('!HBBBBB', a, b, 0x3, RoomId, User_ID,
                                      Room_Id[0])
                    self.buf_switch += buf  #formation petit a petit du buf a envoyer dabs le response event pour l'event switch room
                Response_Switch_Room = struct.pack('!BHBHB', 0x0D, Seq_Number,
                                                   0, 1, Status_Code)

                self.transport.write(Response_Switch_Room, host_port)
                self.response = Response_Switch_Room

    #----------------------------- RESPONSE_LOGOUT -----------------------------------------------

            if Message_Type == 0x02:
                # Détermination du room Id du client
                Room_Name = self.serverProxy.getUserById(User_ID).userChatRoom
                if Room_Name == ROOM_IDS.MAIN_ROOM:
                    RoomId = 0
                else:
                    RoomId = self.serverProxy.getMovieByTitle(
                        Room_Name).movieId
                if RoomId == 0:
                    Status_Code = 0
                    # Supression du client de la liste
                    self.serverProxy.removeUser(
                        self.serverProxy.getUserById(User_ID).userName)
                    increment_Event_Id(self)
                    a = (self.Last_event_Id
                         & int('111111111111111100000000', 2)) >> 8
                    b = (self.Last_event_Id) & 255
                    buf = struct.pack('!HBBBB', a, b, 0x4, RoomId, User_ID)
                    self.buf_logout += buf  #formation petit a petit du buf a envoyer dans le response event pour l'event logout

                    self.timer[User_ID - 1].cancel()
                    userList = self.serverProxy.getUserList()

                else:
                    Status_Code = 1
                Response_Logout = struct.pack('!BHBHB', 0x03, Seq_Number, 0, 1,
                                              Status_Code)
                self.transport.write(Response_Logout, host_port)
                self.response = Response_Logout

    #----------------------------- RESPONSE_EVENTS -----------------------------------------------

            if Message_Type == 0x06:
                # Récupération du data
                (LastEventId_a, LastEventId_b, Nbr_Events,
                 Room_Id) = struct.unpack('!HBBB', datagram[6:])
                LastEventId = (LastEventId_a << 8) | LastEventId_b
                buf = bytearray(0)
                event_nbr = 0
                v = 0
                i = 0
                p = 0

                # Si l'utilisateur demande les événements d'un room précis
                if Room_Id != 0:
                    # Event : new message
                    while (i <= len(self.buf_new_msg) - 1):
                        taille_msg = struct.unpack(
                            '!H', self.buf_new_msg[i + 6:i + 8])
                        p = int(taille_msg[0]) + 8
                        v += p
                        if (self.buf_new_msg[i + 4] == Room_Id) and (
                            ((self.buf_new_msg[i] << 16) |
                             (self.buf_new_msg[i + 1] << 8)
                             | self.buf_new_msg[i + 2]) > LastEventId):
                            buf += self.buf_new_msg[i:v]
                            event_nbr += 1
                        i += p
                # Event : new user
                    v = 0
                    i = 0
                    p = 0

                    while (i <= len(self.buf_new_user) - 1):
                        ul = self.buf_new_user[i + 6]
                        p = int(ul) + 7
                        v += p
                        if (((self.buf_new_user[i] << 16) |
                             (self.buf_new_user[i + 1] << 8)
                             | self.buf_new_user[i + 2]) > LastEventId):
                            buf += self.buf_new_user[i:v]
                            event_nbr += 1
                        i += p
                # Event : logout
                    p = 0
                    i = 0
                    v = 0

                    while (i <= len(self.buf_logout) - 1):
                        p = 6
                        v += p
                        if (((self.buf_logout[i] << 16) |
                             (self.buf_logout[i + 1] << 8)
                             | self.buf_logout[i + 2]) > LastEventId):
                            #if (self.buf_logout[i+4] == Room_Id) and (((self.buf_logout[i]<<16) | (self.buf_logout[i+1]<<8) | self.buf_logout[i+2]) > LastEventId ):
                            buf += self.buf_logout[i:v]
                            event_nbr += 1
                        i += p
                # Event : switch room
                    i = 0
                    v = 0
                    p = 0

                    while (i <= len(self.buf_switch) - 1):
                        p = 7
                        v += p
                        if (self.buf_switch[i + 6] == Room_Id) and (
                            ((self.buf_switch[i] << 16) |
                             (self.buf_switch[i + 1] << 8)
                             | self.buf_switch[i + 2]) > LastEventId):
                            buf += self.buf_switch[i:v]

                            event_nbr += 1
                        if (self.buf_switch[i + 6] == 0) and (
                            ((self.buf_switch[i] << 16) |
                             (self.buf_switch[i + 1] << 8)
                             | self.buf_switch[i + 2]) > LastEventId):
                            buf += self.buf_switch[i:v]

                            event_nbr += 1
                        i += p
                    buf1 = struct.pack('!BHBHB', 0x07, Seq_Number, 0,
                                       len(buf) + 1, event_nbr)
                    buf1 += buf

                # Si l'utilisateur demande tous les événements
                else:
                    # Event : new message
                    p = 0
                    i = 0

                    while (i <= len(self.buf_new_msg) - 1):
                        taille_msg = struct.unpack(
                            '!H', self.buf_new_msg[i + 6:i + 8])
                        p = int(taille_msg[0]) + 8
                        v += p
                        if (((self.buf_new_msg[i] << 16) |
                             (self.buf_new_msg[i + 1] << 8)
                             | self.buf_new_msg[i + 2]) > LastEventId):
                            buf += self.buf_new_msg[i:v]

                        i += p
                # Event : new user
                    p = 0
                    i = 0
                    v = 0
                    while (i <= len(self.buf_new_user) - 1):
                        ul = self.buf_new_user[i + 6]
                        p = int(ul) + 7
                        v += p
                        if (((self.buf_new_user[i] << 16) |
                             (self.buf_new_user[i + 1] << 8)
                             | self.buf_new_user[i + 2]) > LastEventId):

                            buf += self.buf_new_user[i:v]
                        i += p
                # Event : logout
                    p = 0
                    i = 0
                    v = 0

                    while (i <= len(self.buf_logout) - 1):
                        p = 6
                        v += p
                        if (((self.buf_logout[i] << 16) |
                             (self.buf_logout[i + 1] << 8)
                             | self.buf_logout[i + 2]) > LastEventId):
                            buf += self.buf_logout[i:v]
                        i += p
                # Event : switch room
                    p = 0
                    i = 0
                    v = 0

                    while (i <= len(self.buf_switch) - 1):
                        p = 7
                        v += p

                        if (((self.buf_switch[i] << 16) |
                             (self.buf_switch[i + 1] << 8)
                             | self.buf_switch[i + 2]) > LastEventId):
                            buf += self.buf_switch[i:v]
                        i += p

                    p = 0
                    i = 0

                    buf1 = struct.pack('!BHBHB', 0x07, Seq_Number, 0,
                                       len(buf) + 1, Nbr_Events)
                    buf1 += buf
                self.transport.write(buf1, host_port)
                self.response = buf1
        pass
Beispiel #25
0
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        self.num_sequence = 0
        self.num_sequence_server = 0
        self.users = []
        self.numDeconection = 0
        self.numJoinRoom = 0
        self.numMainRoom = 0
        self.listUser = []
        self.movies = []
        self.filattente = []
        self.username = ''
        self.num_error = 0
        self.error_count = 0
        self.retrans_server = 0

    # fonction pour verifier si on a recu un ack
    def traitementAck(self, numSeq):

        for p in self.filattente:
            if (p[0] == numSeq):
                p[2] = 1
                #print(p)
                #print(self.filattente)
                #if numSeq==self.numDeconection and numSeq>=1:
                #   self.clientProxy.applicationQuit()
                #  break
                self.num_sequence += 1
                print(self.num_sequence)
                print('******************ack envoye par le serveur')
                self.filattente.remove(p)

    #fonction pour envoyer le paquet si jamais on a toujours pas recu d ack
    def sendAndWait(self, host_port):
        for p in self.filattente:
            if (p[4] == host_port):
                print(self.filattente)
                if (
                        p[1] <= 7
                ):  # 6+1 correspond au nombre maximum de fois qu'on doit ramener un paquet
                    if (p[2] == 0):
                        self.transport.write(p[3], host_port)
                        p[1] += 1
                        print(self.filattente)
                        print('nombre de message envoye:' + str(p[1]))
                        reactor.callLater(1, self.sendAndWait, host_port)
                    elif (p[2] == 1):
                        print('Le paquet a ete aquitte')
                        self.filattente.remove(p)

                else:
                    print('Le paquet envoye est perdu')
                    self.filattente.remove(p)

                    #EFFECTUER LES COMMANDE DE DECONNECTION ET AFFICAHGE DE MESSAGE DE DECONNEXION
                    #DANS LE CAS DUNE CONNEXION, DECONNEXION, CHANGEMNT DE ROOM
                    self.clientProxy.connectionRejectedONE(
                        "\nLa connexion au serveur à été rompue\nVous devez vous reconnecter"
                    )
                    #self.clientProxy.applicationQuit()

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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.
        """
        """
        #Connecting to the server
        #self.transport.connect(self.serverAddress, self.serverPort)
        #The message length taille du paquet 
        msg_length = 4 + len(userName.encode('utf-8'))
        #Combining the sequence number and the type
        #num_seq = self.num_sequence << 4 
        #connection_type = 1
        seq_and_connection = util.prepare_header(self.num_sequence,1)
        #print(bin(seq_and_connection))
        #Packing the username
        length_username = str(len(userName))
        buf = struct.pack('!hh'+length_username+'s', msg_length, seq_and_connection, userName.encode('utf-8'))
        self.transport.write(buf, (self.serverAddress, self.serverPort))
        """
        self.username = userName
        buf = util.format_login(userName)
        self.transport.write(buf, (self.serverAddress, self.serverPort))

        self.filattente.append(
            [0, 1, 0, buf, (self.serverAddress, self.serverPort)])
        print(self.filattente)
        reactor.callLater(1, self.sendAndWait,
                          (self.serverAddress, self.serverPort))

        moduleLogger.debug('loginRequest called with username=%s', 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.
        """
        buf = util.format_chat(self.num_sequence, 9, self.username, message)
        self.transport.write(buf, (self.serverAddress, self.serverPort))

        #self.transport.write(buf, (self.serverAddress, self.serverPort))

        #self.transport.write(buf, (self.serverAddress, self.serverPort))

        self.filattente.append([
            self.num_sequence, 1, 0, buf, (self.serverAddress, self.serverPort)
        ])
        #print(self.filattente)
        reactor.callLater(1, self.sendAndWait,
                          (self.serverAddress, self.serverPort))

        #self.transport.write(buf, (self.serverAddress, self.serverPort))

        #self.transport.write(buf, (self.serverAddress, self.serverPort))

        print(util.get_username_fromChat(buf), " :")

        print(util.get_message_test(buf))

        pass

    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.

    
        #A faire envoyer demande de deconnexion
        buf2=util.format_select_film(roomName, self.num_sequence)
        print("jeveuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuupannnnnnnnnnnn")
        self.transport.write(buf2, (self.serverAddress, self.serverPort))
        self.filattente.append([self.num_sequence,1,0,buf2,(self.serverAddress, self.serverPort)])
        reactor.callLater(1,self.sendAndWait,(self.serverAddress, self.serverPort))    
        self.numJoinRoom=self.num_sequence
         
         RETRANSMISSION PAS ENCORE GERER+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+
        
        #print("jeeeeeeeeeeveuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuupannnnnnnnnnnn")

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

            buf2 = util.format_select_film(roomName, self.num_sequence)
            print(
                "jeveuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuupannnnnnnnnnnn"
            )
            self.transport.write(buf2, (self.serverAddress, self.serverPort))
            self.numJoinRoom = self.num_sequence
            self.filattente.append([
                self.num_sequence, 1, 0, buf2,
                (self.serverAddress, self.serverPort)
            ])
            reactor.callLater(1, self.sendAndWait,
                              (self.serverAddress, self.serverPort))
            #self.clientProxy.joinRoomOKONE()

        else:
            buf2 = util.format_header(4, self.num_sequence)
            #print("jeveuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuupannnnnnnnnnnn")
            self.transport.write(buf2, (self.serverAddress, self.serverPort))
            self.numJoinRoom = self.num_sequence
            self.filattente.append([
                self.num_sequence, 1, 0, buf2,
                (self.serverAddress, self.serverPort)
            ])
            reactor.callLater(1, self.sendAndWait,
                              (self.serverAddress, self.serverPort))
            #self.clientProxy.joinRoomOKONE()
        #"""

        #self.clientProxy.joinRoomOKONE()

        pass

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """

        #"""
        #A faire envoyer demande de deconnexion
        buf2 = util.format_header(2, self.num_sequence)
        print("jeveuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuupannnnnnnnnnnn")
        self.transport.write(buf2, (self.serverAddress, self.serverPort))
        self.numDeconection = self.num_sequence
        self.filattente.append([
            self.num_sequence, 1, 0, buf2,
            (self.serverAddress, self.serverPort)
        ])
        reactor.callLater(1, self.sendAndWait,
                          (self.serverAddress, self.serverPort))

        #"""

        print(
            "jeeeeeeeeeeveuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuupannnnnnnnnnnn"
        )
        #self.clientProxy.applicationQuit()

        pass

    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_type = util.get_type(datagram)
        #packet_numSeq= util.get_numSequence (datagram)

        if packet_type == 0:  #Reception d'un ACK
            packet_numSeq = util.get_numSequence(datagram)
            self.traitementAck(packet_numSeq)
            print("*******************ACK DU SERVER", packet_numSeq)
            print("************************MON NUM SEQ", self.num_sequence)
            print("****-----------------*ACK CONNEXION REQUEST****")

            if packet_numSeq == self.numDeconection and packet_numSeq > 0:
                self.clientProxy.applicationQuit()

            if packet_numSeq == self.numJoinRoom and packet_numSeq > 0:
                self.clientProxy.joinRoomOKONE()

        packet_numSeq = util.get_numSequence(datagram)
        if self.num_sequence_server == packet_numSeq and packet_type != 0:

            self.retrans_server = 0
            self.error_count = 0
            #
            if packet_type == 5:  # Reception liste des films

                buf = util.format_ack(packet_numSeq)
                self.transport.write(buf, (host_port[0], host_port[1]))

                self.num_sequence_server += 1

                #sending the ACK message-----------------------APRES ENVOIE ACK +1 AU NUM SÉQUENCE DU CLIENT AFAIRE

                print("*******************ACK DU SERVER", packet_numSeq)
                print("************************MON NUM SEQ", self.num_sequence)
                self.movies = util.get_moviesList(datagram)
                print(self.movies)
                """""" """""" """""" """"""
                #self.clientProxy.initCompleteONE(self.listUser,self.movies)
                #print(packet_type)
                """""" """"""

            elif packet_type == 6:  # Reception liste des Users

                if self.listUser == []:

                    buf = util.format_ack(packet_numSeq)
                    self.transport.write(buf, (host_port[0], host_port[1]))
                    self.num_sequence_server += 1

                    print(
                        "********************************Reception USER**************************"
                    )
                    #print(util.format_usersList(self.usersList,self.serverProxy.getMovieList()))
                    print(datagram)
                    self.listUser = util.get_usersList(datagram, self.movies)
                    #self.filattente.append([2,1,0,listUser,(host_port[0], host_port[1])])
                    #self.transport.write(listUser, (host_port[0], host_port[1]))
                    print(self.listUser)
                    print(self.movies)
                    #print(listUser)

                    self.clientProxy.initCompleteONE(self.listUser,
                                                     self.movies)
                    #print(packet_type)

                else:
                    buf = util.format_ack(packet_numSeq)
                    self.transport.write(buf, (host_port[0], host_port[1]))
                    self.num_sequence_server += 1

                    self.listUser = util.get_usersList(datagram, self.movies)
                    self.clientProxy.setUserListONE(self.listUser)

            elif packet_type == 7:  #        --------------  ACCEPTATION DE CONNECTION

                #self.users.append(self.username)
                #print(packet_type)
                # self.clientProxy.initCompleteONE(self.users,self.movies)

                buf = util.format_ack(packet_numSeq)
                self.transport.write(buf, (host_port[0], host_port[1]))
                self.num_sequence_server += 1

                print("*******************ACK DU SERVER", packet_numSeq)
                print("***********", packet_numSeq)

            elif packet_type == 8:
                buf = util.format_ack(packet_numSeq)
                self.transport.write(buf, (host_port[0], host_port[1]))
                #self.num_sequence_server+=1

                self.clientProxy.connectionRejectedONE(
                    "\nLe pseudo que vous avez entrez est deja utilisé, ou trop long.\nVeuillez réessayer avec un autre"
                )

            elif packet_type == 9:  #
                print("Yorobo")

                buf = util.format_ack(packet_numSeq)
                self.transport.write(buf, (host_port[0], host_port[1]))
                self.num_sequence_server += 1

                sender = util.get_username_fromChat(datagram)
                message = util.get_message(datagram)
                if sender != self.username:
                    self.clientProxy.chatMessageReceivedONE(sender, message)

        #"""
        elif self.num_sequence_server != packet_numSeq and packet_type != 0:
            #else:
            """     
            print("+-+-+-+-+-+-Jai recu un doublon on dirait+-+-+-+-+-+-+-")
            #self.num_sequence_client
            buf=util.format_ack(packet_numSeq)
            self.transport.write(buf, (host_port[0], host_port[1]))
            #self.num_sequence_client+=1 


            """

            if packet_numSeq != self.num_error:
                if self.error_count != 7:
                    self.retrans_server = 0
                    self.error_count = +1
                    print(
                        "+-+-+-+-+-+-Jai recu un numSeq innatendue on dirait+-+-+-+-+-+-+-"
                    )
                    print(packet_numSeq)
                    print(self.num_sequence_server)
                    #self.num_sequence_client
                    buf = util.format_ack(packet_numSeq)
                    self.transport.write(buf, (host_port[0], host_port[1]))
                    #self.num_sequence_client+=1
                elif self.error_count == 7:
                    self.clientProxy.applicationQuit()

            elif packet_numSeq == self.num_error:
                if self.retrans_server != 7 and self.error_count != 7:
                    self.error_count = +1
                    self.retrans_server += 1
                    print(
                        "+-+-+-+-+-+-Jai recu un doublon on dirait+-+-+-+-+-+-+-"
                    )
                    #self.num_sequence_client
                    buf = util.format_ack(packet_numSeq)
                    self.transport.write(buf, (host_port[0], host_port[1]))
                    #self.num_sequence_client+=1

                elif self.retrans_server == 7 or self.error_count == 7:
                    self.clientProxy.applicationQuit()

            self.num_error = packet_numSeq
            #"""

        #"""

        print("num sequence du server attendue", self.num_sequence_server)
        print("num sequence du client ", self.num_sequence)

        pass
class c2wUdpChatClientProtocol(DatagramProtocol):
    

    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address (or the name) of the c2w server.

        .. attribute:: serverPort

            The port number used by the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

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

        self.serverAddress = serverAddress
        self.serverPort = serverPort
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        self.nbtime = 0
        self.movielist=''
        self.USERID=0
        self.userName=''
        self.roomName=''
        self.flag=0
        self.obj=None
        self.flaguser=0
        self.flagmovie=0
        self.clientsequencenb=0
        self.userListresult=[]
        self.movieListresult=[]
        self.movieListstock=[]
        self.userListstock=[]
        self.location=-1
        self.roomId=0
        self.message=''
        self.count=0
        self.prefrg=0
        self.moviefrg=''
        self.movielengthfrg=0
        self.userlengthfrg=0
        self.previousserverseqnb=-1
       
        
    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport
        
    
    def sendRequest(self, buf, adress):
        """
        :param line: the text of the question from the user interface
        :type line: string

        This function must send the request to the server.
        """
        self.transport.write(buf,adress)
     #### send login request
    def sendLoginRequestOIE(self, userName):
        """
        :param string userName: The user name that the user has typed.

        The controller calls this function as soon as the user clicks on
        the login button.
        """
       
        moduleLogger.debug('loginRequest called with username=%s', userName)
        
        self.userName=userName
        lenUserName=len(userName)
        
        s=struct.Struct('!BBBBH'+str(lenUserName)+'s')
        packdata=s.pack(*(3,0,0,0,lenUserName, userName))
        adress=(self.serverAddress,self.serverPort)
        
        self.sendRequest(packdata,adress)
        self.nbtime=self.nbtime+1
      
    ####Set the time out    
        if(self.nbtime<=3):
            
            self.timeout(userName,0)
        if(self.nbtime==4):
            self.nbtime=0
            
    ### Send movie list ACK
                
    def sendMovieListAck(self,sequencenb,userid):
        #moduleLogger.debug('loginRequest called with username=%s', )
        buf=ctypes.create_string_buffer(6)
        struct.pack_into('>BBBBH',buf,0,79,sequencenb,userid,0,0)
        adress=(self.serverAddress,self.serverPort)
        self.sendRequest(buf,adress)
    ### Send user list ACK
    
    def sendUserListAck(self,sequencenb,userid):
        #moduleLogger.debug('loginRequest called with username=%s', )
        buf=ctypes.create_string_buffer(6)
        struct.pack_into('!BBBBH',buf,0,87,sequencenb,userid,0,0)
        adress=(self.serverAddress,self.serverPort)
        self.sendRequest(buf,adress)
    ### Send message ACK
    
    def sendmessageAck(self,serversequencenb,userid,roomtype):
        buf=ctypes.create_string_buffer(6)
        if(roomtype==0):
            struct.pack_into('!BBBBH',buf,0,112,serversequencenb,userid,0,0)
           
        if(roomtype==1):
            struct.pack_into('!BBBBH',buf,0,113,serversequencenb,userid,0,0)
    
        adress=(self.serverAddress,self.serverPort)
        self.sendRequest(buf,adress)
        
        
     ###### Send chat message    
        
    def sendChatMessageOIE(self, message):
        """
        :param message: The text of the chat message.
        :type message: string

        Called **by the controller**  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.
           
        """
        length=len(message)
        if(length<140):
            self.message=message
           
            buf=ctypes.create_string_buffer(6+length)
            if(self.location==0):                                                 #### location=0 mean user is being mainroom, and send chat message
                
                struct.pack_into('!BBBBH'+str(length)+'s',buf,0,4,self.clientsequencenb,self.USERID,0,length,message) 
                adress=(self.serverAddress,self.serverPort)
                self.sendRequest(buf,adress)
            if(self.location==1):                                                 #### location=1 mean user is already in mainroom, and send chat message
               
                struct.pack_into('!BBBBH'+str(length)+'s',buf,0,5,self.clientsequencenb,self.USERID,self.roomId,length,message) 
                adress=(self.serverAddress,self.serverPort)
                self.sendRequest(buf,adress)
            self.nbtime=self.nbtime+1
             #### set the timeout
            if(self.nbtime<=3):
              
                self.timeout(message,2)
            if(self.nbtime==4):
                self.nbtime=0
        

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

        Called **by the controller**  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.
            
        """
        moduleLogger.debug('loginRequest called with username=%s', )
        
        if(self.location==0):                                              #### location=0  user is being mainroom, and send room request
                   
            for tuple in self.movieListstock:                              ##### take roomid from roomname
                if tuple[0]==roomName:
                    roomid=tuple[3]
          
            self.roomName=roomName
            self.roomId = roomid
    
            buf=ctypes.create_string_buffer(6)
            struct.pack_into('!BBBBH',buf,0,35,self.clientsequencenb,self.USERID,roomid,0) 
            adress=(self.serverAddress,self.serverPort)
            self.sendRequest(buf,adress)
            
            
            
            
        if(self.location==1):                                              #### location=1 mean user is already in mainroom, and send request to leave movingroom
            buf=ctypes.create_string_buffer(6)
            struct.pack_into('!BBBBH',buf,0,33,self.clientsequencenb,self.USERID,0,0)   
            adress=(self.serverAddress,self.serverPort)
         
            self.sendRequest(buf,adress)
        self.nbtime=self.nbtime+1
        if(self.nbtime<=3):
           
            self.timeout(roomName,1)
        if(self.nbtime==4):
            self.nbtime=0
        
        
            
        
        
        
    #### send request to leave out application
    
    def sendLeaveSystemRequestOIE(self):
        """
        Called **by the controller**  when the user
        has clicked on the leave button in the main room.
        """
        pass
        
        
        buf=ctypes.create_string_buffer(6)
        struct.pack_into('!BBBBH',buf,0,60,self.clientsequencenb,self.USERID,0,0)
        adress=(self.serverAddress,self.serverPort)
        
        self.sendRequest(buf,adress)
        self.nbtime=self.nbtime+1
        if(self.nbtime<=3):
          
            self.timeout(0,3)
        if(self.nbtime==4):
            self.nbtime=0
    
        
     #### timeout function
    def timeout(self,data,functionid):
        
       
        
       
        if(self.nbtime==3):
          
            self.obj.cancel()
            if(functionid==0):
                self.clientProxy.connectionRejectedONE('connection failed,please try again')    ##if in case mainroom to movieroom, we think client don't quit
        if(self.flag==0):
           
           
            if(functionid==0):
                self.obj=reactor.callLater(3,self.sendLoginRequestOIE,data)
            if(functionid==1):
                self.obj=reactor.callLater(3,self.sendJoinRoomRequestOIE,data)
            if(functionid==2):
               
                self.obj=reactor.callLater(3,self.sendChatMessageOIE,data)
            if(functionid==3):
                self.obj=reactor.callLater(3,self.sendLeaveSystemRequestOIE)
            
            
    ### data recived
    def datagramReceived(self, buf, (host, port)):
        """
        :param string datagram: the payload of the UDP packet.
        :param host: the IP address of the source.
        :param port: the source port.

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

       
        adress=(host, port)
        
       
        
        tuple1=struct.unpack_from('>B',buf[0])
      
        
        frg=self.getbit(tuple1[0],1,1)
        
        ack=self.getbit(tuple1[0],2,2)
        
        mestype=self.getbit(tuple1[0],3,6)
        roomtype=self.getbit(tuple1[0],7,8)
        tuple2=struct.unpack_from('>B',buf[1])
     
        serversequencenb=tuple2[0]	
        tuple3=struct.unpack_from('>B',buf[2])
        userid=tuple3[0]
        tuple4=struct.unpack_from('>B',buf[3])
        destid=tuple4[0]
        tuple5=struct.unpack_from('>H',buf[4:6])
       
        length=tuple5[0]
        if (ack==1 and mestype==8 and self.location==0):         #### use when receiving room request ACK
            port=struct.unpack_from('>H',buf[6:8])[0]
            ip1 = struct.unpack_from('>B',buf[8])[0]
            ip2 = struct.unpack_from('>B',buf[9])[0]
            ip3 = struct.unpack_from('>B',buf[10])[0]
            ip4 = struct.unpack_from('>B',buf[11])[0]
        
            
        else:
            tuple6=struct.unpack_from(str(length)+'s',buf[6:])
            data=tuple6[0]
        
    
        if(ack==1 and mestype==0):  ## login ack
            
            self.flag=1
            #self.timeout(data)
      
            self.nbtime=0
            self.obj.cancel()
            self.USERID=userid
            
            self.flag=0
        if(ack==1 and mestype==1):   ## chat message ack
            
            self.flag=1
            #self.timeout(data)
        
            self.nbtime=0
            self.obj.cancel()
            self.clientsequencenb=self.clientsequencenb+1
          
            self.flag=0
        
        
        if(ack==0 and mestype==12):                             #receive the forward message
          
            self.sendmessageAck(serversequencenb,self.USERID,roomtype)
            #self.count=self.count+1
      
            userid=int(data[0])
           
    
            for user in self.userListstock:
              
                if user[0]==userid:
                
                    userName=user[1]
            
            self.clientProxy.chatMessageReceivedONE(userName, data[1:])
             
        if(ack==1 and mestype==14):   ### error message
            errmes=struct.unpack_from('>B',data[0])[0]
          
            if(errmes==6):
                self.clientProxy.connectionRejectedONE('username not available')
            
            elif(errmes==4):
                self.obj.cancel()

        if(mestype==3 and ack==0):	## receive the movielist given by the server,client send movielistack to server
              
            self.sendMovieListAck(serversequencenb,userid)
                         ### flag indicate that client has already received the movie list
            if(frg==1 and serversequencenb > self.previousserverseqnb):
                self.prefrg=1
                self.moviefrg=self.moviefrg+data
                self.movielengthfrg=self.movielengthfrg+length
                self.previousserverseqnb=serversequencenb
            if (frg==0 and self.prefrg==1 and serversequencenb > self.previousserverseqnb):
                self.moviefrg=self.moviefrg+data
                self.prefrg=0
                self.movielist=self.moviefrg
                self.movielistlength=self.movielengthfrg+length
                self.previousserverseqnb=serversequencenb
                self.flagmovie=1

            if(frg==0 and self.prefrg==0):
                self.movielist=data
                self.movielistlength=length
    
                self.flagmovie=1     
        if(mestype==5 and ack==0 and userid==self.USERID):	##if it is the userlist given by the server,client send userlistack to server(from mainroom or movieroom)             
            
       
            self.sendUserListAck(serversequencenb,userid)
            
                       ##when the user is already in mainroom or movieroom, he receives userlist update
                
            
            if(frg==1 and serversequencenb > self.previousserverseqnb):               ## we use the server's sequence nb to distinguish the different fragmentation
                self.prefrg=1
                self.userfrg=self.userfrg+data
                self.userlengthfrg=self.userlengthfrg+length
                self.previousserverseqnb=serversequencenb
            if (frg==0 and self.prefrg==1 and serversequencenb > self.previousserverseqnb):
                self.userfrg=self.userfrg+data
                self.prefrg=0
                self.userlist=self.userfrg
                self.userlistlength=self.userlengthfrg+length
                self.previousserverseqnb=serversequencenb
                self.flaguser=1                                                      ###flag indicate that client has already received the userlist

            if(frg==0 and self.prefrg==0):
                self.userlist=data
                self.userlistlength=length
                self.flaguser=1
            if(self.location==0 or self.location==1):
                self.flagmovie=1    
        if(self.flaguser==1 and self.flagmovie==1):      ## to check that client has received both movielist and userlist
            i=0
            j=0
            self.userListstock=[]
            movieListresult=[]
           
            while(i<self.userlistlength):                
                            
                namelength=struct.unpack_from('>B',self.userlist[i])[0]
              
                userid=struct.unpack_from('>B',self.userlist[i+1])[0]
              
                status=struct.unpack_from('>B',self.userlist[i+2])[0]
               
                
                
                p=i
                
                
                i=i+3+namelength
                
                usernameoflist=struct.unpack_from(str(i-p-3)+'s',self.userlist[p+3:i])[0]#self.userlist[p+3:i-1]
                userid=struct.unpack_from('>B',self.userlist[p+1])[0]
                if(status==128):
                    tuple1=(userid,usernameoflist,ROOM_IDS.MAIN_ROOM)
                if(status==0):
                    
                    tuple1=(userid,usernameoflist,ROOM_IDS.MOVIE_ROOM)
                    if(destid==self.roomId):                             # for broadcast in a specific movieroom
                        
                        for tuple in self.movieListstock:                
                            if tuple[3]==destid:                         #just get one movie
                                tuple1=(userid,usernameoflist,tuple[0])  # get user list with the movietitle with client in the movingroom
                   
            
                self.userListresult.append((tuple1[1],tuple1[2]))
                self.userListstock.append(tuple1)
            if(self.location==0 or self.location==1):
                
                self.clientProxy.setUserListONE(self.userListresult)
            
            if(self.location==-1):                                        #### location=-1 for the first time client receive movie list after login sucessful
                while(j<self.movielistlength):                
                    namelength=struct.unpack_from('>B',self.movielist[j])[0]
                    roomid=struct.unpack_from('>B',self.movielist[j+1])[0]
                    p=j
                    j=j+2+namelength
                    
                    movietitleoflist=struct.unpack_from(str(j-p-2)+'s',self.movielist[p+2:j])[0]
                  
                    tuplesafe=(movietitleoflist,1,1,roomid)
                    tuple=(movietitleoflist,1,1)
                  
                    self.movieListstock.append(tuplesafe)
                    self.movieListresult.append(tuple)
                ###############use for  and display movie and user list
                self.clientProxy.initCompleteONE(self.userListresult, self.movieListresult)
            self.userListresult=[]
            if roomtype==0:
                self.location=0                                                #successully login and receive userlist and movielist
      
            self.flaguser=0
            self.flagmovie=0
        
        # ACK leave movie room 
        if (ack==1 and mestype==8 and self.location==1):
            self.flag=1
            self.nbtime=0
            #self.timeout(data)
         
            
            self.obj.cancel()     
            self.clientProxy.joinRoomOKONE()
            self.location=0
            self.flag=0
        
        
        else:
            if(ack==1 and mestype==8 and self.location==0):            ## change room
                self.nbtime=0
                self.flag=1
            
               
                self.obj.cancel()
                self.clientsequencenb=self.clientsequencenb+1
                self.location=1
                ipAdresslist= [str(ip1),str(ip2),str(ip3),str(ip4)]
                point="."
                ipAdress = point.join(ipAdresslist)
                
            
                self.clientProxy.userUpdateReceivedONE(self.userName, self.roomName)
            
                self.clientProxy.updateMovieAddressPort(self.roomName,ipAdress,port)
           
                self.clientProxy.joinRoomOKONE()
               
            
                self.flag=0
        ####ACK leave system
        if(ack==1 and mestype==15):
            
            self.flag=1
            self.nbtime=0
            #self.timeout(data)
          
            
            self.obj.cancel()     
            self.clientProxy.leaveSystemOKONE()
            self.location=-1
            self.flag=0
Beispiel #27
0
 def startProtocol(self):
     """
     DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!
     """
     self.transport = LossyTransport(self.transport, self.lossPr)
     DatagramProtocol.transport = self.transport
Beispiel #28
0
class c2wUdpChatServerProtocol(DatagramProtocol):
    nbreOfHelloSent = {}
    UserToken = {}
    hostPortSequence = {}

    def __init__(self, serverProxy, lossPr, sequenceNumberSentHello=None):
        """
        :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 lossPr: The packet loss probability for outgoing packets.  Do
            not modify this value!

        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:: serverProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """
        #: The serverProxy, which the protocol must use
        #: to interact with the server (to access the movie list and to
        #: access and modify the user list).
        self.serverProxy = serverProxy
        self.lossPr = lossPr
        self.SessionToken = 0
        self.tokenSequenceList = []
        self.SequenceNumber = 0
        self.userID = 0
        self.ACK = False
        self.c = 0
        self.ce = 0
        self.ACKofLRS = False
        self.sequenceNumberSentHello = sequenceNumberSentHello

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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.
        """
        global UserToken
        global hostPortSequence
        Packet = struct.unpack('>BBHHH' + str(len(datagram) - 8) + 's',
                               datagram)
        Version = Packet[0] // (2**4)
        Type = Packet[0] - (2**4) * (Packet[0] // (2**4))
        if Packet[3] > 0:
            self.SessionToken = c2wUdpChatServerProtocol.UserToken[host_port]

        else:
            self.SessionToken = Packet[1] * (2**16) + Packet[2]

        PayloadSize = Packet[4]
        Payload = Packet[5]
        self.SequenceNumber = Packet[3]

        if Type == 0:
            if self.sequenceNumberSentHello == c2wUdpChatServerProtocol.hostPortSequence[
                    host_port]:
                self.ACK = True

        c2wUdpChatServerProtocol.hostPortSequence[host_port] = Packet[3]

        if Type != 0:  ## if the datagram isn't an ACK we have to send one to the client
            Ack = struct.pack(
                '>BBHHH', 16, self.SessionToken // (2**16),
                self.SessionToken - (2**16) * (self.SessionToken // (2**16)),
                c2wUdpChatServerProtocol.hostPortSequence[host_port], 0)
            self.transport.write(Ack, host_port)

        if Type == 1:
            decodedLoginRequest = self.decodeLoginRequest(Payload, host_port)
            ResponseCode, data = decodedLoginRequest[0], decodedLoginRequest[1]
            self.loginResponse(ResponseCode, data, host_port)
        if Type == 5:
            roomID = struct.unpack('>H', Payload)[0]

            user = self.serverProxy.getUserByAddress(host_port)
            print('my token', c2wUdpChatServerProtocol.UserToken[host_port])
            for movie in self.serverProxy.getMovieList():
                if movie.movieId == roomID:
                    self.serverProxy.updateUserChatroom(
                        user.userName, movie.movieTitle)
                    self.serverProxy.startStreamingMovie(movie.movieTitle)
            if roomID == 1:
                self.serverProxy.stopStreamingMovie(user.userChatRoom)
                self.serverProxy.updateUserChatroom(user.userName,
                                                    ROOM_IDS.MAIN_ROOM)

            self.sendToAll(Version)
            #self.tokenSequenceList.append(SessionToken)
            #self.tokenSequenceList.append(SequenceNumber)
            #Packet=struct.unpack('>BBHHH'+str(len(datagram)-8)+'s',datagram)
            #Version=Packet[0]//2**4
            #Type=Packet[0]-Packet[0]//2**4
            #SessionToken=Packet[1]*(2**16)+Packet[2]
            #SequenceNumber=Packet[3]
            #PayloadSize=Packet[4]
            #Payload=Packet[5]
        if Type == 7:
            username = self.serverProxy.getUserByAddress(host_port).userName
            self.serverProxy.removeUser(username)
            del c2wUdpChatServerProtocol.UserToken[host_port]

            self.sendToAll(Version)
            #self.sendToAll(Version)
        if Type == 3:
            self.sendToAll(Version)
        if Type == 6:
            sender = self.serverProxy.getUserByAddress(host_port)
            for user in self.serverProxy.getUserList():
                if user.userAddress != host_port and sender.userChatRoom == user.userChatRoom:

                    c2wUdpChatServerProtocol.hostPortSequence[
                        user.userAddress] += 1
                    sessionToken = c2wUdpChatServerProtocol.UserToken[
                        user.userAddress]
                    Message = struct.pack(
                        '>BBHHH' + str(len(Payload)) + 's',
                        Version * 2**4 + Type, sessionToken // (2**16),
                        sessionToken - (2**16) * (sessionToken // (2**16)),
                        c2wUdpChatServerProtocol.hostPortSequence[
                            user.userAddress], len(Payload), Payload)
                    self.transport.write(Message, user.userAddress)
        if c2wUdpChatServerProtocol.hostPortSequence[
                host_port] >= 1 and self.serverProxy.getUserByAddress(
                    host_port) != False:
            Hello = reactor.callLater(10, self.Hello, host_port)
            if self.c == 3:

                username = self.serverProxy.getUserByAddress(
                    host_port).userName
                self.serverProxy.removeUser(username)
                self.sendToAll(Version)

    def decodeLoginRequest(self, Payload, host_port):
        uData = struct.unpack('>H' + str(len(Payload) - 2) + 's', Payload)
        uName = struct.unpack('H' + str(len(uData[1]) - 2) + 's', uData[1])
        userName = uName[1].decode('utf-8')
        if self.SessionToken != 0:
            ResponseCode = 1
            uData = struct.pack('>H' + str(len(uData[1])) + 's', 0, uData[1])
        if len(userName) > 100:
            ResponseCode = 2
            uData = struct.pack('>H' + str(len(uData[1])) + 's', 0, uData[1])

        elif self.serverProxy.userExists(userName) == True:
            ResponseCode = 3
            uData = struct.pack('>H' + str(len(uData[1])) + 's', 0, uData[1])

        elif len(self.serverProxy.getUserList()) > 65535:
            ResponseCode = 4
            uData = struct.pack('H' + str(len(uData[1])) + 's', 0, uData[1])

        else:
            ResponseCode = 0
            self.ce += 1

            self.userID = self.serverProxy.addUser(userName,
                                                   ROOM_IDS.MAIN_ROOM, None,
                                                   host_port)

            self.SessionToken = random.getrandbits(24)
            c2wUdpChatServerProtocol.UserToken[host_port] = self.SessionToken

            uData = struct.pack('>H' + str(len(uData[1])) + 's', self.userID,
                                uData[1])
        return (ResponseCode, uData)

    def loginResponse(self, ResponseCode, uData, host_port):
        self.lastSequenceNumberSentLR = self.SequenceNumber
        Version = 1
        Type = 2
        Payload = struct.pack('>B' + str(len(uData)) + 's', ResponseCode,
                              uData)

        LoginResponse = struct.pack(
            '>BBHHH' + str(len(Payload)) + 's', Version * 2**4 + Type,
            self.SessionToken // (2**16),
            self.SessionToken - (2**16) * (self.SessionToken // (2**16)),
            c2wUdpChatServerProtocol.hostPortSequence[host_port], len(Payload),
            Payload)
        self.transport.write(LoginResponse, host_port)
        #if ResponseCode!=0:

        if ResponseCode == 0:
            self.sendToAll(Version)

    def sendToAll(self, Version):
        Type = 4
        RST = self.RST('Main Room')

        for user in self.serverProxy.getUserList():
            c2wUdpChatServerProtocol.hostPortSequence[user.userAddress] += 1

            sessionToken = c2wUdpChatServerProtocol.UserToken[user.userAddress]
            RSTall = struct.pack(
                '>BBHHH', Version * 2**4 + Type, sessionToken //
                (2**16), sessionToken - (2**16) * (sessionToken // (2**16)),
                c2wUdpChatServerProtocol.hostPortSequence[user.userAddress],
                len(RST)) + RST
            self.transport.write(RSTall, user.userAddress)

    def RST(self, Rname):
        if Rname == 'Main Room':
            RST1 = b""
            RoomID = 1
            MovieIP = 0
            MoviePort = 0
            MovieL = self.serverProxy.getMovieList()
            UsersList = []

            for User in self.serverProxy.getUserList():
                if User.userChatRoom == ROOM_IDS.MAIN_ROOM:
                    UsersList.append(
                        struct.pack('>HH' + str(len(User.userName)) + 's',
                                    User.userId, len(User.userName),
                                    User.userName.encode('utf-8')))
            Userlist = struct.pack('>H', len(UsersList))

            for user in UsersList:
                Userlist += user
            for movie in MovieL:
                RST1 += self.RST(movie.movieTitle)
            RST = struct.pack('>HH' + str(len(Rname)) + 'sIH', RoomID,
                              len(Rname), Rname.encode('utf-8'), MovieIP,
                              MoviePort) + Userlist + struct.pack(
                                  '>H', len(MovieL)) + RST1

            return RST
        else:
            movie = self.serverProxy.getMovieByTitle(Rname)
            RoomId = movie.movieId
            MovieIP = movie.movieIpAddress
            MoviePort = movie.moviePort
            MovieL = []
            RoomName = struct.pack('>H' + str(len(Rname)) + 's', len(Rname),
                                   Rname.encode('utf-8'))
            UsersList = []
            for User in self.serverProxy.getUserList():

                if User.userChatRoom == Rname or User.userChatRoom == ROOM_IDS.MOVIE_ROOM:
                    UsersList.append(
                        struct.pack('>HH' + str(len(User.userName)) + 's',
                                    User.userId, len(User.userName),
                                    User.userName.encode('utf-8')))
            Userlist = struct.pack('>H', len(UsersList))
            for user in UsersList:
                Userlist += user

            return struct.pack(
                '>H',
                RoomId) + RoomName + encodeIPadress(MovieIP) + struct.pack(
                    '>H', MoviePort) + Userlist + struct.pack(
                        '>H', len(MovieL))

    def Hello(self, host_port):

        ##for user in self.serverProxy.getUserList():
        #if user.userAddress==host_port:
        #username=user.userName
        if self.serverProxy.getUserByAddress(host_port) != False:
            c2wUdpChatServerProtocol.hostPortSequence[host_port] += 1
            sessionToken = c2wUdpChatServerProtocol.UserToken[host_port]
            self.sequenceNumberSentHello = c2wUdpChatServerProtocol.hostPortSequence[
                host_port]
            Version = 1
            Type = 8
            self.c += 1
            Hello = struct.pack(
                '>BBHHH', Version * 2**4 + Type, self.SessionToken // (2**16),
                sessionToken - (2**16) * (sessionToken // (2**16)),
                c2wUdpChatServerProtocol.hostPortSequence[host_port], 0)
            self.transport.write(Hello, host_port)

            if self.c <= 3:
                if self.ACK == False:
                    c2wUdpChatServerProtocol.hostPortSequence[
                        host_port] = c2wUdpChatServerProtocol.hostPortSequence[
                            host_port] - 1
                    reactor.callLater(10, self.Hello, host_port)

#self.serverProxy.addUser(userName,'Main Room',None,host_port)
#SequenceNumber+=1
#RoomIdentifier=1
#RoomName=struct.pack('>H9s',9,'Main Room'.encode('utf-8'))
#MovieIP=0
#MoviePort=0
#UsersMainRoom=[]
#for user in self.serverProxy.getUserList():
#if user.userChatRoom=='Main Room':
#UsersMainRoom.append(struct.pack('>HH'+str(len(user.userName))+'s',user.userId,len(user.userName),userName.encode('utf-8')))
#NumberOfFilms=len(self.serverProxy.getUserList())
#for Movie in self.serverProxy.getUserList():
#RoomId=self.serverProxy.getMovieAddrPort(Movie)
#RoomName=self.serverProxy.
#length UsersMainRoom
#Room List : number of films available , pour chaque film Room Identifier , Room Name , MovieIP , MoviePort

        pass
Beispiel #29
0
class c2wUdpChatServerProtocol(DatagramProtocol):
    def __init__(self, serverProxy, lossPr):
        """
        :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 lossPr: The packet loss probability for outgoing packets.  Do
            not modify this value!

        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:: serverProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """
        #: The serverProxy, which the protocol must use
        #: to interact with the server (to access the movie list and to
        #: access and modify the user list).
        self.serverProxy = serverProxy
        self.lossPr = lossPr
        #{host_port: sequenceNumbersent,type} the server to the client
        self.usersequenceNumber = {}

        #{host_port : sesion}
        self.usersession = {}
        #{host_port : count}
        self.usercount = {}
        #        #{useraddress, user name}
        #        self.addresstouser={}

        #{host_port : flag} to store the sequence of message received
        self.userflag = {}
        #function callLater
        self.send = {}
        self.loginpacket = {}
        #to determine if the login is successful
        self.response = {}
        # 1- leave the systeme 0- non
        self.leave = {}
        #        #{host_port : sequence received without ack}
        #        self.receive={}
        #to store the room id
        self.roomID = [1]
        for movie in self.serverProxy.getMovieList():
            self.roomID.append(movie.movieId)

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

#    def generateSequenceNumber(self,userName):
#        """
#        for every client
#        the sequence number incremented by one for each new packet
#        the sequence number after 65535 is 0
#        """
#        self.usersequenceNumber[userName][0] +=1
#        self.usersequenceNumber[userName][0] = self.usersequenceNumber[userName][0] % 65535
#        return self.usersequenceNumber[userName][0]

    def addr2dec(self, addr):
        """
        Convert  ip address to hexadecimal
        """
        items = [int(x) for x in addr.split(".")]
        return sum([items[i] << [24, 16, 8, 0][i] for i in range(4)])

    def ackResponse(self, datagram, host_port):
        """
         When receiving a package from the server, respond to an ack to confirm the reception
         Here we need to unpack the received datagram, extract the sessionToken, Sequencenumber
         the payload here is a 0
        """

        version = 1
        # the type of the ACK message is 0
        typeMessage = 0
        # Then we use the method called struct to finish the process of packing package and of unpacking package.
        # Specifilly, we use struct.pack and struct.unpack.
        # we have to divide the session(3 bits) into 2 parts of which the first part counts 2 bits,
        sessionToken_1, = struct.unpack('>H', datagram[1:3])
        # and the second part counts 1 bit.
        sessionToken_2, = struct.unpack('>B', datagram[3:4])
        sequenceNumber, = struct.unpack('>H', datagram[4:6])
        # the payloadSize is null due to the specification
        payloadSize = 0
        buf = struct.pack('>BHBHH', version * 16 + typeMessage, sessionToken_1,
                          sessionToken_2, sequenceNumber, payloadSize)
        print('********Send ACK**************')
        print("ack :", buf)

        self.transport.write(buf, (host_port))

    def sendChatMessageONE(self, datagram, host_port):
        """
        The server now receives the message from the client. The next server will forward this 
        message to all users in the same room. So we will now consider extracting the user's ID 
        and then looking up his current room by ID.
        Traverse all users in this room and send this message to each user.
        """

        # By checking the specification, we know that the userID's position inside the package is [8,10]
        # and messageLength is [10,12]

        userID, = struct.unpack('>H', datagram[8:10])

        messageLength, = struct.unpack('>H', datagram[10:12])
        message, = struct.unpack('>%ds' % messageLength, datagram[12:])
        # Here we call the method which is implented by our prof,
        # it calls getUserList() who belongs to serverProxy.
        alluserList = self.serverProxy.getUserList()

        # Then we find all the users in the userList, we expect to find the userRoom by using the userName.
        for user in alluserList:
            if user.userId == userID:
                userRoom = user.userChatRoom
                userName = user.userName
        for user in alluserList:
            if user.userChatRoom == userRoom and user.userName != userName:
                version = 1
                typeMessage = 6
                sessionToken_1 = self.usersession[user.userAddress][0]
                sessionToken_2 = self.usersession[user.userAddress][1]

                # the userID(2 bits) and messageLength(2 bits), so here we add 4 bits with the messageLength.
                payloadSize = 4 + messageLength

                sequenceNumber = self.usersequenceNumber[user.userAddress][0]
                self.usersequenceNumber[user.userAddress][1] = 6
                # Stop sending more than three times
                buf = struct.pack('>BHBHHHH%ds' % messageLength,
                                  version * 16 + typeMessage, sessionToken_1,
                                  sessionToken_2, sequenceNumber, payloadSize,
                                  userID, messageLength, message)

                # the limit times for transferring  messages is 3 times.
                # if the we reach the limit, we suppose that this user is out of line.(we call removeUser())
                if self.usercount[user.userAddress][0] == 3:
                    print("Connection Lost")
                    if self.leave[user.userAddress] == 0:
                        self.serverProxy.removeUser(user.userName)
                        self.leave[user.userAddress] = 1
                        for user in self.serverProxy.getUserList():
                            if user.userChatRoom == ROOM_IDS.MAIN_ROOM or user.userChatRoom == userRoom:
                                self.roomState(user.userAddress)

                else:
                    #send the packet
                    print('*********Send Message**************')
                    print("message :", buf)
                    #                    print('***********************')
                    self.transport.write(buf, user.userAddress)

                    # Here we consider retransmitting this message after timing 1s without receiving ack response.
                    # Stop sending more than three times
                    # To realize this fonction, we call a method in reactor called callLater()
                    self.usercount[user.userAddress][0] += 1
                    if self.usercount[user.userAddress][0] <= 3:
                        self.send[user.userAddress] = [
                            reactor.callLater(1, self.sendChatMessageONE,
                                              datagram, host_port)
                        ]

    def loginResponse(self, datagram, host_port):
        """
        when receiving the login request sent by the client, the server sent the login response
        """
        version = 1
        typeMessage = 2
        userLength, = struct.unpack('>H', datagram[10:12])
        userName, = struct.unpack('>%ds' % userLength,
                                  datagram[12:12 + userLength])
        userName = userName.decode()
        print(userName)

        #        #to store the address of the client
        #        self.addresstouser[host_port]=[userName]

        # if login successful:
        if self.usercount[host_port][0] != 0:
            buf = self.loginpacket[host_port][0]
        else:
            # Here we determine the loginRequest, we use responseCode (1 byte) to determine
            # The first case is Invalid User, which means that the user name has illegal characters.
            #Here we use regular expressions. Need to introduce re library.
            try:
                # we use the concept Regular Expression to solve this part
                if re.search(u'[^a-zA-Z0-9_.éèàçî]', userName):
                    responseCode = 1

                # The second case is that the username is too long (len(userName) > 100).
                elif userLength > 100:
                    responseCode = 2

                # The third situation is user name existed
                elif self.serverProxy.userExists(userName):
                    responseCode = 3

                # The fourth situation is Service not available
                elif len(self.serverProxy.getUserList()) > 65535:
                    responseCode = 4
                else:
                    responseCode = 0

            #Catching anomalies
            except userName:
                responseCode = 255
            # if login successful:
            if responseCode == 0:

                userIdentifier = self.serverProxy.addUser(
                    userName, ROOM_IDS.MAIN_ROOM, None, host_port)

                sequenceNumber = 0
                #Randomly generated 24bits binaire
                sessionToken = random.getrandbits(24)
                print("sessionToken :", sessionToken)
                sessionToken_1 = sessionToken // 256
                sessionToken_2 = sessionToken % 256

                # Here we get a response code, so here we add 5 instead of 4
                payloadSize = 5 + userLength
                buf = struct.pack('>BHBHHBHH%ds' % userLength,
                                  version * 16 + typeMessage, sessionToken_1,
                                  sessionToken_2, sequenceNumber, payloadSize,
                                  responseCode, userIdentifier, userLength,
                                  userName.encode('utf-8'))

            # if login is failed
            else:
                # sessionToken = 0
                sessionToken = 0
                sessionToken_1 = sessionToken // 256
                sessionToken_2 = sessionToken % 256
                sequenceNumber = 0
                userIdentifier = 0
                payloadSize = 5 + userLength
                buf = struct.pack('>BHBHHBHH%ds' % userLength,
                                  version * 16 + typeMessage, sessionToken_1,
                                  sessionToken_2, sequenceNumber, payloadSize,
                                  responseCode, userIdentifier, userLength,
                                  userName.encode('utf-8'))

            self.usersession[host_port] = [sessionToken_1, sessionToken_2]
            self.usersequenceNumber[host_port] = [0, 2]
            self.loginpacket[host_port] = [buf]
            self.response[host_port] = [responseCode]

        # Stop sending more than three times
        if self.usercount[host_port][0] == 3:
            print("Connection Lost")
            if self.leave[host_port] == 0 and self.response[host_port][0] == 0:
                self.serverProxy.removeUser(userName)
                self.leave[host_port] = 1
                for user in self.serverProxy.getUserList():
                    if user.userChatRoom == ROOM_IDS.MAIN_ROOM:
                        self.roomState(user.userAddress)

        else:
            print('********Send LoginResponse***************')
            print("loginresponse :", buf)
            #            print('***********************')
            self.transport.write(buf, (host_port))

            # Here we consider retransmitting this message after timing 1s without receiving ack response.
            # Stop sending more than three times
            self.usercount[host_port][0] += 1
            if self.usercount[host_port][0] <= 3:
                self.send[host_port] = [
                    reactor.callLater(1, self.loginResponse, datagram,
                                      host_port)
                ]

    def messageMainroom(self):
        """
        pack the data of the mainroom
        """
        #Create a new user list in the main room
        userMainList = []
        #Extract all users
        alluserList = self.serverProxy.getUserList()
        #Find the user in the main room in the list and add it to userMainList
        for user in alluserList:
            if user.userChatRoom == ROOM_IDS.MAIN_ROOM:
                userMainList.append((user.userName, user.userId))

        #to pack the data of the mainroom
        roomIdentifier = 1
        roomName = "Main Room"
        movieIP = 0
        moviePort = 0
        userNumber = len(userMainList)
        buf = struct.pack('>HH%dsIHH' % len(roomName.encode('utf-8')),
                          roomIdentifier, len(roomName.encode('utf-8')),
                          roomName.encode('utf-8'), movieIP, moviePort,
                          userNumber)
        for i in range(userNumber):
            userName = userMainList[i][0]
            userLength = len(userName.encode('utf-8'))
            userIdentifier = userMainList[i][1]
            buf = buf + struct.pack('>HH%ds' % userLength, userIdentifier,
                                    userLength, userName.encode('utf-8'))
            #print("mainroom", buf)
        return buf

    def messageMovieroom(self, movieTitle):
        """
         pack the data of the movie room
        """
        #Create a new user list in the movie room
        userMovieList = []
        #Extract all users
        alluserList = self.serverProxy.getUserList()
        #Extract all movies
        allmovieList = self.serverProxy.getMovieList()

        #to find the user in the movie room
        for user in alluserList:
            if user.userChatRoom == movieTitle:
                userMovieList.append((user.userName, user.userId))

        #to pack the data in the movie room

        for movie in allmovieList:
            if movie.movieTitle == movieTitle:
                roomIdentifier = movie.movieId
                roomName = movieTitle
                movieIP = self.addr2dec(movie.movieIpAddress)
                #print("ip :", movieIP)
                moviePort = movie.moviePort
                userNumber = len(userMovieList)
                buf = struct.pack('>HH%dsIHH' % len(roomName.encode('utf-8')),
                                  roomIdentifier,
                                  len(roomName.encode('utf-8')),
                                  roomName.encode('utf-8'), movieIP, moviePort,
                                  userNumber)
                for i in range(userNumber):
                    userName = userMovieList[i][0]
                    userLength = len(userName.encode('utf-8'))
                    userIdentifier = userMovieList[i][1]
                    buf = buf + struct.pack('>HH%ds' % userLength,
                                            userIdentifier, userLength,
                                            userName.encode('utf-8'))
                roomList = 0
                buf = buf + struct.pack('>H', roomList)
        #print("movieroom" , buf)
        return buf

    def roomState(self, host_port):
        """
        to send the room state
        """

        version = 1
        typeMessage = 4

        #to get the room of the client
        user = self.serverProxy.getUserByAddress(host_port)
        sessionToken_1 = self.usersession[host_port][0]
        sessionToken_2 = self.usersession[host_port][1]
        room = user.userChatRoom

        sequenceNumber = self.usersequenceNumber[host_port][0]
        self.usersequenceNumber[host_port][1] = 4

        if room == ROOM_IDS.MAIN_ROOM:

            #if the client in the main room , call the function messageMainroom()
            mainbuf = self.messageMainroom()
            roomListLength = len(self.serverProxy.getMovieList())
            #to get the data of the movie room
            roomListbuf = struct.pack('>H', roomListLength)
            for movie in self.serverProxy.getMovieList():
                roomListbuf = roomListbuf + self.messageMovieroom(
                    movie.movieTitle)
            payloadSize = len(mainbuf) + len(roomListbuf)
            #pack the header
            headbuf = struct.pack('>BHBHH', version * 16 + typeMessage,
                                  sessionToken_1, sessionToken_2,
                                  sequenceNumber, payloadSize)
            #the whole packet
            buf = headbuf + mainbuf + roomListbuf

        #if the client in the movie room
        else:
            #to call the function messageMovieroom(room)
            moviebuf = self.messageMovieroom(room)
            payloadSize = len(moviebuf)
            #the header
            headbuf = struct.pack('>BHBHH', version * 16 + typeMessage,
                                  sessionToken_1, sessionToken_2,
                                  sequenceNumber, payloadSize)
            #the whole packet
            buf = headbuf + moviebuf

        # Stop sending more than three times
        if self.usercount[host_port][0] == 3:
            print("Connection Lost")
            if self.leave[host_port] == 0:
                self.serverProxy.removeUser(user.userName)
                self.leave[host_port] = 1
                for user in self.serverProxy.getUserList():
                    if (user.userChatRoom == ROOM_IDS.MAIN_ROOM
                            or user.userChatRoom == room):
                        self.roomState(user.userAddress)

        else:
            #send the packet
            print('********Send RoomState***************')
            print("roomState :", buf)
            #            print('***********************')
            self.transport.write(buf, (host_port))
            # Here we consider retransmitting this message after timing 1s without receiving ack response.
            # Stop sending more than three times
            self.usercount[host_port][0] += 1
            if self.usercount[host_port][0] <= 3:
                self.send[host_port] = [
                    reactor.callLater(1, self.roomState, host_port)
                ]

    def hello(self, sequenceNumber, host_port):
        """
        to check the client connection is still alive
        """

        #        print("***************************************")
        #        print("now number",self.userflag[userName][0])
        #        print("past number",sequenceNumber)

        #the sequence number received no change
        if sequenceNumber == self.userflag[host_port][0]:

            #more than three consecutive HEL without receiving an ack ,remove the user
            if self.usercount[host_port][0] == 3:
                print("Connection Lost")
                if self.leave[host_port] == 0:
                    user = self.serverProxy.getUserByAddress(host_port)
                    room = user.userChatRoom
                    self.serverProxy.removeUser(user.userName)
                    self.leave[host_port] = 1
                    for user in self.serverProxy.getUserList():
                        if (user.userChatRoom == ROOM_IDS.MAIN_ROOM
                                or user.userChatRoom == room):
                            self.roomState(user.userAddress)

            else:

                #send the packet
                version = 1
                typeMessage = 8
                sessionToken_1 = self.usersession[host_port][0]
                sessionToken_2 = self.usersession[host_port][1]

                sequence = self.usersequenceNumber[host_port][0]
                self.usersequenceNumber[host_port][1] = 8
                payloadSize = 0
                buf = struct.pack('>BHBHH', version * 16 + typeMessage,
                                  sessionToken_1, sessionToken_2, sequence,
                                  payloadSize)
                print('********Send Hello***************')
                print("hello :", buf)
                #               print('***********************')
                self.transport.write(buf, (host_port))
                # Here we consider retransmitting this message after timing 1s without receiving ack response.
                # Stop sending more than three times
                self.usercount[host_port][0] += 1
                if self.usercount[host_port][0] <= 3:
                    self.send[host_port] = [
                        reactor.callLater(1, self.hello, sequenceNumber,
                                          host_port)
                    ]

    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.
        """

        #        print(host_port)
        # Here we extract the first byte of the received data, including
        #the version and  type, where we tend to take out the type.
        buf, = struct.unpack('>B', datagram[0:1])
        typeMessage = buf % 16

        (sessionToken_1, sessionToken_2,
         sequenceNumber) = struct.unpack('>HBH', datagram[1:6])
        self.userflag[host_port] = [sequenceNumber]
        print('********Datagram Received**************')
        print("type :", typeMessage)
        print("sequence number", sequenceNumber)
        print("datagramReceived :", datagram)
        #        print('***********************')
        # The first step we determine the type of information , if the type is ack, we need to
        # determine if the ack is received correctly, if the message is correctly,we cancel resend the packet
        if typeMessage == 0:

            if sequenceNumber == self.usersequenceNumber[host_port][
                    0] and sessionToken_1 == self.usersession[host_port][
                        0] and sessionToken_2 == self.usersession[host_port][1]:
                print("*******ACK Received******")
                self.send[host_port][0].cancel()
                self.usercount[host_port] = [0]
                self.usersequenceNumber[host_port][0] = (
                    self.usersequenceNumber[host_port][0] + 1) % 65535
                if sequenceNumber == 0 and self.usersequenceNumber[host_port][
                        1] == 2 and self.response[host_port][0] == 0:
                    for user in self.serverProxy.getUserList():
                        if user.userChatRoom == ROOM_IDS.MAIN_ROOM:
                            self.roomState(user.userAddress)

        #if the type is not an ack, we should respond the server to confirm the reception of the packet
        else:
            self.ackResponse(datagram, host_port)

            # typeMessage = 1 means request login;we call the function loginResponse
            if typeMessage == 1:

                print("login request")
                #the first sequncenumber is 0

                self.leave[host_port] = 0
                self.usercount[host_port] = [0]
                self.loginResponse(datagram, host_port)

            #typeMessage =5 :request join room ;
            elif typeMessage == 5 and sessionToken_1 == self.usersession[
                    host_port][0] and sessionToken_2 == self.usersession[
                        host_port][1]:

                print("join room")
                usernow = self.serverProxy.getUserByAddress(host_port)
                roomId, = struct.unpack('>H', datagram[8:10])
                # room id is wrong
                if roomId not in self.roomID:
                    self.roomState(host_port)

                else:
                    #the client joins to main room
                    if roomId == 1:
                        self.serverProxy.stopStreamingMovie(
                            usernow.userChatRoom)
                        userPastroom = usernow.userChatRoom
                        self.serverProxy.updateUserChatroom(
                            usernow.userName, ROOM_IDS.MAIN_ROOM)
                        for user in self.serverProxy.getUserList():
                            if (user.userChatRoom == ROOM_IDS.MAIN_ROOM
                                    or user.userChatRoom == userPastroom):
                                self.roomState(user.userAddress)

                    #the client joins to movie room
                    else:
                        for movie in self.serverProxy.getMovieList():
                            if movie.movieId == roomId:
                                self.serverProxy.updateUserChatroom(
                                    usernow.userName, movie.movieTitle)
                                self.serverProxy.startStreamingMovie(
                                    movie.movieTitle)
                                for user in self.serverProxy.getUserList():
                                    if (user.userChatRoom == movie.movieTitle
                                            or user.userChatRoom
                                            == ROOM_IDS.MAIN_ROOM):
                                        self.roomState(user.userAddress)

            #typeMessage =7 : leave system
            elif typeMessage == 7 and sessionToken_1 == self.usersession[
                    host_port][0] and sessionToken_2 == self.usersession[
                        host_port][1]:

                print("leave system")

                usernow = self.serverProxy.getUserByAddress(host_port)
                self.serverProxy.removeUser(usernow.userName)
                self.leave[host_port] = 1
                for user in self.serverProxy.getUserList():
                    if user.userChatRoom == ROOM_IDS.MAIN_ROOM:
                        self.roomState(user.userAddress)
        #typeMessage =7 : send message
            elif typeMessage == 6 and sessionToken_1 == self.usersession[
                    host_port][0] and sessionToken_2 == self.usersession[
                        host_port][1]:

                print("chat message")
                self.sendChatMessageONE(datagram, host_port)
#            #sequence number received add 1
#            self.receive[host_port] = (self.receive[host_port]+1) % 65535
        if self.leave[host_port] == 0 and self.response[host_port][0] == 0:
            #call the function hello , if no message receiving during 10s
            reactor.callLater(10, self.hello, sequenceNumber, host_port)
class c2wUdpChatServerProtocol(DatagramProtocol):

    def __init__(self, serverProxy, lossPr):
        """
        :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 lossPr: The packet loss probability for outgoing packets.  Do
            not modify this value!

        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:: serverProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. note::
            You must add attributes and methods to this class in order
            to have a working and complete implementation of the c2w
            protocol.
        """
        #: The serverProxy, which the protocol must use
        #: to interact with the server (to access the movie list and to 
        #: access and modify the user list).
        self.serverProxy = serverProxy
        self.lossPr = lossPr
        self.tailleHeader=4
        self.listUser={}
        
    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport
        
    def sendAck(self, message, user): #envoyer un message d'acquittement
        """
        Takes in parameter:
        :param string message: the message received
        :param string user: param user user: instance of the receiver user
        
        Used to send an acknolegment message when a message is received
        from a client
        """
        ack={}
        ack["taille"]=self.tailleHeader
        ack["Type"]=63
        
        numberSeq = message.get("seq")
        if (numberSeq == user.userSeq):
            ack["seq"]=message.get("seq")
            user.incrementeUserSeq()
        else:
            ack["seq"]=user.userSeq-1
        send=encoder(ack)
        print("E : {0}".format(ack))
        self.transport.write(send, (user.host, user.port))


    def addUser(self, name, message, user): #ajouter un nouvel utilisateur à la liste des utilisateurs utilisant l'application (cote serveur)
        """
        Takes in parameters :
        :param string name: the username of the new user
        :param string message: the message received
        :param user user: instance of the concerned user
    
        Used to add the user to the server.
        1) Username check :
            - not already used
            - less than 124 caracter
            - does not contain spaces
            
        2) Add the new user to the user list on the server in the MAIN ROOM
        """
        if (self.serverProxy.getUserByName(name)): #verifier si le nom d'utilisateur est dejà utilise ou non sur la liste
            dico={}
            dico["taille"]=self.tailleHeader+1
            dico["Type"]=8
            dico["erreur"]=1
            return dico #envoyer un message avec une erreur "1"
        
        if (len(name.encode('utf-8'))>124):  #verifier si le nom d'utilisateur ne depasse pas 124 caractères
            dico={}
            dico["taille"]=self.tailleHeader+1
            dico["Type"]=8
            dico["erreur"]=2 #envoyer un message avec une erreur "2"
            return dico
            
        if (" " in name): #verifier si le nom d'utilisateur contient des espaces
            dico={}
            dico["taille"]=self.tailleHeader+1
            dico["Type"]=8
            dico["erreur"]=3 #envoyer un message avec une erreur "3"
            return dico
            
        self.serverProxy.addUser(message.get("user"), ROOM_IDS.MAIN_ROOM, None,(user.host,user.port)) #si aucune des conditions n'est respectee, c'est que le nom peut etre utilise, on ajoute alors l'utilisateur à la liste
        dico={}
        dico["taille"]=self.tailleHeader
        dico["Type"]=7
        return dico
        
        
    def sendMessageToUserChat(self, message, user):
        """
        Takes in parameters :
        :param dict message: the received message
        :param user user: instance of the concerned user
            
        Adds the message in the wainting list of the receiver.
        If this list contains only ONE message, the sendMessageToClient
        function if launched.
        """
        message["seq"]=user.serverSeq
        user.addMessage(message)
        if(len(user.message)==1):
            self.sendMessageToClient(user)
            
            
    def sendMessageToClient(self, user):
        """
        Takes in parameters :
        :param user user: instance of the concerned user
        
        Sends the message to the concerned client and launchs the  
        sendAndWait function
        """
        message=user.message[0]
        message["seq"]=user.serverSeq
        send=encoder(message)
        print("E nom {0} : {1}".format(user.name,message))
        self.transport.write(send, (user.host,user.port))
        user.idSend=reactor.callLater(1, self.sendAndWait, user)
        
    
    def sendAndWait(self, user):
        """
        Takes in parameter :
        :param user user: instance of the concerned user
            
        Sets the SendAndWait functionality : it sends the message 10 times,
        every seconds
        
        """
        if(user.numberTransmission<10):
            send=encoder(user.message[0])
            print("E nom {0} : {1}".format(user.name,user.message[0]))
            #print("E : {0}".format(user.message[0]))
            self.transport.write(send, (user.host, user.port))
            user.numberTransmission+=1
            user.idSend=reactor.callLater(1, self.sendAndWait, user)
        if(user.numberTransmission==10):
            print("salut : {0}".format(user.name))
            user.idSend.cancel()
            self.deleteUser(user)
            
            
    def sendMovies(self, message):
        """
        Takes in parameter:
        :param dict message: the received message
        
        Function used to get the movies availables on the server and to send 
        them in a list to the newly connected client
        """
        movies=self.serverProxy.getMovieList() #recuperer la liste des films aupres du serveur 
        films={} #creatrion du dictionnaire à RENVOYER
        films["seq"]=message.get("seq")+1
        films["Type"]=2
        i=0
        taille=0
        while(i<len(movies)):
            films["ip{0}".format(i)]=movies[i].movieIpAddress #sur 4 octets
            films["port{0}".format(i)]=movies[i].moviePort #sur 1 octet
            films["Id{0}".format(i)]=movies[i].movieId #sur 1 octet
            films["nom{0}".format(i)]=movies[i].movieTitle #taille variable
            films["taille{0}".format(i)]=8+len(movies[i].movieTitle) #inclu ip, port, id, nom et lui meme sur 2 octets
            taille+=films.get("taille{0}".format(i))
            i+=1
            
        films["taille"]=self.tailleHeader+taille
        return films
        
    def sendUsers(self,message):
        """
        Takes in parameter:
        :param dict message: the received message
        
        Function used to get the users connected on the server and to send 
        them in a list to the newly connected client
        """
        
        users=self.serverProxy.getUserList()#recuper la liste des utilisateurs 
        utilisateurs={} #creatrion du dictionnaire à RENVOYER
        utilisateurs["seq"]=message.get("seq")+2
        utilisateurs["Type"]=3
        i=0
        taille=0
        
        while(i<len(users)): #tant que l'on arrive pas a la fin de la liste des utilisateurs
            utilisateurs["user{0}".format(i)]=users[i].userName #taille variable
            if(users[i].userChatRoom==ROOM_IDS.MAIN_ROOM): #si l'utilisateur est dans la main room ...
                utilisateurs["Id{0}".format(i)]=0 #l'id a envoyer est 0
            
            else:#sinon ...
                room=users[i].userChatRoom #on recupere l'id de la room dans lequel il se trouve
                print("roooooooooooooooooooom : {0}".format(room))
                movie=self.serverProxy.getMovieById(room)
                utilisateurs["Id{0}".format(i)]=movie.movieId #sur 1 octet
            utilisateurs["taille{0}".format(i)]=2+len(users[i].userName.encode('utf-8'))
            taille+=utilisateurs.get("taille{0}".format(i))
            i+=1
        utilisateurs["taille"]=self.tailleHeader+taille        
        return utilisateurs
        
    def updateUser(self,user,roomId):
        """
        Takes in parameter:
        :param user user: instance of the concerned user
        :param int roomId : the new room's id where the client is now connected
        
        Used to update the status of a user : in which room he is or if he has left the application
        This message is sent to all the users connected
        """
        dicoUpdate={}
        userName=user.name #recuperer l'utisateur dont on doit envoyer le nouveau statut
        dicoUpdate["seq"]=0
        dicoUpdate["Type"]=4
        dicoUpdate["taille"]=4+1+len(userName.encode('utf-8'))
        dicoUpdate["user"]=userName
        
        if(roomId==ROOM_IDS.MAIN_ROOM): #si l'utilisateur est dans la main room
            dicoUpdate["Id"]=0 # l'id vaut 0
        
        else: #sinon...
            dicoUpdate["Id"]=roomId #il vaut l'id passé en parametre

        allUsers=self.serverProxy.getUserList() #recuperation de la liste des utilisateurs connectes
        
        for u in allUsers: #pour chacun des utilisateurs de la liste:
            receiver=self.listUser.get("{0}".format(u.userAddress)) #on recupere l'instrance TCP pour cet utilisateur
            self.sendMessageToUserChat(dicoUpdate, receiver) #on envoie le dictionnaire a chaque client

            
    def messageToForward(self,message,user):
        """
        Takes in parameter:
        :param dict message: the received message
        :param user user: instance of the concerned user
        
        Used to prepare the message which will be forwarded
        
        e.g : chat message
        """
        dicoToSend={}
        dicoToSend["Type"]=10
        dicoToSend["size"]=len(user.name.encode('utf-8'))
        dicoToSend["user"]=user.name
        dicoToSend["message"]=message
        dicoToSend["taille"]=self.tailleHeader+1+len(user.name.encode('utf-8'))+len(message.encode('utf-8'))
        return dicoToSend
    
    def gestionStream(self, movieId):
        """
        Takes in parameter:
        :param int movieId : the id of the movie which have to be started
        
        Used to start the streaming of a movie
        """
        
        self.serverProxy.startStreamingMovie(self.serverProxy.getMovieById(movieId).movieTitle)
        
    def deleteUser(self, user):
        """
        Takes in parameter:
        :param user user: instance of the concerned user
        
        Used to delete a user on the server when this one 
        has totally left the application
        """
        
        if(self.serverProxy.getUserByAddress((user.host,user.port))):
            self.serverProxy.removeUser(user.name)
            self.updateUser(user,255) #id donné lorsqu'un utilisateur quitte la plateforme
            del self.listUser["{}".format((user.host,user.port))]
        else:
            del self.listUser["{}".format((user.host,user.port))]
            print(self.listUser)
    
    def receiverReady(self, user):
        """
        Takes in parameter:
        :param user user: instance of the concerned user
        
        Used to increment the client's sequence number on the server. It means
        that the client is ready to receive another message from the server
        """
        if(user.error==0): #si le message de connexion ne contient pas d'erreur
            user.idSend.cancel()  #on arrete le S&W
            user.delMessage() #on supprime le message de la liste des message a envoyer a l'utilisateur
            user.incrementeServerSeq() #on incremente le numero de sequence de cet utilisateur sur le serveur
            user.numberTransmission=1 #on réinitialise le numbre de transmissions
            
            if(len(user.message)>0): #si la la liste des messages a envoyer au client n'est pas vide
                self.sendMessageToClient(user) #on envoie le message suivant
            
        else: #sinon
            print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
            print(user.idSend)
            user.idSend.cancel() #on arrete le S&W           
            self.deleteUser(user) #on supprime l'utilisateur
            
    def forwardMessage(self, message, user):
        """
        Takes in parameter:
        :param dict message: the received message
        :param user user: instance of the concerned user

        Used to send the message which will be forwarded
        
        e.g : chat message
        """
        
        idMovieSender=self.serverProxy.getUserByName(user.name).userChatRoom#recherche de l'id de la room dans laquelle se trouve l'utilisateur
        usersList=self.serverProxy.getUserList()  #on recupere la liste des utilisateurs connectes au serveur
        receivers=[] #liste contenant les destinataires
        i=0
        while(i<len(usersList)): #tant que l'on arrive pas au bout de la liste des utilisateurs
            if(usersList[i].userChatRoom==idMovieSender): #si le destinataire est dans la meme room que l'emetteur
                receivers.append(usersList[i]) #on l'ajoute dans la liste des destinataires  
            i+=1
        
        for u in receivers: #pour chaque destinataire
            receiver=self.listUser.get("{0}".format(u.userAddress)) #on recupere l'instrance TCP pour cet utilisateur
            self.sendMessageToUserChat(message, receiver)#on envoie le dictionnaire a chaque client
                
    def joinOKRoom(self, message):
        """
        Takes in parameter:
        :param dict message: the received message
        
        Used to prepare the message which is sent to accept that a user has
        changed of room
        
        """
        
        dicoToSend={}
        dicoToSend["Type"]=11
        dicoToSend["taille"]=4
        return dicoToSend
    
        
    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.
        """
        
        message = decoder(datagram) #on decode le message reçu
        print("\nR : {0}".format(message))
        
        if(self.listUser.get("{}".format(host_port))==None): #si l'utilisateur n'existe pas
            self.listUser["{}".format(host_port)]=userChat(message.get("user"),host_port) #on le crée
        
        user = self.listUser.get("{0}".format(host_port))
        Type = message.get("Type")
        Seq = message.get("seq")
        
        if Type == 63: #si le message est un acquittement
          if (Seq == user.serverSeq): #si le num de seq de l'ack est celui enregsitre sur le server
              self.receiverReady(user)
        
        else:#si ce n'est pas un ack
            if Seq < user.userSeq: #si le num de seq recu est inferieur a celui du client enregsitre sur le serveur
                self.sendAck(message, user) #on envoe un ack (=deja traite)
            
            else: #sinon
                self.sendAck(message, user) #on envoie un ack avant traitement
                
                if Type==1:  #si le message est une inscription
                    print(message.get("user"))
                    testAdding=self.addUser(message.get("user"), message, user)#on essaye d'ajouter l'utilisateur sur le serveur
                    if (len(testAdding) > 2): # si le retour contient un champ erreur en plus de l'entete
                        user.error=1  #on place la variable error a 1 pour signifier qu'une erreur est survenue
                        self.sendMessageToUserChat(testAdding, user) #on le place dans la liste des message a envoyer a l'utilisateur
                    
                    else: #s'il n'y a pas d'erreur
                        self.sendMessageToUserChat(testAdding, user)#on le place dans la liste des message a envoyer a l'utilisateur
                        movies=self.sendMovies(message)#recupere la liste des films
                        self.sendMessageToUserChat(movies, user)#on la place dans la liste des message a envoyer a l'utilisateur
                        users=self.sendUsers(message)#on recupere la liste des utilisateurs
                        self.sendMessageToUserChat(users, user)#on la place dans la liste des message a envoyer a l'utilisateur
                        self.updateUser(user,ROOM_IDS.MAIN_ROOM) #on actualise l'emplacement de l'utilisateur (il se trouve dans la main room)
                
                if Type==5: #si le message est un message de chat
                    messageToForward=self.messageToForward(message.get("message"), user)#on prepare le message a transferer
                    self.forwardMessage(messageToForward, user)#on transfere le message a tous les utilisateurs presents dans la main room
                    
                if Type==6: #si le message est une requete pour changer de room
                    okRoom = self.joinOKRoom(message)#on prepare a envoyer le message d'aceptation
                    self.sendMessageToUserChat(okRoom, user) #on le place dans la liste des message à envoyer à l'utilisateur
                    movieId=message.get("Id")#on recupere l'id de la nouvelle room
                    if movieId==0: #s'il vaut 0
                        self.serverProxy.updateUserChatroom(user.name, ROOM_IDS.MAIN_ROOM)#on actualise le statut de l'utilisateur qui se trouve dans la main room
                    
                    else: #sinon
                        self.serverProxy.updateUserChatroom(user.name, movieId) #on actualise le statut de l'utilisateur qui se trouve dans une movie room   
                        
                    self.updateUser(user,movieId) #on actualise le statut
                    
                if Type==9: #si le message est une requete de deconnexion
                    self.deleteUser(user) self.deleteUser() #on supprime l'utilisateur du serveur
                    

        pass
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        self.seq = 1
        self.tailleHeader = 4
        self.dicoFilm = {
        }  # dictionnaire {Id:titreFilm,.....} ex:{"5":"Big Bunny",....}
        #Useful for the programming of the send & wait policy
        self.compteurSAW = 0
        self.Ackrecieved = False
        self.user = ""  # le nom d utilisateur que le client va utiliser: ca ne changera pas

    def incrementeSeq(self):
        if (self.seq < 1023):
            self.seq += 1
        else:
            self.seq = 1

    def writingMessage(self, Liste):
        """
            Will be used for the function in the reactors. The reactor function callLater() has 3 arguments. Delay, the function to call and its argument
            It is thus easier to use function with only one argument for callLater
            """
        [message, (adresse, port)] = Liste
        self.transport.write(message, (adresse, port))

    def sendAndWait(self, message):

        #on initialise la variable qui va être appelée par la fonction callLater
        ListeArg = [message, (self.serverAddress, self.serverPort)]

        #on initialise les deux callLater qui vont être utilisées au cas où
        callServer = reactor.callLater(1, self.writingMessage, ListeArg)
        message = ListeArg[0]
        RerunFunction = reactor.callLater(1, self.sendAndWait, message)

        if self.compteurSAW == 10:
            #notifier le serveur avec un message d'erreur
            print(
                "warning, didn't recieved any message of the following type:",
                str(63))

        else:
            if self.AckRecieved == False:
                #si aucun message de type 63 n'est reçu, on en renvoie un
                self.compteurSAW += 1
                print("compteurSAW =", self.compteurSAW, "at time:",
                      time.time())
                reactor.run()
            else:

                #une fois que cela s'est fait, on arrete les envois en boucles.
                callServer.cancel()
                RerunFunction.cancel()
                #on réinitialise l'attribut AckRecieved
                self.AckRecieved = False
                pass

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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)
        dico = {}
        dico["taille"] = self.tailleHeader + len(userName)
        dico["Type"] = 1
        dico["seq"] = self.seq
        dico["user"] = userName
        self.user = userName
        connexionRq = encoder(dico)
        self.transport.write(connexionRq,
                             (self.serverAddress, self.serverPort))

        #sendAndWait(connexionRq)

    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.
        """
        #on prépare le message pour l'envoie au serveur
        dicoMessage = {}
        dicoMessage["taille"] = self.tailleHeader + len(message)
        dicoMessage["Type"] = 5
        dicoMessage["seq"] = self.seq
        dicoMessage["message"] = message
        msgchat = encoder(dicoMessage)
        self.transport.write(msgchat, (self.serverAddress, self.serverPort))
        #on applique la politique de send-and-wait
        self.sendAndWait(msgchat)
        #une fois que le serveur a acquitté, on attends la liste de film

        pass

    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.
        """
        #on prépare le message pour l'envoie au serveur
        #print("roomname={0}".format(roomName))
        dicoRequete = {}
        dicoRequete["taille"] = self.tailleHeader + 1
        dicoRequete["Type"] = 6
        dicoRequete["seq"] = self.seq
        if roomName == ROOM_IDS.MAIN_ROOM:
            dicoRequete["Id"] = 0
        else:
            for Id, nom in self.dicoFilm.items():
                if nom == roomName:
                    dicoRequete["Id"] = int(Id)
        joindreRq = encoder(dicoRequete)
        #sendAndWait(joindreRq)
        self.transport.write(joindreRq, (self.serverAddress, self.serverPort))

        pass

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        logoutDico = {}
        logoutDico["taille"] = self.tailleHeader
        logoutDico["Type"] = 9
        logoutDico["sequence"] = self.seq
        paquet = encoder(logoutDico)
        self.transport.write(paquet, (self.serverAddress, self.serverPort))

        pass

    def sendAcknowledgeOIE(
            self, ackSeq
    ):  #ackSeq est la sequence contenue dans le message à acquitter
        """
        Send an aknowledgment message
        """
        ackDico = {}
        ackDico["taille"] = self.tailleHeader
        ackDico["Type"] = 63
        ackDico["seq"] = ackSeq
        ackDatagram = encoder(ackDico)
        self.transport.write(ackDatagram,
                             (self.serverAddress, self.serverPort))

    def datagramReceived(self, datagram, host_port):  # a finir
        """
        :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.
        """
        messageDico = decoder(datagram)
        Type = messageDico.get("Type")
        ##if Type!=63: #il faut acquitter tous les paquets sauf un acquittement

        if Type == 2:  #le datagram contient la liste des films

            self.movieList = []
            i = 0
            while "taille{0}".format(i) in messageDico:
                #print(messageDico)
                tupleTemporaire = (str(messageDico["nom{}".format(i)]),
                                   str(messageDico["ip{}".format(i)]),
                                   str(messageDico["port{}".format(i)]))
                self.movieList.append(tupleTemporaire)
                self.dicoFilm["{0}".format(messageDico["Id{}".format(
                    i)])] = messageDico["nom{0}".format(i)]
                print(self.dicoFilm)
                i += 1
            ackSeq = messageDico["seq"]
            self.sendAcknowledgeOIE(ackSeq)

        if Type == 3:  #Le datagram contient la liste des utilisateurs
            self.userList = [(self.user, ROOM_IDS.MAIN_ROOM)]
            i = 0
            while "taille{0}".format(i) in messageDico:
                if messageDico["Id{0}".format(i)] == 0:
                    roomName = ROOM_IDS.MAIN_ROOM
                else:
                    roomId = messageDico["Id{0}".format(
                        i)]  #roomId est un str contenant un decimal: ex  "5"
                    roomName = self.dicoFilm["{0}".format(roomId)]
                tupleTemporaire = (str(messageDico["user{0}".format(i)]),
                                   roomName)
                print("tupletemporaire={0}".format(tupleTemporaire))
                self.userList.append(tupleTemporaire)
                i += 1
            #print(self.userList)
            #print(self.movieList)
            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

            self.clientProxy.initCompleteONE(self.userList, self.movieList)

        if Type == 4:  # le datagram est une MAJ utilisateur
            #print("entree type 4")
            roomId = messageDico["Id"]
            userName = messageDico["user"]

            if roomId == 0:
                roomName = ROOM_IDS.MAIN_ROOM
            else:  #chercher le titre du Film associé à cet Id (et pas le nom générique ROOM_IDS.MOVIE_ROOM)
                for Id, nom in self.dicoFilm.items():
                    if int(Id) == roomId:
                        roomName = nom
                #roomName=ROOM_IDS.MOVIE_ROOM
            for Tuple in self.userList:
                if Tuple[0] == userName:
                    self.userList[self.userList.index(Tuple)][1] = roomName
            #self.setUserListONE(self.userList)
            self.clientProxy.userUpdateReceivedONE(userName, roomName)

        if Type == 7:  #  inscription acceptee
            #self.clientProxy.joinRoomOKONE() #charger l interface graphique
            #ackSeq=messageDico["seq"]  #pour l'acquittement du datagram
            #self.sendAcknowledgeOIE(ackSeq)
            pass

        if Type == 8:  # error: inscription refusee
            errorCode = messageDico["erreur"]
            if errorCode == 1:
                self.clientProxy.connectionRejectedONE(
                    "nom d'utilisateur déjà utilisé")
            elif errorCode == 2:
                self.clientProxy.connectionRejectedONE(
                    "nom d'utilisateur dépassant 254 octets")
            elif errorCode == 3:
                self.clientProxy.connectionRejectedONE(
                    "nom d'utilisateur contenant un ou plusieurs espaces")

        if Type == 10:  #recevoir un message de chat des autres utilisateurs
            if not messageDico["user"] == self.user:
                rUserName = messageDico["user"]
                message = messageDico["message"]
                self.clientProxy.chatMessageReceivedONE(rUserName, message)

            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

        if Type == 11:  # ack: connexion a une salle réussie
            self.clientProxy.joinRoomOKONE()

        if Type == 12:  # ack: connexion a une salle echouee ou rejetee
            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

            self.clientProxy.connectionRejectedONE(
                "Echec: veuillez vous reconnecter"
            )  #message erreur + reouverture de l interface pour une nouvelle tentative

        if Type == 63:
            self.AckRecieved = True
            #on incrémente le numéro de séquence
            self.incrementeSeq()
        else:
            ackSeq = messageDico["seq"]  #pour l'acquittement du datagram
            self.sendAcknowledgeOIE(ackSeq)

        return messageDico
Beispiel #32
0
class c2wUdpChatClientProtocol(DatagramProtocol):

    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        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.queuepacket=[]

        self.sendAndWait=True

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

    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,(self.serverAddress, self.serverPort))
        #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.
        """

        # print(printable)
        # message=''.join(filter(lambda x: x in printable, message))
        # print(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,(self.serverAddress, self.serverPort))




    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.room_wanted=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,(self.serverAddress, self.serverPort))


        # connection to a movie room:
        else:


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


    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, (self.serverAddress, self.serverPort))

    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)





    def chatReceived(self,packet,datagram):


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



        len_sender = struct.unpack_from('!B', datagram, 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, datagram)


        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,host_port):
        self.error('wrongNumSeq:'+str(self.expected_num_seq), host_port)







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


    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


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

        self.user_list=[]

        packet.data=[]


        offset=4
        len_Rooms = struct.unpack_from("!H", datagram, 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', datagram, 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', datagram, offset=offset)[0]

                    packet.data.append(len_UserName)

                    offset+=1

                    user=struct.unpack_from( "!" + str(len_UserName) + "s", datagram, 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, datagram):

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

        offset = 4
        len_users = struct.unpack_from("!H", datagram, 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', datagram, offset=offset)[0]

            packet.data.append(len_UserName)

            offset += 1

            user = struct.unpack_from("!" + str(len_UserName) + "s", datagram, 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,datagram):

        self.movie_list=[]
        packet.data = []
        len_movie_list=struct.unpack_from("!H",datagram,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,datagram,offset=offset)[0]
            packet.data.append(len_movie_title)



            format="!"+str(len_movie_title)+"s"
            offset+=1
            movie_title=struct.unpack_from(format,datagram,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,datagram,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,datagram,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,host_port,call_count=1):#this function assure the SendAndWait protocol


        if self.sendAndWait == True and call_count==1:

            print('CLIENT SEND PACKET', packet)

            self.sent_packet_history[packet.num_seq] = packet

            self.sendAndWait=False

            self.transport.write(packet.pack(), host_port)
            call_count+=1
            if call_count <= 4:
                #pass
                self.timer=reactor.callLater(5, self.sendPacket,packet, host_port, call_count)


        elif call_count>1:
            print('CLIENT SEND PACKET', packet)
            self.transport.write(packet.pack(), host_port)
            call_count += 1
            if call_count <= 4:
                # pass
                self.timer = reactor.callLater(5, self.sendPacket, packet, host_port, call_count)

        else:

            self.queuepacket.append((packet,host_port))


    def sendqueuepacket(self):
        print("SEND AND WAIIIIIT")
        for packethost in self.queuepacket:
            self.sendPacket(*packethost)

        self.queuepacket=[]




    def ack(self,packet,host_port):

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

    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]
Beispiel #33
0
class c2wUdpChatClientProtocol(DatagramProtocol):
    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        #: the serial number of the packet send by the client
        self.sequenceNumber = 0
        # : the instance of a client-server connection
        self.sessionToken_1 = 0
        self.sessionToken_2 = 0
        #: the name of  the client
        self.userName = ''
        #: the identifier of the client
        self.userIdentifier = 0
        #:the state of the client 0 - login in to the server; 1 - enter the main room
        self.userState = 0
        #:{roomname: roomid}
        self.roomId = {}
        #:{userid : username}
        self.idUser = {}
        #:{sequenceNumber:typeMessage}
        self.sequencetotype = {}
        #: the number of times the same packet was sent
        self.callCount = 0
        #: to store the room name which the client wants to join
        self.roomName = ''
        #function callLater
        self.send = None

    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport

#    def generateSequenceNumber(self):
#        """
#        the sequence number incremented by one for each new packet
#        the sequence number after 65535 is 0
#        """
#        self.sequenceNumber+=1
#        self.sequenceNumber = self.sequenceNumber % 65535
#        return self.sequenceNumber

    def dec2addr(self, dec):
        """
        Convert  hexadecimal to  ip address 
        """
        return ".".join([str(dec >> x & 0xff) for x in [24, 16, 8, 0]])

    def ackResponse(self, datagram):
        """
         When receiving a package from the server, respond to an ack to confirm the reception
         Here we need to unpack the received datagram, extract the sessionToken, Sequencenumber
         the payload here is a 0
        """
        version = 1
        typeMessage = 0
        sessionToken_1, = struct.unpack('>H', datagram[1:3])
        sessionToken_2, = struct.unpack('>B', datagram[3:4])
        sequenceNumber, = struct.unpack('>H', datagram[4:6])
        payloadSize = 0
        buf = struct.pack('>BHBHH', version * 16 + typeMessage, sessionToken_1,
                          sessionToken_2, sequenceNumber, payloadSize)
        print('*********Send ACK**************')
        print("ack :", buf)

        self.transport.write(buf, (self.serverAddress, self.serverPort))

    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)
        # Stop sending more than three times
        if self.callCount == 3:
            self.clientProxy.connectionRejectedONE("Connection Lost")

        version = 1
        typeMessage = 1
        sessionToken = 0
        sessionToken_1 = sessionToken // 256
        sessionToken_2 = sessionToken % 256
        sequenceNumber = 0
        userIdentifier = 0
        userLength = len(userName.encode('utf-8'))
        payloadSize = 4 + len(userName.encode('utf-8'))

        # Here we create a buffer to store data, buffer is the standard data type after pack.
        buf = struct.pack('>BHBHHHH%ds' % userLength,
                          version * 16 + typeMessage, sessionToken_1,
                          sessionToken_2, sequenceNumber, payloadSize,
                          userIdentifier, userLength, userName.encode('utf-8'))
        print('********Send LoginRequest***************')
        print("sendLoginRequest :", buf)

        self.transport.write(buf, (self.serverAddress, self.serverPort))
        #Store the serial number and type of the sent message
        self.sequencetotype[sequenceNumber] = [typeMessage]

        # Here we consider retransmitting this message after timing 1s without receiving ack response.

        self.callCount += 1
        if self.callCount <= 3:
            #function callLater
            self.send = reactor.callLater(1, self.sendLoginRequestOIE,
                                          userName)

#    def requestRoomState(self) :
#       #向服务器发送房间状态的请求
#        version = 1
#        typeMessage = 3
#        sequenceNumber = self.generateSequenceNumber()
#        payloadSize = 0
#        buf = struct.pack('>BHBHH' , version*16+typeMessage, self.sessionToken_1, self.sessionToken_2,
#                         sequenceNumber, payloadSize)
#        print("requestRoomSteat:" , buf)
#        self.transport.write(buf,(self.serverAddress,self.serverPort))
#

    def unpackMovieroomdata(self, datagram):
        """
        unpack the data of the movie room
        """
        # to store the user data
        userList = []
        # to unpack the data in the movie room
        (roomIdentifier, roomNameLength) = struct.unpack('>HH', datagram[8:12])
        roomName, = struct.unpack('>%ds' % roomNameLength,
                                  datagram[12:12 + roomNameLength])
        roomName = roomName.decode()
        offset = 12 + roomNameLength
        (movieIP, moviePort,
         userNumber) = struct.unpack('>IHH', datagram[offset:offset + 8])
        movieIP = self.dec2addr(movieIP)
        offset += 8
        #circuler in order to unpack the data of the user
        if userNumber != 0:
            for i in range(userNumber):
                (userIdentifier,
                 userNameLength) = struct.unpack('>HH',
                                                 datagram[offset:offset + 4])
                offset += 4
                userName, = struct.unpack(
                    '>%ds' % userNameLength,
                    datagram[offset:offset + userNameLength])
                userName = userName.decode()
                #to store the identifier and name of other client
                self.idUser[userIdentifier] = [userName]
                offset += userNameLength
                # to add the user to userList
                userList.append((userName, roomName))

        return userList

    def unpackMainroomdata(self, datagram):
        """
        unpack the data of the main room
        """

        # to store the user data
        userList = []
        #to store the movie data
        movieList = []
        (roomIdentifier, roomNameLength) = struct.unpack('>HH', datagram[8:12])
        #the number of user in the main room
        offset = 18 + roomNameLength
        userNumber, = struct.unpack('>H', datagram[offset:offset + 2])
        offset += 2
        #Recycling to unpacke the user data of the main room
        for i in range(userNumber):
            (userIdentifier,
             userNameLength) = struct.unpack('>HH',
                                             datagram[offset:offset + 4])
            offset += 4
            userName, = struct.unpack('>%ds' % userNameLength,
                                      datagram[offset:offset + userNameLength])
            userName = userName.decode()
            #to store the identifier and name of other client
            self.idUser[userIdentifier] = [userName]
            offset += userNameLength
            userList.append((userName, ROOM_IDS.MAIN_ROOM))
        #unpack the number of movie room
        movieRoomNumber, = struct.unpack('>H', datagram[offset:offset + 2])
        offset += 2
        #Recycling to unpacke the  data of the movie room
        for i in range(movieRoomNumber):
            (movieId,
             movieNameLength) = struct.unpack('>HH',
                                              datagram[offset:offset + 4])
            offset += 4
            movieName, = struct.unpack(
                '>%ds' % movieNameLength,
                datagram[offset:offset + movieNameLength])
            movieName = movieName.decode()
            offset += movieNameLength
            (movieIP, moviePort,
             userNumber) = struct.unpack('>IHH', datagram[offset:offset + 8])
            movieIP = self.dec2addr(movieIP)
            offset += 8
            # to add roomname and roomid to the dictionary
            self.roomId[movieName] = [movieId]
            # to add the movie data to movieList
            movieList.append((movieName, movieIP, moviePort))
            #Recycling to unpacke the  user data in the movie room
            if userNumber == 0:
                offset += 2
            else:
                for i in range(userNumber):
                    (userIdentifier, userNameLength) = struct.unpack(
                        '>HH', datagram[offset:offset + 4])
                    offset += 4
                    userName, = struct.unpack(
                        '>%ds' % userNameLength,
                        datagram[offset:offset + userNameLength])
                    userName = userName.decode()
                    #to store the identifier and name of other client
                    self.idUser[userIdentifier] = [userName]
                    offset += userNameLength
                    userList.append((userName, movieName))
                offset += 2
        return userList, movieList

    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.
        """
        # Stop sending more than three times
        if self.callCount == 3:
            self.clientProxy.connectionRejectedONE("Connection Lost")

        version = 1
        typeMessage = 6

        sequenceNumber = self.sequenceNumber
        payloadSize = 4 + len(message.encode('utf-8'))
        #pack the whole message
        buf = struct.pack('>BHBHHHH%ds' % len(message.encode('utf-8')),
                          version * 16 + typeMessage, self.sessionToken_1,
                          self.sessionToken_2, sequenceNumber, payloadSize,
                          self.userIdentifier, len(message.encode('utf-8')),
                          message.encode('utf-8'))
        print('********Send Message***************')
        print("send message:", buf)

        self.transport.write(buf, (self.serverAddress, self.serverPort))
        #Store the serial number and type of the sent message
        self.sequencetotype[sequenceNumber] = [typeMessage]

        # Here we consider retransmitting this message after timing 1s without receiving ack response.

        self.callCount += 1
        if self.callCount <= 3:
            self.send = reactor.callLater(1, self.sendChatMessageOIE, message)

    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.
        """
        # Stop sending more than three times

        if self.callCount == 3:
            self.clientProxy.connectionRejectedONE("Connection Lost")

        self.roomName = roomName
        version = 1
        typeMessage = 5

        sequenceNumber = self.sequenceNumber
        payloadSize = 2
        buf = struct.pack('>BHBHHH', version * 16 + typeMessage,
                          self.sessionToken_1, self.sessionToken_2,
                          sequenceNumber, payloadSize,
                          self.roomId[roomName][0])
        print('********Send Join Room Request***************')
        print("JoinRoomRequest:", buf)

        self.transport.write(buf, (self.serverAddress, self.serverPort))
        #Store the serial number and type of the sent message
        self.sequencetotype[sequenceNumber] = [typeMessage]

        # Here we consider retransmitting this message after timing 1s without receiving ack response.

        self.callCount += 1
        if self.callCount <= 3:
            self.send = reactor.callLater(1, self.sendJoinRoomRequestOIE,
                                          roomName)

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        # Stop sending more than three times
        if self.callCount == 3:
            self.clientProxy.connectionRejectedONE("Connection Lost")

        version = 1
        typeMessage = 7

        sequenceNumber = self.sequenceNumber
        payloadSize = 0
        buf = struct.pack('>BHBHH', version * 16 + typeMessage,
                          self.sessionToken_1, self.sessionToken_2,
                          sequenceNumber, payloadSize)
        print('*********Send Leave System Request**************')
        print("LeaveSystemRequest:", buf)

        self.transport.write(buf, (self.serverAddress, self.serverPort))
        #Store the serial number and type of the sent message
        self.sequencetotype[sequenceNumber] = [typeMessage]

        # Here we consider retransmitting this message after timing 1s without receiving ack response.

        self.callCount += 1
        if self.callCount <= 3:
            self.send = reactor.callLater(1, self.sendLeaveSystemRequestOIE)

    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.
        """

        # Here we extract the first byte of the received data, including
        #the version and  type, where we tend to take out the type.
        buf, = struct.unpack('>B', datagram[0:1])
        typeMessage = buf % 16

        (sessionToken_1, sessionToken_2,
         sequenceNumber) = struct.unpack('>HBH', datagram[1:6])
        print('********Datagram Received***************')
        print("type :", typeMessage)
        print("sequence number", sequenceNumber)
        print("datagramReceived :", datagram)

        # The first step we determine the type of information , if the type is ack, we need to
        # determine if the ack is received correctly, if the message is correctly,we cancel resend the packet
        if typeMessage == 0:

            if sequenceNumber == self.sequenceNumber and sessionToken_1 == self.sessionToken_1 and sessionToken_2 == self.sessionToken_2:
                print("*******ACK Received******")
                self.send.cancel()
                self.callCount = 0
                self.sequenceNumber = (self.sequenceNumber + 1) % 65535
                # If the type is 7, it means the server has received the request to leave the system, then the customer leaves
                if self.sequencetotype[sequenceNumber][0] == 7:
                    self.clientProxy.userUpdateReceivedONE(
                        self.userName, ROOM_IDS.OUT_OF_THE_SYSTEM_ROOM)
                    self.clientProxy.leaveSystemOKONE()
                # If the type is 5, it means the server has received the request to join the room.
                if self.sequencetotype[sequenceNumber][0] == 5:
                    self.clientProxy.userUpdateReceivedONE(
                        self.userName, self.roomName)
                    self.clientProxy.joinRoomOKONE()

        #if the type is not an ack, we should respond the server to confirm the reception of the packet
#        elif typeMessage != 0 and sequenceNumber == self.receive :
#            self.receive = (self.receive + 1)%65535
        else:
            self.ackResponse(datagram)
            # typeMessage = 2 means the loginResponse.
            if typeMessage == 2:
                print("login response")
                #take out  the responseCode and determine if it is a successful login
                (responseCode, userIdentifier,
                 userNameLength) = struct.unpack('>BHH', datagram[8:13])
                userName, = struct.unpack('>%ds' % userNameLength,
                                          datagram[13:13 + userNameLength])
                userName = userName.decode()

                #responseCode = 0, login successful
                if responseCode == 0:

                    #to store the session token assigned by the server
                    (self.sessionToken_1, self.sessionToken_2) = struct.unpack(
                        '>HB', datagram[1:4])
                    self.userName = userName
                    self.userIdentifier = userIdentifier
                #otherwise the login is refused
                elif responseCode == 1:
                    self.clientProxy.connectionRejectedONE("Invalide User")
                elif responseCode == 2:
                    self.clientProxy.connectionRejectedONE("Username too long")
                elif responseCode == 3:
                    self.clientProxy.connectionRejectedONE(
                        "Username not available")
                elif responseCode == 4:
                    self.clientProxy.connectionRejectedONE(
                        "Service not available")
                elif responseCode == 255:
                    self.clientProxy.connectionRejectedONE("Unknown Error")

            # type=6, the client receives the chatMessage by other client
            if typeMessage == 6 and sessionToken_1 == self.sessionToken_1 and sessionToken_2 == self.sessionToken_2:
                print("chat message")
                (userId, messageLength) = struct.unpack('>HH', datagram[8:12])
                message, = struct.unpack('>%ds' % messageLength, datagram[12:])
                self.clientProxy.chatMessageReceivedONE(
                    self.idUser[userId][0], message.decode())

            # type=4, the room state
            if typeMessage == 4 and sessionToken_1 == self.sessionToken_1 and sessionToken_2 == self.sessionToken_2:
                print("room state")
                (roomIdentifier,
                 roomNameLength) = struct.unpack('>HH', datagram[8:12])
                roomName, = struct.unpack('>%ds' % roomNameLength,
                                          datagram[12:12 + roomNameLength])
                roomName = roomName.decode()

                #the room is Main ROOM
                if roomName == "Main Room":
                    self.roomId[ROOM_IDS.MAIN_ROOM] = [roomIdentifier]
                    userList, movieList = self.unpackMainroomdata(datagram)
                    #if login successful,initial the room
                    if self.userState == 0:
                        self.clientProxy.initCompleteONE(userList, movieList)
                        self.userState = 1
                    #update the user list
                    else:
                        self.clientProxy.setUserListONE(userList)
                #the room is movie room,update the user list
                else:
                    userList = self.unpackMovieroomdata(datagram)
                    self.clientProxy.setUserListONE(userList)
class c2wUdpChatClientProtocol(DatagramProtocol):

    def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
        """
        :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.
        :param clientProxy: The clientProxy, which the protocol must use
            to interact with the Graphical User Interface.

        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 attributes:

        .. attribute:: serverAddress

            The IP address of the c2w server.

        .. attribute:: serverPort

            The port number of the c2w server.

        .. attribute:: clientProxy

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

        .. attribute:: lossPr

            The packet loss probability for outgoing packets.  Do
            not modify this value!  (It is used by startProtocol.)

        .. 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 of the c2w server.
        self.serverPort = serverPort
        #: The clientProxy, which the protocol must use
        #: to interact with the Graphical User Interface.
        self.clientProxy = clientProxy
        self.lossPr = lossPr
        self.num=0
        self.movieList=[]
        self.userList=[]
        self.ackReceived ={}
        self.tryTime={}	
        self.resend={}
        self.isrefused=False
        self.isWatching=True

        
        #each time we initiliaze the client, the number of sequence begins at 0
    
    
    def numConstruct(self):
        #each time we send a sequence, we need to use this function to realize the increasement ot 
        #sequence number  
            
        numSequence=self.num
        self.num+=1
        return numSequence   
    
    def datagramSplit(datagram):
        dataHead=struct.unpack('>I',datagram[0:4])
        numSequenceBin=(bin(datahHead[0])[2:].rjust(32,'0')[8:18])
        print(numSequenceBin)

        return(numSequenceBin)
        
        
     
    def ackConstructor(self):
        typeAck=80
        numSeq=datagramSplit(datagram)
        longueurAck=longueur[2:].rjust(14,"0")
        ack0bin=bin(typeAck)[2:].rjust(8,"0")+numSeq+longueurAck
        ack0=int(ack0bin,2)

        ack=struct.pack('>I',ack0)
        print(ack,'ack is constructed')
        return(ack)
       

       
    def startProtocol(self):
        """
        DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

        If in doubt, do not add anything to this method.  Just ignore it.
        It is used to randomly drop outgoing packets if the -l
        command line option is used.
        """
        self.transport = LossyTransport(self.transport, self.lossPr)
        DatagramProtocol.transport = self.transport
    def headConstruct(self,typeDatagram,numSequence,longueur):
        #para all three are of the type int
        print('gihifhsidfhu',numSequence)

        Type=bin(typeDatagram)[2:].rjust(8,"0")
        

        NumSeq=bin(numSequence)[2:].rjust(10,"0")

        Longueur=bin(longueur)[2:].rjust(14, "0")
        
        head=Type+NumSeq+Longueur
        
        return(head)
    def sendAgain(self,datagram,numSeq,host_port):
            print('12')    
            print(numSeq,datagram,host_port)
            if self.isrefused==True:
                return
            if self.tryTime[numSeq] <= 4 and self.ackReceived[numSeq] == False :
                    print('send agaim')    
                    self.transport.write(datagram,host_port)
                    print('resend the datagram',datagram)
                    self.tryTime[numSeq]+=1
                    reactor.callLater(5,self.sendAgain,datagram,numSeq,host_port)
            else:
                if(self.ackReceived[numSeq] == True ):
                    print('this datagram has been responded',datagram)
                    
                elif(self.tryTime[numSeq] > 4):
                    print('time out for the datagram\'s ack',datagram)    
    
         
    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.
        """
        numSequence=self.numConstruct()
        #each time when we need to send a new datagram to server, need to construct a new number of sequence
        print('number of sequence')

        head=self.headConstruct(0,numSequence,len(userName)+1)

        print(head,'head')
        
        self.resend[numSequence]=None
        HeaderUserName=bin(len(userName))[2:].rjust(8,"0")

        UserNameString='' 
        
        for i in userName:
            print(i)
            BinEach=bin(ord(i))
            m=BinEach[2:].rjust(8,"0")
            UserNameString=UserNameString+m
            print('test usernamestring',UserNameString)
       
        Corps=HeaderUserName+UserNameString
        
        datagramBIN=head+Corps
        
        print(userName) 
        self.userName=userName
        print(self.userName,'self de username while logging in ')
        userName=userName.encode("utf-8")
        print(int(head,2),len(userName),'test errors in struct')
        datagram=struct.pack('>Ib%ds'%len(userName),int(head,2),len(userName),userName)
        
        self.transport.write(datagram,(self.serverAddress,self.serverPort))
        
        self.tryTime[numSequence]=0 
        self.ackReceived[numSequence]=False 
        
        self.resend[numSequence]=reactor.callLater(5,self.sendAgain,datagram,numSequence,(self.serverAddress,self.serverPort))
        
        
        print(datagram)
        


 
    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.
        """
        typeDatagramBin=bin(64)[2:].rjust(8,"0")
        numSeqInt=self.numConstruct()
        numSeqBin=bin(numSeqInt)[2:].rjust(10,'0')
        longueur=len(message)+len(self.userName)+2
        longueurBin=bin(longueur)[2:].rjust(14, "0")
        head=typeDatagramBin+numSeqBin+longueurBin
        m0=struct.pack('>I',int(head,2))
        m1=struct.pack('b%ds'%len(self.userName),len(self.userName),self.userName.encode('utf-8'))
        m2=struct.pack('b%ds'%len(message),len(message),message.encode('utf-8'))
        datagram=m0+m1+m2
        
        self.transport.write(datagram,(self.serverAddress,self.serverPort))
        print('senda message for chatting to the server',datagram)
                  

            
    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.
        """
        
        print('now i am trying to entre a video room',roomName)
        if(type(roomName)==str):
            self.isWatching=True
            self.nowRoom=roomName
                
            numSequence=self.numConstruct()
            
            print('number of sequence',numSequence)
            
            TypeBin=bin(48)
            Type=TypeBin[2:].rjust(8,"0")
            
            NumSeqBin=bin(numSequence)
            NumSeq=NumSeqBin[2:].rjust(10,"0")
            
          
           
            print('check the name of room',roomName,type(roomName))
            LongueurInt=len(roomName)+1
            
            LongueurBin=bin(LongueurInt)
            Longueur=LongueurBin[2:].rjust(14, "0")
            
            head=Type+NumSeq+Longueur
            print(head,'head')
            
            
            roomName=roomName.encode("utf-8")
           
            datagram=struct.pack('>Ib%ds'%len(roomName),int(head,2),len(roomName),roomName)
            
            
            self.transport.write(datagram,(self.serverAddress,self.serverPort))
            print(datagram,'datagram for entring a video room')
            
            #self.clientProxy.setUserListONE(('5alice',ROOM_IDS.MOVIE_ROOM))
            
            
            print('check the join movie room',self.userName, roomName,type(self.userName), type(roomName))
            self.clientProxy.userUpdateReceivedONE(self.userName,'threzr')
            print('is this youdoisuisoq')
   
            self.clientProxy.joinRoomOKONE()

            
        else:
            self.isWatching=True
            print('now i am leaving present movie room')
            numSequence=self.numConstruct()
            
            print('number of sequence',numSequence)
            
            TypeBin=bin(49)
            Type=TypeBin[2:].rjust(8,"0")
            
            NumSeqBin=bin(numSequence)
            NumSeq=NumSeqBin[2:].rjust(10,"0")
            
          
           
        
            LongueurInt=0
            
            LongueurBin=bin(LongueurInt)
            Longueur=LongueurBin[2:].rjust(14, "0")
            
            head=Type+NumSeq+Longueur
            print(head,'head')
            
            
           
           
            datagram=struct.pack('>I',int(head,2))
            
            
            self.transport.write(datagram,(self.serverAddress,self.serverPort))
            self.clientProxy.joinRoomOKONE()
            
        

    def sendLeaveSystemRequestOIE(self):
        """
        Called by the client proxy  when the user
        has clicked on the leave button in the main room.
        """
        print('hi now i am leaving this system')
        

        self.clientProxy.userUpdateReceivedONE(self.userName,ROOM_IDS.OUT_OF_THE_SYSTEM_ROOM)
        
  
       
        Type=3
        typeLeave=bin(Type)[2:].rjust(8,"0")
        
        numSequence=self.num
        self.num+=1
        NumSeqBin=bin(numSequence)
        NumSeq=NumSeqBin[2:].rjust(10,"0")


        longueur=bin(0)
        longueur=longueur[2:].rjust(14,"0")
        
        datagram=typeLeave+NumSeq+longueur

        datagram_leave=struct.pack('>I',int(datagram,2))
        self.transport.write(datagram_leave,(self.serverAddress,self.serverPort))
      
        
        self.clientProxy.applicationQuit()
    def test(self,datagram):
        if not(datagram==''):
                number=datagram[0:2]
                print( number)
                number=struct.unpack('>H',number)[0]
        
                print('number in room',number)
                if not(number==0):
                        datagram=datagram[2:]
                        for i in range(number):
                
                                lenI=struct.unpack('b',datagram[0])[0]
                                print(datagram[3:3+lenI])
                                list1.append(datagram[1:1+lenI])
                                datagram=datagram[1+lenI:]
                                
                        self.test(datagram)  
                         
    def buildSalon(self,datagram):
        print('exam datagram in buildSalon',datagram)
        if(len(datagram)==2 or len(datagram)==0):
            return
        numInRoom=struct.unpack('>H',datagram[0:2])[0]
        print(numInRoom,'nulber of users in the room presenr')
        if (numInRoom==0):
            datagram=datagram[2:]
            print(datagram,'datagram after 0')
        if not(numInRoom==0):
            datagram=datagram[2:]
            print(datagram,'datagram')
            for i in range(numInRoom):
                print('hi')
                print(datagram[0])
                lenUsername=datagram[0]
                print(type(lenUsername),lenUsername)
                username=struct.unpack('%ds'%lenUsername,datagram[1:1+lenUsername])[0]
                self.list1.append(username.decode('utf-8'))
                datagram=datagram[1+lenUsername:]
        print('length dqtqgrqm',len(datagram))
        print(self.list1,'self.list1')
        
        self.buildSalon(datagram)
                                
    def ackConstructor(self,datagram):
        typeAck=80
        dataHead=struct.unpack('>I',datagram[0:4])
        #split the number of sequence in this datagram

        numSeq=bin(dataHead[0])[2:].rjust(32,'0')[-24:-14]
        print(numSeq,'number of seq')
        lengthAck=bin(0)[2:].rjust(14,"0")
        print(bin(typeAck)[2:].rjust(8,"0"),numSeq,lengthAck,'check ack')
        ackInt=int(bin(typeAck)[2:].rjust(8,"0")+numSeq+lengthAck,2)
        ack=struct.pack('>I',ackInt) 
        return ack
        
    def getNumSeqFromAck(self,ack):
        #split the number of sequence from ack datagram
        unpack=struct.unpack('>I',ack)
        numSeq=int(bin(unpack[0])[-24:-14],2)
        return numSeq
        
    def datagramReceived(self, datagram, host_port):
        #time.sleep(6)
        print('test datagram received ',datagram)
        typeDatagram=struct.unpack('b',datagram[0:1])[0]
        print(typeDatagram,'typeDatagram')
        if(typeDatagram == 80):
            print('now the server receive an ack from client:',datagram)
            numSeqAck=self.getNumSeqFromAck(datagram)
            print('the number of sequence ack is:',numSeqAck)                        
            self.ackReceived[numSeqAck] = True

        if(typeDatagram != 80):
            print('receive a datagram not an ack?')
            #self.transport.write(ackConstructor(datagram),host_port)
            ack=self.ackConstructor(datagram)
            print('send an ack:',ack,'to be a response of datagram:',datagram)
            self.transport.write(ack,(self.serverAddress,self.serverPort))
           
            '''
            self.transport.write(ack,host_port)
            '''
           # numSeq=datagramSplit(datagram)
            
            
            '''
            numSequenceBin=(bin(dataHead[0])[2:].rjust(32,'0')[8:18])
  
            numSeq=numSequenceBin

            longueur=bin(0)
            longueurAck=longueur[2:].rjust(14,"0")
            ack=struct.pack('>I',0) 
            self.transport.write(ack,host_port)
            '''
            '''
            
            ack0bin=bin(typeAck)[2:].rjust(8,"0")+numSeq+longueurAck
            ack0=int(ack0bin,2)
            ack=struct.pack('>I',ack0) 
            self.transport.write(ack,host_port)
            '''
            if(typeDatagram == 1):##Connexion etablie
                print('The connection is created!')
                #here we need to build the movie list intelligent ici just for a test
                #movieList=[('Sintel - Trailer', '127.0.0.1', 1040), ('Great Guy', '127.0.0.1', 1090), 'Big Buck Bunny', '127.0.0.1', 1034), ('The Night Before Christmas', '127.0.0.1', 1100), ('Battleship Potemkin', '127.0.0.1', 1070)]
                #self.clientProxy.initCompleteONE([],movieList)
                
            if(typeDatagram== 2):##Connexion echouee
                self.isrefused=True
                
                print('now this admission request is refused')
                
            if(typeDatagram == -128):   
                print('receive an error message of type 128',datagram) 
                #erroMessage=
                error=datagram[5:].decode('utf-8')
                print(error,type(error))
                self.clientProxy.connectionRejectedONE(error)
                
                
             
            if(typeDatagram ==19):#receive the user list
                numSalon=datagram[4:6]
                print(numSalon,'0:split from datagram user list')
                numSalon=struct.unpack('>H',numSalon)[0]
                print(numSalon,'split from datagram user list')

                print('datagram with info user salon',datagram)
                numSalon=datagram[4:6]
                numSalon=struct.unpack('>H',numSalon)[0]
                list0=[]
                self.list1=[]
                print(numSalon)
                numSalonP=datagram[6:8]
                numSalonP=struct.unpack('>H',numSalonP)[0]
                print('numSalonP',numSalonP)
                datagram=datagram[8:]
                print(datagram,'test0')
                print('test user list datagram',datagram)
                if not (numSalonP==0):
                        print('the main room is not vide')
                        for i in range(numSalonP):
                                print(datagram[0],type(datagram[0]))
                                lenUsername=datagram[0]
                                print(lenUsername,'length of username')
                                username=struct.unpack('%ds'%lenUsername,datagram[1:1+lenUsername])[0]
                                print(username,type(username))
                                list0.append(username.decode('utf-8'))
                                datagram=datagram[1+lenUsername:]
                        print(datagram,len(datagram),2*(numSalon-1),'the last datagram')  
                        if (len(datagram)==2*(numSalon-1)):
                            print('no other users in movie room')
                        else:
                            print('anymore')
                            self.buildSalon(datagram)
                            

                            
                print(list0,'list0',self.list1,'list1')
                self.userList=[]
                if not (len(list0)==0):
                    print('0test',self.userList)
                    for i in list0:
                        self.userList.append((i,ROOM_IDS.MAIN_ROOM))
                if not (len(self.list1)==0):
                    print('1test',self.userList)
                    for i in self.list1:
                        self.userList.append((i,ROOM_IDS.MOVIE_ROOM)) 
                           
                #self.clientProxy.setUserListONE(self.userList)
                print(self.userList,'test self.userList for setOne')
                if(len(self.movieList)>0):
                    self.clientProxy. setUserListONE(self.userList)
                print('show me the result of userList',self.userList)
                

            if(typeDatagram ==16):#receive the movie list
                print('receive movie list for server')
                head=struct.unpack('>IH',datagram[0:6])
                print('head after unpacking',head)
                numMovie=int(head[1])
                corps=datagram[6:]
                print('corps of movieLIst',corps)
                head=bin(head[0]).rjust(32,"0")
                print('datargame head',head)
                
                
                print('check number of movie',numMovie)
                for i in range(numMovie):
                    print('hiiii',corps[0])
                    lenMovieName=corps[0]
                    print(i,type(i))
                    print('movie name 555',corps[1:1+lenMovieName])
                    movieName=corps[1:1+lenMovieName]
                    print('movie name',str(movieName))
                    print('movie name',type(movieName))
                    print('test movie name',str(movieName[2:]))
                    movieName=movieName.decode("utf-8")
                    ip=struct.unpack('4b',corps[1+lenMovieName:5+lenMovieName])
                    print(ip)
                    ipStr=str(ip[0])
                    for i in ip[1:]:
                        ipStr+='.'+str(i)
                        
                    print('test string ip',ipStr)
                    port=struct.unpack('>H',corps[5+lenMovieName:7+lenMovieName])
                    print(port,'test port')
                    print(int(port[0]))
                    port=int(port[0])
                    corps=corps[7+lenMovieName:]
                    
                    print(str(movieName),'hhhhh')
                    self.movieList.append((movieName,ipStr,port))
                    print('check if movie list is correct',self.movieList) 
                    print('check if movie list is correct',self.userList)
                    
                print('head',head)
                print(self.movieList,'if the movie list unpack by the client if correct',self.userList)
                
               
                self.clientProxy.initCompleteONE(self.userList,self.movieList)

            if(typeDatagram ==18):
                print('receive 18 datagram:',datagram)  
                numSame=datagram[5]
                listRoom=[]
                print('number of users in the same room',numSame)
                l=datagram[6:]
                for i in range(numSame):
                    lenName=l[0]
                    name=struct.unpack('%ds'%lenName,l[1:1+lenName])[0].decode('utf-8')
                    print('name test',name)
                    
                    listRoom.append((name,self.nowRoom))
                    l=l[1+lenName:]
                print('test listRoom',listRoom)
                self.clientProxy.setUserListONE(listRoom)    
                
            if(typeDatagram ==65):
                print('recieve 65',datagram)
                lenUsername=datagram[4]

                userName=struct.unpack('%ds'%lenUsername,datagram[5:5+lenUsername])[0]


               
                lenmss=datagram[5+lenUsername]
                print(datagram[5+lenUsername+lenmss:],len(datagram[5+lenUsername+1:]))
                mess=struct.unpack('%ds'%lenmss,datagram[6+lenUsername:])[0]
                print('the user',userName,type(userName), 'is send here',mess,type(mess))
                self.clientProxy.chatMessageReceivedONE(userName.decode('utf-8'), mess.decode('utf-8')) 
                    
        else:
            print('no case satisfied')
            
            
            
            
            '''
            if(typeDatagram == 1):##Connexion etablie
                print('The connection is created!')
                #self.clientProxy.initCompleteONE(userList,movieList)
                
            if(typeDatagram == 2):##Connexion echouee
                self.clientProxy.connectionRejectedONE('userName exists')
                print('Error connection(same userName)!')
            '''
                      
    """
        :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.
        when we receive a datagram, firstly we need to split the datagram to 
        clearly see the part of Type, NumSeq, Longueur, Corps
    """ 
    """except we receive an acquitement, we must send back a message of acquitement    
Beispiel #35
0
 def startProtocol(self):
     """
     DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!
     """
     self.transport = LossyTransport(self.transport, self.lossPr)
     DatagramProtocol.transport = self.transport
Beispiel #36
0
class c2wUdpChatClientProtocol(DatagramProtocol):

	def __init__(self, serverAddress, serverPort, clientProxy, lossPr):
		"""
		: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.
		:param clientProxy: The clientProxy, which the protocol must use
			to interact with the Graphical User Interface.

		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 attributes:

		.. attribute:: serverAddress

			The IP address (or the name) of the c2w server.

		.. attribute:: serverPort

			The port number used by the c2w server.

		.. attribute:: clientProxy

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

		.. attribute:: lossPr

			The packet loss probability for outgoing packets.  Do
			not modify this value!  (It is used by startProtocol.)

		.. note::
			You must add attributes and methods to this class in order
			to have a working and complete implementation of the c2w
			protocol.
		"""
		self.serverAddress = serverAddress
		self.serverPort = serverPort
		self.clientProxy = clientProxy
		self.lossPr = lossPr
		self.idcall = None
		self.status = None
		self.userID = None
		self.seq_num =0
		self.expected_seq_num=0
		self.listOfUserName =[]
		self.listOfUserId = ()
		self.userNames=[]
		self.listOfTitles=[]
		self.listOfMovieId=[]
		self.usernamesUpdated=0
		self.listOfMovies=[]
		self.NbrMovie = None
		self.NbrUser = None
		self.current_movie_room_id=None
		self.requested_movie_room_id=None
		self.type_last_message=None
		self.connected= False
		self.requestMovieName = None
		self.MovieName = None


	def startProtocol(self):
		"""
		DO NOT MODIFY THE FIRST TWO LINES OF THIS METHOD!!

		If in doubt, do not add anything to this method.  Just ignore it.
		It is used to randomly drop outgoing packets if the -l
		command line option is used.
		"""
		self.transport = LossyTransport(self.transport, self.lossPr)
		DatagramProtocol.transport = self.transport


	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.
		"""
		if type(userName)==str :		
			moduleLogger.debug('loginRequest called with username=%s', userName)
			TYPE = '0001'
			self.type_last_message=int(TYPE,2)
			A = '0'
			R = '0'
			ACK_NUM = 0
			DATA=userName
			buffer_length = 6 + len(DATA)
			buf = ctypes.create_string_buffer(buffer_length)
			fourbyte = (int(TYPE,2) << 28) + (int(A,2) << 27) + (int(R,2) << 26) + (int(str(ACK_NUM),2) << 13) + (int(str(self.seq_num),2) << 0)
			struct.pack_into('>IH'+str(len(DATA))+'s',buf,0,fourbyte, buffer_length,DATA)
			self.transport.write(buf.raw,(self.serverAddress,self.serverPort))
			self.idcall = reactor.callLater(3.0,self.sendLoginRequestOIE,[userName])   

		else :
			if type(userName)==list :
				if not(userName==[]):
					first_username=userName[0]
					self.sendLoginRequestOIE(first_username)
					userName.pop(0)
					self.sendLoginRequestOIE(userName)
				else:
					return
		

				
	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.
		"""
		ACK_NUM = 0;

		self.send_Public_Message(ACK_NUM,self.seq_num,self.userID,message)
		self.idcall = reactor.callLater(3.0,self.sendChatMessageOIE,[message])
	
	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.
		"""
		ACK_NUM = 0;

		if(roomName == ROOM_IDS.MAIN_ROOM):
			self.requested_movie_room_id= 0
			self.status = 1
			self.MovieName =  ROOM_IDS.MAIN_ROOM
			self.send_MainRoom_Request(ACK_NUM,self.seq_num,self.userID)
		else:			
			indexOfRoom = self.listOfTitles.index(roomName)
			self.MovieName = roomName
			self.status = 0			
			movieId = self.listOfMovieId[indexOfRoom]
			self.send_MovieRoom_Request(ACK_NUM,self.seq_num,self.userID,movieId)
		self.idcall = reactor.callLater(3.0,self.sendJoinRoomRequestOIE,[roomName])	

		
		
	def sendLeaveSystemRequestOIE(self):
		"""
		Called by the client proxy  when the user
		has clicked on the leave button in the main room.
		"""
		ACK_NUM = 0
		self.disconnect(ACK_NUM,self.seq_num,self.userID)
		self.clientProxy.applicationQuit()
		self.idcall = reactor.callLater(3.0,self.sendLeaveSystemRequestOIE)
				        
	def datagramReceived(self, data, (host, port)):
		"""
		:param data: The message received from the server
		:type data: A string of indeterminate length

		Twisted calls this method whenever new data is received on this
		connection.
		"""
		j=struct.unpack_from('!I',data[0:])[0]
		if(j==12):
			l=data[4:].split('.')			
			for item in l:
				if not(item==''):
					self.listOfMovieId.append(int(item))
		else:
			dataParsed = core.parseReceivedData(data)
			TYPE = dataParsed[0]
			data_extracted = dataParsed[6]						
			if (TYPE == 2 and self.connected == False):
				self.AnalyseUserMessage(data_extracted)
				self.clientProxy.initCompleteONE(self.listOfUserName,self.listOfMovies)
				self.sendAck(dataParsed[5])
				self.connected =True
			elif(TYPE == 2 and self.connected ==True and self.status == 1):
				self.AnalyseUserMessage(data_extracted)				
				self.clientProxy.setUserListONE(self.listOfUserName) 	
			elif(TYPE == 2 and self.connected ==True and self.status == 0):
				self.AnalyseUserMessageForMovieRoom(self.MovieName,data_extracted)				
				self.clientProxy.setUserListONE(self.listOfUserName) 
			elif (TYPE == 3):
				self.AnalyseMovieMessage(data_extracted)				
				self.sendAck(dataParsed[5])
			elif (TYPE == 4):
				PublicMessage_infos= core.extract_public_message(data_extracted)
				userId = PublicMessage_infos[0]
				indiceUser = self.listOfUserId.index(userId)
				username=self.listOfUserName[indiceUser][0]
				self.clientProxy.chatMessageReceivedONE(username,PublicMessage_infos[2])						
				self.sendAck(dataParsed[5])
			elif (TYPE == 5):
				PrivateMessage_infos = core.extract_private_message(data_extracted)
				userId = PrivateMessage_infos[0]
				indiceUser = self.listOfUserId.index(userId)
				username=self.listOfUserName[indiceUser][0]
				self.clientProxy.chatMessageReceivedONE(username,PrivateMessage_infos[2])
				self.sendAck(dataParsed[5])
			elif (TYPE == 14):
				self.idcall.cancel()
				self.ReceiveLoginResponse(data_extracted)					
				self.sendAck(dataParsed[5])
			elif (TYPE == 15):
				self.idcall.cancel()
				self.seq_num +=1
				if self.type_last_message == 8:
					self.clientProxy.leaveSystemOKONE()
				elif (self.type_last_message == 6 ):
					self.current_movie_room_id=self.requested_movie_room_id				
					self.clientProxy.joinRoomOKONE()	
				elif ( self.type_last_message == 7):
					self.current_movie_room_id=self.requested_movie_room_id				
					self.clientProxy.joinRoomOKONE()
			elif (TYPE == 0):
				self.extract_error(data_extracted)