]> Git Repo - qemu.git/blob - libcacard/vscclient.c
target-arm: Correct condition for taking VIRQ and VFIQ
[qemu.git] / libcacard / vscclient.c
1 /*
2  * Tester for VSCARD protocol, client side.
3  *
4  * Can be used with ccid-card-passthru.
5  *
6  * Copyright (c) 2011 Red Hat.
7  * Written by Alon Levy.
8  *
9  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10  * See the COPYING.LIB file in the top-level directory.
11  */
12
13 #ifndef _WIN32
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <netdb.h>
17 #define closesocket(x) close(x)
18 #endif
19
20 #include "qemu-common.h"
21
22 #include "vscard_common.h"
23
24 #include "vreader.h"
25 #include "vcard_emul.h"
26 #include "vevent.h"
27
28 static int verbose;
29
30 static void
31 print_byte_array(
32     uint8_t *arrBytes,
33     unsigned int nSize
34 ) {
35     int i;
36     for (i = 0; i < nSize; i++) {
37         printf("%02X ", arrBytes[i]);
38     }
39     printf("\n");
40 }
41
42 static void
43 print_usage(void) {
44     printf("vscclient [-c <certname> .. -e <emul_args> -d <level>%s] "
45             "<host> <port>\n",
46 #ifdef USE_PASSTHRU
47     " -p");
48     printf(" -p use passthrough mode\n");
49 #else
50    "");
51 #endif
52     vcard_emul_usage();
53 }
54
55 static GIOChannel *channel_socket;
56 static GByteArray *socket_to_send;
57 static CompatGMutex socket_to_send_lock;
58 static guint socket_tag;
59
60 static void
61 update_socket_watch(void);
62
63 static gboolean
64 do_socket_send(GIOChannel *source,
65                GIOCondition condition,
66                gpointer data)
67 {
68     gsize bw;
69     GError *err = NULL;
70
71     g_return_val_if_fail(socket_to_send->len != 0, FALSE);
72     g_return_val_if_fail(condition & G_IO_OUT, FALSE);
73
74     g_io_channel_write_chars(channel_socket,
75         (gchar *)socket_to_send->data, socket_to_send->len, &bw, &err);
76     if (err != NULL) {
77         g_error("Error while sending socket %s", err->message);
78         return FALSE;
79     }
80     g_byte_array_remove_range(socket_to_send, 0, bw);
81
82     if (socket_to_send->len == 0) {
83         update_socket_watch();
84         return FALSE;
85     }
86     return TRUE;
87 }
88
89 static gboolean
90 socket_prepare_sending(gpointer user_data)
91 {
92     update_socket_watch();
93
94     return FALSE;
95 }
96
97 static int
98 send_msg(
99     VSCMsgType type,
100     uint32_t reader_id,
101     const void *msg,
102     unsigned int length
103 ) {
104     VSCMsgHeader mhHeader;
105
106     g_mutex_lock(&socket_to_send_lock);
107
108     if (verbose > 10) {
109         printf("sending type=%d id=%u, len =%u (0x%x)\n",
110                type, reader_id, length, length);
111     }
112
113     mhHeader.type = htonl(type);
114     mhHeader.reader_id = 0;
115     mhHeader.length = htonl(length);
116     g_byte_array_append(socket_to_send, (guint8 *)&mhHeader, sizeof(mhHeader));
117     g_byte_array_append(socket_to_send, (guint8 *)msg, length);
118     g_idle_add(socket_prepare_sending, NULL);
119
120     g_mutex_unlock(&socket_to_send_lock);
121
122     return 0;
123 }
124
125 static VReader *pending_reader;
126 static CompatGMutex pending_reader_lock;
127 static CompatGCond pending_reader_condition;
128
129 #define MAX_ATR_LEN 40
130 static gpointer
131 event_thread(gpointer arg)
132 {
133     unsigned char atr[MAX_ATR_LEN];
134     int atr_len;
135     VEvent *event;
136     unsigned int reader_id;
137
138
139     while (1) {
140         const char *reader_name;
141
142         event = vevent_wait_next_vevent();
143         if (event == NULL) {
144             break;
145         }
146         reader_id = vreader_get_id(event->reader);
147         if (reader_id == VSCARD_UNDEFINED_READER_ID &&
148             event->type != VEVENT_READER_INSERT) {
149             /* ignore events from readers qemu has rejected */
150             /* if qemu is still deciding on this reader, wait to see if need to
151              * forward this event */
152             g_mutex_lock(&pending_reader_lock);
153             if (!pending_reader || (pending_reader != event->reader)) {
154                 /* wasn't for a pending reader, this reader has already been
155                  * rejected by qemu */
156                 g_mutex_unlock(&pending_reader_lock);
157                 vevent_delete(event);
158                 continue;
159             }
160             /* this reader hasn't been told its status from qemu yet, wait for
161              * that status */
162             while (pending_reader != NULL) {
163                 g_cond_wait(&pending_reader_condition, &pending_reader_lock);
164             }
165             g_mutex_unlock(&pending_reader_lock);
166             /* now recheck the id */
167             reader_id = vreader_get_id(event->reader);
168             if (reader_id == VSCARD_UNDEFINED_READER_ID) {
169                 /* this reader was rejected */
170                 vevent_delete(event);
171                 continue;
172             }
173             /* reader was accepted, now forward the event */
174         }
175         switch (event->type) {
176         case VEVENT_READER_INSERT:
177             /* tell qemu to insert a new CCID reader */
178             /* wait until qemu has responded to our first reader insert
179              * before we send a second. That way we won't confuse the responses
180              * */
181             g_mutex_lock(&pending_reader_lock);
182             while (pending_reader != NULL) {
183                 g_cond_wait(&pending_reader_condition, &pending_reader_lock);
184             }
185             pending_reader = vreader_reference(event->reader);
186             g_mutex_unlock(&pending_reader_lock);
187             reader_name = vreader_get_name(event->reader);
188             if (verbose > 10) {
189                 printf(" READER INSERT: %s\n", reader_name);
190             }
191             send_msg(VSC_ReaderAdd,
192                 reader_id, /* currerntly VSCARD_UNDEFINED_READER_ID */
193                 NULL, 0 /* TODO reader_name, strlen(reader_name) */);
194             break;
195         case VEVENT_READER_REMOVE:
196             /* future, tell qemu that an old CCID reader has been removed */
197             if (verbose > 10) {
198                 printf(" READER REMOVE: %u\n", reader_id);
199             }
200             send_msg(VSC_ReaderRemove, reader_id, NULL, 0);
201             break;
202         case VEVENT_CARD_INSERT:
203             /* get the ATR (intended as a response to a power on from the
204              * reader */
205             atr_len = MAX_ATR_LEN;
206             vreader_power_on(event->reader, atr, &atr_len);
207             /* ATR call functions as a Card Insert event */
208             if (verbose > 10) {
209                 printf(" CARD INSERT %u: ", reader_id);
210                 print_byte_array(atr, atr_len);
211             }
212             send_msg(VSC_ATR, reader_id, atr, atr_len);
213             break;
214         case VEVENT_CARD_REMOVE:
215             /* Card removed */
216             if (verbose > 10) {
217                 printf(" CARD REMOVE %u:\n", reader_id);
218             }
219             send_msg(VSC_CardRemove, reader_id, NULL, 0);
220             break;
221         default:
222             break;
223         }
224         vevent_delete(event);
225     }
226     return NULL;
227 }
228
229
230 static unsigned int
231 get_id_from_string(char *string, unsigned int default_id)
232 {
233     unsigned int id = atoi(string);
234
235     /* don't accidentally swith to zero because no numbers have been supplied */
236     if ((id == 0) && *string != '0') {
237         return default_id;
238     }
239     return id;
240 }
241
242 static int
243 on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming)
244 {
245     uint32_t *capabilities = (incoming->capabilities);
246     int num_capabilities =
247         1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
248     int i;
249
250     incoming->version = ntohl(incoming->version);
251     if (incoming->version != VSCARD_VERSION) {
252         if (verbose > 0) {
253             printf("warning: host has version %d, we have %d\n",
254                 verbose, VSCARD_VERSION);
255         }
256     }
257     if (incoming->magic != VSCARD_MAGIC) {
258         printf("unexpected magic: got %d, expected %d\n",
259             incoming->magic, VSCARD_MAGIC);
260         return -1;
261     }
262     for (i = 0 ; i < num_capabilities; ++i) {
263         capabilities[i] = ntohl(capabilities[i]);
264     }
265     /* Future: check capabilities */
266     /* remove whatever reader might be left in qemu,
267      * in case of an unclean previous exit. */
268     send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0);
269     /* launch the event_thread. This will trigger reader adds for all the
270      * existing readers */
271     g_thread_new("vsc/event", event_thread, NULL);
272     return 0;
273 }
274
275
276 enum {
277     STATE_HEADER,
278     STATE_MESSAGE,
279 };
280
281 #define APDUBufSize 270
282
283 static gboolean
284 do_socket_read(GIOChannel *source,
285                GIOCondition condition,
286                gpointer data)
287 {
288     int rv;
289     int dwSendLength;
290     int dwRecvLength;
291     uint8_t pbRecvBuffer[APDUBufSize];
292     static uint8_t pbSendBuffer[APDUBufSize];
293     VReaderStatus reader_status;
294     VReader *reader = NULL;
295     static VSCMsgHeader mhHeader;
296     VSCMsgError *error_msg;
297     GError *err = NULL;
298
299     static gchar *buf;
300     static gsize br, to_read;
301     static int state = STATE_HEADER;
302
303     if (state == STATE_HEADER && to_read == 0) {
304         buf = (gchar *)&mhHeader;
305         to_read = sizeof(mhHeader);
306     }
307
308     if (to_read > 0) {
309         g_io_channel_read_chars(source, (gchar *)buf, to_read, &br, &err);
310         if (err != NULL) {
311             g_error("error while reading: %s", err->message);
312         }
313         buf += br;
314         to_read -= br;
315         if (to_read != 0) {
316             return TRUE;
317         }
318     }
319
320     if (state == STATE_HEADER) {
321         mhHeader.type = ntohl(mhHeader.type);
322         mhHeader.reader_id = ntohl(mhHeader.reader_id);
323         mhHeader.length = ntohl(mhHeader.length);
324         if (verbose) {
325             printf("Header: type=%d, reader_id=%u length=%d (0x%x)\n",
326                    mhHeader.type, mhHeader.reader_id, mhHeader.length,
327                    mhHeader.length);
328         }
329         switch (mhHeader.type) {
330         case VSC_APDU:
331         case VSC_Flush:
332         case VSC_Error:
333         case VSC_Init:
334             buf = (gchar *)pbSendBuffer;
335             to_read = mhHeader.length;
336             state = STATE_MESSAGE;
337             return TRUE;
338         default:
339             fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type);
340             return FALSE;
341         }
342     }
343
344     if (state == STATE_MESSAGE) {
345         switch (mhHeader.type) {
346         case VSC_APDU:
347             if (verbose) {
348                 printf(" recv APDU: ");
349                 print_byte_array(pbSendBuffer, mhHeader.length);
350             }
351             /* Transmit received APDU */
352             dwSendLength = mhHeader.length;
353             dwRecvLength = sizeof(pbRecvBuffer);
354             reader = vreader_get_reader_by_id(mhHeader.reader_id);
355             reader_status = vreader_xfr_bytes(reader,
356                                               pbSendBuffer, dwSendLength,
357                                               pbRecvBuffer, &dwRecvLength);
358             if (reader_status == VREADER_OK) {
359                 mhHeader.length = dwRecvLength;
360                 if (verbose) {
361                     printf(" send response: ");
362                     print_byte_array(pbRecvBuffer, mhHeader.length);
363                 }
364                 send_msg(VSC_APDU, mhHeader.reader_id,
365                          pbRecvBuffer, dwRecvLength);
366             } else {
367                 rv = reader_status; /* warning: not meaningful */
368                 send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t));
369             }
370             vreader_free(reader);
371             reader = NULL; /* we've freed it, don't use it by accident
372                               again */
373             break;
374         case VSC_Flush:
375             /* TODO: actually flush */
376             send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0);
377             break;
378         case VSC_Error:
379             error_msg = (VSCMsgError *) pbSendBuffer;
380             if (error_msg->code == VSC_SUCCESS) {
381                 g_mutex_lock(&pending_reader_lock);
382                 if (pending_reader) {
383                     vreader_set_id(pending_reader, mhHeader.reader_id);
384                     vreader_free(pending_reader);
385                     pending_reader = NULL;
386                     g_cond_signal(&pending_reader_condition);
387                 }
388                 g_mutex_unlock(&pending_reader_lock);
389                 break;
390             }
391             printf("warning: qemu refused to add reader\n");
392             if (error_msg->code == VSC_CANNOT_ADD_MORE_READERS) {
393                 /* clear pending reader, qemu can't handle any more */
394                 g_mutex_lock(&pending_reader_lock);
395                 if (pending_reader) {
396                     pending_reader = NULL;
397                     /* make sure the event loop doesn't hang */
398                     g_cond_signal(&pending_reader_condition);
399                 }
400                 g_mutex_unlock(&pending_reader_lock);
401             }
402             break;
403         case VSC_Init:
404             if (on_host_init(&mhHeader, (VSCMsgInit *)pbSendBuffer) < 0) {
405                 return FALSE;
406             }
407             break;
408         default:
409             g_assert_not_reached();
410             return FALSE;
411         }
412
413         state = STATE_HEADER;
414     }
415
416
417     return TRUE;
418 }
419
420 static gboolean
421 do_socket(GIOChannel *source,
422           GIOCondition condition,
423           gpointer data)
424 {
425     /* not sure if two watches work well with a single win32 sources */
426     if (condition & G_IO_OUT) {
427         if (!do_socket_send(source, condition, data)) {
428             return FALSE;
429         }
430     }
431
432     if (condition & G_IO_IN) {
433         if (!do_socket_read(source, condition, data)) {
434             return FALSE;
435         }
436     }
437
438     return TRUE;
439 }
440
441 static void
442 update_socket_watch(void)
443 {
444     gboolean out = socket_to_send->len > 0;
445
446     if (socket_tag != 0) {
447         g_source_remove(socket_tag);
448     }
449
450     socket_tag = g_io_add_watch(channel_socket,
451         G_IO_IN | (out ? G_IO_OUT : 0), do_socket, NULL);
452 }
453
454 static gboolean
455 do_command(GIOChannel *source,
456            GIOCondition condition,
457            gpointer data)
458 {
459     char *string;
460     VCardEmulError error;
461     static unsigned int default_reader_id;
462     unsigned int reader_id;
463     VReader *reader = NULL;
464     GError *err = NULL;
465
466     g_assert(condition & G_IO_IN);
467
468     reader_id = default_reader_id;
469     g_io_channel_read_line(source, &string, NULL, NULL, &err);
470     if (err != NULL) {
471         g_error("Error while reading command: %s", err->message);
472     }
473
474     if (string != NULL) {
475         if (strncmp(string, "exit", 4) == 0) {
476             /* remove all the readers */
477             VReaderList *list = vreader_get_reader_list();
478             VReaderListEntry *reader_entry;
479             printf("Active Readers:\n");
480             for (reader_entry = vreader_list_get_first(list); reader_entry;
481                  reader_entry = vreader_list_get_next(reader_entry)) {
482                 VReader *reader = vreader_list_get_reader(reader_entry);
483                 vreader_id_t reader_id;
484                 reader_id = vreader_get_id(reader);
485                 if (reader_id == -1) {
486                     continue;
487                 }
488                 /* be nice and signal card removal first (qemu probably should
489                  * do this itself) */
490                 if (vreader_card_is_present(reader) == VREADER_OK) {
491                     send_msg(VSC_CardRemove, reader_id, NULL, 0);
492                 }
493                 send_msg(VSC_ReaderRemove, reader_id, NULL, 0);
494             }
495             exit(0);
496         } else if (strncmp(string, "insert", 6) == 0) {
497             if (string[6] == ' ') {
498                 reader_id = get_id_from_string(&string[7], reader_id);
499             }
500             reader = vreader_get_reader_by_id(reader_id);
501             if (reader != NULL) {
502                 error = vcard_emul_force_card_insert(reader);
503                 printf("insert %s, returned %d\n",
504                        vreader_get_name(reader), error);
505             } else {
506                 printf("no reader by id %u found\n", reader_id);
507             }
508         } else if (strncmp(string, "remove", 6) == 0) {
509             if (string[6] == ' ') {
510                 reader_id = get_id_from_string(&string[7], reader_id);
511             }
512             reader = vreader_get_reader_by_id(reader_id);
513             if (reader != NULL) {
514                 error = vcard_emul_force_card_remove(reader);
515                 printf("remove %s, returned %d\n",
516                        vreader_get_name(reader), error);
517             } else {
518                 printf("no reader by id %u found\n", reader_id);
519             }
520         } else if (strncmp(string, "select", 6) == 0) {
521             if (string[6] == ' ') {
522                 reader_id = get_id_from_string(&string[7],
523                                                VSCARD_UNDEFINED_READER_ID);
524             }
525             if (reader_id != VSCARD_UNDEFINED_READER_ID) {
526                 reader = vreader_get_reader_by_id(reader_id);
527             }
528             if (reader) {
529                 printf("Selecting reader %u, %s\n", reader_id,
530                         vreader_get_name(reader));
531                 default_reader_id = reader_id;
532             } else {
533                 printf("Reader with id %u not found\n", reader_id);
534             }
535         } else if (strncmp(string, "debug", 5) == 0) {
536             if (string[5] == ' ') {
537                 verbose = get_id_from_string(&string[6], 0);
538             }
539             printf("debug level = %d\n", verbose);
540         } else if (strncmp(string, "list", 4) == 0) {
541             VReaderList *list = vreader_get_reader_list();
542             VReaderListEntry *reader_entry;
543             printf("Active Readers:\n");
544             for (reader_entry = vreader_list_get_first(list); reader_entry;
545                  reader_entry = vreader_list_get_next(reader_entry)) {
546                 VReader *reader = vreader_list_get_reader(reader_entry);
547                 vreader_id_t reader_id;
548                 reader_id = vreader_get_id(reader);
549                 if (reader_id == -1) {
550                     continue;
551                 }
552                 printf("%3u %s %s\n", reader_id,
553                        vreader_card_is_present(reader) == VREADER_OK ?
554                        "CARD_PRESENT" : "            ",
555                        vreader_get_name(reader));
556             }
557             printf("Inactive Readers:\n");
558             for (reader_entry = vreader_list_get_first(list); reader_entry;
559                  reader_entry = vreader_list_get_next(reader_entry)) {
560                 VReader *reader = vreader_list_get_reader(reader_entry);
561                 vreader_id_t reader_id;
562                 reader_id = vreader_get_id(reader);
563                 if (reader_id != -1) {
564                     continue;
565                 }
566
567                 printf("INA %s %s\n",
568                        vreader_card_is_present(reader) == VREADER_OK ?
569                        "CARD_PRESENT" : "            ",
570                        vreader_get_name(reader));
571             }
572             vreader_list_delete(list);
573         } else if (*string != 0) {
574             printf("valid commands:\n");
575             printf("insert [reader_id]\n");
576             printf("remove [reader_id]\n");
577             printf("select reader_id\n");
578             printf("list\n");
579             printf("debug [level]\n");
580             printf("exit\n");
581         }
582     }
583     vreader_free(reader);
584     printf("> ");
585     fflush(stdout);
586
587     return TRUE;
588 }
589
590
591 /* just for ease of parsing command line arguments. */
592 #define MAX_CERTS 100
593
594 static int
595 connect_to_qemu(
596     const char *host,
597     const char *port
598 ) {
599     struct addrinfo hints;
600     struct addrinfo *server;
601     int ret, sock;
602
603     sock = socket(AF_INET, SOCK_STREAM, 0);
604     if (sock < 0) {
605         /* Error */
606         fprintf(stderr, "Error opening socket!\n");
607         return -1;
608     }
609
610     memset(&hints, 0, sizeof(struct addrinfo));
611     hints.ai_family = AF_UNSPEC;
612     hints.ai_socktype = SOCK_STREAM;
613     hints.ai_flags = 0;
614     hints.ai_protocol = 0;          /* Any protocol */
615
616     ret = getaddrinfo(host, port, &hints, &server);
617
618     if (ret != 0) {
619         /* Error */
620         fprintf(stderr, "getaddrinfo failed\n");
621         goto cleanup_socket;
622     }
623
624     if (connect(sock, server->ai_addr, server->ai_addrlen) < 0) {
625         /* Error */
626         fprintf(stderr, "Could not connect\n");
627         goto cleanup_socket;
628     }
629     if (verbose) {
630         printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader));
631     }
632     return sock;
633
634 cleanup_socket:
635     closesocket(sock);
636     return -1;
637 }
638
639 int
640 main(
641     int argc,
642     char *argv[]
643 ) {
644     GMainLoop *loop;
645     GIOChannel *channel_stdin;
646     char *qemu_host;
647     char *qemu_port;
648
649     VCardEmulOptions *command_line_options = NULL;
650
651     char *cert_names[MAX_CERTS];
652     char *emul_args = NULL;
653     int cert_count = 0;
654     int c, sock;
655
656 #ifdef _WIN32
657     WSADATA Data;
658
659     if (WSAStartup(MAKEWORD(2, 2), &Data) != 0) {
660         c = WSAGetLastError();
661         fprintf(stderr, "WSAStartup: %d\n", c);
662         return 1;
663     }
664 #endif
665 #if !GLIB_CHECK_VERSION(2, 31, 0)
666     if (!g_thread_supported()) {
667          g_thread_init(NULL);
668     }
669 #endif
670
671     while ((c = getopt(argc, argv, "c:e:pd:")) != -1) {
672         switch (c) {
673         case 'c':
674             if (cert_count >= MAX_CERTS) {
675                 printf("too many certificates (max = %d)\n", MAX_CERTS);
676                 exit(5);
677             }
678             cert_names[cert_count++] = optarg;
679             break;
680         case 'e':
681             emul_args = optarg;
682             break;
683         case 'p':
684             print_usage();
685             exit(4);
686             break;
687         case 'd':
688             verbose = get_id_from_string(optarg, 1);
689             break;
690         }
691     }
692
693     if (argc - optind != 2) {
694         print_usage();
695         exit(4);
696     }
697
698     if (cert_count > 0) {
699         char *new_args;
700         int len, i;
701         /* if we've given some -c options, we clearly we want do so some
702          * software emulation.  add that emulation now. this is NSS Emulator
703          * specific */
704         if (emul_args == NULL) {
705             emul_args = (char *)"db=\"/etc/pki/nssdb\"";
706         }
707 #define SOFT_STRING ",soft=(,Virtual Reader,CAC,,"
708              /* 2 == close paren & null */
709         len = strlen(emul_args) + strlen(SOFT_STRING) + 2;
710         for (i = 0; i < cert_count; i++) {
711             len += strlen(cert_names[i])+1; /* 1 == comma */
712         }
713         new_args = g_malloc(len);
714         strcpy(new_args, emul_args);
715         strcat(new_args, SOFT_STRING);
716         for (i = 0; i < cert_count; i++) {
717             strcat(new_args, cert_names[i]);
718             strcat(new_args, ",");
719         }
720         strcat(new_args, ")");
721         emul_args = new_args;
722     }
723     if (emul_args) {
724         command_line_options = vcard_emul_options(emul_args);
725     }
726
727     qemu_host = g_strdup(argv[argc - 2]);
728     qemu_port = g_strdup(argv[argc - 1]);
729     sock = connect_to_qemu(qemu_host, qemu_port);
730     if (sock == -1) {
731         fprintf(stderr, "error opening socket, exiting.\n");
732         exit(5);
733     }
734
735     socket_to_send = g_byte_array_new();
736     vcard_emul_init(command_line_options);
737     loop = g_main_loop_new(NULL, TRUE);
738
739     printf("> ");
740     fflush(stdout);
741
742 #ifdef _WIN32
743     channel_stdin = g_io_channel_win32_new_fd(STDIN_FILENO);
744 #else
745     channel_stdin = g_io_channel_unix_new(STDIN_FILENO);
746 #endif
747     g_io_add_watch(channel_stdin, G_IO_IN, do_command, NULL);
748 #ifdef _WIN32
749     channel_socket = g_io_channel_win32_new_socket(sock);
750 #else
751     channel_socket = g_io_channel_unix_new(sock);
752 #endif
753     g_io_channel_set_encoding(channel_socket, NULL, NULL);
754     /* we buffer ourself for thread safety reasons */
755     g_io_channel_set_buffered(channel_socket, FALSE);
756
757     /* Send init message, Host responds (and then we send reader attachments) */
758     VSCMsgInit init = {
759         .version = htonl(VSCARD_VERSION),
760         .magic = VSCARD_MAGIC,
761         .capabilities = {0}
762     };
763     send_msg(VSC_Init, 0, &init, sizeof(init));
764
765     g_main_loop_run(loop);
766     g_main_loop_unref(loop);
767
768     g_io_channel_unref(channel_stdin);
769     g_io_channel_unref(channel_socket);
770     g_byte_array_free(socket_to_send, TRUE);
771
772     closesocket(sock);
773     return 0;
774 }
This page took 0.06515 seconds and 4 git commands to generate.