blob: 79040f7b307bf9589607f0daa8668b9d9939c373 [file] [log] [blame]
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10** GNU General Public License for more details.
11*/
12#include "android/hw-qemud.h"
13#include "android/utils/debug.h"
14#include "android/utils/misc.h"
15#include "android/utils/system.h"
16#include "android/utils/bufprint.h"
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -070017#include "android/looper.h"
Ot ten Thije871da2a2010-09-20 10:29:22 +010018#include "hw/hw.h"
David 'Digit' Turnerf5bc01c2013-12-17 10:33:07 +010019#include "hw/android/goldfish/pipe.h"
David 'Digit' Turnere7216d82013-12-15 00:51:13 +010020#include "sysemu/char.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010021#include "android/charpipe.h"
22#include "android/cbuffer.h"
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +020023#include "utils/panic.h"
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070024
Vladimir Chtchetkine7ffddd62011-08-05 10:15:04 -070025#define D(...) VERBOSE_PRINT(qemud,__VA_ARGS__)
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070026#define D_ACTIVE VERBOSE_CHECK(qemud)
27
28/* the T(...) macro is used to dump traffic */
29#define T_ACTIVE 0
30
31#if T_ACTIVE
32#define T(...) VERBOSE_PRINT(qemud,__VA_ARGS__)
33#else
34#define T(...) ((void)0)
35#endif
36
37/* max serial MTU. Don't change this without modifying
38 * development/emulator/qemud/qemud.c as well.
39 */
40#define MAX_SERIAL_PAYLOAD 4000
41
42/* max framed data payload. Must be < (1 << 16)
43 */
44#define MAX_FRAME_PAYLOAD 65535
45
Ot ten Thije871da2a2010-09-20 10:29:22 +010046/* Version number of snapshots code. Increment whenever the data saved
47 * or the layout in which it is saved is changed.
48 */
Vladimir Chtchetkined0e28722011-10-05 14:25:07 -070049#define QEMUD_SAVE_VERSION 2
Ot ten Thije871da2a2010-09-20 10:29:22 +010050
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +010051#ifndef min
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -070052#define min(a, b) (((a) < (b)) ? (a) : (b))
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +010053#endif
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070054
David Turner791d8612009-04-13 18:01:32 -070055/* define SUPPORT_LEGACY_QEMUD to 1 if you want to support
56 * talking to a legacy qemud daemon. See docs/ANDROID-QEMUD.TXT
57 * for details.
58 */
Jun Nakajima334ab472011-02-02 23:49:59 -080059#ifdef TARGET_ARM
David Turner791d8612009-04-13 18:01:32 -070060#define SUPPORT_LEGACY_QEMUD 1
Jun Nakajima334ab472011-02-02 23:49:59 -080061#endif
62#ifdef TARGET_I386
63#define SUPPORT_LEGACY_QEMUD 0 /* no legacy support */
64#endif
David Turnerfbcbf422009-04-15 06:50:16 -070065#if SUPPORT_LEGACY_QEMUD
66#include "telephony/android_modem.h"
67#include "telephony/modem_driver.h"
68#endif
69
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070070/*
David Turner791d8612009-04-13 18:01:32 -070071 * This implements support for the 'qemud' multiplexing communication
72 * channel between clients running in the emulated system and 'services'
73 * provided by the emulator.
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070074 *
David Turner791d8612009-04-13 18:01:32 -070075 * For additional details, please read docs/ANDROID-QEMUD.TXT
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070076 *
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070077 */
78
79/*
80 * IMPLEMENTATION DETAILS:
81 *
82 * We use one charpipe to connect the emulated serial port to the 'QemudSerial'
83 * object. This object is used to receive data from the serial port, and
84 * unframe messages (i.e. extract payload length + channel id from header,
85 * then the payload itself), before sending them to a generic receiver.
86 *
87 * The QemudSerial object can also be used to send messages to the daemon
88 * through the serial port (see qemud_serial_send())
89 *
90 * The multiplexer is connected to one or more 'service' objects.
91 * are themselves connected through a charpipe to an emulated device or
92 * control sub-module in the emulator.
93 *
94 * tty <==charpipe==> QemudSerial ---> QemudMultiplexer ----> QemudClient
95 * ^ |
96 * | |
97 * +--------------------------------------+
98 *
99 */
100
101/** HANDLING INCOMING DATA FRAMES
102 **/
103
David Turner791d8612009-04-13 18:01:32 -0700104/* A QemudSink is just a handly data structure that is used to
105 * read a fixed amount of bytes into a buffer
106 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700107typedef struct QemudSink {
Ot ten Thije871da2a2010-09-20 10:29:22 +0100108 int used; /* number of bytes already used */
109 int size; /* total number of bytes in buff */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700110 uint8_t* buff;
111} QemudSink;
112
Ot ten Thije871da2a2010-09-20 10:29:22 +0100113/* save the state of a QemudSink to a snapshot.
114 *
115 * The buffer pointer is not saved, since it usually points to buffer
116 * fields in other structs, which have save functions themselves. It
117 * is up to the caller to make sure the buffer is correctly saved and
118 * restored.
119 */
120static void
121qemud_sink_save(QEMUFile* f, QemudSink* s)
122{
123 qemu_put_be32(f, s->used);
124 qemu_put_be32(f, s->size);
125}
126
127/* load the state of a QemudSink from a snapshot.
128 */
129static int
130qemud_sink_load(QEMUFile* f, QemudSink* s)
131{
132 s->used = qemu_get_be32(f);
133 s->size = qemu_get_be32(f);
134 return 0;
135}
136
137
David Turner791d8612009-04-13 18:01:32 -0700138/* reset a QemudSink, i.e. provide a new destination buffer address
139 * and its size in bytes.
140 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700141static void
142qemud_sink_reset( QemudSink* ss, int size, uint8_t* buffer )
143{
Ot ten Thije871da2a2010-09-20 10:29:22 +0100144 ss->used = 0;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700145 ss->size = size;
146 ss->buff = buffer;
147}
148
David Turner791d8612009-04-13 18:01:32 -0700149/* try to fill the sink by reading bytes from the source buffer
150 * '*pmsg' which contains '*plen' bytes
151 *
152 * this functions updates '*pmsg' and '*plen', and returns
153 * 1 if the sink's destination buffer is full, or 0 otherwise.
154 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700155static int
156qemud_sink_fill( QemudSink* ss, const uint8_t* *pmsg, int *plen)
157{
Ot ten Thije871da2a2010-09-20 10:29:22 +0100158 int avail = ss->size - ss->used;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700159
160 if (avail <= 0)
161 return 1;
162
163 if (avail > *plen)
164 avail = *plen;
165
Ot ten Thije871da2a2010-09-20 10:29:22 +0100166 memcpy(ss->buff + ss->used, *pmsg, avail);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700167 *pmsg += avail;
168 *plen -= avail;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100169 ss->used += avail;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700170
Ot ten Thije871da2a2010-09-20 10:29:22 +0100171 return (ss->used == ss->size);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700172}
173
David Turner791d8612009-04-13 18:01:32 -0700174/* returns the number of bytes needed to fill a sink's destination
175 * buffer.
176 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700177static int
178qemud_sink_needed( QemudSink* ss )
179{
Ot ten Thije871da2a2010-09-20 10:29:22 +0100180 return ss->size - ss->used;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700181}
182
183/** HANDLING SERIAL PORT CONNECTION
184 **/
185
186/* The QemudSerial object receives data from the serial port charpipe.
187 * It parses the header to extract the channel id and payload length,
188 * then the message itself.
189 *
190 * Incoming messages are sent to a generic receiver identified by
191 * the 'recv_opaque' and 'recv_func' parameters to qemud_serial_init()
192 *
193 * It also provides qemud_serial_send() which can be used to send
194 * messages back through the serial port.
195 */
196
197#define HEADER_SIZE 6
198
199#define LENGTH_OFFSET 2
200#define LENGTH_SIZE 4
201
202#define CHANNEL_OFFSET 0
203#define CHANNEL_SIZE 2
204
David Turner791d8612009-04-13 18:01:32 -0700205#if SUPPORT_LEGACY_QEMUD
206typedef enum {
207 QEMUD_VERSION_UNKNOWN,
208 QEMUD_VERSION_LEGACY,
209 QEMUD_VERSION_NORMAL
210} QemudVersion;
211
212# define LEGACY_LENGTH_OFFSET 0
213# define LEGACY_CHANNEL_OFFSET 4
214#endif
215
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700216/* length of the framed header */
217#define FRAME_HEADER_SIZE 4
218
219#define BUFFER_SIZE MAX_SERIAL_PAYLOAD
220
221/* out of convenience, the incoming message is zero-terminated
222 * and can be modified by the receiver (e.g. for tokenization).
223 */
224typedef void (*QemudSerialReceive)( void* opaque, int channel, uint8_t* msg, int msglen);
225
226typedef struct QemudSerial {
227 CharDriverState* cs; /* serial charpipe endpoint */
228
229 /* managing incoming packets from the serial port */
230 ABool need_header;
231 int overflow;
232 int in_size;
233 int in_channel;
David Turner791d8612009-04-13 18:01:32 -0700234#if SUPPORT_LEGACY_QEMUD
235 QemudVersion version;
236#endif
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700237 QemudSink header[1];
238 QemudSink payload[1];
239 uint8_t data0[MAX_SERIAL_PAYLOAD+1];
240
241 /* receiver */
242 QemudSerialReceive recv_func; /* receiver callback */
243 void* recv_opaque; /* receiver user-specific data */
244} QemudSerial;
245
246
Ot ten Thije871da2a2010-09-20 10:29:22 +0100247/* Save the state of a QemudSerial to a snapshot file.
248 */
249static void
250qemud_serial_save(QEMUFile* f, QemudSerial* s)
251{
252 /* cs, recv_func and recv_opaque are not saved, as these are assigned only
253 * during emulator init. A load within a session can re-use the values
254 * already assigned, a newly launched emulator has freshly assigned values.
255 */
256
257 /* state of incoming packets from the serial port */
258 qemu_put_be32(f, s->need_header);
259 qemu_put_be32(f, s->overflow);
260 qemu_put_be32(f, s->in_size);
261 qemu_put_be32(f, s->in_channel);
262#if SUPPORT_LEGACY_QEMUD
263 qemu_put_be32(f, s->version);
264#endif
265 qemud_sink_save(f, s->header);
266 qemud_sink_save(f, s->payload);
267 qemu_put_be32(f, MAX_SERIAL_PAYLOAD+1);
268 qemu_put_buffer(f, s->data0, MAX_SERIAL_PAYLOAD+1);
269}
270
271/* Load the state of a QemudSerial from a snapshot file.
272 */
273static int
274qemud_serial_load(QEMUFile* f, QemudSerial* s)
275{
276 /* state of incoming packets from the serial port */
277 s->need_header = qemu_get_be32(f);
278 s->overflow = qemu_get_be32(f);
279 s->in_size = qemu_get_be32(f);
280 s->in_channel = qemu_get_be32(f);
281#if SUPPORT_LEGACY_QEMUD
282 s->version = qemu_get_be32(f);
283#endif
284 qemud_sink_load(f, s->header);
285 qemud_sink_load(f, s->payload);
286
287 /* s->header and s->payload are only ever connected to s->data0 */
288 s->header->buff = s->payload->buff = s->data0;
289
290 int len = qemu_get_be32(f);
291 if (len - 1 > MAX_SERIAL_PAYLOAD) {
292 D("%s: load failed: size of saved payload buffer (%d) exceeds "
293 "current maximum (%d)\n",
294 __FUNCTION__, len - 1, MAX_SERIAL_PAYLOAD);
295 return -EIO;
296 }
297 int ret;
298 if ((ret = qemu_get_buffer(f, s->data0, len)) != len) {
299 D("%s: failed to load serial buffer contents (tried reading %d bytes, got %d)\n",
300 __FUNCTION__, len, ret);
301 return -EIO;
302 }
303
304 return 0;
305}
306
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700307/* called by the charpipe to see how much bytes can be
308 * read from the serial port.
309 */
310static int
311qemud_serial_can_read( void* opaque )
312{
313 QemudSerial* s = opaque;
314
315 if (s->overflow > 0) {
316 return s->overflow;
317 }
318
319 /* if in_size is 0, we're reading the header */
320 if (s->need_header)
321 return qemud_sink_needed(s->header);
322
323 /* otherwise, we're reading the payload */
324 return qemud_sink_needed(s->payload);
325}
326
327/* called by the charpipe to read data from the serial
328 * port. 'len' cannot be more than the value returned
329 * by 'qemud_serial_can_read'.
330 */
331static void
332qemud_serial_read( void* opaque, const uint8_t* from, int len )
333{
334 QemudSerial* s = opaque;
335
336 T("%s: received %3d bytes: '%s'", __FUNCTION__, len, quote_bytes((const void*)from, len));
337
338 while (len > 0) {
339 int avail;
340
341 /* skip overflow bytes */
342 if (s->overflow > 0) {
343 avail = s->overflow;
344 if (avail > len)
345 avail = len;
346
347 from += avail;
348 len -= avail;
349 continue;
350 }
351
352 /* read header if needed */
353 if (s->need_header) {
354 if (!qemud_sink_fill(s->header, (const uint8_t**)&from, &len))
355 break;
356
David Turner791d8612009-04-13 18:01:32 -0700357#if SUPPORT_LEGACY_QEMUD
358 if (s->version == QEMUD_VERSION_UNKNOWN) {
359 /* if we receive "001200" as the first header, then we
360 * detected a legacy qemud daemon. See the comments
361 * in qemud_serial_send_legacy_probe() for details.
362 */
363 if ( !memcmp(s->data0, "001200", 6) ) {
364 D("%s: legacy qemud detected.", __FUNCTION__);
365 s->version = QEMUD_VERSION_LEGACY;
David Turnerfbcbf422009-04-15 06:50:16 -0700366 /* tell the modem to use legacy emulation mode */
367 amodem_set_legacy(android_modem);
David Turner791d8612009-04-13 18:01:32 -0700368 } else {
369 D("%s: normal qemud detected.", __FUNCTION__);
370 s->version = QEMUD_VERSION_NORMAL;
371 }
372 }
373
374 if (s->version == QEMUD_VERSION_LEGACY) {
375 s->in_size = hex2int( s->data0 + LEGACY_LENGTH_OFFSET, LENGTH_SIZE );
376 s->in_channel = hex2int( s->data0 + LEGACY_CHANNEL_OFFSET, CHANNEL_SIZE );
377 } else {
378 s->in_size = hex2int( s->data0 + LENGTH_OFFSET, LENGTH_SIZE );
379 s->in_channel = hex2int( s->data0 + CHANNEL_OFFSET, CHANNEL_SIZE );
380 }
381#else
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700382 /* extract payload length + channel id */
383 s->in_size = hex2int( s->data0 + LENGTH_OFFSET, LENGTH_SIZE );
384 s->in_channel = hex2int( s->data0 + CHANNEL_OFFSET, CHANNEL_SIZE );
David Turner791d8612009-04-13 18:01:32 -0700385#endif
Ot ten Thije871da2a2010-09-20 10:29:22 +0100386 s->header->used = 0;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700387
388 if (s->in_size <= 0 || s->in_channel < 0) {
389 D("%s: bad header: '%.*s'", __FUNCTION__, HEADER_SIZE, s->data0);
390 continue;
391 }
392
393 if (s->in_size > MAX_SERIAL_PAYLOAD) {
394 D("%s: ignoring huge serial packet: length=%d channel=%1",
395 __FUNCTION__, s->in_size, s->in_channel);
396 s->overflow = s->in_size;
397 continue;
398 }
399
400 /* prepare 'in_data' for payload */
401 s->need_header = 0;
402 qemud_sink_reset(s->payload, s->in_size, s->data0);
403 }
404
405 /* read payload bytes */
406 if (!qemud_sink_fill(s->payload, &from, &len))
407 break;
408
409 /* zero-terminate payload, then send it to receiver */
410 s->payload->buff[s->payload->size] = 0;
411 D("%s: channel=%2d len=%3d '%s'", __FUNCTION__,
412 s->in_channel, s->payload->size,
413 quote_bytes((const void*)s->payload->buff, s->payload->size));
414
415 s->recv_func( s->recv_opaque, s->in_channel, s->payload->buff, s->payload->size );
416
417 /* prepare for new header */
418 s->need_header = 1;
419 }
420}
421
David Turner791d8612009-04-13 18:01:32 -0700422
423#if SUPPORT_LEGACY_QEMUD
424static void
425qemud_serial_send_legacy_probe( QemudSerial* s )
426{
427 /* we're going to send a specially crafted packet to the qemud
428 * daemon, this will help us determine whether we're talking
429 * to a legacy or a normal daemon.
430 *
431 * the trick is to known that a legacy daemon uses the following
432 * header:
433 *
434 * <length><channel><payload>
435 *
436 * while the normal one uses:
437 *
438 * <channel><length><payload>
439 *
440 * where <channel> is a 2-hexchar string, and <length> a 4-hexchar
441 * string.
442 *
443 * if we send a header of "000100", it is interpreted:
444 *
445 * - as the header of a 1-byte payload by the legacy daemon
446 * - as the header of a 256-byte payload by the normal one.
447 *
448 * we're going to send something that looks like:
449 *
450 * "000100" + "X" +
451 * "000b00" + "connect:gsm" +
452 * "000b00" + "connect:gps" +
453 * "000f00" + "connect:control" +
454 * "00c210" + "0"*194
455 *
456 * the normal daemon will interpret this as a 256-byte payload
457 * for channel 0, with garbage content ("X000b00conn...") which
458 * will be silently ignored.
459 *
460 * on the other hand, the legacy daemon will see it as a
461 * series of packets:
462 *
463 * one message "X" on channel 0, which will force the daemon
464 * to send back "001200ko:unknown command" as its first answer.
465 *
466 * three "connect:<xxx>" messages used to receive the channel
467 * numbers of the three legacy services implemented by the daemon.
468 *
469 * a garbage packet of 194 zeroes for channel 16, which will be
470 * silently ignored.
471 */
472 uint8_t tab[194];
473
474 memset(tab, 0, sizeof(tab));
475 qemu_chr_write(s->cs, (uint8_t*)"000100X", 7);
476 qemu_chr_write(s->cs, (uint8_t*)"000b00connect:gsm", 17);
477 qemu_chr_write(s->cs, (uint8_t*)"000b00connect:gps", 17);
478 qemu_chr_write(s->cs, (uint8_t*)"000f00connect:control", 21);
479 qemu_chr_write(s->cs, (uint8_t*)"00c210", 6);
480 qemu_chr_write(s->cs, tab, sizeof(tab));
481}
482#endif /* SUPPORT_LEGACY_QEMUD */
483
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700484/* intialize a QemudSerial object with a charpipe endpoint
485 * and a receiver.
486 */
487static void
488qemud_serial_init( QemudSerial* s,
489 CharDriverState* cs,
490 QemudSerialReceive recv_func,
491 void* recv_opaque )
492{
493 s->cs = cs;
494 s->recv_func = recv_func;
495 s->recv_opaque = recv_opaque;
496 s->need_header = 1;
497 s->overflow = 0;
498
499 qemud_sink_reset( s->header, HEADER_SIZE, s->data0 );
500 s->in_size = 0;
501 s->in_channel = -1;
502
David Turner791d8612009-04-13 18:01:32 -0700503#if SUPPORT_LEGACY_QEMUD
504 s->version = QEMUD_VERSION_UNKNOWN;
505 qemud_serial_send_legacy_probe(s);
506#endif
507
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700508 qemu_chr_add_handlers( cs,
509 qemud_serial_can_read,
510 qemud_serial_read,
511 NULL,
512 s );
513}
514
515/* send a message to the serial port. This will add the necessary
516 * header.
517 */
518static void
519qemud_serial_send( QemudSerial* s,
520 int channel,
521 ABool framing,
522 const uint8_t* msg,
523 int msglen )
524{
525 uint8_t header[HEADER_SIZE];
526 uint8_t frame[FRAME_HEADER_SIZE];
527 int avail, len = msglen;
528
529 if (msglen <= 0 || channel < 0)
530 return;
531
532 D("%s: channel=%2d len=%3d '%s'",
533 __FUNCTION__, channel, msglen,
534 quote_bytes((const void*)msg, msglen));
535
536 if (framing) {
537 len += FRAME_HEADER_SIZE;
538 }
539
540 /* packetize the payload for the serial MTU */
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100541 while (len > 0)
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700542 {
543 avail = len;
544 if (avail > MAX_SERIAL_PAYLOAD)
545 avail = MAX_SERIAL_PAYLOAD;
546
547 /* write this packet's header */
David Turner791d8612009-04-13 18:01:32 -0700548#if SUPPORT_LEGACY_QEMUD
549 if (s->version == QEMUD_VERSION_LEGACY) {
550 int2hex(header + LEGACY_LENGTH_OFFSET, LENGTH_SIZE, avail);
551 int2hex(header + LEGACY_CHANNEL_OFFSET, CHANNEL_SIZE, channel);
552 } else {
553 int2hex(header + LENGTH_OFFSET, LENGTH_SIZE, avail);
554 int2hex(header + CHANNEL_OFFSET, CHANNEL_SIZE, channel);
555 }
556#else
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700557 int2hex(header + LENGTH_OFFSET, LENGTH_SIZE, avail);
558 int2hex(header + CHANNEL_OFFSET, CHANNEL_SIZE, channel);
David Turner791d8612009-04-13 18:01:32 -0700559#endif
560 T("%s: '%.*s'", __FUNCTION__, HEADER_SIZE, header);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700561 qemu_chr_write(s->cs, header, HEADER_SIZE);
562
563 /* insert frame header when needed */
564 if (framing) {
565 int2hex(frame, FRAME_HEADER_SIZE, msglen);
David Turner791d8612009-04-13 18:01:32 -0700566 T("%s: '%.*s'", __FUNCTION__, FRAME_HEADER_SIZE, frame);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700567 qemu_chr_write(s->cs, frame, FRAME_HEADER_SIZE);
568 avail -= FRAME_HEADER_SIZE;
569 len -= FRAME_HEADER_SIZE;
570 framing = 0;
571 }
572
573 /* write message content */
David Turner791d8612009-04-13 18:01:32 -0700574 T("%s: '%.*s'", __FUNCTION__, avail, msg);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700575 qemu_chr_write(s->cs, msg, avail);
576 msg += avail;
577 len -= avail;
578 }
579}
580
581/** CLIENTS
582 **/
583
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700584/* Descriptor for a data buffer pending to be sent to a qemud pipe client.
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700585 *
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700586 * When a service decides to send data to the client, there could be cases when
587 * client is not ready to read them. In this case there is no GoldfishPipeBuffer
588 * available to write service's data to, So, we need to cache that data into the
589 * client descriptor, and "send" them over to the client in _qemudPipe_recvBuffers
590 * callback. Pending service data is stored in the client descriptor as a list
591 * of QemudPipeMessage instances.
592 */
593typedef struct QemudPipeMessage QemudPipeMessage;
594struct QemudPipeMessage {
595 /* Message to send. */
596 uint8_t* message;
597 /* Message size. */
598 size_t size;
599 /* Offset in the message buffer of the chunk, that has not been sent
600 * to the pipe yet. */
601 size_t offset;
602 /* Links next message in the client. */
603 QemudPipeMessage* next;
604};
605
606
607/* A QemudClient models a single client as seen by the emulator.
608 * Each client has its own channel id (for the serial qemud), or pipe descriptor
609 * (for the pipe based qemud), and belongs to a given QemudService (see below).
610 *
611 * There is a global list of serial clients used to multiplex incoming
612 * messages from the channel id (see qemud_multiplexer_serial_recv()). Pipe
613 * clients don't need multiplexing, because they are communicated via qemud pipes
614 * that are unique for each client.
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700615 *
616 */
617
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700618/* Defines type of the client: pipe, or serial.
619 */
620typedef enum QemudProtocol {
621 /* Client is communicating via pipe. */
622 QEMUD_PROTOCOL_PIPE,
623 /* Client is communicating via serial port. */
624 QEMUD_PROTOCOL_SERIAL
625} QemudProtocol;
626
Vladimir Chtchetkine59385322011-08-18 15:53:48 -0700627/* Descriptor for a QEMUD pipe connection.
628 *
629 * Every time a client connects to the QEMUD via pipe, an instance of this
630 * structure is created to represent a connection used by new pipe client.
631 */
632typedef struct QemudPipe {
633 /* Pipe descriptor. */
634 void* hwpipe;
635 /* Looper used for I/O */
636 void* looper;
637 /* Service for this pipe. */
638 QemudService* service;
639 /* Client for this pipe. */
640 QemudClient* client;
641} QemudPipe;
642
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700643struct QemudClient {
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700644 /* Defines protocol, used by the client. */
645 QemudProtocol protocol;
646
647 /* Fields that are common for all protocols. */
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700648 char* param;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700649 void* clie_opaque;
650 QemudClientRecv clie_recv;
651 QemudClientClose clie_close;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100652 QemudClientSave clie_save;
653 QemudClientLoad clie_load;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700654 QemudService* service;
655 QemudClient* next_serv; /* next in same service */
656 QemudClient* next;
657 QemudClient** pref;
658
659 /* framing support */
660 int framing;
661 ABool need_header;
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100662 ABool closing;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700663 QemudSink header[1];
664 uint8_t header0[FRAME_HEADER_SIZE];
665 QemudSink payload[1];
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700666
667 /* Fields that are protocol-specific. */
668 union {
669 /* Serial-specific fields. */
670 struct {
671 int channel;
672 QemudSerial* serial;
673 } Serial;
674 /* Pipe-specific fields. */
675 struct {
Vladimir Chtchetkine59385322011-08-18 15:53:48 -0700676 QemudPipe* qemud_pipe;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700677 QemudPipeMessage* messages;
678 } Pipe;
679 } ProtocolSelector;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700680};
681
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700682static ABool
683_is_pipe_client(QemudClient* client)
684{
685 return (client-> protocol == QEMUD_PROTOCOL_PIPE) ? true : false;
686}
687
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700688static void qemud_service_remove_client( QemudService* service,
689 QemudClient* client );
690
691/* remove a QemudClient from global list */
692static void
693qemud_client_remove( QemudClient* c )
694{
695 c->pref[0] = c->next;
696 if (c->next)
697 c->next->pref = c->pref;
698
699 c->next = NULL;
700 c->pref = &c->next;
701}
702
703/* add a QemudClient to global list */
704static void
705qemud_client_prepend( QemudClient* c, QemudClient** plist )
706{
707 c->next = *plist;
708 c->pref = plist;
709 *plist = c;
710 if (c->next)
711 c->next->pref = &c->next;
712}
713
714/* receive a new message from a client, and dispatch it to
715 * the real service implementation.
716 */
717static void
718qemud_client_recv( void* opaque, uint8_t* msg, int msglen )
719{
720 QemudClient* c = opaque;
721
722 /* no framing, things are simple */
723 if (!c->framing) {
724 if (c->clie_recv)
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200725 c->clie_recv( c->clie_opaque, msg, msglen, c );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700726 return;
727 }
728
729 /* framing */
730
731#if 1
732 /* special case, in 99% of cases, everything is in
733 * the incoming message, and we can do all we need
734 * directly without dynamic allocation.
735 */
736 if (msglen > FRAME_HEADER_SIZE &&
737 c->need_header == 1 &&
738 qemud_sink_needed(c->header) == 0)
739 {
740 int len = hex2int( msg, FRAME_HEADER_SIZE );
741
742 if (len >= 0 && msglen == len + FRAME_HEADER_SIZE) {
743 if (c->clie_recv)
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100744 c->clie_recv( c->clie_opaque,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700745 msg+FRAME_HEADER_SIZE,
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200746 msglen-FRAME_HEADER_SIZE, c );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700747 return;
748 }
749 }
750#endif
751
752 while (msglen > 0) {
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700753 uint8_t *data;
754
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700755 /* read the header */
756 if (c->need_header) {
757 int frame_size;
758 uint8_t* data;
759
760 if (!qemud_sink_fill(c->header, (const uint8_t**)&msg, &msglen))
761 break;
762
763 frame_size = hex2int(c->header0, 4);
764 if (frame_size == 0) {
765 D("%s: ignoring empty frame", __FUNCTION__);
766 continue;
767 }
768 if (frame_size < 0) {
769 D("%s: ignoring corrupted frame header '.*s'",
770 __FUNCTION__, FRAME_HEADER_SIZE, c->header0 );
771 continue;
772 }
773
774 AARRAY_NEW(data, frame_size+1); /* +1 for terminating zero */
775 qemud_sink_reset(c->payload, frame_size, data);
776 c->need_header = 0;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100777 c->header->used = 0;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700778 }
779
780 /* read the payload */
781 if (!qemud_sink_fill(c->payload, (const uint8_t**)&msg, &msglen))
782 break;
783
784 c->payload->buff[c->payload->size] = 0;
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700785 c->need_header = 1;
786 data = c->payload->buff;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700787
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700788 /* Technically, calling 'clie_recv' can destroy client object 'c'
789 * if it decides to close the connection, so ensure we don't
790 * use/dereference it after the call. */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700791 if (c->clie_recv)
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200792 c->clie_recv( c->clie_opaque, c->payload->buff, c->payload->size, c );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700793
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700794 AFREE(data);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700795 }
796}
797
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700798/* Sends data to a pipe-based client.
799 */
800static void
801_qemud_pipe_send(QemudClient* client, const uint8_t* msg, int msglen);
802
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700803/* Frees memory allocated for the qemud client.
804 */
805static void
806_qemud_client_free(QemudClient* c)
807{
808 if ( c != NULL) {
809 if (_is_pipe_client(c)) {
810 /* Free outstanding messages. */
811 QemudPipeMessage** msg_list = &c->ProtocolSelector.Pipe.messages;
812 while (*msg_list != NULL) {
813 QemudPipeMessage* to_free = *msg_list;
814 *msg_list = to_free->next;
815 free(to_free);
816 }
817 }
818 if (c->param != NULL) {
819 free(c->param);
820 }
821 AFREE(c);
822 }
823}
824
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700825/* disconnect a client. this automatically frees the QemudClient.
826 * note that this also removes the client from the global list
827 * and from its service's list, if any.
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -0800828 * Param:
829 * opaque - QemuClient instance
830 * guest_close - For pipe clients control whether or not the disconnect is
831 * caused by guest closing the pipe handle (in which case 1 is passed in
832 * this parameter). For serial clients this parameter is ignored.
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700833 */
834static void
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -0800835qemud_client_disconnect( void* opaque, int guest_close )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700836{
837 QemudClient* c = opaque;
838
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100839 if (c->closing) { /* recursive call, exit immediately */
840 return;
841 }
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -0800842
843 if (_is_pipe_client(c) && !guest_close) {
844 /* This is emulator component (rather than the guest) closing a pipe
845 * client. Since pipe clients are controlled strictly by the guest, we
846 * don't actually close the client here, but notify the guest about the
847 * client being disconnected. Then we will do the real client close when
848 * the guest explicitly closes the pipe, in which case this routine will
849 * be called from the _qemudPipe_closeFromGuest callback with guest_close
850 * set to 1. */
851 char tmp[128], *p=tmp, *end=p+sizeof(tmp);
852 p = bufprint(tmp, end, "disconnect:00");
853 _qemud_pipe_send(c, (uint8_t*)tmp, p-tmp);
854 return;
855 }
856
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100857 c->closing = 1;
858
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700859 /* remove from current list */
860 qemud_client_remove(c);
861
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700862 if (_is_pipe_client(c)) {
Vladimir Chtchetkine59385322011-08-18 15:53:48 -0700863 /* We must NULL the client reference in the QemuPipe for this connection,
864 * so if a sudden receive request comes after client has been closed, we
865 * don't blow up. */
866 c->ProtocolSelector.Pipe.qemud_pipe->client = NULL;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700867 } else if (c->ProtocolSelector.Serial.channel > 0) {
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -0800868 /* send a disconnect command to the daemon */
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700869 char tmp[128], *p=tmp, *end=p+sizeof(tmp);
870 p = bufprint(tmp, end, "disconnect:%02x",
871 c->ProtocolSelector.Serial.channel);
872 qemud_serial_send(c->ProtocolSelector.Serial.serial, 0, 0, (uint8_t*)tmp, p-tmp);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700873 }
874
875 /* call the client close callback */
876 if (c->clie_close) {
877 c->clie_close(c->clie_opaque);
878 c->clie_close = NULL;
879 }
880 c->clie_recv = NULL;
881
882 /* remove from service list, if any */
883 if (c->service) {
884 qemud_service_remove_client(c->service, c);
885 c->service = NULL;
886 }
887
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700888 _qemud_client_free(c);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700889}
890
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700891/* allocate a new QemudClient object
892 * NOTE: channel_id valie is used as a selector between serial and pipe clients.
893 * Since channel_id < 0 is an invalid value for a serial client, it would
894 * indicate that creating client is a pipe client. */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700895static QemudClient*
896qemud_client_alloc( int channel_id,
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700897 const char* client_param,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700898 void* clie_opaque,
899 QemudClientRecv clie_recv,
900 QemudClientClose clie_close,
Ot ten Thije871da2a2010-09-20 10:29:22 +0100901 QemudClientSave clie_save,
902 QemudClientLoad clie_load,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700903 QemudSerial* serial,
904 QemudClient** pclients )
905{
906 QemudClient* c;
907
908 ANEW0(c);
909
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700910 if (channel_id < 0) {
911 /* Allocating a pipe client. */
912 c->protocol = QEMUD_PROTOCOL_PIPE;
913 c->ProtocolSelector.Pipe.messages = NULL;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -0700914 c->ProtocolSelector.Pipe.qemud_pipe = NULL;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700915 } else {
916 /* Allocating a serial client. */
917 c->protocol = QEMUD_PROTOCOL_SERIAL;
918 c->ProtocolSelector.Serial.serial = serial;
919 c->ProtocolSelector.Serial.channel = channel_id;
920 }
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700921 c->param = client_param ? ASTRDUP(client_param) : NULL;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700922 c->clie_opaque = clie_opaque;
923 c->clie_recv = clie_recv;
924 c->clie_close = clie_close;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100925 c->clie_save = clie_save;
926 c->clie_load = clie_load;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700927 c->service = NULL;
928 c->next_serv = NULL;
929 c->next = NULL;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700930 c->framing = 0;
931 c->need_header = 1;
932 qemud_sink_reset(c->header, FRAME_HEADER_SIZE, c->header0);
933
934 qemud_client_prepend(c, pclients);
935
936 return c;
937}
938
Ot ten Thije871da2a2010-09-20 10:29:22 +0100939/* forward */
940static void qemud_service_save_name( QEMUFile* f, QemudService* s );
941static char* qemud_service_load_name( QEMUFile* f );
942static QemudService* qemud_service_find( QemudService* service_list,
943 const char* service_name );
944static QemudClient* qemud_service_connect_client( QemudService *sv,
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700945 int channel_id,
946 const char* client_param);
Ot ten Thije871da2a2010-09-20 10:29:22 +0100947
948/* Saves the client state needed to re-establish connections on load.
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200949 * Note that we save only serial clients here. The pipe clients will be
950 * saved along with the pipe to which they are attached.
Ot ten Thije871da2a2010-09-20 10:29:22 +0100951 */
952static void
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200953qemud_serial_client_save(QEMUFile* f, QemudClient* c)
Ot ten Thije871da2a2010-09-20 10:29:22 +0100954{
955 /* save generic information */
956 qemud_service_save_name(f, c->service);
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200957 qemu_put_string(f, c->param);
958 qemu_put_be32(f, c->ProtocolSelector.Serial.channel);
Ot ten Thije871da2a2010-09-20 10:29:22 +0100959
960 /* save client-specific state */
961 if (c->clie_save)
962 c->clie_save(f, c, c->clie_opaque);
963
964 /* save framing configuration */
965 qemu_put_be32(f, c->framing);
966 if (c->framing) {
967 qemu_put_be32(f, c->need_header);
968 /* header sink always connected to c->header0, no need to save */
969 qemu_put_be32(f, FRAME_HEADER_SIZE);
970 qemu_put_buffer(f, c->header0, FRAME_HEADER_SIZE);
971 /* payload sink */
972 qemud_sink_save(f, c->payload);
973 qemu_put_buffer(f, c->payload->buff, c->payload->size);
974 }
975}
976
977/* Loads client state from file, then starts a new client connected to the
978 * corresponding service.
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200979 * Note that we load only serial clients here. The pipe clients will be
980 * loaded along with the pipe to which they were attached.
Ot ten Thije871da2a2010-09-20 10:29:22 +0100981 */
982static int
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200983qemud_serial_client_load(QEMUFile* f, QemudService* current_services, int version )
Ot ten Thije871da2a2010-09-20 10:29:22 +0100984{
985 char *service_name = qemud_service_load_name(f);
986 if (service_name == NULL)
987 return -EIO;
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200988 char* param = qemu_get_string(f);
Ot ten Thije871da2a2010-09-20 10:29:22 +0100989 /* get current service instance */
990 QemudService *sv = qemud_service_find(current_services, service_name);
991 if (sv == NULL) {
992 D("%s: load failed: unknown service \"%s\"\n",
993 __FUNCTION__, service_name);
994 return -EIO;
995 }
996
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200997 int channel = qemu_get_be32(f);
Vladimir Chtchetkined0e28722011-10-05 14:25:07 -0700998
Ot ten Thije871da2a2010-09-20 10:29:22 +0100999 if (channel == 0) {
1000 D("%s: illegal snapshot: client for control channel must no be saved\n",
1001 __FUNCTION__);
1002 return -EIO;
1003 }
1004
1005 /* re-connect client */
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001006 QemudClient* c = qemud_service_connect_client(sv, channel, param);
Ot ten Thije871da2a2010-09-20 10:29:22 +01001007 if(c == NULL)
1008 return -EIO;
1009
1010 /* load client-specific state */
1011 int ret;
1012 if (c->clie_load)
1013 if ((ret = c->clie_load(f, c, c->clie_opaque)))
1014 return ret; /* load failure */
1015
1016 /* load framing configuration */
1017 c->framing = qemu_get_be32(f);
1018 if (c->framing) {
1019
1020 /* header buffer */
1021 c->need_header = qemu_get_be32(f);
1022 int header_size = qemu_get_be32(f);
1023 if (header_size > FRAME_HEADER_SIZE) {
1024 D("%s: load failed: payload buffer requires %d bytes, %d available\n",
1025 __FUNCTION__, header_size, FRAME_HEADER_SIZE);
1026 return -EIO;
1027 }
1028 int ret;
1029 if ((ret = qemu_get_buffer(f, c->header0, header_size)) != header_size) {
1030 D("%s: frame header buffer load failed: expected %d bytes, got %d\n",
1031 __FUNCTION__, header_size, ret);
1032 return -EIO;
1033 }
1034
1035 /* payload sink */
1036 if ((ret = qemud_sink_load(f, c->payload)))
1037 return ret;
1038
1039 /* replace payload buffer by saved data */
1040 if (c->payload->buff) {
1041 AFREE(c->payload->buff);
1042 }
1043 AARRAY_NEW(c->payload->buff, c->payload->size+1); /* +1 for terminating zero */
1044 if ((ret = qemu_get_buffer(f, c->payload->buff, c->payload->size)) != c->payload->size) {
1045 D("%s: frame payload buffer load failed: expected %d bytes, got %d\n",
1046 __FUNCTION__, c->payload->size, ret);
1047 AFREE(c->payload->buff);
1048 return -EIO;
1049 }
1050 }
1051
1052 return 0;
1053}
1054
1055
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001056/** SERVICES
1057 **/
1058
1059/* A QemudService models a _named_ service facility implemented
1060 * by the emulator, that clients in the emulated system can connect
1061 * to.
1062 *
1063 * Each service can have a limit on the number of clients they
1064 * accept (this number if unlimited if 'max_clients' is 0).
1065 *
1066 * Each service maintains a list of active QemudClients and
1067 * can also be used to create new QemudClient objects through
1068 * its 'serv_opaque' and 'serv_connect' fields.
1069 */
1070struct QemudService {
1071 const char* name;
1072 int max_clients;
1073 int num_clients;
1074 QemudClient* clients;
1075 QemudServiceConnect serv_connect;
Ot ten Thije871da2a2010-09-20 10:29:22 +01001076 QemudServiceSave serv_save;
1077 QemudServiceLoad serv_load;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001078 void* serv_opaque;
1079 QemudService* next;
1080};
1081
1082/* Create a new QemudService object */
1083static QemudService*
1084qemud_service_new( const char* name,
1085 int max_clients,
1086 void* serv_opaque,
1087 QemudServiceConnect serv_connect,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001088 QemudServiceSave serv_save,
1089 QemudServiceLoad serv_load,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001090 QemudService** pservices )
1091{
1092 QemudService* s;
1093
1094 ANEW0(s);
1095 s->name = ASTRDUP(name);
1096 s->max_clients = max_clients;
1097 s->num_clients = 0;
1098 s->clients = NULL;
1099
1100 s->serv_opaque = serv_opaque;
1101 s->serv_connect = serv_connect;
Ot ten Thije871da2a2010-09-20 10:29:22 +01001102 s->serv_save = serv_save;
1103 s->serv_load = serv_load;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001104
1105 s->next = *pservices;
1106 *pservices = s;
1107
1108 return s;
1109}
1110
1111/* used internally to populate a QemudService object with a
1112 * new QemudClient */
1113static void
1114qemud_service_add_client( QemudService* s, QemudClient* c )
1115{
1116 c->service = s;
1117 c->next_serv = s->clients;
1118 s->clients = c;
1119 s->num_clients += 1;
1120}
1121
1122/* used internally to remove a QemudClient from a QemudService */
1123static void
1124qemud_service_remove_client( QemudService* s, QemudClient* c )
1125{
1126 QemudClient** pnode = &s->clients;
1127 QemudClient* node;
1128
1129 /* remove from clients linked-list */
1130 for (;;) {
1131 node = *pnode;
1132 if (node == NULL) {
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001133 D("%s: could not find client for service '%s'",
1134 __FUNCTION__, s->name);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001135 return;
1136 }
1137 if (node == c)
1138 break;
1139 pnode = &node->next_serv;
1140 }
1141
1142 *pnode = node->next_serv;
1143 s->num_clients -= 1;
1144}
1145
Ot ten Thije871da2a2010-09-20 10:29:22 +01001146/* ask the service to create a new QemudClient. Note that we
1147 * assume that this calls qemud_client_new() which will add
1148 * the client to the service's list automatically.
1149 *
1150 * returns the client or NULL if an error occurred
1151 */
1152static QemudClient*
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001153qemud_service_connect_client(QemudService *sv,
1154 int channel_id,
1155 const char* client_param)
Ot ten Thije871da2a2010-09-20 10:29:22 +01001156{
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001157 QemudClient* client =
1158 sv->serv_connect( sv->serv_opaque, sv, channel_id, client_param );
Ot ten Thije871da2a2010-09-20 10:29:22 +01001159 if (client == NULL) {
1160 D("%s: registration failed for '%s' service",
1161 __FUNCTION__, sv->name);
1162 return NULL;
1163 }
Ot ten Thije871da2a2010-09-20 10:29:22 +01001164 D("%s: registered client channel %d for '%s' service",
1165 __FUNCTION__, channel_id, sv->name);
1166 return client;
1167}
1168
1169/* find a registered service by name.
1170 */
1171static QemudService*
1172qemud_service_find( QemudService* service_list, const char* service_name)
1173{
1174 QemudService* sv = NULL;
1175 for (sv = service_list; sv != NULL; sv = sv->next) {
1176 if (!strcmp(sv->name, service_name)) {
1177 break;
1178 }
1179 }
1180 return sv;
1181}
1182
1183/* Save the name of the given service.
1184 */
1185static void
1186qemud_service_save_name(QEMUFile* f, QemudService* s)
1187{
1188 int len = strlen(s->name) + 1; // include '\0' terminator
1189 qemu_put_be32(f, len);
1190 qemu_put_buffer(f, (const uint8_t *) s->name, len);
1191}
1192
1193/* Load the name of a service. Returns a pointer to the loaded name, or NULL
1194 * on failure.
1195 */
1196static char*
1197qemud_service_load_name( QEMUFile* f )
1198{
1199 int ret;
1200 int name_len = qemu_get_be32(f);
1201 char *service_name = android_alloc(name_len);
1202 if ((ret = qemu_get_buffer(f, (uint8_t*)service_name, name_len) != name_len)) {
1203 D("%s: service name load failed: expected %d bytes, got %d\n",
1204 __FUNCTION__, name_len, ret);
1205 AFREE(service_name);
1206 return NULL;
1207 }
1208 if (service_name[name_len - 1] != '\0') {
1209 char last = service_name[name_len - 1];
1210 service_name[name_len - 1] = '\0'; /* make buffer contents printable */
1211 D("%s: service name load failed: expecting NULL-terminated string, but "
1212 "last char is '%c' (buffer contents: '%s%c')\n",
1213 __FUNCTION__, name_len, last, service_name, last);
1214 AFREE(service_name);
1215 return NULL;
1216 }
1217
1218 return service_name;
1219}
1220
1221/* Saves state of a service.
1222 */
1223static void
1224qemud_service_save(QEMUFile* f, QemudService* s)
1225{
1226 qemud_service_save_name(f, s);
1227 qemu_put_be32(f, s->max_clients);
1228 qemu_put_be32(f, s->num_clients);
1229
1230 if (s->serv_save)
1231 s->serv_save(f, s, s->serv_opaque);
1232}
1233
1234/* Loads service state from file, then updates the currently running instance
1235 * of that service to mirror the loaded state. If the service is not running,
1236 * the load process is aborted.
1237 *
1238 * Parameter 'current_services' should be the list of active services.
1239 */
1240static int
1241qemud_service_load( QEMUFile* f, QemudService* current_services )
1242{
1243 char* service_name = qemud_service_load_name(f);
1244 if (service_name == NULL)
1245 return -EIO;
1246
1247 /* get current service instance */
1248 QemudService *sv = qemud_service_find(current_services, service_name);
1249 if (sv == NULL) {
1250 D("%s: loading failed: service \"%s\" not available\n",
1251 __FUNCTION__, service_name);
1252 return -EIO;
1253 }
1254
1255 /* reconfigure service as required */
1256 sv->max_clients = qemu_get_be32(f);
1257 sv->num_clients = qemu_get_be32(f);
1258
1259 /* load service specific data */
1260 int ret;
1261 if (sv->serv_load)
1262 if ((ret = sv->serv_load(f, sv, sv->serv_opaque)))
1263 return ret; /* load failure */
1264
1265 return 0;
1266}
1267
1268
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001269/** MULTIPLEXER
1270 **/
1271
1272/* A QemudMultiplexer object maintains the global state of the
1273 * qemud service facility. It holds a QemudSerial object to
1274 * maintain the state of the serial port connection.
1275 *
1276 * The QemudMultiplexer receives all incoming messages from
1277 * the serial port, and dispatches them to the appropriate
1278 * QemudClient.
1279 *
1280 * It also has a global list of clients, and a global list of
1281 * services.
1282 *
1283 * Finally, the QemudMultiplexer has a special QemudClient used
1284 * to handle channel 0, i.e. the control channel used to handle
1285 * connections and disconnections of clients.
1286 */
1287typedef struct QemudMultiplexer QemudMultiplexer;
1288
1289struct QemudMultiplexer {
1290 QemudSerial serial[1];
1291 QemudClient* clients;
1292 QemudService* services;
1293};
1294
1295/* this is the serial_recv callback that is called
1296 * whenever an incoming message arrives through the serial port
1297 */
1298static void
1299qemud_multiplexer_serial_recv( void* opaque,
1300 int channel,
1301 uint8_t* msg,
1302 int msglen )
1303{
1304 QemudMultiplexer* m = opaque;
1305 QemudClient* c = m->clients;
1306
1307 /* dispatch to an existing client if possible
1308 * note that channel 0 is handled by a special
1309 * QemudClient that is setup in qemud_multiplexer_init()
1310 */
1311 for ( ; c != NULL; c = c->next ) {
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001312 if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel == channel) {
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001313 qemud_client_recv(c, msg, msglen);
1314 return;
1315 }
1316 }
1317
1318 D("%s: ignoring %d bytes for unknown channel %d",
1319 __FUNCTION__, msglen, channel);
1320}
1321
1322/* handle a new connection attempt. This returns 0 on
1323 * success, -1 if the service name is unknown, or -2
1324 * if the service's maximum number of clients has been
1325 * reached.
1326 */
1327static int
1328qemud_multiplexer_connect( QemudMultiplexer* m,
1329 const char* service_name,
1330 int channel_id )
1331{
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001332 /* find the corresponding registered service by name */
Ot ten Thije871da2a2010-09-20 10:29:22 +01001333 QemudService* sv = qemud_service_find(m->services, service_name);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001334 if (sv == NULL) {
1335 D("%s: no registered '%s' service", __FUNCTION__, service_name);
1336 return -1;
1337 }
1338
1339 /* check service's client count */
1340 if (sv->max_clients > 0 && sv->num_clients >= sv->max_clients) {
1341 D("%s: registration failed for '%s' service: too many clients (%d)",
1342 __FUNCTION__, service_name, sv->num_clients);
1343 return -2;
1344 }
1345
Ot ten Thije871da2a2010-09-20 10:29:22 +01001346 /* connect a new client to the service on the given channel */
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001347 if (qemud_service_connect_client(sv, channel_id, NULL) == NULL)
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001348 return -1;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001349
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001350 return 0;
1351}
1352
1353/* disconnect a given client from its channel id */
1354static void
1355qemud_multiplexer_disconnect( QemudMultiplexer* m,
1356 int channel )
1357{
1358 QemudClient* c;
1359
1360 /* find the client by its channel id, then disconnect it */
1361 for (c = m->clients; c; c = c->next) {
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001362 if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel == channel) {
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001363 D("%s: disconnecting client %d",
1364 __FUNCTION__, channel);
1365 /* note thatt this removes the client from
1366 * m->clients automatically.
1367 */
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001368 c->ProtocolSelector.Serial.channel = -1; /* no need to send disconnect:<id> */
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -08001369 qemud_client_disconnect(c, 0);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001370 return;
1371 }
1372 }
1373 D("%s: disconnecting unknown channel %d",
1374 __FUNCTION__, channel);
1375}
1376
Ot ten Thije871da2a2010-09-20 10:29:22 +01001377/* disconnects all channels, except for the control channel, without informing
1378 * the daemon in the guest that disconnection has occurred.
1379 *
1380 * Used to silently kill clients when restoring emulator state snapshots.
1381 */
1382static void
1383qemud_multiplexer_disconnect_noncontrol( QemudMultiplexer* m )
1384{
1385 QemudClient* c;
1386 QemudClient* next = m->clients;
1387
1388 while (next) {
1389 c = next;
1390 next = c->next; /* disconnect frees c, remember next in advance */
1391
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001392 if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0) {
1393 /* skip control channel */
Ot ten Thije871da2a2010-09-20 10:29:22 +01001394 D("%s: disconnecting client %d",
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001395 __FUNCTION__, c->ProtocolSelector.Serial.channel);
Ot ten Thije871da2a2010-09-20 10:29:22 +01001396 D("%s: disconnecting client %d\n",
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001397 __FUNCTION__, c->ProtocolSelector.Serial.channel);
1398 c->ProtocolSelector.Serial.channel = -1; /* do not send disconnect:<id> */
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -08001399 qemud_client_disconnect(c, 0);
Ot ten Thije871da2a2010-09-20 10:29:22 +01001400 }
1401 }
1402}
1403
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001404/* handle control messages. This is used as the receive
1405 * callback for the special QemudClient setup to manage
1406 * channel 0.
1407 *
1408 * note that the message is zero-terminated for convenience
1409 * (i.e. msg[msglen] is a valid memory read that returns '\0')
1410 */
1411static void
David 'Digit' Turner318e4f22009-05-25 18:01:03 +02001412qemud_multiplexer_control_recv( void* opaque,
1413 uint8_t* msg,
1414 int msglen,
1415 QemudClient* client )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001416{
1417 QemudMultiplexer* mult = opaque;
1418 uint8_t* msgend = msg + msglen;
1419 char tmp[64], *p=tmp, *end=p+sizeof(tmp);
1420
1421 /* handle connection attempts.
1422 * the client message must be "connect:<service-name>:<id>"
David Turnerfff1ae52009-04-05 14:22:28 -07001423 * where <id> is a 2-char hexadecimal string, which must be > 0
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001424 */
1425 if (msglen > 8 && !memcmp(msg, "connect:", 8))
1426 {
1427 const char* service_name = (const char*)msg + 8;
1428 int channel, ret;
1429 char* q;
1430
1431 q = strchr(service_name, ':');
David Turnerfff1ae52009-04-05 14:22:28 -07001432 if (q == NULL || q+3 != (char*)msgend) {
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001433 D("%s: malformed connect message: '%.*s' (offset=%d)",
1434 __FUNCTION__, msglen, (const char*)msg, q ? q-(char*)msg : -1);
1435 return;
1436 }
1437 *q++ = 0; /* zero-terminate service name */
David Turnerfff1ae52009-04-05 14:22:28 -07001438 channel = hex2int((uint8_t*)q, 2);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001439 if (channel <= 0) {
1440 D("%s: malformed channel id '%.*s",
David Turnerfff1ae52009-04-05 14:22:28 -07001441 __FUNCTION__, 2, q);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001442 return;
1443 }
1444
1445 ret = qemud_multiplexer_connect(mult, service_name, channel);
1446 /* the answer can be one of:
1447 * ok:connect:<id>
1448 * ko:connect:<id>:<reason-for-failure>
1449 */
1450 if (ret < 0) {
1451 if (ret == -1) {
1452 /* could not connect */
David Turnerfff1ae52009-04-05 14:22:28 -07001453 p = bufprint(tmp, end, "ko:connect:%02x:unknown service", channel);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001454 } else {
David Turnerfff1ae52009-04-05 14:22:28 -07001455 p = bufprint(tmp, end, "ko:connect:%02x:service busy", channel);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001456 }
1457 }
1458 else {
David Turnerfff1ae52009-04-05 14:22:28 -07001459 p = bufprint(tmp, end, "ok:connect:%02x", channel);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001460 }
1461 qemud_serial_send(mult->serial, 0, 0, (uint8_t*)tmp, p-tmp);
1462 return;
1463 }
1464
1465 /* handle client disconnections,
1466 * this message arrives when the client has closed the connection.
David Turnerfff1ae52009-04-05 14:22:28 -07001467 * format: "disconnect:<id>" where <id> is a 2-hex channel id > 0
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001468 */
David Turnerfff1ae52009-04-05 14:22:28 -07001469 if (msglen == 13 && !memcmp(msg, "disconnect:", 11)) {
1470 int channel_id = hex2int(msg+11, 2);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001471 if (channel_id <= 0) {
1472 D("%s: malformed disconnect channel id: '%.*s'",
David Turnerfff1ae52009-04-05 14:22:28 -07001473 __FUNCTION__, 2, msg+11);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001474 return;
1475 }
1476 qemud_multiplexer_disconnect(mult, channel_id);
1477 return;
1478 }
1479
David Turner791d8612009-04-13 18:01:32 -07001480#if SUPPORT_LEGACY_QEMUD
1481 /* an ok:connect:<service>:<id> message can be received if we're
1482 * talking to a legacy qemud daemon, i.e. one running in a 1.0 or
1483 * 1.1 system image.
1484 *
1485 * we should treat is as a normal "connect:" attempt, except that
1486 * we must not send back any acknowledgment.
1487 */
1488 if (msglen > 11 && !memcmp(msg, "ok:connect:", 11)) {
1489 const char* service_name = (const char*)msg + 11;
1490 char* q = strchr(service_name, ':');
1491 int channel;
1492
1493 if (q == NULL || q+3 != (char*)msgend) {
1494 D("%s: malformed legacy connect message: '%.*s' (offset=%d)",
1495 __FUNCTION__, msglen, (const char*)msg, q ? q-(char*)msg : -1);
1496 return;
1497 }
1498 *q++ = 0; /* zero-terminate service name */
1499 channel = hex2int((uint8_t*)q, 2);
1500 if (channel <= 0) {
1501 D("%s: malformed legacy channel id '%.*s",
1502 __FUNCTION__, 2, q);
1503 return;
1504 }
1505
1506 switch (mult->serial->version) {
1507 case QEMUD_VERSION_UNKNOWN:
1508 mult->serial->version = QEMUD_VERSION_LEGACY;
1509 D("%s: legacy qemud daemon detected.", __FUNCTION__);
1510 break;
1511
1512 case QEMUD_VERSION_LEGACY:
1513 /* nothing unusual */
1514 break;
1515
1516 default:
1517 D("%s: weird, ignoring legacy qemud control message: '%.*s'",
1518 __FUNCTION__, msglen, msg);
1519 return;
1520 }
1521
1522 /* "hw-control" was called "control" in 1.0/1.1 */
1523 if (!strcmp(service_name,"control"))
1524 service_name = "hw-control";
1525
1526 qemud_multiplexer_connect(mult, service_name, channel);
1527 return;
1528 }
1529
1530 /* anything else, don't answer for legacy */
1531 if (mult->serial->version == QEMUD_VERSION_LEGACY)
1532 return;
1533#endif /* SUPPORT_LEGACY_QEMUD */
1534
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001535 /* anything else is a problem */
1536 p = bufprint(tmp, end, "ko:unknown command");
1537 qemud_serial_send(mult->serial, 0, 0, (uint8_t*)tmp, p-tmp);
1538}
1539
1540/* initialize the global QemudMultiplexer.
1541 */
1542static void
1543qemud_multiplexer_init( QemudMultiplexer* mult,
1544 CharDriverState* serial_cs )
1545{
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001546 /* initialize serial handler */
1547 qemud_serial_init( mult->serial,
1548 serial_cs,
1549 qemud_multiplexer_serial_recv,
1550 mult );
1551
1552 /* setup listener for channel 0 */
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +01001553 qemud_client_alloc(0,
1554 NULL,
1555 mult,
1556 qemud_multiplexer_control_recv,
1557 NULL, NULL, NULL,
1558 mult->serial,
1559 &mult->clients );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001560}
1561
1562/* the global multiplexer state */
1563static QemudMultiplexer _multiplexer[1];
1564
1565/** HIGH-LEVEL API
1566 **/
1567
1568/* this function must be used in the serv_connect callback
1569 * of a given QemudService object (see qemud_service_register()
1570 * below). It is used to register a new QemudClient to acknowledge
1571 * a new client connection.
1572 *
1573 * 'clie_opaque', 'clie_recv' and 'clie_close' are used to
1574 * send incoming client messages to the corresponding service
1575 * implementation, or notify the service that a client has
1576 * disconnected.
1577 */
1578QemudClient*
1579qemud_client_new( QemudService* service,
1580 int channelId,
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001581 const char* client_param,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001582 void* clie_opaque,
1583 QemudClientRecv clie_recv,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001584 QemudClientClose clie_close,
1585 QemudClientSave clie_save,
1586 QemudClientLoad clie_load )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001587{
1588 QemudMultiplexer* m = _multiplexer;
1589 QemudClient* c = qemud_client_alloc( channelId,
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001590 client_param,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001591 clie_opaque,
1592 clie_recv,
1593 clie_close,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001594 clie_save,
1595 clie_load,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001596 m->serial,
1597 &m->clients );
1598
1599 qemud_service_add_client(service, c);
1600 return c;
1601}
1602
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001603/* Caches a service message into the client's descriptor.
1604 *
1605 * See comments on QemudPipeMessage structure for more info.
1606 */
1607static void
1608_qemud_pipe_cache_buffer(QemudClient* client, const uint8_t* msg, int msglen)
1609{
1610 QemudPipeMessage* buf;
1611 QemudPipeMessage** ins_at = &client->ProtocolSelector.Pipe.messages;
1612
1613 /* Allocate descriptor big enough to contain message as well. */
1614 buf = (QemudPipeMessage*)malloc(msglen + sizeof(QemudPipeMessage));
1615 if (buf != NULL) {
1616 /* Message starts right after the descriptor. */
1617 buf->message = (uint8_t*)buf + sizeof(QemudPipeMessage);
1618 buf->size = msglen;
1619 memcpy(buf->message, msg, msglen);
1620 buf->offset = 0;
1621 buf->next = NULL;
1622 while (*ins_at != NULL) {
1623 ins_at = &(*ins_at)->next;
1624 }
1625 *ins_at = buf;
1626 /* Notify the pipe that there is data to read. */
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07001627 goldfish_pipe_wake(client->ProtocolSelector.Pipe.qemud_pipe->hwpipe,
1628 PIPE_WAKE_READ);
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001629 }
1630}
1631
1632/* Sends service message to the client.
1633 */
1634static void
1635_qemud_pipe_send(QemudClient* client, const uint8_t* msg, int msglen)
1636{
1637 uint8_t frame[FRAME_HEADER_SIZE];
1638 int avail, len = msglen;
1639 int framing = client->framing;
1640
1641 if (msglen <= 0)
1642 return;
1643
1644 D("%s: len=%3d '%s'",
1645 __FUNCTION__, msglen, quote_bytes((const void*)msg, msglen));
1646
1647 if (framing) {
1648 len += FRAME_HEADER_SIZE;
1649 }
1650
1651 /* packetize the payload for the serial MTU */
1652 while (len > 0)
1653 {
1654 avail = len;
1655 if (avail > MAX_SERIAL_PAYLOAD)
1656 avail = MAX_SERIAL_PAYLOAD;
1657
1658 /* insert frame header when needed */
1659 if (framing) {
1660 int2hex(frame, FRAME_HEADER_SIZE, msglen);
1661 T("%s: '%.*s'", __FUNCTION__, FRAME_HEADER_SIZE, frame);
1662 _qemud_pipe_cache_buffer(client, frame, FRAME_HEADER_SIZE);
1663 avail -= FRAME_HEADER_SIZE;
1664 len -= FRAME_HEADER_SIZE;
1665 framing = 0;
1666 }
1667
1668 /* write message content */
1669 T("%s: '%.*s'", __FUNCTION__, avail, msg);
1670 _qemud_pipe_cache_buffer(client, msg, avail);
1671 msg += avail;
1672 len -= avail;
1673 }
1674}
1675
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001676/* this can be used by a service implementation to send an answer
1677 * or message to a specific client.
1678 */
1679void
1680qemud_client_send ( QemudClient* client, const uint8_t* msg, int msglen )
1681{
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001682 if (_is_pipe_client(client)) {
1683 _qemud_pipe_send(client, msg, msglen);
1684 } else {
1685 qemud_serial_send(client->ProtocolSelector.Serial.serial,
1686 client->ProtocolSelector.Serial.channel,
1687 client->framing != 0, msg, msglen);
1688 }
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001689}
1690
1691/* enable framing for this client. When TRUE, this will
1692 * use internally a simple 4-hexchar header before each
1693 * message exchanged through the serial port.
1694 */
1695void
1696qemud_client_set_framing( QemudClient* client, int framing )
1697{
1698 /* release dynamic buffer if we're disabling framing */
1699 if (client->framing) {
1700 if (!client->need_header) {
1701 AFREE(client->payload->buff);
1702 client->need_header = 1;
1703 }
1704 }
1705 client->framing = !!framing;
1706}
1707
1708/* this can be used by a service implementation to close a
1709 * specific client connection.
1710 */
1711void
1712qemud_client_close( QemudClient* client )
1713{
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -08001714 qemud_client_disconnect(client, 0);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001715}
1716
1717
Ot ten Thije871da2a2010-09-20 10:29:22 +01001718/** SNAPSHOT SUPPORT
1719 **/
1720
1721/* Saves the number of clients.
1722 */
1723static void
1724qemud_client_save_count(QEMUFile* f, QemudClient* c)
1725{
1726 unsigned int client_count = 0;
1727 for( ; c; c = c->next) // walk over linked list
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001728 /* skip control channel, which is not saved, and pipe channels that
1729 * are saved along with the pipe. */
1730 if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0)
Ot ten Thije871da2a2010-09-20 10:29:22 +01001731 client_count++;
1732
1733 qemu_put_be32(f, client_count);
1734}
1735
1736/* Saves the number of services currently available.
1737 */
1738static void
1739qemud_service_save_count(QEMUFile* f, QemudService* s)
1740{
1741 unsigned int service_count = 0;
1742 for( ; s; s = s->next ) // walk over linked list
1743 service_count++;
1744
1745 qemu_put_be32(f, service_count);
1746}
1747
1748/* Save QemuD state to snapshot.
1749 *
1750 * The control channel has no state of its own, other than the local variables
1751 * in qemud_multiplexer_control_recv. We can therefore safely skip saving it,
1752 * which spares us dealing with the exception of a client not connected to a
1753 * service.
1754 */
1755static void
1756qemud_save(QEMUFile* f, void* opaque)
1757{
1758 QemudMultiplexer *m = opaque;
1759
1760 qemud_serial_save(f, m->serial);
1761
1762 /* save service states */
1763 qemud_service_save_count(f, m->services);
1764 QemudService *s;
1765 for (s = m->services; s; s = s->next)
1766 qemud_service_save(f, s);
1767
1768 /* save client channels */
1769 qemud_client_save_count(f, m->clients);
1770 QemudClient *c;
1771 for (c = m->clients; c; c = c->next) {
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001772 /* skip control channel, and pipe clients */
1773 if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0) {
1774 qemud_serial_client_save(f, c);
Ot ten Thije871da2a2010-09-20 10:29:22 +01001775 }
1776 }
1777
1778}
1779
1780
1781/* Checks whether the same services are available at this point as when the
1782 * snapshot was made.
1783 */
1784static int
1785qemud_load_services( QEMUFile* f, QemudService* current_services )
1786{
1787 int i, ret;
1788 int service_count = qemu_get_be32(f);
1789 for (i = 0; i < service_count; i++) {
1790 if ((ret = qemud_service_load(f, current_services)))
1791 return ret;
1792 }
1793
1794 return 0;
1795}
1796
1797/* Removes all active non-control clients, then creates new ones with state
1798 * taken from the snapshot.
1799 *
1800 * We do not send "disconnect" commands, over the channel. If we did, we might
1801 * stop clients in the restored guest, resulting in an incorrect restore.
1802 *
1803 * Instead, we silently replace the clients that were running before the
1804 * restore with new clients, whose state we copy from the snapshot. Since
1805 * everything is multiplexed over one link, only the multiplexer notices the
1806 * changes, there is no communication with the guest.
1807 */
1808static int
Vladimir Chtchetkined0e28722011-10-05 14:25:07 -07001809qemud_load_clients(QEMUFile* f, QemudMultiplexer* m, int version )
Ot ten Thije871da2a2010-09-20 10:29:22 +01001810{
1811 /* Remove all clients, except on the control channel.*/
1812 qemud_multiplexer_disconnect_noncontrol(m);
1813
1814 /* Load clients from snapshot */
1815 int client_count = qemu_get_be32(f);
1816 int i, ret;
1817 for (i = 0; i < client_count; i++) {
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001818 if ((ret = qemud_serial_client_load(f, m->services, version))) {
Ot ten Thije871da2a2010-09-20 10:29:22 +01001819 return ret;
1820 }
1821 }
1822
1823 return 0;
1824}
1825
1826/* Load QemuD state from file.
1827 */
1828static int
1829qemud_load(QEMUFile *f, void* opaque, int version)
1830{
1831 QemudMultiplexer *m = opaque;
1832
1833 int ret;
Ot ten Thije871da2a2010-09-20 10:29:22 +01001834
1835 if ((ret = qemud_serial_load(f, m->serial)))
1836 return ret;
1837 if ((ret = qemud_load_services(f, m->services)))
1838 return ret;
Vladimir Chtchetkined0e28722011-10-05 14:25:07 -07001839 if ((ret = qemud_load_clients(f, m, version)))
Ot ten Thije871da2a2010-09-20 10:29:22 +01001840 return ret;
1841
1842 return 0;
1843}
1844
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001845/*------------------------------------------------------------------------------
1846 *
1847 * QEMUD PIPE service callbacks
1848 *
1849 * ----------------------------------------------------------------------------*/
1850
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001851/* Saves pending pipe message to the snapshot file. */
1852static void
1853_save_pipe_message(QEMUFile* f, QemudPipeMessage* msg)
1854{
1855 qemu_put_be32(f, msg->size);
1856 qemu_put_be32(f, msg->offset);
1857 qemu_put_buffer(f, msg->message, msg->size);
1858}
1859
1860/* Loads pending pipe messages from the snapshot file.
1861 * Return:
1862 * List of pending pipe messages loaded from snapshot, or NULL if snapshot didn't
1863 * contain saved messages.
1864 */
1865static QemudPipeMessage*
1866_load_pipe_message(QEMUFile* f)
1867{
1868 QemudPipeMessage* ret = NULL;
1869 QemudPipeMessage** next = &ret;
1870
1871 uint32_t size = qemu_get_be32(f);
1872 while (size != 0) {
1873 QemudPipeMessage* wrk;
1874 ANEW0(wrk);
1875 *next = wrk;
1876 wrk->size = size;
1877 wrk->offset = qemu_get_be32(f);
1878 wrk->message = malloc(wrk->size);
1879 if (wrk->message == NULL) {
1880 APANIC("Unable to allocate buffer for pipe's pending message.");
1881 }
1882 qemu_get_buffer(f, wrk->message, wrk->size);
1883 next = &wrk->next;
1884 *next = NULL;
1885 size = qemu_get_be32(f);
1886 }
1887
1888 return ret;
1889}
1890
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001891/* This is a callback that gets invoked when guest is connecting to the service.
1892 *
1893 * Here we will create a new client as well as pipe descriptor representing new
1894 * connection.
1895 */
1896static void*
1897_qemudPipe_init(void* hwpipe, void* _looper, const char* args)
1898{
1899 QemudMultiplexer *m = _multiplexer;
1900 QemudService* sv = m->services;
1901 QemudClient* client;
1902 QemudPipe* pipe = NULL;
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001903 char service_name[512];
1904 const char* client_args;
1905 size_t srv_name_len;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001906
1907 /* 'args' passed in this callback represents name of the service the guest is
1908 * connecting to. It can't be NULL. */
1909 if (args == NULL) {
1910 D("%s: Missing address!", __FUNCTION__);
1911 return NULL;
1912 }
1913
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001914 /* 'args' contain service name, and optional parameters for the client that
1915 * is about to be created in this call. The parameters are separated from the
1916 * service name wit ':'. Separate service name from the client param. */
1917 client_args = strchr(args, ':');
1918 if (client_args != NULL) {
1919 srv_name_len = min(client_args - args, sizeof(service_name) - 1);
1920 client_args++; // Past the ':'
1921 if (*client_args == '\0') {
1922 /* No actual parameters. */
1923 client_args = NULL;
1924 }
1925 } else {
1926 srv_name_len = min(strlen(args), sizeof(service_name) - 1);
1927 }
1928 memcpy(service_name, args, srv_name_len);
1929 service_name[srv_name_len] = '\0';
1930
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001931 /* Lookup registered service by its name. */
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001932 while (sv != NULL && strcmp(sv->name, service_name)) {
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001933 sv = sv->next;
1934 }
1935 if (sv == NULL) {
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001936 D("%s: Service '%s' has not been registered!", __FUNCTION__, service_name);
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001937 return NULL;
1938 }
1939
1940 /* Create a client for this connection. -1 as a channel ID signals that this
1941 * is a pipe client. */
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001942 client = qemud_service_connect_client(sv, -1, client_args);
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001943 if (client != NULL) {
1944 ANEW0(pipe);
1945 pipe->hwpipe = hwpipe;
1946 pipe->looper = _looper;
1947 pipe->service = sv;
1948 pipe->client = client;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07001949 client->ProtocolSelector.Pipe.qemud_pipe = pipe;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001950 }
1951
1952 return pipe;
1953}
1954
1955/* Called when the guest wants to close the channel.
1956*/
1957static void
1958_qemudPipe_closeFromGuest( void* opaque )
1959{
1960 QemudPipe* pipe = opaque;
1961 QemudClient* client = pipe->client;
1962 D("%s", __FUNCTION__);
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07001963 if (client != NULL) {
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -08001964 qemud_client_disconnect(client, 1);
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07001965 } else {
1966 D("%s: Unexpected NULL client", __FUNCTION__);
1967 }
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001968}
1969
1970/* Called when the guest has sent some data to the client.
1971 */
1972static int
1973_qemudPipe_sendBuffers(void* opaque,
1974 const GoldfishPipeBuffer* buffers,
1975 int numBuffers)
1976{
1977 QemudPipe* pipe = opaque;
1978 QemudClient* client = pipe->client;
1979 size_t transferred = 0;
1980
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07001981 if (client == NULL) {
1982 D("%s: Unexpected NULL client", __FUNCTION__);
1983 return -1;
1984 }
1985
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001986 if (numBuffers == 1) {
1987 /* Simple case: all data are in one buffer. */
1988 D("%s: %s", __FUNCTION__, quote_bytes((char*)buffers->data, buffers->size));
1989 qemud_client_recv(client, buffers->data, buffers->size);
1990 transferred = buffers->size;
1991 } else {
1992 /* If there are multiple buffers involved, collect all data in one buffer
1993 * before calling the high level client. */
1994 uint8_t* msg, *wrk;
1995 int n;
1996 for (n = 0; n < numBuffers; n++) {
1997 transferred += buffers[n].size;
1998 }
1999 msg = malloc(transferred);
2000 wrk = msg;
2001 for (n = 0; n < numBuffers; n++) {
2002 memcpy(wrk, buffers[n].data, buffers[n].size);
2003 wrk += buffers[n].size;
2004 }
2005 D("%s: %s", __FUNCTION__, quote_bytes((char*)msg, transferred));
2006 qemud_client_recv(client, msg, transferred);
2007 free(msg);
2008 }
2009
2010 return transferred;
2011}
2012
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002013/* Called when the guest is reading data from the client.
2014 */
2015static int
2016_qemudPipe_recvBuffers(void* opaque, GoldfishPipeBuffer* buffers, int numBuffers)
2017{
2018 QemudPipe* pipe = opaque;
2019 QemudClient* client = pipe->client;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07002020 QemudPipeMessage** msg_list;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002021 GoldfishPipeBuffer* buff = buffers;
2022 GoldfishPipeBuffer* endbuff = buffers + numBuffers;
2023 size_t sent_bytes = 0;
2024 size_t off_in_buff = 0;
2025
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07002026 if (client == NULL) {
2027 D("%s: Unexpected NULL client", __FUNCTION__);
2028 return -1;
2029 }
2030
2031 msg_list = &client->ProtocolSelector.Pipe.messages;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002032 if (*msg_list == NULL) {
2033 /* No data to send. Let it block until we wake it up with
2034 * PIPE_WAKE_READ when service sends data to the client. */
2035 return PIPE_ERROR_AGAIN;
2036 }
2037
2038 /* Fill in goldfish buffers while they are still available, and there are
2039 * messages in the client's message list. */
2040 while (buff != endbuff && *msg_list != NULL) {
2041 QemudPipeMessage* msg = *msg_list;
2042 /* Message data fiting the current pipe's buffer. */
Vladimir Chtchetkine1875d372011-09-07 10:05:07 -07002043 size_t to_copy = min(msg->size - msg->offset, buff->size - off_in_buff);
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002044 memcpy(buff->data + off_in_buff, msg->message + msg->offset, to_copy);
2045 /* Update offsets. */
2046 off_in_buff += to_copy;
2047 msg->offset += to_copy;
2048 sent_bytes += to_copy;
2049 if (msg->size == msg->offset) {
2050 /* We're done with the current message. Go to the next one. */
2051 *msg_list = msg->next;
2052 free(msg);
2053 }
2054 if (off_in_buff == buff->size) {
2055 /* Current pipe buffer is full. Continue with the next one. */
2056 buff++;
Vladimir Chtchetkine1875d372011-09-07 10:05:07 -07002057 off_in_buff = 0;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002058 }
2059 }
2060
2061 D("%s: -> %u (of %u)", __FUNCTION__, sent_bytes, buffers->size);
2062
2063 return sent_bytes;
2064}
2065
2066static unsigned
2067_qemudPipe_poll(void* opaque)
2068{
2069 QemudPipe* pipe = opaque;
2070 QemudClient* client = pipe->client;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07002071 unsigned ret = 0;
2072
2073 if (client != NULL) {
Vladimir Chtchetkinefd165052011-08-25 08:06:26 -07002074 ret |= PIPE_POLL_OUT;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07002075 if (client->ProtocolSelector.Pipe.messages != NULL) {
Vladimir Chtchetkinefd165052011-08-25 08:06:26 -07002076 ret |= PIPE_POLL_IN;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07002077 }
2078 } else {
2079 D("%s: Unexpected NULL client", __FUNCTION__);
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002080 }
2081
2082 return ret;
2083}
2084
2085static void
2086_qemudPipe_wakeOn(void* opaque, int flags)
2087{
2088 D("%s: -> %X", __FUNCTION__, flags);
2089}
2090
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02002091static void
2092_qemudPipe_save(void* opaque, QEMUFile* f )
2093{
2094 QemudPipe* qemud_pipe = (QemudPipe*)opaque;
2095 QemudClient* c = qemud_pipe->client;
2096 QemudPipeMessage* msg = c->ProtocolSelector.Pipe.messages;
2097
2098 /* save generic information */
2099 qemud_service_save_name(f, c->service);
2100 qemu_put_string(f, c->param);
2101
2102 /* Save pending messages. */
2103 while (msg != NULL) {
2104 _save_pipe_message(f, msg);
2105 msg = msg->next;
2106 }
2107 /* End of pending messages. */
2108 qemu_put_be32(f, 0);
2109
2110 /* save client-specific state */
2111 if (c->clie_save)
2112 c->clie_save(f, c, c->clie_opaque);
2113
2114 /* save framing configuration */
2115 qemu_put_be32(f, c->framing);
2116 if (c->framing) {
2117 qemu_put_be32(f, c->need_header);
2118 /* header sink always connected to c->header0, no need to save */
2119 qemu_put_be32(f, FRAME_HEADER_SIZE);
2120 qemu_put_buffer(f, c->header0, FRAME_HEADER_SIZE);
2121 /* payload sink */
2122 qemud_sink_save(f, c->payload);
2123 qemu_put_buffer(f, c->payload->buff, c->payload->size);
2124 }
2125}
2126
2127static void*
2128_qemudPipe_load(void* hwpipe, void* pipeOpaque, const char* args, QEMUFile* f)
2129{
2130 QemudPipe* qemud_pipe = NULL;
2131 char* param;
2132 char *service_name = qemud_service_load_name(f);
2133 if (service_name == NULL)
2134 return NULL;
2135 /* get service instance for the loading client*/
2136 QemudService *sv = qemud_service_find(_multiplexer->services, service_name);
2137 if (sv == NULL) {
2138 D("%s: load failed: unknown service \"%s\"\n",
2139 __FUNCTION__, service_name);
2140 return NULL;
2141 }
2142
2143 /* Load saved parameters. */
2144 param = qemu_get_string(f);
2145
2146 /* re-connect client */
2147 QemudClient* c = qemud_service_connect_client(sv, -1, param);
2148 if(c == NULL)
2149 return NULL;
2150
2151 /* Load pending messages. */
2152 c->ProtocolSelector.Pipe.messages = _load_pipe_message(f);
2153
2154 /* load client-specific state */
2155 if (c->clie_load && c->clie_load(f, c, c->clie_opaque)) {
2156 /* load failure */
2157 return NULL;
2158 }
2159
2160 /* load framing configuration */
2161 c->framing = qemu_get_be32(f);
2162 if (c->framing) {
2163
2164 /* header buffer */
2165 c->need_header = qemu_get_be32(f);
2166 int header_size = qemu_get_be32(f);
2167 if (header_size > FRAME_HEADER_SIZE) {
2168 D("%s: load failed: payload buffer requires %d bytes, %d available\n",
2169 __FUNCTION__, header_size, FRAME_HEADER_SIZE);
2170 return NULL;
2171 }
2172 int ret;
2173 if ((ret = qemu_get_buffer(f, c->header0, header_size)) != header_size) {
2174 D("%s: frame header buffer load failed: expected %d bytes, got %d\n",
2175 __FUNCTION__, header_size, ret);
2176 return NULL;
2177 }
2178
2179 /* payload sink */
2180 if ((ret = qemud_sink_load(f, c->payload)))
2181 return NULL;
2182
2183 /* replace payload buffer by saved data */
2184 if (c->payload->buff) {
2185 AFREE(c->payload->buff);
2186 }
2187 AARRAY_NEW(c->payload->buff, c->payload->size+1); /* +1 for terminating zero */
2188 if ((ret = qemu_get_buffer(f, c->payload->buff, c->payload->size)) != c->payload->size) {
2189 D("%s: frame payload buffer load failed: expected %d bytes, got %d\n",
2190 __FUNCTION__, c->payload->size, ret);
2191 AFREE(c->payload->buff);
2192 return NULL;
2193 }
2194 }
2195
2196 /* Associate the client with the pipe. */
2197 ANEW0(qemud_pipe);
2198 qemud_pipe->hwpipe = hwpipe;
2199 qemud_pipe->looper = pipeOpaque;
2200 qemud_pipe->service = sv;
2201 qemud_pipe->client = c;
2202 c->ProtocolSelector.Pipe.qemud_pipe = qemud_pipe;
2203
2204 return qemud_pipe;
2205}
2206
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002207/* QEMUD pipe functions.
2208 */
2209static const GoldfishPipeFuncs _qemudPipe_funcs = {
2210 _qemudPipe_init,
2211 _qemudPipe_closeFromGuest,
2212 _qemudPipe_sendBuffers,
2213 _qemudPipe_recvBuffers,
2214 _qemudPipe_poll,
2215 _qemudPipe_wakeOn,
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02002216 _qemudPipe_save,
2217 _qemudPipe_load,
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002218};
2219
2220/* Initializes QEMUD pipe interface.
2221 */
2222static void
2223_android_qemud_pipe_init(void)
2224{
2225 static ABool _qemud_pipe_initialized = false;
2226
2227 if (!_qemud_pipe_initialized) {
2228 goldfish_pipe_add_type( "qemud", looper_newCore(), &_qemudPipe_funcs );
2229 _qemud_pipe_initialized = true;
2230 }
2231}
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002232
2233/* this is the end of the serial charpipe that must be passed
2234 * to the emulated tty implementation. The other end of the
2235 * charpipe must be passed to qemud_multiplexer_init().
2236 */
2237static CharDriverState* android_qemud_cs;
2238
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002239/* Initializes QEMUD serial interface.
2240 */
2241static void
2242_android_qemud_serial_init(void)
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002243{
2244 CharDriverState* cs;
2245
2246 if (android_qemud_cs != NULL)
2247 return;
2248
2249 if (qemu_chr_open_charpipe( &android_qemud_cs, &cs ) < 0) {
2250 derror( "%s: can't create charpipe to serial port",
2251 __FUNCTION__ );
2252 exit(1);
2253 }
2254
2255 qemud_multiplexer_init(_multiplexer, cs);
Ot ten Thije871da2a2010-09-20 10:29:22 +01002256
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +01002257 register_savevm(NULL,
2258 "qemud",
2259 0,
2260 QEMUD_SAVE_VERSION,
2261 qemud_save,
2262 qemud_load,
2263 _multiplexer);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002264}
2265
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002266extern void
2267android_qemud_init( void )
2268{
2269 D("%s", __FUNCTION__);
2270 /* We don't know in advance whether the guest system supports qemud pipes,
2271 * so we will initialize both qemud machineries, the legacy (over serial
2272 * port), and the new one (over qemu pipe). Then we let the guest to connect
2273 * via one, or the other. */
2274 _android_qemud_serial_init();
2275 _android_qemud_pipe_init();
2276}
2277
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002278/* return the serial charpipe endpoint that must be used
2279 * by the emulated tty implementation.
2280 */
2281CharDriverState* android_qemud_get_cs( void )
2282{
2283 if (android_qemud_cs == NULL)
2284 android_qemud_init();
2285
2286 return android_qemud_cs;
2287}
2288
2289/* this function is used to register a new named qemud-based
2290 * service. You must provide 'serv_opaque' and 'serv_connect'
2291 * which will be called whenever a new client tries to connect
2292 * to the services.
2293 *
2294 * 'serv_connect' shall return NULL if the connection is refused,
2295 * or a handle to a new QemudClient otherwise. The latter can be
2296 * created through qemud_client_new() defined above.
2297 *
2298 * 'max_clients' is the maximum number of clients accepted by
2299 * the service concurrently. If this value is 0, then any number
2300 * of clients can connect.
2301 */
2302QemudService*
2303qemud_service_register( const char* service_name,
2304 int max_clients,
2305 void* serv_opaque,
Ot ten Thije871da2a2010-09-20 10:29:22 +01002306 QemudServiceConnect serv_connect,
2307 QemudServiceSave serv_save,
2308 QemudServiceLoad serv_load )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002309{
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002310 QemudService* sv;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002311 QemudMultiplexer* m = _multiplexer;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002312
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002313 android_qemud_init();
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002314
2315 sv = qemud_service_new(service_name,
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002316 max_clients,
2317 serv_opaque,
2318 serv_connect,
2319 serv_save,
2320 serv_load,
2321 &m->services);
2322 D("Registered QEMUD service %s", service_name);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002323 return sv;
2324}
2325
2326/* broadcast a given message to all clients of a given QemudService
2327 */
2328extern void
2329qemud_service_broadcast( QemudService* sv,
2330 const uint8_t* msg,
2331 int msglen )
2332{
2333 QemudClient* c;
2334
2335 for (c = sv->clients; c; c = c->next_serv)
2336 qemud_client_send(c, msg, msglen);
2337}
2338
2339
2340
2341/*
2342 * The following code is used for backwards compatibility reasons.
2343 * It allows you to implement a given qemud-based service through
2344 * a charpipe.
2345 *
2346 * In other words, this implements a QemudService and corresponding
2347 * QemudClient that connects a qemud client running in the emulated
2348 * system, to a CharDriverState object implemented through a charpipe.
2349 *
2350 * QemudCharClient <===charpipe====> (char driver user)
2351 *
2352 * For example, this is used to implement the "gsm" service when the
2353 * modem emulation is provided through an external serial device.
2354 *
2355 * A QemudCharService can have only one client by definition.
2356 * There is no QemudCharClient object because we can store a single
2357 * CharDriverState handle in the 'opaque' field for simplicity.
2358 */
2359
2360typedef struct {
2361 QemudService* service;
2362 CharDriverState* cs;
2363} QemudCharService;
2364
2365/* called whenever a new message arrives from a qemud client.
2366 * this simply sends the message through the charpipe to the user.
2367 */
2368static void
David 'Digit' Turner318e4f22009-05-25 18:01:03 +02002369_qemud_char_client_recv( void* opaque, uint8_t* msg, int msglen,
2370 QemudClient* client )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002371{
2372 CharDriverState* cs = opaque;
2373 qemu_chr_write(cs, msg, msglen);
2374}
2375
2376/* we don't expect clients of char. services to exit. Just
2377 * print an error to signal an unexpected situation. We should
2378 * be able to recover from these though, so don't panic.
2379 */
2380static void
2381_qemud_char_client_close( void* opaque )
Vladimir Chtchetkine5297e192011-08-12 12:15:25 -07002382
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002383{
Vladimir Chtchetkine5297e192011-08-12 12:15:25 -07002384 QemudClient* client = opaque;
2385
2386 /* At this point modem driver still uses char pipe to communicate with
2387 * hw-qemud, while communication with the guest is done over qemu pipe.
2388 * So, when guest disconnects from the qemu pipe, and emulator-side client
2389 * goes through the disconnection process, this routine is called, since it
2390 * has been set to called during service registration. Unless modem driver
2391 * is changed to drop char pipe communication, this routine will be called
2392 * due to guest disconnection. As long as the client was a qemu pipe - based
2393 * client, it's fine, since we don't really need to do anything in this case.
2394 */
2395 if (!_is_pipe_client(client)) {
2396 derror("unexpected qemud char. channel close");
2397 }
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002398}
2399
2400
2401/* called by the charpipe to know how much data can be read from
2402 * the user. Since we send everything directly to the serial port
2403 * we can return an arbitrary number.
2404 */
2405static int
2406_qemud_char_service_can_read( void* opaque )
2407{
2408 return 8192; /* whatever */
2409}
2410
2411/* called to read data from the charpipe and send it to the client.
2412 * used qemud_service_broadcast() even if there is a single client
2413 * because we don't need a QemudCharClient object this way.
2414 */
2415static void
2416_qemud_char_service_read( void* opaque, const uint8_t* from, int len )
2417{
2418 QemudService* sv = opaque;
2419 qemud_service_broadcast( sv, from, len );
2420}
2421
2422/* called when a qemud client tries to connect to a char. service.
2423 * we simply create a new client and open the charpipe to receive
2424 * data from it.
2425 */
2426static QemudClient*
Vladimir Chtchetkine1875d372011-09-07 10:05:07 -07002427_qemud_char_service_connect(void* opaque,
2428 QemudService* sv,
2429 int channel,
2430 const char* client_param )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002431{
2432 CharDriverState* cs = opaque;
Vladimir Chtchetkine1875d372011-09-07 10:05:07 -07002433 QemudClient* c = qemud_client_new( sv, channel, client_param,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002434 cs,
2435 _qemud_char_client_recv,
Ot ten Thije871da2a2010-09-20 10:29:22 +01002436 _qemud_char_client_close,
2437 NULL, NULL );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002438
2439 /* now we can open the gates :-) */
2440 qemu_chr_add_handlers( cs,
2441 _qemud_char_service_can_read,
2442 _qemud_char_service_read,
2443 NULL,
2444 sv );
2445
2446 return c;
2447}
2448
2449/* returns a charpipe endpoint that can be used by an emulated
2450 * device or external serial port to implement a char. service
2451 */
2452int
2453android_qemud_get_channel( const char* name, CharDriverState* *pcs )
2454{
2455 CharDriverState* cs;
2456
2457 if (qemu_chr_open_charpipe(&cs, pcs) < 0) {
2458 derror("can't open charpipe for '%s' qemud service", name);
2459 exit(2);
2460 }
Ot ten Thije871da2a2010-09-20 10:29:22 +01002461 qemud_service_register(name, 1, cs, _qemud_char_service_connect, NULL, NULL);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002462 return 0;
2463}
2464
2465/* set the character driver state for a given qemud communication channel. this
2466 * is used to attach the channel to an external char driver device directly.
2467 * returns 0 on success, -1 on error
2468 */
2469int
2470android_qemud_set_channel( const char* name, CharDriverState* peer_cs )
2471{
David Turnerfff1ae52009-04-05 14:22:28 -07002472 CharDriverState* char_buffer = qemu_chr_open_buffer(peer_cs);
2473
2474 if (char_buffer == NULL)
2475 return -1;
2476
Ot ten Thije871da2a2010-09-20 10:29:22 +01002477 qemud_service_register(name, 1, char_buffer, _qemud_char_service_connect,
2478 NULL, NULL);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002479 return 0;
2480}