Exemple #1
0
 def construct_simple(self, tp):
     """Construct simple message.
     
     For example a HELLO message if tp=CQC_TP_HELLO.
     """
     hdr = CQCHeader()
     hdr.setVals(CQC_VERSION, tp, self._appID, 0)
     msg = hdr.pack()
     return msg
Exemple #2
0
    def construct_command_headers(self, qID, command, **kwargs):
        """Construct a commmand consisting of a list of header objects.

        Extra arguments are only used if the command if of a type that 
        needs them.

        - **Arguments**

            :qID:               qubit ID
            :command:           Command to be executed, eg CQC_CMD_H
            :nofify:            Do we wish to be notified when done.
            :block:             Do we want the qubit to be blocked
        """
        # Construct extra header if needed.
        xtra_hdr = None
        if command == CQC_CMD_SEND or command == CQC_CMD_EPR:
            xtra_hdr = CQCCommunicationHeader()
            remote_appID = kwargs.get("remote_appID", 0)
            remote_node = kwargs.get("remote_node", 0)
            remote_port = kwargs.get("remote_port", 0)
            xtra_hdr.setVals(remote_appID, remote_node, remote_port)
        elif command == CQC_CMD_CNOT or command == CQC_CMD_CPHASE:
            xtra_hdr = CQCXtraQubitHeader()
            xtra_qID = kwargs.get("xtra_qID", 0)
            xtra_hdr.setVals(xtra_qID)
        elif (command == CQC_CMD_ROT_X or command == CQC_CMD_ROT_Y
              or command == CQC_CMD_ROT_Z):
            xtra_hdr = CQCRotationHeader()
            step = kwargs.get("step", 0)
            xtra_hdr.setVals(step)
        elif command == CQC_CMD_MEASURE or command == CQC_CMD_MEASURE_INPLACE:
            xtra_hdr = CQCAssignHeader()
            ref_id = kwargs.get("ref_id", 0)
            xtra_hdr.setVals(ref_id)

        # If xtra_hdr is None, we don't need an extra message.
        if xtra_hdr is None:
            header_length = CQCCmdHeader.HDR_LENGTH
        else:
            header_length = CQCCmdHeader.HDR_LENGTH + xtra_hdr.HDR_LENGTH

        # Construct Header
        hdr = CQCHeader()
        hdr.setVals(CQC_VERSION, CQC_TP_COMMAND, self._appID, header_length)

        # Construct Command
        cmd_hdr = CQCCmdHeader()
        notify = int(kwargs.get("notify", True))
        block = int(kwargs.get("block", True))
        action = int(kwargs.get("action", False))
        cmd_hdr.setVals(qID, command, notify, block, action)

        headers = [hdr, cmd_hdr]
        if xtra_hdr is not None:
            headers.append(xtra_hdr)

        return headers
Exemple #3
0
 def create_return_message(app_id, msg_type, length=0, cqc_version=CQC_VERSION):
     """
     Creates a messaage that the protocol should send back
     :param app_id: the app_id to which the message should be send
     :param msg_type: the type of message to return
     :param length: the length of additional message
     :param cqc_version: The cqc version of the message
     :return: a new header message to be send back
     """
     hdr = CQCHeader()
     hdr.setVals(cqc_version, msg_type, app_id, length)
     return hdr.pack()
Exemple #4
0
    def _send_back_cqc(self, header, msgType, length=0):
        """
        Return a simple CQC header with the specified type.

        header	 CQC header of the packet we respond to
        msgType  Message type to return
        length	 Length of additional message
        """
        hdr = CQCHeader()
        hdr.setVals(CQC_VERSION, msgType, header.app_id, length)

        msg = hdr.pack()
        self.transport.write(msg)
Exemple #5
0
def main():

    # In this example, we are Alice.
    myName = "Alice"

    # Initialize the connection
    cqc = init(myName)

    # Send Hello message
    print("App {} tells CQC: 'HELLO'".format(myName))
    hdr = CQCHeader()
    hdr.setVals(CQC_VERSION, CQC_TP_HELLO, 0, 0)
    msg = hdr.pack()
    cqc.send(msg)

    # Receive return message
    data = cqc.recv(192)
    hdr = CQCHeader(data)
    if hdr.tp == CQC_TP_HELLO:
        print("CQC tells App {}: 'HELLO'".format(myName))
    else:
        print("Did not receive a hello message, but rather: {}".format(
            hdr.printable()))

        # Close the connection
    cqc.close()
Exemple #6
0
    def insert_cqc_header(self,
                          cqc_type: CQCType,
                          version=CQC_VERSION) -> None:
        """
        Inserts a CQC Header at index 0 of self._pending_headers.
        Invoke this method *after* all other headers are pended, so that the correct message length is calculated.
        """

        # Count the total message length
        message_length = 0
        for header in self._pending_headers:
            message_length += header.HDR_LENGTH

        # Build the CQC Header
        cqc_header = CQCHeader()
        cqc_header.setVals(CQC_VERSION, cqc_type, self._appID, message_length)

        # Insert CQC Header at the front
        self._pending_headers.insert(0, cqc_header)
Exemple #7
0
    def sendGetTime(self, qID, notify=1, block=1, action=0):
        """Sends get-time message

        - **Arguments**

            :qID:         qubit ID
            :command:     Command to be executed, eg CQC_CMD_H
            :notify:     Do we wish to be notified when done.
            :block:         Do we want the qubit to be blocked
            :action:     Are there more commands to be executed
        """
        # Send Header
        hdr = CQCHeader()
        hdr.setVals(CQC_VERSION, CQC_TP_GET_TIME, self._appID,
                    CQCCmdHeader.HDR_LENGTH)
        msg = hdr.pack()
        self.commit(msg)

        # Send Command
        cmd_hdr = CQCCmdHeader()
        cmd_hdr.setVals(qID, 0, notify, block, action)
        cmd_msg = cmd_hdr.pack()
        self.commit(cmd_msg)
Exemple #8
0
def is_error_message(message: bytes):

    # Only CQCHeaders can be error messages, so if the length does not correspond it is not an error message
    try:
        header = CQCHeader(message)
    # A ValueError is raised by Header.__init__ if the message cannot be read as a CQCHeader.
    # Since only CQCHeaders can contain errors, this means the message is not an error
    except ValueError:
        return False

    error_types = {
        CQCType.ERR_GENERAL, CQCType.ERR_INUSE, CQCType.ERR_NOQUBIT,
        CQCType.ERR_TIMEOUT, CQCType.ERR_UNKNOWN, CQCType.ERR_UNSUPP
    }

    if header.tp in error_types:
        return True
    else:
        return False
Exemple #9
0
    def dataReceived(self, data):
        """
        Receive data. We will always wait to receive enough data for the
        header, and then the entire packet first before commencing processing.
        """
        # Read whatever we received into a buffer
        if self.buf:
            self.buf = self.buf + data
        else:
            self.buf = data

            # If we don't have the CQC header yet, try and read it in full.
        if not self.gotCQCHeader:
            if len(self.buf) < CQC_HDR_LENGTH:
                # Not enough data for CQC header, return and wait for the rest
                return

                # Got enough data for the CQC Header so read it in
            self.gotCQCHeader = True
            raw_header = self.buf[0:CQC_HDR_LENGTH]
            self.currHeader = CQCHeader(raw_header)

            # Remove the header from the buffer
            self.buf = self.buf[CQC_HDR_LENGTH:len(self.buf)]

            logging.debug("CQC %s: Read CQC Header: %s", self.name,
                          self.currHeader.printable())

            # Check whether we already received all the data
        if len(self.buf) < self.currHeader.length:
            # Still waiting for data
            logging.debug(
                "CQC %s: Incomplete data. Waiting. Current length %s, "
                "required length %s",
                self.name,
                len(self.buf),
                self.currHeader.length,
            )
            return

            # We got the header and all the data for this packet. Start processing.
            # Update our app ID
        self.app_id = self.currHeader.app_id
        # Invoke the relevant message handler, processing the possibly
        # remaining data
        try:
            self._parseData(self.currHeader,
                            self.buf[0:self.currHeader.length])
        except Exception as e:
            print(e)
            import traceback

            traceback.print_exc()

            # if self.currHeader.tp in self.messageHandlers:
            # 	self.messageHandlers[self.currHeader.tp](self.currHeader, )
            # else:
            # 	self._send_back_cqc(self.currHeader, CQC_ERR_UNSUPP)

            # Reset and await the next packet
        self.gotCQCHeader = False

        # Check if we received data already for the next packet, if so save it
        if self.currHeader.length < len(self.buf):
            self.buf = self.buf[self.currHeader.length:len(self.buf)]
            self.dataReceived(b"")
        else:
            self.buf = None
Exemple #10
0
class CQCProtocol(Protocol):
    # Dictionary storing the next unique qubit id for each used app_id
    _next_q_id = {}

    # Dictionary storing the next unique entanglement id for each used
    # (host_app_id,remote_node,remote_app_id)
    _next_ent_id = {}

    def __init__(self, factory):

        # CQC Factory, including our connection to the SimulaQron backend
        self.factory = factory

        # Default application ID, typically one connection per application but
        # we will deliberately NOT check for that since this is the task of
        # higher layers or an OS
        self.app_id = 0

        # Define the backend to use. Is a setting in settings.ini
        self.messageHandler = factory.backend

        # Flag to determine whether we already received _all_ of the CQC header
        self.gotCQCHeader = False

        # Header for which we are currently processing a packet
        self.currHeader = None

        # Buffer received data (which may arrive in chunks)
        self.buf = None

        # Convenience
        self.name = self.factory.name

        logging.debug("CQC %s: Initialized Protocol", self.name)

    def connectionMade(self):
        pass

    def connectionLost(self, reason=connectionDone):
        pass

    def dataReceived(self, data):
        """
        Receive data. We will always wait to receive enough data for the
        header, and then the entire packet first before commencing processing.
        """
        # Read whatever we received into a buffer
        if self.buf:
            self.buf = self.buf + data
        else:
            self.buf = data

            # If we don't have the CQC header yet, try and read it in full.
        if not self.gotCQCHeader:
            if len(self.buf) < CQC_HDR_LENGTH:
                # Not enough data for CQC header, return and wait for the rest
                return

                # Got enough data for the CQC Header so read it in
            self.gotCQCHeader = True
            raw_header = self.buf[0:CQC_HDR_LENGTH]
            self.currHeader = CQCHeader(raw_header)

            # Remove the header from the buffer
            self.buf = self.buf[CQC_HDR_LENGTH:len(self.buf)]

            logging.debug("CQC %s: Read CQC Header: %s", self.name,
                          self.currHeader.printable())

            # Check whether we already received all the data
        if len(self.buf) < self.currHeader.length:
            # Still waiting for data
            logging.debug(
                "CQC %s: Incomplete data. Waiting. Current length %s, "
                "required length %s",
                self.name,
                len(self.buf),
                self.currHeader.length,
            )
            return

            # We got the header and all the data for this packet. Start processing.
            # Update our app ID
        self.app_id = self.currHeader.app_id
        # Invoke the relevant message handler, processing the possibly
        # remaining data
        try:
            self._parseData(self.currHeader,
                            self.buf[0:self.currHeader.length])
        except Exception as e:
            print(e)
            import traceback

            traceback.print_exc()

            # if self.currHeader.tp in self.messageHandlers:
            # 	self.messageHandlers[self.currHeader.tp](self.currHeader, )
            # else:
            # 	self._send_back_cqc(self.currHeader, CQC_ERR_UNSUPP)

            # Reset and await the next packet
        self.gotCQCHeader = False

        # Check if we received data already for the next packet, if so save it
        if self.currHeader.length < len(self.buf):
            self.buf = self.buf[self.currHeader.length:len(self.buf)]
            self.dataReceived(b"")
        else:
            self.buf = None

    @inlineCallbacks
    def _parseData(self, header, data):
        try:
            yield self.messageHandler.handle_cqc_message(header, data)
            messages = self.messageHandler.retrieve_return_messages()
        except Exception as e:
            raise e

        if messages:
            # self.factory._lock.acquire()
            for msg in messages:
                self.transport.write(msg)
                # self.factory._lock.release()

    def _send_back_cqc(self, header, msgType, length=0):
        """
        Return a simple CQC header with the specified type.

        header	 CQC header of the packet we respond to
        msgType  Message type to return
        length	 Length of additional message
        """
        hdr = CQCHeader()
        hdr.setVals(CQC_VERSION, msgType, header.app_id, length)

        msg = hdr.pack()
        self.transport.write(msg)

    def new_qubit_id(self, app_id):
        """
        Returns a new unique qubit id for the specified app_id. Used by cmd_new
        and cmd_recv
        """
        if app_id in CQCProtocol._next_q_id:
            q_id = CQCProtocol._next_q_id[app_id]
            CQCProtocol._next_q_id[app_id] += 1
            return q_id
        else:
            """
            Returns a new unique qubit id for the specified app_id. Used by
            cmd_new and cmd_recv
            """
            if app_id in CQCProtocol._next_q_id:
                q_id = CQCProtocol._next_q_id[app_id]
                CQCProtocol._next_q_id[app_id] += 1
                return q_id
            else:
                CQCProtocol._next_q_id[app_id] = 1
                return 0

    def new_ent_id(self, host_app_id, remote_node, remote_app_id):
        """
        Returns a new unique entanglement id for the specified host_app_id,
        remote_node and remote_app_id. Used by cmd_epr.
        """
        pair_id = (host_app_id, remote_node, remote_app_id)
        if pair_id in CQCProtocol._next_ent_id:
            ent_id = CQCProtocol._next_ent_id[pair_id]
            CQCProtocol._next_ent_id[pair_id] += 1
            return ent_id
        else:
            CQCProtocol._next_ent_id[pair_id] = 1
            return 0
    def readMessage(self, maxsize=192):  # WHAT IS GOOD SIZE?
        """Receive the whole message from cqc server.

        Returns (CQCHeader,None,None), (CQCHeader,CQCNotifyHeader,None) 
        or (CQCHeader,CQCNotifyHeader,EntInfoHeader) depending on the 
        type of message.

        Maxsize is the max size of message.
        """

        # Initialize checks
        gotCQCHeader = False
        if self.buf:
            checkedBuf = False
        else:
            checkedBuf = True

        while True:
            # If buf does not contain enough data, read in more
            if checkedBuf:
                # Receive data
                data = self._s.recv(maxsize)

                # Read whatever we received into a buffer
                if self.buf:
                    self.buf += data
                else:
                    self.buf = data

                    # If we don't have the CQC header yet, try and read it in full.
            if not gotCQCHeader:
                if len(self.buf) < CQCHeader.HDR_LENGTH:
                    # Not enough data for CQC header, return and wait for the rest
                    checkedBuf = True
                    continue

                    # Got enough data for the CQC Header so read it in
                gotCQCHeader = True
                rawHeader = self.buf[0:CQCHeader.HDR_LENGTH]
                currHeader = CQCHeader(rawHeader)

                # Remove the header from the buffer
                self.buf = self.buf[CQCHeader.HDR_LENGTH:len(self.buf)]

                # Check for error
                self.check_error(currHeader)

                # Check whether we already received all the data
            if len(self.buf) < currHeader.length:
                # Still waiting for data
                checkedBuf = True
                continue
            else:
                break
                # We got all the data, read other headers if there is any
        if currHeader.length == 0:
            return currHeader, None, None
        else:
            if currHeader.tp == CQC_TP_INF_TIME:
                timeinfo_header = self._extract_header(CQCTimeinfoHeader)
                return currHeader, timeinfo_header, None
            elif currHeader.tp == CQC_TP_MEASOUT:
                measout_header = self._extract_header(CQCMeasOutHeader)
                return currHeader, measout_header, None
            elif currHeader.tp in [CQC_TP_RECV, CQC_TP_NEW_OK, CQC_TP_EXPIRE]:
                xtra_qubit_header = self._extract_header(CQCXtraQubitHeader)
                return currHeader, xtra_qubit_header, None
            elif currHeader.tp == CQC_TP_EPR_OK:
                xtra_qubit_header = self._extract_header(CQCXtraQubitHeader)
                ent_info_hdr = self._extract_header(EntInfoHeader)
                return currHeader, xtra_qubit_header, ent_info_hdr