QMP: add server mode to QEMUMonitorProtocol
QEMU supports socket chardevs that establish connections like a server or a client. The QEMUMonitorProtocol class only supports connecting as a client. It is not possible to connect race-free when launching QEMU since trying to connect before QEMU has bound and is listening on the socket results in failure. Add the QEMUMonitorProtocol(server=True) argument to bind and listen on the socket. The QEMU process can then be launched and connects to the already existing QMP socket without a race condition: qmp = qmp.QEMUMonitorProtocol(monitor_path, server=True) popen = subprocess.Popen(args) qmp.accept() Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
This commit is contained in:
		
							parent
							
								
									91b8eddf41
								
							
						
					
					
						commit
						37628f11c6
					
				
							
								
								
									
										43
									
								
								QMP/qmp.py
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								QMP/qmp.py
									
									
									
									
									
								
							@ -22,19 +22,24 @@ class QMPCapabilitiesError(QMPError):
 | 
				
			|||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class QEMUMonitorProtocol:
 | 
					class QEMUMonitorProtocol:
 | 
				
			||||||
    def __init__(self, address):
 | 
					    def __init__(self, address, server=False):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Create a QEMUMonitorProtocol class.
 | 
					        Create a QEMUMonitorProtocol class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @param address: QEMU address, can be either a unix socket path (string)
 | 
					        @param address: QEMU address, can be either a unix socket path (string)
 | 
				
			||||||
                        or a tuple in the form ( address, port ) for a TCP
 | 
					                        or a tuple in the form ( address, port ) for a TCP
 | 
				
			||||||
                        connection
 | 
					                        connection
 | 
				
			||||||
        @note No connection is established, this is done by the connect() method
 | 
					        @param server: server mode listens on the socket (bool)
 | 
				
			||||||
 | 
					        @raise socket.error on socket connection errors
 | 
				
			||||||
 | 
					        @note No connection is established, this is done by the connect() or
 | 
				
			||||||
 | 
					              accept() methods
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        self.__events = []
 | 
					        self.__events = []
 | 
				
			||||||
        self.__address = address
 | 
					        self.__address = address
 | 
				
			||||||
        self.__sock = self.__get_sock()
 | 
					        self.__sock = self.__get_sock()
 | 
				
			||||||
        self.__sockfile = self.__sock.makefile()
 | 
					        if server:
 | 
				
			||||||
 | 
					            self.__sock.bind(self.__address)
 | 
				
			||||||
 | 
					            self.__sock.listen(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __get_sock(self):
 | 
					    def __get_sock(self):
 | 
				
			||||||
        if isinstance(self.__address, tuple):
 | 
					        if isinstance(self.__address, tuple):
 | 
				
			||||||
@ -43,6 +48,17 @@ class QEMUMonitorProtocol:
 | 
				
			|||||||
            family = socket.AF_UNIX
 | 
					            family = socket.AF_UNIX
 | 
				
			||||||
        return socket.socket(family, socket.SOCK_STREAM)
 | 
					        return socket.socket(family, socket.SOCK_STREAM)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __negotiate_capabilities(self):
 | 
				
			||||||
 | 
					        self.__sockfile = self.__sock.makefile()
 | 
				
			||||||
 | 
					        greeting = self.__json_read()
 | 
				
			||||||
 | 
					        if greeting is None or not greeting.has_key('QMP'):
 | 
				
			||||||
 | 
					            raise QMPConnectError
 | 
				
			||||||
 | 
					        # Greeting seems ok, negotiate capabilities
 | 
				
			||||||
 | 
					        resp = self.cmd('qmp_capabilities')
 | 
				
			||||||
 | 
					        if "return" in resp:
 | 
				
			||||||
 | 
					            return greeting
 | 
				
			||||||
 | 
					        raise QMPCapabilitiesError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __json_read(self, only_event=False):
 | 
					    def __json_read(self, only_event=False):
 | 
				
			||||||
        while True:
 | 
					        while True:
 | 
				
			||||||
            data = self.__sockfile.readline()
 | 
					            data = self.__sockfile.readline()
 | 
				
			||||||
@ -67,14 +83,19 @@ class QEMUMonitorProtocol:
 | 
				
			|||||||
        @raise QMPCapabilitiesError if fails to negotiate capabilities
 | 
					        @raise QMPCapabilitiesError if fails to negotiate capabilities
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        self.__sock.connect(self.__address)
 | 
					        self.__sock.connect(self.__address)
 | 
				
			||||||
        greeting = self.__json_read()
 | 
					        return self.__negotiate_capabilities()
 | 
				
			||||||
        if greeting is None or not greeting.has_key('QMP'):
 | 
					
 | 
				
			||||||
            raise QMPConnectError
 | 
					    def accept(self):
 | 
				
			||||||
        # Greeting seems ok, negotiate capabilities
 | 
					        """
 | 
				
			||||||
        resp = self.cmd('qmp_capabilities')
 | 
					        Await connection from QMP Monitor and perform capabilities negotiation.
 | 
				
			||||||
        if "return" in resp:
 | 
					
 | 
				
			||||||
            return greeting
 | 
					        @return QMP greeting dict
 | 
				
			||||||
        raise QMPCapabilitiesError
 | 
					        @raise socket.error on socket connection errors
 | 
				
			||||||
 | 
					        @raise QMPConnectError if the greeting is not received
 | 
				
			||||||
 | 
					        @raise QMPCapabilitiesError if fails to negotiate capabilities
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.__sock, _ = self.__sock.accept()
 | 
				
			||||||
 | 
					        return self.__negotiate_capabilities()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def cmd_obj(self, qmp_cmd):
 | 
					    def cmd_obj(self, qmp_cmd):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user