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