blob: e80abed8ab77f46b6924e216b6a24ea0aec80cf4 [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"
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -070019#include "hw/goldfish_pipe.h"
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070020#include "qemu-char.h"
21#include "charpipe.h"
22#include "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
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -070051#define min(a, b) (((a) < (b)) ? (a) : (b))
52
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070053
David Turner791d8612009-04-13 18:01:32 -070054/* define SUPPORT_LEGACY_QEMUD to 1 if you want to support
55 * talking to a legacy qemud daemon. See docs/ANDROID-QEMUD.TXT
56 * for details.
57 */
Jun Nakajima334ab472011-02-02 23:49:59 -080058#ifdef TARGET_ARM
David Turner791d8612009-04-13 18:01:32 -070059#define SUPPORT_LEGACY_QEMUD 1
Jun Nakajima334ab472011-02-02 23:49:59 -080060#endif
61#ifdef TARGET_I386
62#define SUPPORT_LEGACY_QEMUD 0 /* no legacy support */
63#endif
David Turnerfbcbf422009-04-15 06:50:16 -070064#if SUPPORT_LEGACY_QEMUD
65#include "telephony/android_modem.h"
66#include "telephony/modem_driver.h"
67#endif
68
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070069/*
David Turner791d8612009-04-13 18:01:32 -070070 * This implements support for the 'qemud' multiplexing communication
71 * channel between clients running in the emulated system and 'services'
72 * provided by the emulator.
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070073 *
David Turner791d8612009-04-13 18:01:32 -070074 * For additional details, please read docs/ANDROID-QEMUD.TXT
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070075 *
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070076 */
77
78/*
79 * IMPLEMENTATION DETAILS:
80 *
81 * We use one charpipe to connect the emulated serial port to the 'QemudSerial'
82 * object. This object is used to receive data from the serial port, and
83 * unframe messages (i.e. extract payload length + channel id from header,
84 * then the payload itself), before sending them to a generic receiver.
85 *
86 * The QemudSerial object can also be used to send messages to the daemon
87 * through the serial port (see qemud_serial_send())
88 *
89 * The multiplexer is connected to one or more 'service' objects.
90 * are themselves connected through a charpipe to an emulated device or
91 * control sub-module in the emulator.
92 *
93 * tty <==charpipe==> QemudSerial ---> QemudMultiplexer ----> QemudClient
94 * ^ |
95 * | |
96 * +--------------------------------------+
97 *
98 */
99
100/** HANDLING INCOMING DATA FRAMES
101 **/
102
David Turner791d8612009-04-13 18:01:32 -0700103/* A QemudSink is just a handly data structure that is used to
104 * read a fixed amount of bytes into a buffer
105 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700106typedef struct QemudSink {
Ot ten Thije871da2a2010-09-20 10:29:22 +0100107 int used; /* number of bytes already used */
108 int size; /* total number of bytes in buff */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700109 uint8_t* buff;
110} QemudSink;
111
Ot ten Thije871da2a2010-09-20 10:29:22 +0100112/* save the state of a QemudSink to a snapshot.
113 *
114 * The buffer pointer is not saved, since it usually points to buffer
115 * fields in other structs, which have save functions themselves. It
116 * is up to the caller to make sure the buffer is correctly saved and
117 * restored.
118 */
119static void
120qemud_sink_save(QEMUFile* f, QemudSink* s)
121{
122 qemu_put_be32(f, s->used);
123 qemu_put_be32(f, s->size);
124}
125
126/* load the state of a QemudSink from a snapshot.
127 */
128static int
129qemud_sink_load(QEMUFile* f, QemudSink* s)
130{
131 s->used = qemu_get_be32(f);
132 s->size = qemu_get_be32(f);
133 return 0;
134}
135
136
David Turner791d8612009-04-13 18:01:32 -0700137/* reset a QemudSink, i.e. provide a new destination buffer address
138 * and its size in bytes.
139 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700140static void
141qemud_sink_reset( QemudSink* ss, int size, uint8_t* buffer )
142{
Ot ten Thije871da2a2010-09-20 10:29:22 +0100143 ss->used = 0;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700144 ss->size = size;
145 ss->buff = buffer;
146}
147
David Turner791d8612009-04-13 18:01:32 -0700148/* try to fill the sink by reading bytes from the source buffer
149 * '*pmsg' which contains '*plen' bytes
150 *
151 * this functions updates '*pmsg' and '*plen', and returns
152 * 1 if the sink's destination buffer is full, or 0 otherwise.
153 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700154static int
155qemud_sink_fill( QemudSink* ss, const uint8_t* *pmsg, int *plen)
156{
Ot ten Thije871da2a2010-09-20 10:29:22 +0100157 int avail = ss->size - ss->used;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700158
159 if (avail <= 0)
160 return 1;
161
162 if (avail > *plen)
163 avail = *plen;
164
Ot ten Thije871da2a2010-09-20 10:29:22 +0100165 memcpy(ss->buff + ss->used, *pmsg, avail);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700166 *pmsg += avail;
167 *plen -= avail;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100168 ss->used += avail;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700169
Ot ten Thije871da2a2010-09-20 10:29:22 +0100170 return (ss->used == ss->size);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700171}
172
David Turner791d8612009-04-13 18:01:32 -0700173/* returns the number of bytes needed to fill a sink's destination
174 * buffer.
175 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700176static int
177qemud_sink_needed( QemudSink* ss )
178{
Ot ten Thije871da2a2010-09-20 10:29:22 +0100179 return ss->size - ss->used;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700180}
181
182/** HANDLING SERIAL PORT CONNECTION
183 **/
184
185/* The QemudSerial object receives data from the serial port charpipe.
186 * It parses the header to extract the channel id and payload length,
187 * then the message itself.
188 *
189 * Incoming messages are sent to a generic receiver identified by
190 * the 'recv_opaque' and 'recv_func' parameters to qemud_serial_init()
191 *
192 * It also provides qemud_serial_send() which can be used to send
193 * messages back through the serial port.
194 */
195
196#define HEADER_SIZE 6
197
198#define LENGTH_OFFSET 2
199#define LENGTH_SIZE 4
200
201#define CHANNEL_OFFSET 0
202#define CHANNEL_SIZE 2
203
David Turner791d8612009-04-13 18:01:32 -0700204#if SUPPORT_LEGACY_QEMUD
205typedef enum {
206 QEMUD_VERSION_UNKNOWN,
207 QEMUD_VERSION_LEGACY,
208 QEMUD_VERSION_NORMAL
209} QemudVersion;
210
211# define LEGACY_LENGTH_OFFSET 0
212# define LEGACY_CHANNEL_OFFSET 4
213#endif
214
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700215/* length of the framed header */
216#define FRAME_HEADER_SIZE 4
217
218#define BUFFER_SIZE MAX_SERIAL_PAYLOAD
219
220/* out of convenience, the incoming message is zero-terminated
221 * and can be modified by the receiver (e.g. for tokenization).
222 */
223typedef void (*QemudSerialReceive)( void* opaque, int channel, uint8_t* msg, int msglen);
224
225typedef struct QemudSerial {
226 CharDriverState* cs; /* serial charpipe endpoint */
227
228 /* managing incoming packets from the serial port */
229 ABool need_header;
230 int overflow;
231 int in_size;
232 int in_channel;
David Turner791d8612009-04-13 18:01:32 -0700233#if SUPPORT_LEGACY_QEMUD
234 QemudVersion version;
235#endif
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700236 QemudSink header[1];
237 QemudSink payload[1];
238 uint8_t data0[MAX_SERIAL_PAYLOAD+1];
239
240 /* receiver */
241 QemudSerialReceive recv_func; /* receiver callback */
242 void* recv_opaque; /* receiver user-specific data */
243} QemudSerial;
244
245
Ot ten Thije871da2a2010-09-20 10:29:22 +0100246/* Save the state of a QemudSerial to a snapshot file.
247 */
248static void
249qemud_serial_save(QEMUFile* f, QemudSerial* s)
250{
251 /* cs, recv_func and recv_opaque are not saved, as these are assigned only
252 * during emulator init. A load within a session can re-use the values
253 * already assigned, a newly launched emulator has freshly assigned values.
254 */
255
256 /* state of incoming packets from the serial port */
257 qemu_put_be32(f, s->need_header);
258 qemu_put_be32(f, s->overflow);
259 qemu_put_be32(f, s->in_size);
260 qemu_put_be32(f, s->in_channel);
261#if SUPPORT_LEGACY_QEMUD
262 qemu_put_be32(f, s->version);
263#endif
264 qemud_sink_save(f, s->header);
265 qemud_sink_save(f, s->payload);
266 qemu_put_be32(f, MAX_SERIAL_PAYLOAD+1);
267 qemu_put_buffer(f, s->data0, MAX_SERIAL_PAYLOAD+1);
268}
269
270/* Load the state of a QemudSerial from a snapshot file.
271 */
272static int
273qemud_serial_load(QEMUFile* f, QemudSerial* s)
274{
275 /* state of incoming packets from the serial port */
276 s->need_header = qemu_get_be32(f);
277 s->overflow = qemu_get_be32(f);
278 s->in_size = qemu_get_be32(f);
279 s->in_channel = qemu_get_be32(f);
280#if SUPPORT_LEGACY_QEMUD
281 s->version = qemu_get_be32(f);
282#endif
283 qemud_sink_load(f, s->header);
284 qemud_sink_load(f, s->payload);
285
286 /* s->header and s->payload are only ever connected to s->data0 */
287 s->header->buff = s->payload->buff = s->data0;
288
289 int len = qemu_get_be32(f);
290 if (len - 1 > MAX_SERIAL_PAYLOAD) {
291 D("%s: load failed: size of saved payload buffer (%d) exceeds "
292 "current maximum (%d)\n",
293 __FUNCTION__, len - 1, MAX_SERIAL_PAYLOAD);
294 return -EIO;
295 }
296 int ret;
297 if ((ret = qemu_get_buffer(f, s->data0, len)) != len) {
298 D("%s: failed to load serial buffer contents (tried reading %d bytes, got %d)\n",
299 __FUNCTION__, len, ret);
300 return -EIO;
301 }
302
303 return 0;
304}
305
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700306/* called by the charpipe to see how much bytes can be
307 * read from the serial port.
308 */
309static int
310qemud_serial_can_read( void* opaque )
311{
312 QemudSerial* s = opaque;
313
314 if (s->overflow > 0) {
315 return s->overflow;
316 }
317
318 /* if in_size is 0, we're reading the header */
319 if (s->need_header)
320 return qemud_sink_needed(s->header);
321
322 /* otherwise, we're reading the payload */
323 return qemud_sink_needed(s->payload);
324}
325
326/* called by the charpipe to read data from the serial
327 * port. 'len' cannot be more than the value returned
328 * by 'qemud_serial_can_read'.
329 */
330static void
331qemud_serial_read( void* opaque, const uint8_t* from, int len )
332{
333 QemudSerial* s = opaque;
334
335 T("%s: received %3d bytes: '%s'", __FUNCTION__, len, quote_bytes((const void*)from, len));
336
337 while (len > 0) {
338 int avail;
339
340 /* skip overflow bytes */
341 if (s->overflow > 0) {
342 avail = s->overflow;
343 if (avail > len)
344 avail = len;
345
346 from += avail;
347 len -= avail;
348 continue;
349 }
350
351 /* read header if needed */
352 if (s->need_header) {
353 if (!qemud_sink_fill(s->header, (const uint8_t**)&from, &len))
354 break;
355
David Turner791d8612009-04-13 18:01:32 -0700356#if SUPPORT_LEGACY_QEMUD
357 if (s->version == QEMUD_VERSION_UNKNOWN) {
358 /* if we receive "001200" as the first header, then we
359 * detected a legacy qemud daemon. See the comments
360 * in qemud_serial_send_legacy_probe() for details.
361 */
362 if ( !memcmp(s->data0, "001200", 6) ) {
363 D("%s: legacy qemud detected.", __FUNCTION__);
364 s->version = QEMUD_VERSION_LEGACY;
David Turnerfbcbf422009-04-15 06:50:16 -0700365 /* tell the modem to use legacy emulation mode */
366 amodem_set_legacy(android_modem);
David Turner791d8612009-04-13 18:01:32 -0700367 } else {
368 D("%s: normal qemud detected.", __FUNCTION__);
369 s->version = QEMUD_VERSION_NORMAL;
370 }
371 }
372
373 if (s->version == QEMUD_VERSION_LEGACY) {
374 s->in_size = hex2int( s->data0 + LEGACY_LENGTH_OFFSET, LENGTH_SIZE );
375 s->in_channel = hex2int( s->data0 + LEGACY_CHANNEL_OFFSET, CHANNEL_SIZE );
376 } else {
377 s->in_size = hex2int( s->data0 + LENGTH_OFFSET, LENGTH_SIZE );
378 s->in_channel = hex2int( s->data0 + CHANNEL_OFFSET, CHANNEL_SIZE );
379 }
380#else
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700381 /* extract payload length + channel id */
382 s->in_size = hex2int( s->data0 + LENGTH_OFFSET, LENGTH_SIZE );
383 s->in_channel = hex2int( s->data0 + CHANNEL_OFFSET, CHANNEL_SIZE );
David Turner791d8612009-04-13 18:01:32 -0700384#endif
Ot ten Thije871da2a2010-09-20 10:29:22 +0100385 s->header->used = 0;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700386
387 if (s->in_size <= 0 || s->in_channel < 0) {
388 D("%s: bad header: '%.*s'", __FUNCTION__, HEADER_SIZE, s->data0);
389 continue;
390 }
391
392 if (s->in_size > MAX_SERIAL_PAYLOAD) {
393 D("%s: ignoring huge serial packet: length=%d channel=%1",
394 __FUNCTION__, s->in_size, s->in_channel);
395 s->overflow = s->in_size;
396 continue;
397 }
398
399 /* prepare 'in_data' for payload */
400 s->need_header = 0;
401 qemud_sink_reset(s->payload, s->in_size, s->data0);
402 }
403
404 /* read payload bytes */
405 if (!qemud_sink_fill(s->payload, &from, &len))
406 break;
407
408 /* zero-terminate payload, then send it to receiver */
409 s->payload->buff[s->payload->size] = 0;
410 D("%s: channel=%2d len=%3d '%s'", __FUNCTION__,
411 s->in_channel, s->payload->size,
412 quote_bytes((const void*)s->payload->buff, s->payload->size));
413
414 s->recv_func( s->recv_opaque, s->in_channel, s->payload->buff, s->payload->size );
415
416 /* prepare for new header */
417 s->need_header = 1;
418 }
419}
420
David Turner791d8612009-04-13 18:01:32 -0700421
422#if SUPPORT_LEGACY_QEMUD
423static void
424qemud_serial_send_legacy_probe( QemudSerial* s )
425{
426 /* we're going to send a specially crafted packet to the qemud
427 * daemon, this will help us determine whether we're talking
428 * to a legacy or a normal daemon.
429 *
430 * the trick is to known that a legacy daemon uses the following
431 * header:
432 *
433 * <length><channel><payload>
434 *
435 * while the normal one uses:
436 *
437 * <channel><length><payload>
438 *
439 * where <channel> is a 2-hexchar string, and <length> a 4-hexchar
440 * string.
441 *
442 * if we send a header of "000100", it is interpreted:
443 *
444 * - as the header of a 1-byte payload by the legacy daemon
445 * - as the header of a 256-byte payload by the normal one.
446 *
447 * we're going to send something that looks like:
448 *
449 * "000100" + "X" +
450 * "000b00" + "connect:gsm" +
451 * "000b00" + "connect:gps" +
452 * "000f00" + "connect:control" +
453 * "00c210" + "0"*194
454 *
455 * the normal daemon will interpret this as a 256-byte payload
456 * for channel 0, with garbage content ("X000b00conn...") which
457 * will be silently ignored.
458 *
459 * on the other hand, the legacy daemon will see it as a
460 * series of packets:
461 *
462 * one message "X" on channel 0, which will force the daemon
463 * to send back "001200ko:unknown command" as its first answer.
464 *
465 * three "connect:<xxx>" messages used to receive the channel
466 * numbers of the three legacy services implemented by the daemon.
467 *
468 * a garbage packet of 194 zeroes for channel 16, which will be
469 * silently ignored.
470 */
471 uint8_t tab[194];
472
473 memset(tab, 0, sizeof(tab));
474 qemu_chr_write(s->cs, (uint8_t*)"000100X", 7);
475 qemu_chr_write(s->cs, (uint8_t*)"000b00connect:gsm", 17);
476 qemu_chr_write(s->cs, (uint8_t*)"000b00connect:gps", 17);
477 qemu_chr_write(s->cs, (uint8_t*)"000f00connect:control", 21);
478 qemu_chr_write(s->cs, (uint8_t*)"00c210", 6);
479 qemu_chr_write(s->cs, tab, sizeof(tab));
480}
481#endif /* SUPPORT_LEGACY_QEMUD */
482
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700483/* intialize a QemudSerial object with a charpipe endpoint
484 * and a receiver.
485 */
486static void
487qemud_serial_init( QemudSerial* s,
488 CharDriverState* cs,
489 QemudSerialReceive recv_func,
490 void* recv_opaque )
491{
492 s->cs = cs;
493 s->recv_func = recv_func;
494 s->recv_opaque = recv_opaque;
495 s->need_header = 1;
496 s->overflow = 0;
497
498 qemud_sink_reset( s->header, HEADER_SIZE, s->data0 );
499 s->in_size = 0;
500 s->in_channel = -1;
501
David Turner791d8612009-04-13 18:01:32 -0700502#if SUPPORT_LEGACY_QEMUD
503 s->version = QEMUD_VERSION_UNKNOWN;
504 qemud_serial_send_legacy_probe(s);
505#endif
506
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700507 qemu_chr_add_handlers( cs,
508 qemud_serial_can_read,
509 qemud_serial_read,
510 NULL,
511 s );
512}
513
514/* send a message to the serial port. This will add the necessary
515 * header.
516 */
517static void
518qemud_serial_send( QemudSerial* s,
519 int channel,
520 ABool framing,
521 const uint8_t* msg,
522 int msglen )
523{
524 uint8_t header[HEADER_SIZE];
525 uint8_t frame[FRAME_HEADER_SIZE];
526 int avail, len = msglen;
527
528 if (msglen <= 0 || channel < 0)
529 return;
530
531 D("%s: channel=%2d len=%3d '%s'",
532 __FUNCTION__, channel, msglen,
533 quote_bytes((const void*)msg, msglen));
534
535 if (framing) {
536 len += FRAME_HEADER_SIZE;
537 }
538
539 /* packetize the payload for the serial MTU */
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100540 while (len > 0)
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700541 {
542 avail = len;
543 if (avail > MAX_SERIAL_PAYLOAD)
544 avail = MAX_SERIAL_PAYLOAD;
545
546 /* write this packet's header */
David Turner791d8612009-04-13 18:01:32 -0700547#if SUPPORT_LEGACY_QEMUD
548 if (s->version == QEMUD_VERSION_LEGACY) {
549 int2hex(header + LEGACY_LENGTH_OFFSET, LENGTH_SIZE, avail);
550 int2hex(header + LEGACY_CHANNEL_OFFSET, CHANNEL_SIZE, channel);
551 } else {
552 int2hex(header + LENGTH_OFFSET, LENGTH_SIZE, avail);
553 int2hex(header + CHANNEL_OFFSET, CHANNEL_SIZE, channel);
554 }
555#else
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700556 int2hex(header + LENGTH_OFFSET, LENGTH_SIZE, avail);
557 int2hex(header + CHANNEL_OFFSET, CHANNEL_SIZE, channel);
David Turner791d8612009-04-13 18:01:32 -0700558#endif
559 T("%s: '%.*s'", __FUNCTION__, HEADER_SIZE, header);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700560 qemu_chr_write(s->cs, header, HEADER_SIZE);
561
562 /* insert frame header when needed */
563 if (framing) {
564 int2hex(frame, FRAME_HEADER_SIZE, msglen);
David Turner791d8612009-04-13 18:01:32 -0700565 T("%s: '%.*s'", __FUNCTION__, FRAME_HEADER_SIZE, frame);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700566 qemu_chr_write(s->cs, frame, FRAME_HEADER_SIZE);
567 avail -= FRAME_HEADER_SIZE;
568 len -= FRAME_HEADER_SIZE;
569 framing = 0;
570 }
571
572 /* write message content */
David Turner791d8612009-04-13 18:01:32 -0700573 T("%s: '%.*s'", __FUNCTION__, avail, msg);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700574 qemu_chr_write(s->cs, msg, avail);
575 msg += avail;
576 len -= avail;
577 }
578}
579
580/** CLIENTS
581 **/
582
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700583/* Descriptor for a data buffer pending to be sent to a qemud pipe client.
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700584 *
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700585 * When a service decides to send data to the client, there could be cases when
586 * client is not ready to read them. In this case there is no GoldfishPipeBuffer
587 * available to write service's data to, So, we need to cache that data into the
588 * client descriptor, and "send" them over to the client in _qemudPipe_recvBuffers
589 * callback. Pending service data is stored in the client descriptor as a list
590 * of QemudPipeMessage instances.
591 */
592typedef struct QemudPipeMessage QemudPipeMessage;
593struct QemudPipeMessage {
594 /* Message to send. */
595 uint8_t* message;
596 /* Message size. */
597 size_t size;
598 /* Offset in the message buffer of the chunk, that has not been sent
599 * to the pipe yet. */
600 size_t offset;
601 /* Links next message in the client. */
602 QemudPipeMessage* next;
603};
604
605
606/* A QemudClient models a single client as seen by the emulator.
607 * Each client has its own channel id (for the serial qemud), or pipe descriptor
608 * (for the pipe based qemud), and belongs to a given QemudService (see below).
609 *
610 * There is a global list of serial clients used to multiplex incoming
611 * messages from the channel id (see qemud_multiplexer_serial_recv()). Pipe
612 * clients don't need multiplexing, because they are communicated via qemud pipes
613 * that are unique for each client.
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700614 *
615 */
616
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700617/* Defines type of the client: pipe, or serial.
618 */
619typedef enum QemudProtocol {
620 /* Client is communicating via pipe. */
621 QEMUD_PROTOCOL_PIPE,
622 /* Client is communicating via serial port. */
623 QEMUD_PROTOCOL_SERIAL
624} QemudProtocol;
625
Vladimir Chtchetkine59385322011-08-18 15:53:48 -0700626/* Descriptor for a QEMUD pipe connection.
627 *
628 * Every time a client connects to the QEMUD via pipe, an instance of this
629 * structure is created to represent a connection used by new pipe client.
630 */
631typedef struct QemudPipe {
632 /* Pipe descriptor. */
633 void* hwpipe;
634 /* Looper used for I/O */
635 void* looper;
636 /* Service for this pipe. */
637 QemudService* service;
638 /* Client for this pipe. */
639 QemudClient* client;
640} QemudPipe;
641
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700642struct QemudClient {
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700643 /* Defines protocol, used by the client. */
644 QemudProtocol protocol;
645
646 /* Fields that are common for all protocols. */
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700647 char* param;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700648 void* clie_opaque;
649 QemudClientRecv clie_recv;
650 QemudClientClose clie_close;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100651 QemudClientSave clie_save;
652 QemudClientLoad clie_load;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700653 QemudService* service;
654 QemudClient* next_serv; /* next in same service */
655 QemudClient* next;
656 QemudClient** pref;
657
658 /* framing support */
659 int framing;
660 ABool need_header;
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100661 ABool closing;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700662 QemudSink header[1];
663 uint8_t header0[FRAME_HEADER_SIZE];
664 QemudSink payload[1];
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700665
666 /* Fields that are protocol-specific. */
667 union {
668 /* Serial-specific fields. */
669 struct {
670 int channel;
671 QemudSerial* serial;
672 } Serial;
673 /* Pipe-specific fields. */
674 struct {
Vladimir Chtchetkine59385322011-08-18 15:53:48 -0700675 QemudPipe* qemud_pipe;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700676 QemudPipeMessage* messages;
677 } Pipe;
678 } ProtocolSelector;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700679};
680
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700681static ABool
682_is_pipe_client(QemudClient* client)
683{
684 return (client-> protocol == QEMUD_PROTOCOL_PIPE) ? true : false;
685}
686
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700687static void qemud_service_remove_client( QemudService* service,
688 QemudClient* client );
689
690/* remove a QemudClient from global list */
691static void
692qemud_client_remove( QemudClient* c )
693{
694 c->pref[0] = c->next;
695 if (c->next)
696 c->next->pref = c->pref;
697
698 c->next = NULL;
699 c->pref = &c->next;
700}
701
702/* add a QemudClient to global list */
703static void
704qemud_client_prepend( QemudClient* c, QemudClient** plist )
705{
706 c->next = *plist;
707 c->pref = plist;
708 *plist = c;
709 if (c->next)
710 c->next->pref = &c->next;
711}
712
713/* receive a new message from a client, and dispatch it to
714 * the real service implementation.
715 */
716static void
717qemud_client_recv( void* opaque, uint8_t* msg, int msglen )
718{
719 QemudClient* c = opaque;
720
721 /* no framing, things are simple */
722 if (!c->framing) {
723 if (c->clie_recv)
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200724 c->clie_recv( c->clie_opaque, msg, msglen, c );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700725 return;
726 }
727
728 /* framing */
729
730#if 1
731 /* special case, in 99% of cases, everything is in
732 * the incoming message, and we can do all we need
733 * directly without dynamic allocation.
734 */
735 if (msglen > FRAME_HEADER_SIZE &&
736 c->need_header == 1 &&
737 qemud_sink_needed(c->header) == 0)
738 {
739 int len = hex2int( msg, FRAME_HEADER_SIZE );
740
741 if (len >= 0 && msglen == len + FRAME_HEADER_SIZE) {
742 if (c->clie_recv)
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100743 c->clie_recv( c->clie_opaque,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700744 msg+FRAME_HEADER_SIZE,
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200745 msglen-FRAME_HEADER_SIZE, c );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700746 return;
747 }
748 }
749#endif
750
751 while (msglen > 0) {
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700752 uint8_t *data;
753
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700754 /* read the header */
755 if (c->need_header) {
756 int frame_size;
757 uint8_t* data;
758
759 if (!qemud_sink_fill(c->header, (const uint8_t**)&msg, &msglen))
760 break;
761
762 frame_size = hex2int(c->header0, 4);
763 if (frame_size == 0) {
764 D("%s: ignoring empty frame", __FUNCTION__);
765 continue;
766 }
767 if (frame_size < 0) {
768 D("%s: ignoring corrupted frame header '.*s'",
769 __FUNCTION__, FRAME_HEADER_SIZE, c->header0 );
770 continue;
771 }
772
773 AARRAY_NEW(data, frame_size+1); /* +1 for terminating zero */
774 qemud_sink_reset(c->payload, frame_size, data);
775 c->need_header = 0;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100776 c->header->used = 0;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700777 }
778
779 /* read the payload */
780 if (!qemud_sink_fill(c->payload, (const uint8_t**)&msg, &msglen))
781 break;
782
783 c->payload->buff[c->payload->size] = 0;
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700784 c->need_header = 1;
785 data = c->payload->buff;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700786
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700787 /* Technically, calling 'clie_recv' can destroy client object 'c'
788 * if it decides to close the connection, so ensure we don't
789 * use/dereference it after the call. */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700790 if (c->clie_recv)
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200791 c->clie_recv( c->clie_opaque, c->payload->buff, c->payload->size, c );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700792
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700793 AFREE(data);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700794 }
795}
796
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700797/* Sends data to a pipe-based client.
798 */
799static void
800_qemud_pipe_send(QemudClient* client, const uint8_t* msg, int msglen);
801
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700802/* Frees memory allocated for the qemud client.
803 */
804static void
805_qemud_client_free(QemudClient* c)
806{
807 if ( c != NULL) {
808 if (_is_pipe_client(c)) {
809 /* Free outstanding messages. */
810 QemudPipeMessage** msg_list = &c->ProtocolSelector.Pipe.messages;
811 while (*msg_list != NULL) {
812 QemudPipeMessage* to_free = *msg_list;
813 *msg_list = to_free->next;
814 free(to_free);
815 }
816 }
817 if (c->param != NULL) {
818 free(c->param);
819 }
820 AFREE(c);
821 }
822}
823
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700824/* disconnect a client. this automatically frees the QemudClient.
825 * note that this also removes the client from the global list
826 * and from its service's list, if any.
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -0800827 * Param:
828 * opaque - QemuClient instance
829 * guest_close - For pipe clients control whether or not the disconnect is
830 * caused by guest closing the pipe handle (in which case 1 is passed in
831 * this parameter). For serial clients this parameter is ignored.
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700832 */
833static void
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -0800834qemud_client_disconnect( void* opaque, int guest_close )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700835{
836 QemudClient* c = opaque;
837
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100838 if (c->closing) { /* recursive call, exit immediately */
839 return;
840 }
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -0800841
842 if (_is_pipe_client(c) && !guest_close) {
843 /* This is emulator component (rather than the guest) closing a pipe
844 * client. Since pipe clients are controlled strictly by the guest, we
845 * don't actually close the client here, but notify the guest about the
846 * client being disconnected. Then we will do the real client close when
847 * the guest explicitly closes the pipe, in which case this routine will
848 * be called from the _qemudPipe_closeFromGuest callback with guest_close
849 * set to 1. */
850 char tmp[128], *p=tmp, *end=p+sizeof(tmp);
851 p = bufprint(tmp, end, "disconnect:00");
852 _qemud_pipe_send(c, (uint8_t*)tmp, p-tmp);
853 return;
854 }
855
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100856 c->closing = 1;
857
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700858 /* remove from current list */
859 qemud_client_remove(c);
860
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700861 if (_is_pipe_client(c)) {
Vladimir Chtchetkine59385322011-08-18 15:53:48 -0700862 /* We must NULL the client reference in the QemuPipe for this connection,
863 * so if a sudden receive request comes after client has been closed, we
864 * don't blow up. */
865 c->ProtocolSelector.Pipe.qemud_pipe->client = NULL;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700866 } else if (c->ProtocolSelector.Serial.channel > 0) {
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -0800867 /* send a disconnect command to the daemon */
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700868 char tmp[128], *p=tmp, *end=p+sizeof(tmp);
869 p = bufprint(tmp, end, "disconnect:%02x",
870 c->ProtocolSelector.Serial.channel);
871 qemud_serial_send(c->ProtocolSelector.Serial.serial, 0, 0, (uint8_t*)tmp, p-tmp);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700872 }
873
874 /* call the client close callback */
875 if (c->clie_close) {
876 c->clie_close(c->clie_opaque);
877 c->clie_close = NULL;
878 }
879 c->clie_recv = NULL;
880
881 /* remove from service list, if any */
882 if (c->service) {
883 qemud_service_remove_client(c->service, c);
884 c->service = NULL;
885 }
886
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700887 _qemud_client_free(c);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700888}
889
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700890/* allocate a new QemudClient object
891 * NOTE: channel_id valie is used as a selector between serial and pipe clients.
892 * Since channel_id < 0 is an invalid value for a serial client, it would
893 * indicate that creating client is a pipe client. */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700894static QemudClient*
895qemud_client_alloc( int channel_id,
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700896 const char* client_param,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700897 void* clie_opaque,
898 QemudClientRecv clie_recv,
899 QemudClientClose clie_close,
Ot ten Thije871da2a2010-09-20 10:29:22 +0100900 QemudClientSave clie_save,
901 QemudClientLoad clie_load,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700902 QemudSerial* serial,
903 QemudClient** pclients )
904{
905 QemudClient* c;
906
907 ANEW0(c);
908
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700909 if (channel_id < 0) {
910 /* Allocating a pipe client. */
911 c->protocol = QEMUD_PROTOCOL_PIPE;
912 c->ProtocolSelector.Pipe.messages = NULL;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -0700913 c->ProtocolSelector.Pipe.qemud_pipe = NULL;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700914 } else {
915 /* Allocating a serial client. */
916 c->protocol = QEMUD_PROTOCOL_SERIAL;
917 c->ProtocolSelector.Serial.serial = serial;
918 c->ProtocolSelector.Serial.channel = channel_id;
919 }
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700920 c->param = client_param ? ASTRDUP(client_param) : NULL;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700921 c->clie_opaque = clie_opaque;
922 c->clie_recv = clie_recv;
923 c->clie_close = clie_close;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100924 c->clie_save = clie_save;
925 c->clie_load = clie_load;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -0700926 c->service = NULL;
927 c->next_serv = NULL;
928 c->next = NULL;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700929 c->framing = 0;
930 c->need_header = 1;
931 qemud_sink_reset(c->header, FRAME_HEADER_SIZE, c->header0);
932
933 qemud_client_prepend(c, pclients);
934
935 return c;
936}
937
Ot ten Thije871da2a2010-09-20 10:29:22 +0100938/* forward */
939static void qemud_service_save_name( QEMUFile* f, QemudService* s );
940static char* qemud_service_load_name( QEMUFile* f );
941static QemudService* qemud_service_find( QemudService* service_list,
942 const char* service_name );
943static QemudClient* qemud_service_connect_client( QemudService *sv,
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -0700944 int channel_id,
945 const char* client_param);
Ot ten Thije871da2a2010-09-20 10:29:22 +0100946
947/* Saves the client state needed to re-establish connections on load.
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200948 * Note that we save only serial clients here. The pipe clients will be
949 * saved along with the pipe to which they are attached.
Ot ten Thije871da2a2010-09-20 10:29:22 +0100950 */
951static void
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200952qemud_serial_client_save(QEMUFile* f, QemudClient* c)
Ot ten Thije871da2a2010-09-20 10:29:22 +0100953{
954 /* save generic information */
955 qemud_service_save_name(f, c->service);
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200956 qemu_put_string(f, c->param);
957 qemu_put_be32(f, c->ProtocolSelector.Serial.channel);
Ot ten Thije871da2a2010-09-20 10:29:22 +0100958
959 /* save client-specific state */
960 if (c->clie_save)
961 c->clie_save(f, c, c->clie_opaque);
962
963 /* save framing configuration */
964 qemu_put_be32(f, c->framing);
965 if (c->framing) {
966 qemu_put_be32(f, c->need_header);
967 /* header sink always connected to c->header0, no need to save */
968 qemu_put_be32(f, FRAME_HEADER_SIZE);
969 qemu_put_buffer(f, c->header0, FRAME_HEADER_SIZE);
970 /* payload sink */
971 qemud_sink_save(f, c->payload);
972 qemu_put_buffer(f, c->payload->buff, c->payload->size);
973 }
974}
975
976/* Loads client state from file, then starts a new client connected to the
977 * corresponding service.
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200978 * Note that we load only serial clients here. The pipe clients will be
979 * loaded along with the pipe to which they were attached.
Ot ten Thije871da2a2010-09-20 10:29:22 +0100980 */
981static int
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200982qemud_serial_client_load(QEMUFile* f, QemudService* current_services, int version )
Ot ten Thije871da2a2010-09-20 10:29:22 +0100983{
984 char *service_name = qemud_service_load_name(f);
985 if (service_name == NULL)
986 return -EIO;
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200987 char* param = qemu_get_string(f);
Ot ten Thije871da2a2010-09-20 10:29:22 +0100988 /* get current service instance */
989 QemudService *sv = qemud_service_find(current_services, service_name);
990 if (sv == NULL) {
991 D("%s: load failed: unknown service \"%s\"\n",
992 __FUNCTION__, service_name);
993 return -EIO;
994 }
995
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +0200996 int channel = qemu_get_be32(f);
Vladimir Chtchetkined0e28722011-10-05 14:25:07 -0700997
Ot ten Thije871da2a2010-09-20 10:29:22 +0100998 if (channel == 0) {
999 D("%s: illegal snapshot: client for control channel must no be saved\n",
1000 __FUNCTION__);
1001 return -EIO;
1002 }
1003
1004 /* re-connect client */
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001005 QemudClient* c = qemud_service_connect_client(sv, channel, param);
Ot ten Thije871da2a2010-09-20 10:29:22 +01001006 if(c == NULL)
1007 return -EIO;
1008
1009 /* load client-specific state */
1010 int ret;
1011 if (c->clie_load)
1012 if ((ret = c->clie_load(f, c, c->clie_opaque)))
1013 return ret; /* load failure */
1014
1015 /* load framing configuration */
1016 c->framing = qemu_get_be32(f);
1017 if (c->framing) {
1018
1019 /* header buffer */
1020 c->need_header = qemu_get_be32(f);
1021 int header_size = qemu_get_be32(f);
1022 if (header_size > FRAME_HEADER_SIZE) {
1023 D("%s: load failed: payload buffer requires %d bytes, %d available\n",
1024 __FUNCTION__, header_size, FRAME_HEADER_SIZE);
1025 return -EIO;
1026 }
1027 int ret;
1028 if ((ret = qemu_get_buffer(f, c->header0, header_size)) != header_size) {
1029 D("%s: frame header buffer load failed: expected %d bytes, got %d\n",
1030 __FUNCTION__, header_size, ret);
1031 return -EIO;
1032 }
1033
1034 /* payload sink */
1035 if ((ret = qemud_sink_load(f, c->payload)))
1036 return ret;
1037
1038 /* replace payload buffer by saved data */
1039 if (c->payload->buff) {
1040 AFREE(c->payload->buff);
1041 }
1042 AARRAY_NEW(c->payload->buff, c->payload->size+1); /* +1 for terminating zero */
1043 if ((ret = qemu_get_buffer(f, c->payload->buff, c->payload->size)) != c->payload->size) {
1044 D("%s: frame payload buffer load failed: expected %d bytes, got %d\n",
1045 __FUNCTION__, c->payload->size, ret);
1046 AFREE(c->payload->buff);
1047 return -EIO;
1048 }
1049 }
1050
1051 return 0;
1052}
1053
1054
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001055/** SERVICES
1056 **/
1057
1058/* A QemudService models a _named_ service facility implemented
1059 * by the emulator, that clients in the emulated system can connect
1060 * to.
1061 *
1062 * Each service can have a limit on the number of clients they
1063 * accept (this number if unlimited if 'max_clients' is 0).
1064 *
1065 * Each service maintains a list of active QemudClients and
1066 * can also be used to create new QemudClient objects through
1067 * its 'serv_opaque' and 'serv_connect' fields.
1068 */
1069struct QemudService {
1070 const char* name;
1071 int max_clients;
1072 int num_clients;
1073 QemudClient* clients;
1074 QemudServiceConnect serv_connect;
Ot ten Thije871da2a2010-09-20 10:29:22 +01001075 QemudServiceSave serv_save;
1076 QemudServiceLoad serv_load;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001077 void* serv_opaque;
1078 QemudService* next;
1079};
1080
1081/* Create a new QemudService object */
1082static QemudService*
1083qemud_service_new( const char* name,
1084 int max_clients,
1085 void* serv_opaque,
1086 QemudServiceConnect serv_connect,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001087 QemudServiceSave serv_save,
1088 QemudServiceLoad serv_load,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001089 QemudService** pservices )
1090{
1091 QemudService* s;
1092
1093 ANEW0(s);
1094 s->name = ASTRDUP(name);
1095 s->max_clients = max_clients;
1096 s->num_clients = 0;
1097 s->clients = NULL;
1098
1099 s->serv_opaque = serv_opaque;
1100 s->serv_connect = serv_connect;
Ot ten Thije871da2a2010-09-20 10:29:22 +01001101 s->serv_save = serv_save;
1102 s->serv_load = serv_load;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001103
1104 s->next = *pservices;
1105 *pservices = s;
1106
1107 return s;
1108}
1109
1110/* used internally to populate a QemudService object with a
1111 * new QemudClient */
1112static void
1113qemud_service_add_client( QemudService* s, QemudClient* c )
1114{
1115 c->service = s;
1116 c->next_serv = s->clients;
1117 s->clients = c;
1118 s->num_clients += 1;
1119}
1120
1121/* used internally to remove a QemudClient from a QemudService */
1122static void
1123qemud_service_remove_client( QemudService* s, QemudClient* c )
1124{
1125 QemudClient** pnode = &s->clients;
1126 QemudClient* node;
1127
1128 /* remove from clients linked-list */
1129 for (;;) {
1130 node = *pnode;
1131 if (node == NULL) {
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001132 D("%s: could not find client for service '%s'",
1133 __FUNCTION__, s->name);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001134 return;
1135 }
1136 if (node == c)
1137 break;
1138 pnode = &node->next_serv;
1139 }
1140
1141 *pnode = node->next_serv;
1142 s->num_clients -= 1;
1143}
1144
Ot ten Thije871da2a2010-09-20 10:29:22 +01001145/* ask the service to create a new QemudClient. Note that we
1146 * assume that this calls qemud_client_new() which will add
1147 * the client to the service's list automatically.
1148 *
1149 * returns the client or NULL if an error occurred
1150 */
1151static QemudClient*
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001152qemud_service_connect_client(QemudService *sv,
1153 int channel_id,
1154 const char* client_param)
Ot ten Thije871da2a2010-09-20 10:29:22 +01001155{
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001156 QemudClient* client =
1157 sv->serv_connect( sv->serv_opaque, sv, channel_id, client_param );
Ot ten Thije871da2a2010-09-20 10:29:22 +01001158 if (client == NULL) {
1159 D("%s: registration failed for '%s' service",
1160 __FUNCTION__, sv->name);
1161 return NULL;
1162 }
Ot ten Thije871da2a2010-09-20 10:29:22 +01001163 D("%s: registered client channel %d for '%s' service",
1164 __FUNCTION__, channel_id, sv->name);
1165 return client;
1166}
1167
1168/* find a registered service by name.
1169 */
1170static QemudService*
1171qemud_service_find( QemudService* service_list, const char* service_name)
1172{
1173 QemudService* sv = NULL;
1174 for (sv = service_list; sv != NULL; sv = sv->next) {
1175 if (!strcmp(sv->name, service_name)) {
1176 break;
1177 }
1178 }
1179 return sv;
1180}
1181
1182/* Save the name of the given service.
1183 */
1184static void
1185qemud_service_save_name(QEMUFile* f, QemudService* s)
1186{
1187 int len = strlen(s->name) + 1; // include '\0' terminator
1188 qemu_put_be32(f, len);
1189 qemu_put_buffer(f, (const uint8_t *) s->name, len);
1190}
1191
1192/* Load the name of a service. Returns a pointer to the loaded name, or NULL
1193 * on failure.
1194 */
1195static char*
1196qemud_service_load_name( QEMUFile* f )
1197{
1198 int ret;
1199 int name_len = qemu_get_be32(f);
1200 char *service_name = android_alloc(name_len);
1201 if ((ret = qemu_get_buffer(f, (uint8_t*)service_name, name_len) != name_len)) {
1202 D("%s: service name load failed: expected %d bytes, got %d\n",
1203 __FUNCTION__, name_len, ret);
1204 AFREE(service_name);
1205 return NULL;
1206 }
1207 if (service_name[name_len - 1] != '\0') {
1208 char last = service_name[name_len - 1];
1209 service_name[name_len - 1] = '\0'; /* make buffer contents printable */
1210 D("%s: service name load failed: expecting NULL-terminated string, but "
1211 "last char is '%c' (buffer contents: '%s%c')\n",
1212 __FUNCTION__, name_len, last, service_name, last);
1213 AFREE(service_name);
1214 return NULL;
1215 }
1216
1217 return service_name;
1218}
1219
1220/* Saves state of a service.
1221 */
1222static void
1223qemud_service_save(QEMUFile* f, QemudService* s)
1224{
1225 qemud_service_save_name(f, s);
1226 qemu_put_be32(f, s->max_clients);
1227 qemu_put_be32(f, s->num_clients);
1228
1229 if (s->serv_save)
1230 s->serv_save(f, s, s->serv_opaque);
1231}
1232
1233/* Loads service state from file, then updates the currently running instance
1234 * of that service to mirror the loaded state. If the service is not running,
1235 * the load process is aborted.
1236 *
1237 * Parameter 'current_services' should be the list of active services.
1238 */
1239static int
1240qemud_service_load( QEMUFile* f, QemudService* current_services )
1241{
1242 char* service_name = qemud_service_load_name(f);
1243 if (service_name == NULL)
1244 return -EIO;
1245
1246 /* get current service instance */
1247 QemudService *sv = qemud_service_find(current_services, service_name);
1248 if (sv == NULL) {
1249 D("%s: loading failed: service \"%s\" not available\n",
1250 __FUNCTION__, service_name);
1251 return -EIO;
1252 }
1253
1254 /* reconfigure service as required */
1255 sv->max_clients = qemu_get_be32(f);
1256 sv->num_clients = qemu_get_be32(f);
1257
1258 /* load service specific data */
1259 int ret;
1260 if (sv->serv_load)
1261 if ((ret = sv->serv_load(f, sv, sv->serv_opaque)))
1262 return ret; /* load failure */
1263
1264 return 0;
1265}
1266
1267
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001268/** MULTIPLEXER
1269 **/
1270
1271/* A QemudMultiplexer object maintains the global state of the
1272 * qemud service facility. It holds a QemudSerial object to
1273 * maintain the state of the serial port connection.
1274 *
1275 * The QemudMultiplexer receives all incoming messages from
1276 * the serial port, and dispatches them to the appropriate
1277 * QemudClient.
1278 *
1279 * It also has a global list of clients, and a global list of
1280 * services.
1281 *
1282 * Finally, the QemudMultiplexer has a special QemudClient used
1283 * to handle channel 0, i.e. the control channel used to handle
1284 * connections and disconnections of clients.
1285 */
1286typedef struct QemudMultiplexer QemudMultiplexer;
1287
1288struct QemudMultiplexer {
1289 QemudSerial serial[1];
1290 QemudClient* clients;
1291 QemudService* services;
1292};
1293
1294/* this is the serial_recv callback that is called
1295 * whenever an incoming message arrives through the serial port
1296 */
1297static void
1298qemud_multiplexer_serial_recv( void* opaque,
1299 int channel,
1300 uint8_t* msg,
1301 int msglen )
1302{
1303 QemudMultiplexer* m = opaque;
1304 QemudClient* c = m->clients;
1305
1306 /* dispatch to an existing client if possible
1307 * note that channel 0 is handled by a special
1308 * QemudClient that is setup in qemud_multiplexer_init()
1309 */
1310 for ( ; c != NULL; c = c->next ) {
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001311 if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel == channel) {
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001312 qemud_client_recv(c, msg, msglen);
1313 return;
1314 }
1315 }
1316
1317 D("%s: ignoring %d bytes for unknown channel %d",
1318 __FUNCTION__, msglen, channel);
1319}
1320
1321/* handle a new connection attempt. This returns 0 on
1322 * success, -1 if the service name is unknown, or -2
1323 * if the service's maximum number of clients has been
1324 * reached.
1325 */
1326static int
1327qemud_multiplexer_connect( QemudMultiplexer* m,
1328 const char* service_name,
1329 int channel_id )
1330{
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001331 /* find the corresponding registered service by name */
Ot ten Thije871da2a2010-09-20 10:29:22 +01001332 QemudService* sv = qemud_service_find(m->services, service_name);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001333 if (sv == NULL) {
1334 D("%s: no registered '%s' service", __FUNCTION__, service_name);
1335 return -1;
1336 }
1337
1338 /* check service's client count */
1339 if (sv->max_clients > 0 && sv->num_clients >= sv->max_clients) {
1340 D("%s: registration failed for '%s' service: too many clients (%d)",
1341 __FUNCTION__, service_name, sv->num_clients);
1342 return -2;
1343 }
1344
Ot ten Thije871da2a2010-09-20 10:29:22 +01001345 /* connect a new client to the service on the given channel */
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001346 if (qemud_service_connect_client(sv, channel_id, NULL) == NULL)
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001347 return -1;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001348
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001349 return 0;
1350}
1351
1352/* disconnect a given client from its channel id */
1353static void
1354qemud_multiplexer_disconnect( QemudMultiplexer* m,
1355 int channel )
1356{
1357 QemudClient* c;
1358
1359 /* find the client by its channel id, then disconnect it */
1360 for (c = m->clients; c; c = c->next) {
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001361 if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel == channel) {
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001362 D("%s: disconnecting client %d",
1363 __FUNCTION__, channel);
1364 /* note thatt this removes the client from
1365 * m->clients automatically.
1366 */
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001367 c->ProtocolSelector.Serial.channel = -1; /* no need to send disconnect:<id> */
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -08001368 qemud_client_disconnect(c, 0);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001369 return;
1370 }
1371 }
1372 D("%s: disconnecting unknown channel %d",
1373 __FUNCTION__, channel);
1374}
1375
Ot ten Thije871da2a2010-09-20 10:29:22 +01001376/* disconnects all channels, except for the control channel, without informing
1377 * the daemon in the guest that disconnection has occurred.
1378 *
1379 * Used to silently kill clients when restoring emulator state snapshots.
1380 */
1381static void
1382qemud_multiplexer_disconnect_noncontrol( QemudMultiplexer* m )
1383{
1384 QemudClient* c;
1385 QemudClient* next = m->clients;
1386
1387 while (next) {
1388 c = next;
1389 next = c->next; /* disconnect frees c, remember next in advance */
1390
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001391 if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0) {
1392 /* skip control channel */
Ot ten Thije871da2a2010-09-20 10:29:22 +01001393 D("%s: disconnecting client %d",
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001394 __FUNCTION__, c->ProtocolSelector.Serial.channel);
Ot ten Thije871da2a2010-09-20 10:29:22 +01001395 D("%s: disconnecting client %d\n",
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001396 __FUNCTION__, c->ProtocolSelector.Serial.channel);
1397 c->ProtocolSelector.Serial.channel = -1; /* do not send disconnect:<id> */
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -08001398 qemud_client_disconnect(c, 0);
Ot ten Thije871da2a2010-09-20 10:29:22 +01001399 }
1400 }
1401}
1402
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001403/* handle control messages. This is used as the receive
1404 * callback for the special QemudClient setup to manage
1405 * channel 0.
1406 *
1407 * note that the message is zero-terminated for convenience
1408 * (i.e. msg[msglen] is a valid memory read that returns '\0')
1409 */
1410static void
David 'Digit' Turner318e4f22009-05-25 18:01:03 +02001411qemud_multiplexer_control_recv( void* opaque,
1412 uint8_t* msg,
1413 int msglen,
1414 QemudClient* client )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001415{
1416 QemudMultiplexer* mult = opaque;
1417 uint8_t* msgend = msg + msglen;
1418 char tmp[64], *p=tmp, *end=p+sizeof(tmp);
1419
1420 /* handle connection attempts.
1421 * the client message must be "connect:<service-name>:<id>"
David Turnerfff1ae52009-04-05 14:22:28 -07001422 * where <id> is a 2-char hexadecimal string, which must be > 0
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001423 */
1424 if (msglen > 8 && !memcmp(msg, "connect:", 8))
1425 {
1426 const char* service_name = (const char*)msg + 8;
1427 int channel, ret;
1428 char* q;
1429
1430 q = strchr(service_name, ':');
David Turnerfff1ae52009-04-05 14:22:28 -07001431 if (q == NULL || q+3 != (char*)msgend) {
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001432 D("%s: malformed connect message: '%.*s' (offset=%d)",
1433 __FUNCTION__, msglen, (const char*)msg, q ? q-(char*)msg : -1);
1434 return;
1435 }
1436 *q++ = 0; /* zero-terminate service name */
David Turnerfff1ae52009-04-05 14:22:28 -07001437 channel = hex2int((uint8_t*)q, 2);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001438 if (channel <= 0) {
1439 D("%s: malformed channel id '%.*s",
David Turnerfff1ae52009-04-05 14:22:28 -07001440 __FUNCTION__, 2, q);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001441 return;
1442 }
1443
1444 ret = qemud_multiplexer_connect(mult, service_name, channel);
1445 /* the answer can be one of:
1446 * ok:connect:<id>
1447 * ko:connect:<id>:<reason-for-failure>
1448 */
1449 if (ret < 0) {
1450 if (ret == -1) {
1451 /* could not connect */
David Turnerfff1ae52009-04-05 14:22:28 -07001452 p = bufprint(tmp, end, "ko:connect:%02x:unknown service", channel);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001453 } else {
David Turnerfff1ae52009-04-05 14:22:28 -07001454 p = bufprint(tmp, end, "ko:connect:%02x:service busy", channel);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001455 }
1456 }
1457 else {
David Turnerfff1ae52009-04-05 14:22:28 -07001458 p = bufprint(tmp, end, "ok:connect:%02x", channel);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001459 }
1460 qemud_serial_send(mult->serial, 0, 0, (uint8_t*)tmp, p-tmp);
1461 return;
1462 }
1463
1464 /* handle client disconnections,
1465 * this message arrives when the client has closed the connection.
David Turnerfff1ae52009-04-05 14:22:28 -07001466 * format: "disconnect:<id>" where <id> is a 2-hex channel id > 0
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001467 */
David Turnerfff1ae52009-04-05 14:22:28 -07001468 if (msglen == 13 && !memcmp(msg, "disconnect:", 11)) {
1469 int channel_id = hex2int(msg+11, 2);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001470 if (channel_id <= 0) {
1471 D("%s: malformed disconnect channel id: '%.*s'",
David Turnerfff1ae52009-04-05 14:22:28 -07001472 __FUNCTION__, 2, msg+11);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001473 return;
1474 }
1475 qemud_multiplexer_disconnect(mult, channel_id);
1476 return;
1477 }
1478
David Turner791d8612009-04-13 18:01:32 -07001479#if SUPPORT_LEGACY_QEMUD
1480 /* an ok:connect:<service>:<id> message can be received if we're
1481 * talking to a legacy qemud daemon, i.e. one running in a 1.0 or
1482 * 1.1 system image.
1483 *
1484 * we should treat is as a normal "connect:" attempt, except that
1485 * we must not send back any acknowledgment.
1486 */
1487 if (msglen > 11 && !memcmp(msg, "ok:connect:", 11)) {
1488 const char* service_name = (const char*)msg + 11;
1489 char* q = strchr(service_name, ':');
1490 int channel;
1491
1492 if (q == NULL || q+3 != (char*)msgend) {
1493 D("%s: malformed legacy connect message: '%.*s' (offset=%d)",
1494 __FUNCTION__, msglen, (const char*)msg, q ? q-(char*)msg : -1);
1495 return;
1496 }
1497 *q++ = 0; /* zero-terminate service name */
1498 channel = hex2int((uint8_t*)q, 2);
1499 if (channel <= 0) {
1500 D("%s: malformed legacy channel id '%.*s",
1501 __FUNCTION__, 2, q);
1502 return;
1503 }
1504
1505 switch (mult->serial->version) {
1506 case QEMUD_VERSION_UNKNOWN:
1507 mult->serial->version = QEMUD_VERSION_LEGACY;
1508 D("%s: legacy qemud daemon detected.", __FUNCTION__);
1509 break;
1510
1511 case QEMUD_VERSION_LEGACY:
1512 /* nothing unusual */
1513 break;
1514
1515 default:
1516 D("%s: weird, ignoring legacy qemud control message: '%.*s'",
1517 __FUNCTION__, msglen, msg);
1518 return;
1519 }
1520
1521 /* "hw-control" was called "control" in 1.0/1.1 */
1522 if (!strcmp(service_name,"control"))
1523 service_name = "hw-control";
1524
1525 qemud_multiplexer_connect(mult, service_name, channel);
1526 return;
1527 }
1528
1529 /* anything else, don't answer for legacy */
1530 if (mult->serial->version == QEMUD_VERSION_LEGACY)
1531 return;
1532#endif /* SUPPORT_LEGACY_QEMUD */
1533
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001534 /* anything else is a problem */
1535 p = bufprint(tmp, end, "ko:unknown command");
1536 qemud_serial_send(mult->serial, 0, 0, (uint8_t*)tmp, p-tmp);
1537}
1538
1539/* initialize the global QemudMultiplexer.
1540 */
1541static void
1542qemud_multiplexer_init( QemudMultiplexer* mult,
1543 CharDriverState* serial_cs )
1544{
1545 QemudClient* control;
1546
1547 /* initialize serial handler */
1548 qemud_serial_init( mult->serial,
1549 serial_cs,
1550 qemud_multiplexer_serial_recv,
1551 mult );
1552
1553 /* setup listener for channel 0 */
1554 control = qemud_client_alloc( 0,
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001555 NULL,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001556 mult,
1557 qemud_multiplexer_control_recv,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001558 NULL, NULL, NULL,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001559 mult->serial,
1560 &mult->clients );
1561}
1562
1563/* the global multiplexer state */
1564static QemudMultiplexer _multiplexer[1];
1565
1566/** HIGH-LEVEL API
1567 **/
1568
1569/* this function must be used in the serv_connect callback
1570 * of a given QemudService object (see qemud_service_register()
1571 * below). It is used to register a new QemudClient to acknowledge
1572 * a new client connection.
1573 *
1574 * 'clie_opaque', 'clie_recv' and 'clie_close' are used to
1575 * send incoming client messages to the corresponding service
1576 * implementation, or notify the service that a client has
1577 * disconnected.
1578 */
1579QemudClient*
1580qemud_client_new( QemudService* service,
1581 int channelId,
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001582 const char* client_param,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001583 void* clie_opaque,
1584 QemudClientRecv clie_recv,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001585 QemudClientClose clie_close,
1586 QemudClientSave clie_save,
1587 QemudClientLoad clie_load )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001588{
1589 QemudMultiplexer* m = _multiplexer;
1590 QemudClient* c = qemud_client_alloc( channelId,
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001591 client_param,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001592 clie_opaque,
1593 clie_recv,
1594 clie_close,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001595 clie_save,
1596 clie_load,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001597 m->serial,
1598 &m->clients );
1599
1600 qemud_service_add_client(service, c);
1601 return c;
1602}
1603
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001604/* Caches a service message into the client's descriptor.
1605 *
1606 * See comments on QemudPipeMessage structure for more info.
1607 */
1608static void
1609_qemud_pipe_cache_buffer(QemudClient* client, const uint8_t* msg, int msglen)
1610{
1611 QemudPipeMessage* buf;
1612 QemudPipeMessage** ins_at = &client->ProtocolSelector.Pipe.messages;
1613
1614 /* Allocate descriptor big enough to contain message as well. */
1615 buf = (QemudPipeMessage*)malloc(msglen + sizeof(QemudPipeMessage));
1616 if (buf != NULL) {
1617 /* Message starts right after the descriptor. */
1618 buf->message = (uint8_t*)buf + sizeof(QemudPipeMessage);
1619 buf->size = msglen;
1620 memcpy(buf->message, msg, msglen);
1621 buf->offset = 0;
1622 buf->next = NULL;
1623 while (*ins_at != NULL) {
1624 ins_at = &(*ins_at)->next;
1625 }
1626 *ins_at = buf;
1627 /* Notify the pipe that there is data to read. */
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07001628 goldfish_pipe_wake(client->ProtocolSelector.Pipe.qemud_pipe->hwpipe,
1629 PIPE_WAKE_READ);
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001630 }
1631}
1632
1633/* Sends service message to the client.
1634 */
1635static void
1636_qemud_pipe_send(QemudClient* client, const uint8_t* msg, int msglen)
1637{
1638 uint8_t frame[FRAME_HEADER_SIZE];
1639 int avail, len = msglen;
1640 int framing = client->framing;
1641
1642 if (msglen <= 0)
1643 return;
1644
1645 D("%s: len=%3d '%s'",
1646 __FUNCTION__, msglen, quote_bytes((const void*)msg, msglen));
1647
1648 if (framing) {
1649 len += FRAME_HEADER_SIZE;
1650 }
1651
1652 /* packetize the payload for the serial MTU */
1653 while (len > 0)
1654 {
1655 avail = len;
1656 if (avail > MAX_SERIAL_PAYLOAD)
1657 avail = MAX_SERIAL_PAYLOAD;
1658
1659 /* insert frame header when needed */
1660 if (framing) {
1661 int2hex(frame, FRAME_HEADER_SIZE, msglen);
1662 T("%s: '%.*s'", __FUNCTION__, FRAME_HEADER_SIZE, frame);
1663 _qemud_pipe_cache_buffer(client, frame, FRAME_HEADER_SIZE);
1664 avail -= FRAME_HEADER_SIZE;
1665 len -= FRAME_HEADER_SIZE;
1666 framing = 0;
1667 }
1668
1669 /* write message content */
1670 T("%s: '%.*s'", __FUNCTION__, avail, msg);
1671 _qemud_pipe_cache_buffer(client, msg, avail);
1672 msg += avail;
1673 len -= avail;
1674 }
1675}
1676
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001677/* this can be used by a service implementation to send an answer
1678 * or message to a specific client.
1679 */
1680void
1681qemud_client_send ( QemudClient* client, const uint8_t* msg, int msglen )
1682{
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001683 if (_is_pipe_client(client)) {
1684 _qemud_pipe_send(client, msg, msglen);
1685 } else {
1686 qemud_serial_send(client->ProtocolSelector.Serial.serial,
1687 client->ProtocolSelector.Serial.channel,
1688 client->framing != 0, msg, msglen);
1689 }
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001690}
1691
1692/* enable framing for this client. When TRUE, this will
1693 * use internally a simple 4-hexchar header before each
1694 * message exchanged through the serial port.
1695 */
1696void
1697qemud_client_set_framing( QemudClient* client, int framing )
1698{
1699 /* release dynamic buffer if we're disabling framing */
1700 if (client->framing) {
1701 if (!client->need_header) {
1702 AFREE(client->payload->buff);
1703 client->need_header = 1;
1704 }
1705 }
1706 client->framing = !!framing;
1707}
1708
1709/* this can be used by a service implementation to close a
1710 * specific client connection.
1711 */
1712void
1713qemud_client_close( QemudClient* client )
1714{
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -08001715 qemud_client_disconnect(client, 0);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001716}
1717
1718
Ot ten Thije871da2a2010-09-20 10:29:22 +01001719/** SNAPSHOT SUPPORT
1720 **/
1721
1722/* Saves the number of clients.
1723 */
1724static void
1725qemud_client_save_count(QEMUFile* f, QemudClient* c)
1726{
1727 unsigned int client_count = 0;
1728 for( ; c; c = c->next) // walk over linked list
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001729 /* skip control channel, which is not saved, and pipe channels that
1730 * are saved along with the pipe. */
1731 if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0)
Ot ten Thije871da2a2010-09-20 10:29:22 +01001732 client_count++;
1733
1734 qemu_put_be32(f, client_count);
1735}
1736
1737/* Saves the number of services currently available.
1738 */
1739static void
1740qemud_service_save_count(QEMUFile* f, QemudService* s)
1741{
1742 unsigned int service_count = 0;
1743 for( ; s; s = s->next ) // walk over linked list
1744 service_count++;
1745
1746 qemu_put_be32(f, service_count);
1747}
1748
1749/* Save QemuD state to snapshot.
1750 *
1751 * The control channel has no state of its own, other than the local variables
1752 * in qemud_multiplexer_control_recv. We can therefore safely skip saving it,
1753 * which spares us dealing with the exception of a client not connected to a
1754 * service.
1755 */
1756static void
1757qemud_save(QEMUFile* f, void* opaque)
1758{
1759 QemudMultiplexer *m = opaque;
1760
1761 qemud_serial_save(f, m->serial);
1762
1763 /* save service states */
1764 qemud_service_save_count(f, m->services);
1765 QemudService *s;
1766 for (s = m->services; s; s = s->next)
1767 qemud_service_save(f, s);
1768
1769 /* save client channels */
1770 qemud_client_save_count(f, m->clients);
1771 QemudClient *c;
1772 for (c = m->clients; c; c = c->next) {
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001773 /* skip control channel, and pipe clients */
1774 if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0) {
1775 qemud_serial_client_save(f, c);
Ot ten Thije871da2a2010-09-20 10:29:22 +01001776 }
1777 }
1778
1779}
1780
1781
1782/* Checks whether the same services are available at this point as when the
1783 * snapshot was made.
1784 */
1785static int
1786qemud_load_services( QEMUFile* f, QemudService* current_services )
1787{
1788 int i, ret;
1789 int service_count = qemu_get_be32(f);
1790 for (i = 0; i < service_count; i++) {
1791 if ((ret = qemud_service_load(f, current_services)))
1792 return ret;
1793 }
1794
1795 return 0;
1796}
1797
1798/* Removes all active non-control clients, then creates new ones with state
1799 * taken from the snapshot.
1800 *
1801 * We do not send "disconnect" commands, over the channel. If we did, we might
1802 * stop clients in the restored guest, resulting in an incorrect restore.
1803 *
1804 * Instead, we silently replace the clients that were running before the
1805 * restore with new clients, whose state we copy from the snapshot. Since
1806 * everything is multiplexed over one link, only the multiplexer notices the
1807 * changes, there is no communication with the guest.
1808 */
1809static int
Vladimir Chtchetkined0e28722011-10-05 14:25:07 -07001810qemud_load_clients(QEMUFile* f, QemudMultiplexer* m, int version )
Ot ten Thije871da2a2010-09-20 10:29:22 +01001811{
1812 /* Remove all clients, except on the control channel.*/
1813 qemud_multiplexer_disconnect_noncontrol(m);
1814
1815 /* Load clients from snapshot */
1816 int client_count = qemu_get_be32(f);
1817 int i, ret;
1818 for (i = 0; i < client_count; i++) {
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001819 if ((ret = qemud_serial_client_load(f, m->services, version))) {
Ot ten Thije871da2a2010-09-20 10:29:22 +01001820 return ret;
1821 }
1822 }
1823
1824 return 0;
1825}
1826
1827/* Load QemuD state from file.
1828 */
1829static int
1830qemud_load(QEMUFile *f, void* opaque, int version)
1831{
1832 QemudMultiplexer *m = opaque;
1833
1834 int ret;
Ot ten Thije871da2a2010-09-20 10:29:22 +01001835
1836 if ((ret = qemud_serial_load(f, m->serial)))
1837 return ret;
1838 if ((ret = qemud_load_services(f, m->services)))
1839 return ret;
Vladimir Chtchetkined0e28722011-10-05 14:25:07 -07001840 if ((ret = qemud_load_clients(f, m, version)))
Ot ten Thije871da2a2010-09-20 10:29:22 +01001841 return ret;
1842
1843 return 0;
1844}
1845
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001846/*------------------------------------------------------------------------------
1847 *
1848 * QEMUD PIPE service callbacks
1849 *
1850 * ----------------------------------------------------------------------------*/
1851
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02001852/* Saves pending pipe message to the snapshot file. */
1853static void
1854_save_pipe_message(QEMUFile* f, QemudPipeMessage* msg)
1855{
1856 qemu_put_be32(f, msg->size);
1857 qemu_put_be32(f, msg->offset);
1858 qemu_put_buffer(f, msg->message, msg->size);
1859}
1860
1861/* Loads pending pipe messages from the snapshot file.
1862 * Return:
1863 * List of pending pipe messages loaded from snapshot, or NULL if snapshot didn't
1864 * contain saved messages.
1865 */
1866static QemudPipeMessage*
1867_load_pipe_message(QEMUFile* f)
1868{
1869 QemudPipeMessage* ret = NULL;
1870 QemudPipeMessage** next = &ret;
1871
1872 uint32_t size = qemu_get_be32(f);
1873 while (size != 0) {
1874 QemudPipeMessage* wrk;
1875 ANEW0(wrk);
1876 *next = wrk;
1877 wrk->size = size;
1878 wrk->offset = qemu_get_be32(f);
1879 wrk->message = malloc(wrk->size);
1880 if (wrk->message == NULL) {
1881 APANIC("Unable to allocate buffer for pipe's pending message.");
1882 }
1883 qemu_get_buffer(f, wrk->message, wrk->size);
1884 next = &wrk->next;
1885 *next = NULL;
1886 size = qemu_get_be32(f);
1887 }
1888
1889 return ret;
1890}
1891
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001892/* This is a callback that gets invoked when guest is connecting to the service.
1893 *
1894 * Here we will create a new client as well as pipe descriptor representing new
1895 * connection.
1896 */
1897static void*
1898_qemudPipe_init(void* hwpipe, void* _looper, const char* args)
1899{
1900 QemudMultiplexer *m = _multiplexer;
1901 QemudService* sv = m->services;
1902 QemudClient* client;
1903 QemudPipe* pipe = NULL;
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001904 char service_name[512];
1905 const char* client_args;
1906 size_t srv_name_len;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001907
1908 /* 'args' passed in this callback represents name of the service the guest is
1909 * connecting to. It can't be NULL. */
1910 if (args == NULL) {
1911 D("%s: Missing address!", __FUNCTION__);
1912 return NULL;
1913 }
1914
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001915 /* 'args' contain service name, and optional parameters for the client that
1916 * is about to be created in this call. The parameters are separated from the
1917 * service name wit ':'. Separate service name from the client param. */
1918 client_args = strchr(args, ':');
1919 if (client_args != NULL) {
1920 srv_name_len = min(client_args - args, sizeof(service_name) - 1);
1921 client_args++; // Past the ':'
1922 if (*client_args == '\0') {
1923 /* No actual parameters. */
1924 client_args = NULL;
1925 }
1926 } else {
1927 srv_name_len = min(strlen(args), sizeof(service_name) - 1);
1928 }
1929 memcpy(service_name, args, srv_name_len);
1930 service_name[srv_name_len] = '\0';
1931
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001932 /* Lookup registered service by its name. */
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001933 while (sv != NULL && strcmp(sv->name, service_name)) {
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001934 sv = sv->next;
1935 }
1936 if (sv == NULL) {
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001937 D("%s: Service '%s' has not been registered!", __FUNCTION__, service_name);
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001938 return NULL;
1939 }
1940
1941 /* Create a client for this connection. -1 as a channel ID signals that this
1942 * is a pipe client. */
Vladimir Chtchetkine4c414822011-08-20 08:55:37 -07001943 client = qemud_service_connect_client(sv, -1, client_args);
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001944 if (client != NULL) {
1945 ANEW0(pipe);
1946 pipe->hwpipe = hwpipe;
1947 pipe->looper = _looper;
1948 pipe->service = sv;
1949 pipe->client = client;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07001950 client->ProtocolSelector.Pipe.qemud_pipe = pipe;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001951 }
1952
1953 return pipe;
1954}
1955
1956/* Called when the guest wants to close the channel.
1957*/
1958static void
1959_qemudPipe_closeFromGuest( void* opaque )
1960{
1961 QemudPipe* pipe = opaque;
1962 QemudClient* client = pipe->client;
1963 D("%s", __FUNCTION__);
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07001964 if (client != NULL) {
Vladimir Chtchetkineef71cb82011-12-07 10:24:33 -08001965 qemud_client_disconnect(client, 1);
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07001966 } else {
1967 D("%s: Unexpected NULL client", __FUNCTION__);
1968 }
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001969}
1970
1971/* Called when the guest has sent some data to the client.
1972 */
1973static int
1974_qemudPipe_sendBuffers(void* opaque,
1975 const GoldfishPipeBuffer* buffers,
1976 int numBuffers)
1977{
1978 QemudPipe* pipe = opaque;
1979 QemudClient* client = pipe->client;
1980 size_t transferred = 0;
1981
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07001982 if (client == NULL) {
1983 D("%s: Unexpected NULL client", __FUNCTION__);
1984 return -1;
1985 }
1986
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07001987 if (numBuffers == 1) {
1988 /* Simple case: all data are in one buffer. */
1989 D("%s: %s", __FUNCTION__, quote_bytes((char*)buffers->data, buffers->size));
1990 qemud_client_recv(client, buffers->data, buffers->size);
1991 transferred = buffers->size;
1992 } else {
1993 /* If there are multiple buffers involved, collect all data in one buffer
1994 * before calling the high level client. */
1995 uint8_t* msg, *wrk;
1996 int n;
1997 for (n = 0; n < numBuffers; n++) {
1998 transferred += buffers[n].size;
1999 }
2000 msg = malloc(transferred);
2001 wrk = msg;
2002 for (n = 0; n < numBuffers; n++) {
2003 memcpy(wrk, buffers[n].data, buffers[n].size);
2004 wrk += buffers[n].size;
2005 }
2006 D("%s: %s", __FUNCTION__, quote_bytes((char*)msg, transferred));
2007 qemud_client_recv(client, msg, transferred);
2008 free(msg);
2009 }
2010
2011 return transferred;
2012}
2013
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002014/* Called when the guest is reading data from the client.
2015 */
2016static int
2017_qemudPipe_recvBuffers(void* opaque, GoldfishPipeBuffer* buffers, int numBuffers)
2018{
2019 QemudPipe* pipe = opaque;
2020 QemudClient* client = pipe->client;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07002021 QemudPipeMessage** msg_list;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002022 GoldfishPipeBuffer* buff = buffers;
2023 GoldfishPipeBuffer* endbuff = buffers + numBuffers;
2024 size_t sent_bytes = 0;
2025 size_t off_in_buff = 0;
2026
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07002027 if (client == NULL) {
2028 D("%s: Unexpected NULL client", __FUNCTION__);
2029 return -1;
2030 }
2031
2032 msg_list = &client->ProtocolSelector.Pipe.messages;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002033 if (*msg_list == NULL) {
2034 /* No data to send. Let it block until we wake it up with
2035 * PIPE_WAKE_READ when service sends data to the client. */
2036 return PIPE_ERROR_AGAIN;
2037 }
2038
2039 /* Fill in goldfish buffers while they are still available, and there are
2040 * messages in the client's message list. */
2041 while (buff != endbuff && *msg_list != NULL) {
2042 QemudPipeMessage* msg = *msg_list;
2043 /* Message data fiting the current pipe's buffer. */
Vladimir Chtchetkine1875d372011-09-07 10:05:07 -07002044 size_t to_copy = min(msg->size - msg->offset, buff->size - off_in_buff);
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002045 memcpy(buff->data + off_in_buff, msg->message + msg->offset, to_copy);
2046 /* Update offsets. */
2047 off_in_buff += to_copy;
2048 msg->offset += to_copy;
2049 sent_bytes += to_copy;
2050 if (msg->size == msg->offset) {
2051 /* We're done with the current message. Go to the next one. */
2052 *msg_list = msg->next;
2053 free(msg);
2054 }
2055 if (off_in_buff == buff->size) {
2056 /* Current pipe buffer is full. Continue with the next one. */
2057 buff++;
Vladimir Chtchetkine1875d372011-09-07 10:05:07 -07002058 off_in_buff = 0;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002059 }
2060 }
2061
2062 D("%s: -> %u (of %u)", __FUNCTION__, sent_bytes, buffers->size);
2063
2064 return sent_bytes;
2065}
2066
2067static unsigned
2068_qemudPipe_poll(void* opaque)
2069{
2070 QemudPipe* pipe = opaque;
2071 QemudClient* client = pipe->client;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07002072 unsigned ret = 0;
2073
2074 if (client != NULL) {
Vladimir Chtchetkinefd165052011-08-25 08:06:26 -07002075 ret |= PIPE_POLL_OUT;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07002076 if (client->ProtocolSelector.Pipe.messages != NULL) {
Vladimir Chtchetkinefd165052011-08-25 08:06:26 -07002077 ret |= PIPE_POLL_IN;
Vladimir Chtchetkine59385322011-08-18 15:53:48 -07002078 }
2079 } else {
2080 D("%s: Unexpected NULL client", __FUNCTION__);
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002081 }
2082
2083 return ret;
2084}
2085
2086static void
2087_qemudPipe_wakeOn(void* opaque, int flags)
2088{
2089 D("%s: -> %X", __FUNCTION__, flags);
2090}
2091
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02002092static void
2093_qemudPipe_save(void* opaque, QEMUFile* f )
2094{
2095 QemudPipe* qemud_pipe = (QemudPipe*)opaque;
2096 QemudClient* c = qemud_pipe->client;
2097 QemudPipeMessage* msg = c->ProtocolSelector.Pipe.messages;
2098
2099 /* save generic information */
2100 qemud_service_save_name(f, c->service);
2101 qemu_put_string(f, c->param);
2102
2103 /* Save pending messages. */
2104 while (msg != NULL) {
2105 _save_pipe_message(f, msg);
2106 msg = msg->next;
2107 }
2108 /* End of pending messages. */
2109 qemu_put_be32(f, 0);
2110
2111 /* save client-specific state */
2112 if (c->clie_save)
2113 c->clie_save(f, c, c->clie_opaque);
2114
2115 /* save framing configuration */
2116 qemu_put_be32(f, c->framing);
2117 if (c->framing) {
2118 qemu_put_be32(f, c->need_header);
2119 /* header sink always connected to c->header0, no need to save */
2120 qemu_put_be32(f, FRAME_HEADER_SIZE);
2121 qemu_put_buffer(f, c->header0, FRAME_HEADER_SIZE);
2122 /* payload sink */
2123 qemud_sink_save(f, c->payload);
2124 qemu_put_buffer(f, c->payload->buff, c->payload->size);
2125 }
2126}
2127
2128static void*
2129_qemudPipe_load(void* hwpipe, void* pipeOpaque, const char* args, QEMUFile* f)
2130{
2131 QemudPipe* qemud_pipe = NULL;
2132 char* param;
2133 char *service_name = qemud_service_load_name(f);
2134 if (service_name == NULL)
2135 return NULL;
2136 /* get service instance for the loading client*/
2137 QemudService *sv = qemud_service_find(_multiplexer->services, service_name);
2138 if (sv == NULL) {
2139 D("%s: load failed: unknown service \"%s\"\n",
2140 __FUNCTION__, service_name);
2141 return NULL;
2142 }
2143
2144 /* Load saved parameters. */
2145 param = qemu_get_string(f);
2146
2147 /* re-connect client */
2148 QemudClient* c = qemud_service_connect_client(sv, -1, param);
2149 if(c == NULL)
2150 return NULL;
2151
2152 /* Load pending messages. */
2153 c->ProtocolSelector.Pipe.messages = _load_pipe_message(f);
2154
2155 /* load client-specific state */
2156 if (c->clie_load && c->clie_load(f, c, c->clie_opaque)) {
2157 /* load failure */
2158 return NULL;
2159 }
2160
2161 /* load framing configuration */
2162 c->framing = qemu_get_be32(f);
2163 if (c->framing) {
2164
2165 /* header buffer */
2166 c->need_header = qemu_get_be32(f);
2167 int header_size = qemu_get_be32(f);
2168 if (header_size > FRAME_HEADER_SIZE) {
2169 D("%s: load failed: payload buffer requires %d bytes, %d available\n",
2170 __FUNCTION__, header_size, FRAME_HEADER_SIZE);
2171 return NULL;
2172 }
2173 int ret;
2174 if ((ret = qemu_get_buffer(f, c->header0, header_size)) != header_size) {
2175 D("%s: frame header buffer load failed: expected %d bytes, got %d\n",
2176 __FUNCTION__, header_size, ret);
2177 return NULL;
2178 }
2179
2180 /* payload sink */
2181 if ((ret = qemud_sink_load(f, c->payload)))
2182 return NULL;
2183
2184 /* replace payload buffer by saved data */
2185 if (c->payload->buff) {
2186 AFREE(c->payload->buff);
2187 }
2188 AARRAY_NEW(c->payload->buff, c->payload->size+1); /* +1 for terminating zero */
2189 if ((ret = qemu_get_buffer(f, c->payload->buff, c->payload->size)) != c->payload->size) {
2190 D("%s: frame payload buffer load failed: expected %d bytes, got %d\n",
2191 __FUNCTION__, c->payload->size, ret);
2192 AFREE(c->payload->buff);
2193 return NULL;
2194 }
2195 }
2196
2197 /* Associate the client with the pipe. */
2198 ANEW0(qemud_pipe);
2199 qemud_pipe->hwpipe = hwpipe;
2200 qemud_pipe->looper = pipeOpaque;
2201 qemud_pipe->service = sv;
2202 qemud_pipe->client = c;
2203 c->ProtocolSelector.Pipe.qemud_pipe = qemud_pipe;
2204
2205 return qemud_pipe;
2206}
2207
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002208/* QEMUD pipe functions.
2209 */
2210static const GoldfishPipeFuncs _qemudPipe_funcs = {
2211 _qemudPipe_init,
2212 _qemudPipe_closeFromGuest,
2213 _qemudPipe_sendBuffers,
2214 _qemudPipe_recvBuffers,
2215 _qemudPipe_poll,
2216 _qemudPipe_wakeOn,
David 'Digit' Turner3e92c2d2011-10-11 03:02:41 +02002217 _qemudPipe_save,
2218 _qemudPipe_load,
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002219};
2220
2221/* Initializes QEMUD pipe interface.
2222 */
2223static void
2224_android_qemud_pipe_init(void)
2225{
2226 static ABool _qemud_pipe_initialized = false;
2227
2228 if (!_qemud_pipe_initialized) {
2229 goldfish_pipe_add_type( "qemud", looper_newCore(), &_qemudPipe_funcs );
2230 _qemud_pipe_initialized = true;
2231 }
2232}
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002233
2234/* this is the end of the serial charpipe that must be passed
2235 * to the emulated tty implementation. The other end of the
2236 * charpipe must be passed to qemud_multiplexer_init().
2237 */
2238static CharDriverState* android_qemud_cs;
2239
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002240/* Initializes QEMUD serial interface.
2241 */
2242static void
2243_android_qemud_serial_init(void)
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002244{
2245 CharDriverState* cs;
2246
2247 if (android_qemud_cs != NULL)
2248 return;
2249
2250 if (qemu_chr_open_charpipe( &android_qemud_cs, &cs ) < 0) {
2251 derror( "%s: can't create charpipe to serial port",
2252 __FUNCTION__ );
2253 exit(1);
2254 }
2255
2256 qemud_multiplexer_init(_multiplexer, cs);
Ot ten Thije871da2a2010-09-20 10:29:22 +01002257
2258 register_savevm( "qemud", 0, QEMUD_SAVE_VERSION,
2259 qemud_save, qemud_load, _multiplexer);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002260}
2261
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002262extern void
2263android_qemud_init( void )
2264{
2265 D("%s", __FUNCTION__);
2266 /* We don't know in advance whether the guest system supports qemud pipes,
2267 * so we will initialize both qemud machineries, the legacy (over serial
2268 * port), and the new one (over qemu pipe). Then we let the guest to connect
2269 * via one, or the other. */
2270 _android_qemud_serial_init();
2271 _android_qemud_pipe_init();
2272}
2273
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002274/* return the serial charpipe endpoint that must be used
2275 * by the emulated tty implementation.
2276 */
2277CharDriverState* android_qemud_get_cs( void )
2278{
2279 if (android_qemud_cs == NULL)
2280 android_qemud_init();
2281
2282 return android_qemud_cs;
2283}
2284
2285/* this function is used to register a new named qemud-based
2286 * service. You must provide 'serv_opaque' and 'serv_connect'
2287 * which will be called whenever a new client tries to connect
2288 * to the services.
2289 *
2290 * 'serv_connect' shall return NULL if the connection is refused,
2291 * or a handle to a new QemudClient otherwise. The latter can be
2292 * created through qemud_client_new() defined above.
2293 *
2294 * 'max_clients' is the maximum number of clients accepted by
2295 * the service concurrently. If this value is 0, then any number
2296 * of clients can connect.
2297 */
2298QemudService*
2299qemud_service_register( const char* service_name,
2300 int max_clients,
2301 void* serv_opaque,
Ot ten Thije871da2a2010-09-20 10:29:22 +01002302 QemudServiceConnect serv_connect,
2303 QemudServiceSave serv_save,
2304 QemudServiceLoad serv_load )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002305{
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002306 QemudService* sv;
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002307 QemudMultiplexer* m = _multiplexer;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002308
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002309 android_qemud_init();
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002310
2311 sv = qemud_service_new(service_name,
Vladimir Chtchetkine77e61ce2011-08-04 12:19:04 -07002312 max_clients,
2313 serv_opaque,
2314 serv_connect,
2315 serv_save,
2316 serv_load,
2317 &m->services);
2318 D("Registered QEMUD service %s", service_name);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002319 return sv;
2320}
2321
2322/* broadcast a given message to all clients of a given QemudService
2323 */
2324extern void
2325qemud_service_broadcast( QemudService* sv,
2326 const uint8_t* msg,
2327 int msglen )
2328{
2329 QemudClient* c;
2330
2331 for (c = sv->clients; c; c = c->next_serv)
2332 qemud_client_send(c, msg, msglen);
2333}
2334
2335
2336
2337/*
2338 * The following code is used for backwards compatibility reasons.
2339 * It allows you to implement a given qemud-based service through
2340 * a charpipe.
2341 *
2342 * In other words, this implements a QemudService and corresponding
2343 * QemudClient that connects a qemud client running in the emulated
2344 * system, to a CharDriverState object implemented through a charpipe.
2345 *
2346 * QemudCharClient <===charpipe====> (char driver user)
2347 *
2348 * For example, this is used to implement the "gsm" service when the
2349 * modem emulation is provided through an external serial device.
2350 *
2351 * A QemudCharService can have only one client by definition.
2352 * There is no QemudCharClient object because we can store a single
2353 * CharDriverState handle in the 'opaque' field for simplicity.
2354 */
2355
2356typedef struct {
2357 QemudService* service;
2358 CharDriverState* cs;
2359} QemudCharService;
2360
2361/* called whenever a new message arrives from a qemud client.
2362 * this simply sends the message through the charpipe to the user.
2363 */
2364static void
David 'Digit' Turner318e4f22009-05-25 18:01:03 +02002365_qemud_char_client_recv( void* opaque, uint8_t* msg, int msglen,
2366 QemudClient* client )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002367{
2368 CharDriverState* cs = opaque;
2369 qemu_chr_write(cs, msg, msglen);
2370}
2371
2372/* we don't expect clients of char. services to exit. Just
2373 * print an error to signal an unexpected situation. We should
2374 * be able to recover from these though, so don't panic.
2375 */
2376static void
2377_qemud_char_client_close( void* opaque )
Vladimir Chtchetkine5297e192011-08-12 12:15:25 -07002378
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002379{
Vladimir Chtchetkine5297e192011-08-12 12:15:25 -07002380 QemudClient* client = opaque;
2381
2382 /* At this point modem driver still uses char pipe to communicate with
2383 * hw-qemud, while communication with the guest is done over qemu pipe.
2384 * So, when guest disconnects from the qemu pipe, and emulator-side client
2385 * goes through the disconnection process, this routine is called, since it
2386 * has been set to called during service registration. Unless modem driver
2387 * is changed to drop char pipe communication, this routine will be called
2388 * due to guest disconnection. As long as the client was a qemu pipe - based
2389 * client, it's fine, since we don't really need to do anything in this case.
2390 */
2391 if (!_is_pipe_client(client)) {
2392 derror("unexpected qemud char. channel close");
2393 }
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002394}
2395
2396
2397/* called by the charpipe to know how much data can be read from
2398 * the user. Since we send everything directly to the serial port
2399 * we can return an arbitrary number.
2400 */
2401static int
2402_qemud_char_service_can_read( void* opaque )
2403{
2404 return 8192; /* whatever */
2405}
2406
2407/* called to read data from the charpipe and send it to the client.
2408 * used qemud_service_broadcast() even if there is a single client
2409 * because we don't need a QemudCharClient object this way.
2410 */
2411static void
2412_qemud_char_service_read( void* opaque, const uint8_t* from, int len )
2413{
2414 QemudService* sv = opaque;
2415 qemud_service_broadcast( sv, from, len );
2416}
2417
2418/* called when a qemud client tries to connect to a char. service.
2419 * we simply create a new client and open the charpipe to receive
2420 * data from it.
2421 */
2422static QemudClient*
Vladimir Chtchetkine1875d372011-09-07 10:05:07 -07002423_qemud_char_service_connect(void* opaque,
2424 QemudService* sv,
2425 int channel,
2426 const char* client_param )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002427{
2428 CharDriverState* cs = opaque;
Vladimir Chtchetkine1875d372011-09-07 10:05:07 -07002429 QemudClient* c = qemud_client_new( sv, channel, client_param,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002430 cs,
2431 _qemud_char_client_recv,
Ot ten Thije871da2a2010-09-20 10:29:22 +01002432 _qemud_char_client_close,
2433 NULL, NULL );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002434
2435 /* now we can open the gates :-) */
2436 qemu_chr_add_handlers( cs,
2437 _qemud_char_service_can_read,
2438 _qemud_char_service_read,
2439 NULL,
2440 sv );
2441
2442 return c;
2443}
2444
2445/* returns a charpipe endpoint that can be used by an emulated
2446 * device or external serial port to implement a char. service
2447 */
2448int
2449android_qemud_get_channel( const char* name, CharDriverState* *pcs )
2450{
2451 CharDriverState* cs;
2452
2453 if (qemu_chr_open_charpipe(&cs, pcs) < 0) {
2454 derror("can't open charpipe for '%s' qemud service", name);
2455 exit(2);
2456 }
Ot ten Thije871da2a2010-09-20 10:29:22 +01002457 qemud_service_register(name, 1, cs, _qemud_char_service_connect, NULL, NULL);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002458 return 0;
2459}
2460
2461/* set the character driver state for a given qemud communication channel. this
2462 * is used to attach the channel to an external char driver device directly.
2463 * returns 0 on success, -1 on error
2464 */
2465int
2466android_qemud_set_channel( const char* name, CharDriverState* peer_cs )
2467{
David Turnerfff1ae52009-04-05 14:22:28 -07002468 CharDriverState* char_buffer = qemu_chr_open_buffer(peer_cs);
2469
2470 if (char_buffer == NULL)
2471 return -1;
2472
Ot ten Thije871da2a2010-09-20 10:29:22 +01002473 qemud_service_register(name, 1, char_buffer, _qemud_char_service_connect,
2474 NULL, NULL);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07002475 return 0;
2476}