From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:32787) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UHZqj-00041O-5W for qemu-devel@nongnu.org; Mon, 18 Mar 2013 09:11:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UHZqd-0000nW-9J for qemu-devel@nongnu.org; Mon, 18 Mar 2013 09:11:37 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39900) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UHZqc-0000n6-UA for qemu-devel@nongnu.org; Mon, 18 Mar 2013 09:11:31 -0400 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r2IDBUoS010633 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 18 Mar 2013 09:11:30 -0400 From: Alon Levy Date: Mon, 18 Mar 2013 15:10:57 +0200 Message-Id: <1363612272-13713-12-git-send-email-alevy@redhat.com> In-Reply-To: <1363612272-13713-1-git-send-email-alevy@redhat.com> References: <1363612272-13713-1-git-send-email-alevy@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH 11/26] libcacard: teach vscclient to use GMainLoop for portability List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: mlureau@redhat.com From: Marc-Andr=C3=A9 Lureau This version handles non-blocking sending and receiving from the socket. Signed-off-by: Marc-Andr=C3=A9 Lureau --- libcacard/vscclient.c | 391 +++++++++++++++++++++++++++++++-------------= ------ 1 file changed, 246 insertions(+), 145 deletions(-) diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c index 5f47634..ac23647 100644 --- a/libcacard/vscclient.c +++ b/libcacard/vscclient.c @@ -10,7 +10,10 @@ * See the COPYING.LIB file in the top-level directory. */ =20 +#ifndef _WIN32 #include +#endif +#include =20 #include "qemu-common.h" #include "qemu/thread.h" @@ -22,9 +25,7 @@ #include "vcard_emul.h" #include "vevent.h" =20 -int verbose; - -int sock; +static int verbose; =20 static void print_byte_array( @@ -51,7 +52,47 @@ print_usage(void) { vcard_emul_usage(); } =20 -static QemuMutex write_lock; +static GIOChannel *channel_socket; +static GByteArray *socket_to_send; +static QemuMutex socket_to_send_lock; +static guint socket_tag; + +static void +update_socket_watch(gboolean out); + +static gboolean +do_socket_send(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + gsize bw; + GError *err =3D NULL; + + g_return_val_if_fail(socket_to_send->len !=3D 0, FALSE); + g_return_val_if_fail(condition & G_IO_OUT, FALSE); + + g_io_channel_write_chars(channel_socket, + (gchar *)socket_to_send->data, socket_to_send->len, &bw, &err); + if (err !=3D NULL) { + g_error("Error while sending socket %s", err->message); + return FALSE; + } + g_byte_array_remove_range(socket_to_send, 0, bw); + + if (socket_to_send->len =3D=3D 0) { + update_socket_watch(FALSE); + return FALSE; + } + return TRUE; +} + +static gboolean +socket_prepare_sending(gpointer user_data) +{ + update_socket_watch(TRUE); + + return FALSE; +} =20 static int send_msg( @@ -60,10 +101,9 @@ send_msg( const void *msg, unsigned int length ) { - int rv; VSCMsgHeader mhHeader; =20 - qemu_mutex_lock(&write_lock); + qemu_mutex_lock(&socket_to_send_lock); =20 if (verbose > 10) { printf("sending type=3D%d id=3D%u, len =3D%u (0x%x)\n", @@ -73,23 +113,11 @@ send_msg( mhHeader.type =3D htonl(type); mhHeader.reader_id =3D 0; mhHeader.length =3D htonl(length); - rv =3D write(sock, &mhHeader, sizeof(mhHeader)); - if (rv < 0) { - /* Error */ - fprintf(stderr, "write header error\n"); - close(sock); - qemu_mutex_unlock(&write_lock); - return 16; - } - rv =3D write(sock, msg, length); - if (rv < 0) { - /* Error */ - fprintf(stderr, "write error\n"); - close(sock); - qemu_mutex_unlock(&write_lock); - return 16; - } - qemu_mutex_unlock(&write_lock); + g_byte_array_append(socket_to_send, (guint8 *)&mhHeader, sizeof(mhHe= ader)); + g_byte_array_append(socket_to_send, (guint8 *)msg, length); + g_idle_add(socket_prepare_sending, NULL); + + qemu_mutex_unlock(&socket_to_send_lock); =20 return 0; } @@ -245,139 +273,203 @@ on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *= incoming) return 0; } =20 + +enum { + STATE_HEADER, + STATE_MESSAGE, +}; + #define APDUBufSize 270 =20 -static int -do_socket_read(void) +static gboolean +do_socket_read(GIOChannel *source, + GIOCondition condition, + gpointer data) { int rv; int dwSendLength; int dwRecvLength; uint8_t pbRecvBuffer[APDUBufSize]; - uint8_t pbSendBuffer[APDUBufSize]; + static uint8_t pbSendBuffer[APDUBufSize]; VReaderStatus reader_status; VReader *reader =3D NULL; - VSCMsgHeader mhHeader; + static VSCMsgHeader mhHeader; VSCMsgError *error_msg; + GError *err =3D NULL; =20 - rv =3D 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 -1; - } - mhHeader.type =3D ntohl(mhHeader.type); - mhHeader.reader_id =3D ntohl(mhHeader.reader_id); - mhHeader.length =3D ntohl(mhHeader.length); - if (verbose) { - printf("Header: type=3D%d, reader_id=3D%u length=3D%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 =3D read(sock, pbSendBuffer, mhHeader.length); - break; - default: - fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.ty= pe); - return -1; + static gchar *buf; + static gsize br, to_read; + static int state =3D STATE_HEADER; + + if (state =3D=3D STATE_HEADER && to_read =3D=3D 0) { + buf =3D (gchar *)&mhHeader; + to_read =3D sizeof(mhHeader); } - switch (mhHeader.type) { - case VSC_APDU: - if (rv < 0) { - /* Error */ - fprintf(stderr, "read error\n"); - close(sock); - return -1; + + if (to_read > 0) { + g_io_channel_read_chars(source, (gchar *)buf, to_read, &br, &err= ); + if (err !=3D NULL) { + g_error("error while reading: %s", err->message); } + buf +=3D br; + to_read -=3D br; + if (to_read !=3D 0) { + return TRUE; + } + } + + if (state =3D=3D STATE_HEADER) { + mhHeader.type =3D ntohl(mhHeader.type); + mhHeader.reader_id =3D ntohl(mhHeader.reader_id); + mhHeader.length =3D ntohl(mhHeader.length); if (verbose) { - printf(" recv APDU: "); - print_byte_array(pbSendBuffer, mhHeader.length); + printf("Header: type=3D%d, reader_id=3D%u length=3D%d (0x%x)= \n", + mhHeader.type, mhHeader.reader_id, mhHeader.length, + mhHeader.length); } - /* Transmit received APDU */ - dwSendLength =3D mhHeader.length; - dwRecvLength =3D sizeof(pbRecvBuffer); - reader =3D vreader_get_reader_by_id(mhHeader.reader_id); - reader_status =3D vreader_xfr_bytes(reader, - pbSendBuffer, dwSendLength, - pbRecvBuffer, &dwRecvLength); - if (reader_status =3D=3D VREADER_OK) { - mhHeader.length =3D dwRecvLength; + switch (mhHeader.type) { + case VSC_APDU: + case VSC_Flush: + case VSC_Error: + case VSC_Init: + buf =3D (gchar *)pbSendBuffer; + to_read =3D mhHeader.length; + state =3D STATE_MESSAGE; + return TRUE; + default: + fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeade= r.type); + return FALSE; + } + } + + if (state =3D=3D STATE_MESSAGE) { + switch (mhHeader.type) { + case VSC_APDU: if (verbose) { - printf(" send response: "); - print_byte_array(pbRecvBuffer, mhHeader.length); + printf(" recv APDU: "); + print_byte_array(pbSendBuffer, mhHeader.length); } - send_msg(VSC_APDU, mhHeader.reader_id, - pbRecvBuffer, dwRecvLength); - } else { - rv =3D reader_status; /* warning: not meaningful */ - send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t= )); - } - vreader_free(reader); - reader =3D 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 =3D (VSCMsgError *) pbSendBuffer; - if (error_msg->code =3D=3D 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 =3D NULL; - qemu_cond_signal(&pending_reader_condition); + /* Transmit received APDU */ + dwSendLength =3D mhHeader.length; + dwRecvLength =3D sizeof(pbRecvBuffer); + reader =3D vreader_get_reader_by_id(mhHeader.reader_id); + reader_status =3D vreader_xfr_bytes(reader, + pbSendBuffer, dwSendLength= , + pbRecvBuffer, &dwRecvLengt= h); + if (reader_status =3D=3D VREADER_OK) { + mhHeader.length =3D dwRecvLength; + if (verbose) { + printf(" send response: "); + print_byte_array(pbRecvBuffer, mhHeader.length); + } + send_msg(VSC_APDU, mhHeader.reader_id, + pbRecvBuffer, dwRecvLength); + } else { + rv =3D reader_status; /* warning: not meaningful */ + send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint= 32_t)); } - qemu_mutex_unlock(&pending_reader_lock); + vreader_free(reader); + reader =3D NULL; /* we've freed it, don't use it by accident + again */ break; - } - printf("warning: qemu refused to add reader\n"); - if (error_msg->code =3D=3D 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 =3D NULL; - /* make sure the event loop doesn't hang */ - qemu_cond_signal(&pending_reader_condition); + case VSC_Flush: + /* TODO: actually flush */ + send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0); + break; + case VSC_Error: + error_msg =3D (VSCMsgError *) pbSendBuffer; + if (error_msg->code =3D=3D 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 =3D NULL; + qemu_cond_signal(&pending_reader_condition); + } + qemu_mutex_unlock(&pending_reader_lock); + break; } - qemu_mutex_unlock(&pending_reader_lock); + printf("warning: qemu refused to add reader\n"); + if (error_msg->code =3D=3D 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 =3D 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 FALSE; + } + break; + default: + g_warn_if_reached(); + return FALSE; } - break; - case VSC_Init: - if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) { - return -1; + + state =3D STATE_HEADER; + } + + + return TRUE; +} + +static gboolean +do_socket(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + /* not sure if two watches work well with a single win32 sources */ + if (condition & G_IO_OUT) { + if (!do_socket_send(source, condition, data)) { + return FALSE; } - break; - default: - printf("Default\n"); - return -1; } =20 - return 0; + if (condition & G_IO_IN) { + if (!do_socket_read(source, condition, data)) { + return FALSE; + } + } + + return TRUE; } =20 static void -do_command(void) +update_socket_watch(gboolean out) +{ + if (socket_tag !=3D 0) { + g_source_remove(socket_tag); + } + + socket_tag =3D g_io_add_watch(channel_socket, + G_IO_IN | (out ? G_IO_OUT : 0), do_socket, NULL); +} + +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 =3D NULL; + GError *err =3D NULL; + + g_assert(condition & G_IO_IN); =20 reader_id =3D default_reader_id; - string =3D fgets(inbuf, sizeof(inbuf), stdin); + g_io_channel_read_line(source, &string, NULL, NULL, &err); + if (err !=3D NULL) { + g_error("Error while reading command: %s", err->message); + } + if (string !=3D NULL) { if (strncmp(string, "exit", 4) =3D=3D 0) { /* remove all the readers */ @@ -491,6 +583,8 @@ do_command(void) vreader_free(reader); printf("> "); fflush(stdout); + + return TRUE; } =20 =20 @@ -504,7 +598,7 @@ connect_to_qemu( ) { struct addrinfo hints; struct addrinfo *server; - int ret; + int ret, sock; =20 sock =3D qemu_socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { @@ -543,6 +637,8 @@ main( int argc, char *argv[] ) { + GMainLoop *loop; + GIOChannel *channel_stdin; char *qemu_host; char *qemu_port; VSCMsgHeader mhHeader; @@ -552,7 +648,10 @@ main( char *cert_names[MAX_CERTS]; char *emul_args =3D NULL; int cert_count =3D 0; - int c, rv; + int c, sock; + + if (socket_init() !=3D 0) + return 1; =20 while ((c =3D getopt(argc, argv, "c:e:pd:")) !=3D -1) { switch (c) { @@ -618,15 +717,33 @@ main( exit(5); } =20 - qemu_mutex_init(&write_lock); + socket_to_send =3D g_byte_array_new(); + qemu_mutex_init(&socket_to_send_lock); qemu_mutex_init(&pending_reader_lock); qemu_cond_init(&pending_reader_condition); =20 vcard_emul_init(command_line_options); =20 + loop =3D g_main_loop_new(NULL, true); + printf("> "); fflush(stdout); =20 +#ifdef _WIN32 + channel_stdin =3D g_io_channel_win32_new_fd(STDIN_FILENO); +#else + channel_stdin =3D g_io_channel_unix_new(STDIN_FILENO); +#endif + g_io_add_watch(channel_stdin, G_IO_IN, do_command, NULL); +#ifdef _WIN32 + channel_socket =3D g_io_channel_win32_new_socket(sock); +#else + channel_socket =3D g_io_channel_unix_new(sock); +#endif + g_io_channel_set_encoding(channel_socket, NULL, NULL); + /* we buffer ourself for thread safety reasons */ + g_io_channel_set_buffered(channel_socket, FALSE); + /* Send init message, Host responds (and then we send reader attachm= ents) */ VSCMsgInit init =3D { .version =3D htonl(VSCARD_VERSION), @@ -635,28 +752,12 @@ main( }; send_msg(VSC_Init, mhHeader.reader_id, &init, sizeof(init)); =20 - do { - fd_set fds; - - FD_ZERO(&fds); - FD_SET(1, &fds); - FD_SET(sock, &fds); + g_main_loop_run(loop); + g_main_loop_unref(loop); =20 - /* waiting on input from the socket */ - rv =3D 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; - } - rv =3D do_socket_read(); - } while (rv >=3D 0); + g_io_channel_unref(channel_stdin); + g_io_channel_unref(channel_socket); + g_byte_array_unref(socket_to_send); =20 return 0; } --=20 1.8.1.4