From patchwork Wed Jun 1 15:54:05 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Capitulino X-Patchwork-Id: 98287 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id BE770B6F8F for ; Thu, 2 Jun 2011 08:46:28 +1000 (EST) Received: from localhost ([::1]:50607 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QRuBF-0003XD-UU for incoming@patchwork.ozlabs.org; Wed, 01 Jun 2011 18:46:26 -0400 Received: from eggs.gnu.org ([140.186.70.92]:43592) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QRti1-0004ha-Kj for qemu-devel@nongnu.org; Wed, 01 Jun 2011 18:16:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QRthz-0001IG-WE for qemu-devel@nongnu.org; Wed, 01 Jun 2011 18:16:13 -0400 Received: from mx1.redhat.com ([209.132.183.28]:4918) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QRnkg-00071L-NG for qemu-devel@nongnu.org; Wed, 01 Jun 2011 11:54:34 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p51FsWOf012001 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 1 Jun 2011 11:54:32 -0400 Received: from localhost (ovpn-113-123.phx2.redhat.com [10.3.113.123]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p51FsVuO032302; Wed, 1 Jun 2011 11:54:31 -0400 From: Luiz Capitulino To: aliguori@us.ibm.com Date: Wed, 1 Jun 2011 12:54:05 -0300 Message-Id: <1306943645-20313-6-git-send-email-lcapitulino@redhat.com> In-Reply-To: <1306943645-20313-1-git-send-email-lcapitulino@redhat.com> References: <1306943645-20313-1-git-send-email-lcapitulino@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Cc: qemu-devel@nongnu.org, Stefan Hajnoczi , armbru@redhat.com Subject: [Qemu-devel] [PATCH 5/5] QMP: add server mode to QEMUMonitorProtocol X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Stefan Hajnoczi 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 Signed-off-by: Luiz Capitulino --- QMP/qmp.py | 43 ++++++++++++++++++++++++++++++++----------- 1 files changed, 32 insertions(+), 11 deletions(-) diff --git a/QMP/qmp.py b/QMP/qmp.py index 2565508..c7dbea0 100644 --- a/QMP/qmp.py +++ b/QMP/qmp.py @@ -22,19 +22,24 @@ class QMPCapabilitiesError(QMPError): pass class QEMUMonitorProtocol: - def __init__(self, address): + def __init__(self, address, server=False): """ Create a QEMUMonitorProtocol class. @param address: QEMU address, can be either a unix socket path (string) or a tuple in the form ( address, port ) for a TCP 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.__address = address 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): if isinstance(self.__address, tuple): @@ -43,6 +48,17 @@ class QEMUMonitorProtocol: family = socket.AF_UNIX 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): while True: data = self.__sockfile.readline() @@ -67,14 +83,19 @@ class QEMUMonitorProtocol: @raise QMPCapabilitiesError if fails to negotiate capabilities """ self.__sock.connect(self.__address) - 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 + return self.__negotiate_capabilities() + + def accept(self): + """ + Await connection from QMP Monitor and perform capabilities negotiation. + + @return QMP greeting dict + @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): """