From patchwork Mon Feb 25 17:56:49 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 222990 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 482DD2C029E for ; Tue, 26 Feb 2013 04:59:28 +1100 (EST) Received: from localhost ([::1]:40546 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UA2Ki-0006P7-Be for incoming@patchwork.ozlabs.org; Mon, 25 Feb 2013 12:59:24 -0500 Received: from eggs.gnu.org ([208.118.235.92]:34596) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UA2K2-0004gF-M4 for qemu-devel@nongnu.org; Mon, 25 Feb 2013 12:58:50 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UA2Jy-0000q8-Nr for qemu-devel@nongnu.org; Mon, 25 Feb 2013 12:58:42 -0500 Received: from mail-pa0-f43.google.com ([209.85.220.43]:61968) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UA2Jx-0000pX-Jk for qemu-devel@nongnu.org; Mon, 25 Feb 2013 12:58:38 -0500 Received: by mail-pa0-f43.google.com with SMTP id bh2so1886229pad.2 for ; Mon, 25 Feb 2013 09:58:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:mime-version:content-type:content-transfer-encoding; bh=tTuji/NEGgzLFgcgxALpH23uD0E5YHRG2BH4fwQCEek=; b=EQiBOdg6lYnCa6H3DZgoHCkfFwY5WKSJ+koFs+80GGqApn1ocR4mutTqz/V7IHTWNX Ay4R8IyOHkXyuFKgitIcpE0FOXmAjIKSbrMe2PZC5mRw9NqfUfhyW2ypB2jHzf3AoXCp FbK8MXwXfDnNTM4R+ymyIIdHBKm83BBZhaWkLVUewH+WWolHVxdYG7uPVWruvXxTbYj9 os3R3UImVUWgBH1RFPQWd6Or/DcwAqz62VeYno6Ebd7zOPD2uX5UKAPHQVtBmhxXbGiZ 9R+28otu2BgX6WCsgcUG8XCxMPVvdo19xX5HWflRJxbidynXd6qAU2VaVnCuxZ56V8OG pRpQ== X-Received: by 10.66.228.38 with SMTP id sf6mr20456649pac.150.1361815116375; Mon, 25 Feb 2013 09:58:36 -0800 (PST) Received: from localhost (142.Red-88-13-163.dynamicIP.rima-tde.net. [88.13.163.142]) by mx.google.com with ESMTPS id t6sm14452577paz.11.2013.02.25.09.58.31 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Mon, 25 Feb 2013 09:58:33 -0800 (PST) From: "=?UTF-8?q?Marc-Andr=C3=A9=20Lureau?=" To: qemu-devel@nongnu.org Date: Mon, 25 Feb 2013 18:56:49 +0100 Message-Id: <1361815009-24145-4-git-send-email-marcandre.lureau@redhat.com> X-Mailer: git-send-email 1.8.1.1.439.g50a6b54 In-Reply-To: <1361815009-24145-1-git-send-email-marcandre.lureau@redhat.com> References: <1361815009-24145-1-git-send-email-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 209.85.220.43 Cc: pbonzini@redhat.com, alevy@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Subject: [Qemu-devel] [PATCH 4/4] libcacard: teach vscclient to use GMainLoop for portability 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: Marc-André Lureau Signed-off-by: Marc-André Lureau --- libcacard/vscclient.c | 374 ++++++++++++++++++++++++++------------------------ 1 file changed, 198 insertions(+), 176 deletions(-) diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c index 9b744f2..ad2ffd1 100644 --- a/libcacard/vscclient.c +++ b/libcacard/vscclient.c @@ -10,7 +10,10 @@ * See the COPYING.LIB file in the top-level directory. */ +#ifndef _WIN32 #include +#endif +#include #include "qemu-common.h" #include "qemu/thread.h" @@ -73,7 +76,7 @@ send_msg( mhHeader.type = htonl(type); mhHeader.reader_id = 0; mhHeader.length = htonl(length); - rv = write(sock, &mhHeader, sizeof(mhHeader)); + rv = send(sock, (char *)&mhHeader, sizeof(mhHeader), 0); if (rv < 0) { /* Error */ fprintf(stderr, "write header error\n"); @@ -81,7 +84,7 @@ send_msg( qemu_mutex_unlock(&write_lock); return 16; } - rv = write(sock, msg, length); + rv = send(sock, (char *)msg, length, 0); if (rv < 0) { /* Error */ fprintf(stderr, "write error\n"); @@ -211,18 +214,179 @@ get_id_from_string(char *string, unsigned int default_id) return id; } -static void -do_command(void) +static int +on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming) +{ + uint32_t *capabilities = (incoming->capabilities); + int num_capabilities = + 1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t)); + int i; + QemuThread thread_id; + + incoming->version = ntohl(incoming->version); + if (incoming->version != VSCARD_VERSION) { + if (verbose > 0) { + printf("warning: host has version %d, we have %d\n", + verbose, VSCARD_VERSION); + } + } + if (incoming->magic != VSCARD_MAGIC) { + printf("unexpected magic: got %d, expected %d\n", + incoming->magic, VSCARD_MAGIC); + return -1; + } + for (i = 0 ; i < num_capabilities; ++i) { + capabilities[i] = ntohl(capabilities[i]); + } + /* Future: check capabilities */ + /* remove whatever reader might be left in qemu, + * in case of an unclean previous exit. */ + send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0); + /* launch the event_thread. This will trigger reader adds for all the + * existing readers */ + qemu_thread_create(&thread_id, event_thread, NULL, 0); + return 0; +} + +#define APDUBufSize 270 + +static gboolean +do_socket(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + gsize rv; + int dwSendLength; + int dwRecvLength; + uint8_t pbRecvBuffer[APDUBufSize]; + uint8_t pbSendBuffer[APDUBufSize]; + VReaderStatus reader_status; + VReader *reader = NULL; + VSCMsgHeader mhHeader; + VSCMsgError *error_msg; + + if (g_io_channel_read_chars(source, + (gchar *)&mhHeader, sizeof(mhHeader), &rv, NULL) + != G_IO_STATUS_NORMAL) { + g_error("error while reading from socket"); + } + + if (rv < sizeof(mhHeader)) { + fprintf(stderr, "header short read %" G_GSIZE_FORMAT "\n", rv); + return 8; + } + mhHeader.type = ntohl(mhHeader.type); + mhHeader.reader_id = ntohl(mhHeader.reader_id); + mhHeader.length = ntohl(mhHeader.length); + if (verbose) { + printf("Header: type=%d, reader_id=%u length=%d (0x%x)\n", + mhHeader.type, mhHeader.reader_id, mhHeader.length, + mhHeader.length); + } + switch (mhHeader.type) { + case VSC_APDU: + case VSC_Flush: + case VSC_Error: + case VSC_Init: + if (g_io_channel_read_chars(source, + (gchar *)pbSendBuffer, mhHeader.length, &rv, NULL) + != G_IO_STATUS_NORMAL) { + g_error("error while reading from socket"); + } + break; + default: + fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type); + return 0; + } + switch (mhHeader.type) { + case VSC_APDU: + if (verbose) { + printf(" recv APDU: "); + print_byte_array(pbSendBuffer, mhHeader.length); + } + /* Transmit received APDU */ + dwSendLength = mhHeader.length; + dwRecvLength = sizeof(pbRecvBuffer); + reader = vreader_get_reader_by_id(mhHeader.reader_id); + reader_status = vreader_xfr_bytes(reader, + pbSendBuffer, dwSendLength, + pbRecvBuffer, &dwRecvLength); + if (reader_status == VREADER_OK) { + mhHeader.length = dwRecvLength; + if (verbose) { + printf(" send response: "); + print_byte_array(pbRecvBuffer, mhHeader.length); + } + send_msg(VSC_APDU, mhHeader.reader_id, + pbRecvBuffer, dwRecvLength); + } else { + rv = reader_status; /* warning: not meaningful */ + send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t)); + } + vreader_free(reader); + reader = NULL; /* we've freed it, don't use it by accident + again */ + break; + case VSC_Flush: + /* TODO: actually flush */ + send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0); + break; + case VSC_Error: + error_msg = (VSCMsgError *) pbSendBuffer; + if (error_msg->code == VSC_SUCCESS) { + qemu_mutex_lock(&pending_reader_lock); + if (pending_reader) { + vreader_set_id(pending_reader, mhHeader.reader_id); + vreader_free(pending_reader); + pending_reader = NULL; + qemu_cond_signal(&pending_reader_condition); + } + qemu_mutex_unlock(&pending_reader_lock); + break; + } + printf("warning: qemu refused to add reader\n"); + if (error_msg->code == VSC_CANNOT_ADD_MORE_READERS) { + /* clear pending reader, qemu can't handle any more */ + qemu_mutex_lock(&pending_reader_lock); + if (pending_reader) { + pending_reader = NULL; + /* make sure the event loop doesn't hang */ + qemu_cond_signal(&pending_reader_condition); + } + qemu_mutex_unlock(&pending_reader_lock); + } + break; + case VSC_Init: + if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) { + return -1; + } + break; + default: + printf("Default\n"); + return 0; + } + + return TRUE; +} + +static gboolean +do_command(GIOChannel *source, + GIOCondition condition, + gpointer data) { - char inbuf[255]; char *string; VCardEmulError error; static unsigned int default_reader_id; unsigned int reader_id; VReader *reader = NULL; + g_assert(condition & G_IO_IN); + reader_id = default_reader_id; - string = fgets(inbuf, sizeof(inbuf), stdin); + if (g_io_channel_read_line(source, &string, + NULL, NULL, NULL) != G_IO_STATUS_NORMAL) + g_error("Error while reading command"); + if (string != NULL) { if (strncmp(string, "exit", 4) == 0) { /* remove all the readers */ @@ -336,10 +500,10 @@ do_command(void) vreader_free(reader); printf("> "); fflush(stdout); -} + return TRUE; +} -#define APDUBufSize 270 /* just for ease of parsing command line arguments. */ #define MAX_CERTS 100 @@ -385,61 +549,18 @@ connect_to_qemu( return sock; } -static int on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming) -{ - uint32_t *capabilities = (incoming->capabilities); - int num_capabilities = - 1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t)); - int i; - int rv; - pthread_t thread_id; - - incoming->version = ntohl(incoming->version); - if (incoming->version != VSCARD_VERSION) { - if (verbose > 0) { - printf("warning: host has version %d, we have %d\n", - verbose, VSCARD_VERSION); - } - } - if (incoming->magic != VSCARD_MAGIC) { - printf("unexpected magic: got %d, expected %d\n", - incoming->magic, VSCARD_MAGIC); - return -1; - } - for (i = 0 ; i < num_capabilities; ++i) { - capabilities[i] = ntohl(capabilities[i]); - } - /* Future: check capabilities */ - /* remove whatever reader might be left in qemu, - * in case of an unclean previous exit. */ - send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0); - /* launch the event_thread. This will trigger reader adds for all the - * existing readers */ - rv = pthread_create(&thread_id, NULL, event_thread, NULL); - if (rv < 0) { - perror("pthread_create"); - return rv; - } - return 0; -} - int main( int argc, char *argv[] ) { + GMainLoop *loop; + GIOChannel *channel_stdin; + GIOChannel *channel_socket; char *qemu_host; char *qemu_port; VSCMsgHeader mhHeader; - VSCMsgError *error_msg; - int rv; - int dwSendLength; - int dwRecvLength; - uint8_t pbRecvBuffer[APDUBufSize]; - uint8_t pbSendBuffer[APDUBufSize]; - VReaderStatus reader_status; - VReader *reader = NULL; VCardEmulOptions *command_line_options = NULL; char *cert_names[MAX_CERTS]; @@ -447,6 +568,9 @@ main( int cert_count = 0; int c; + if (socket_init() != 0) + return 1; + while ((c = getopt(argc, argv, "c:e:pd:")) != -1) { switch (c) { case 'c': @@ -528,130 +652,28 @@ main( }; send_msg(VSC_Init, mhHeader.reader_id, &init, sizeof(init)); - do { - fd_set fds; - - FD_ZERO(&fds); - FD_SET(1, &fds); - FD_SET(sock, &fds); + loop = g_main_loop_new(NULL, true); +#ifdef _WIN32 + channel_stdin = g_io_channel_win32_new_fd(STDIN_FILENO); +#else + channel_stdin = g_io_channel_unix_new(STDIN_FILENO); +#endif + g_io_channel_set_flags(channel_stdin, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch(channel_stdin, G_IO_IN, do_command, NULL); +#ifdef _WIN32 + channel_socket = g_io_channel_win32_new_socket(sock); + /* g_io_channel_win32_set_debug(channel_socket, TRUE); */ +#else + channel_socket = g_io_channel_unix_new(sock); +#endif + g_io_channel_set_encoding(channel_socket, NULL, NULL); + g_io_add_watch(channel_socket, G_IO_IN, do_socket, NULL); - /* waiting on input from the socket */ - rv = select(sock+1, &fds, NULL, NULL, NULL); - if (rv < 0) { - /* handle error */ - perror("select"); - return 7; - } - if (FD_ISSET(1, &fds)) { - do_command(); - } - if (!FD_ISSET(sock, &fds)) { - continue; - } + g_main_loop_run(loop); + g_main_loop_unref(loop); - rv = read(sock, &mhHeader, sizeof(mhHeader)); - if (rv < sizeof(mhHeader)) { - /* Error */ - if (rv < 0) { - perror("header read error\n"); - } else { - fprintf(stderr, "header short read %d\n", rv); - } - return 8; - } - mhHeader.type = ntohl(mhHeader.type); - mhHeader.reader_id = ntohl(mhHeader.reader_id); - mhHeader.length = ntohl(mhHeader.length); - if (verbose) { - printf("Header: type=%d, reader_id=%u length=%d (0x%x)\n", - mhHeader.type, mhHeader.reader_id, mhHeader.length, - mhHeader.length); - } - switch (mhHeader.type) { - case VSC_APDU: - case VSC_Flush: - case VSC_Error: - case VSC_Init: - rv = read(sock, pbSendBuffer, mhHeader.length); - break; - default: - fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type); - return 0; - } - switch (mhHeader.type) { - case VSC_APDU: - if (rv < 0) { - /* Error */ - fprintf(stderr, "read error\n"); - close(sock); - return 8; - } - if (verbose) { - printf(" recv APDU: "); - print_byte_array(pbSendBuffer, mhHeader.length); - } - /* Transmit received APDU */ - dwSendLength = mhHeader.length; - dwRecvLength = sizeof(pbRecvBuffer); - reader = vreader_get_reader_by_id(mhHeader.reader_id); - reader_status = vreader_xfr_bytes(reader, - pbSendBuffer, dwSendLength, - pbRecvBuffer, &dwRecvLength); - if (reader_status == VREADER_OK) { - mhHeader.length = dwRecvLength; - if (verbose) { - printf(" send response: "); - print_byte_array(pbRecvBuffer, mhHeader.length); - } - send_msg(VSC_APDU, mhHeader.reader_id, - pbRecvBuffer, dwRecvLength); - } else { - rv = reader_status; /* warning: not meaningful */ - send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t)); - } - vreader_free(reader); - reader = NULL; /* we've freed it, don't use it by accident - again */ - break; - case VSC_Flush: - /* TODO: actually flush */ - send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0); - break; - case VSC_Error: - error_msg = (VSCMsgError *) pbSendBuffer; - if (error_msg->code == VSC_SUCCESS) { - qemu_mutex_lock(&pending_reader_lock); - if (pending_reader) { - vreader_set_id(pending_reader, mhHeader.reader_id); - vreader_free(pending_reader); - pending_reader = NULL; - qemu_cond_signal(&pending_reader_condition); - } - qemu_mutex_unlock(&pending_reader_lock); - break; - } - printf("warning: qemu refused to add reader\n"); - if (error_msg->code == VSC_CANNOT_ADD_MORE_READERS) { - /* clear pending reader, qemu can't handle any more */ - qemu_mutex_lock(&pending_reader_lock); - if (pending_reader) { - pending_reader = NULL; - /* make sure the event loop doesn't hang */ - qemu_cond_signal(&pending_reader_condition); - } - qemu_mutex_unlock(&pending_reader_lock); - } - break; - case VSC_Init: - if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) { - return -1; - } - break; - default: - printf("Default\n"); - return 0; - } - } while (rv >= 0); + g_io_channel_unref(channel_stdin); + g_io_channel_unref(channel_socket); return 0; }