libcacard: split vscclient main() from socket reading

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Alon Levy <alevy@redhat.com>
This commit is contained in:
Marc-André Lureau 2013-02-25 23:31:14 +01:00 committed by Alon Levy
parent 5354e4d242
commit a50b831ae1

View File

@ -211,6 +211,166 @@ get_id_from_string(char *string, unsigned int default_id)
return id; return id;
} }
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;
}
#define APDUBufSize 270
static int
do_socket_read(void)
{
int rv;
int dwSendLength;
int dwRecvLength;
uint8_t pbRecvBuffer[APDUBufSize];
uint8_t pbSendBuffer[APDUBufSize];
VReaderStatus reader_status;
VReader *reader = NULL;
VSCMsgHeader mhHeader;
VSCMsgError *error_msg;
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 -1;
}
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 -1;
}
switch (mhHeader.type) {
case VSC_APDU:
if (rv < 0) {
/* Error */
fprintf(stderr, "read error\n");
close(sock);
return -1;
}
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 -1;
}
return 0;
}
static void static void
do_command(void) do_command(void)
{ {
@ -339,8 +499,6 @@ do_command(void)
} }
#define APDUBufSize 270
/* just for ease of parsing command line arguments. */ /* just for ease of parsing command line arguments. */
#define MAX_CERTS 100 #define MAX_CERTS 100
@ -385,44 +543,6 @@ connect_to_qemu(
return sock; 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 int
main( main(
int argc, int argc,
@ -431,21 +551,13 @@ main(
char *qemu_host; char *qemu_host;
char *qemu_port; char *qemu_port;
VSCMsgHeader mhHeader; 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; VCardEmulOptions *command_line_options = NULL;
char *cert_names[MAX_CERTS]; char *cert_names[MAX_CERTS];
char *emul_args = NULL; char *emul_args = NULL;
int cert_count = 0; int cert_count = 0;
int c; int c, rv;
while ((c = getopt(argc, argv, "c:e:pd:")) != -1) { while ((c = getopt(argc, argv, "c:e:pd:")) != -1) {
switch (c) { switch (c) {
@ -548,109 +660,7 @@ main(
if (!FD_ISSET(sock, &fds)) { if (!FD_ISSET(sock, &fds)) {
continue; continue;
} }
rv = do_socket_read();
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); } while (rv >= 0);
return 0; return 0;