blob: e91ec78b7c7f21443950f4e04c15dbbf4c8b7315 [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"
Ot ten Thije871da2a2010-09-20 10:29:22 +010017#include "hw/hw.h"
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070018#include "qemu-char.h"
19#include "charpipe.h"
20#include "cbuffer.h"
21
22#define D(...) VERBOSE_PRINT(qemud,__VA_ARGS__)
23#define D_ACTIVE VERBOSE_CHECK(qemud)
24
25/* the T(...) macro is used to dump traffic */
26#define T_ACTIVE 0
27
28#if T_ACTIVE
29#define T(...) VERBOSE_PRINT(qemud,__VA_ARGS__)
30#else
31#define T(...) ((void)0)
32#endif
33
34/* max serial MTU. Don't change this without modifying
35 * development/emulator/qemud/qemud.c as well.
36 */
37#define MAX_SERIAL_PAYLOAD 4000
38
39/* max framed data payload. Must be < (1 << 16)
40 */
41#define MAX_FRAME_PAYLOAD 65535
42
Ot ten Thije871da2a2010-09-20 10:29:22 +010043/* Version number of snapshots code. Increment whenever the data saved
44 * or the layout in which it is saved is changed.
45 */
46#define QEMUD_SAVE_VERSION 1
47
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070048
David Turner791d8612009-04-13 18:01:32 -070049/* define SUPPORT_LEGACY_QEMUD to 1 if you want to support
50 * talking to a legacy qemud daemon. See docs/ANDROID-QEMUD.TXT
51 * for details.
52 */
Jun Nakajima334ab472011-02-02 23:49:59 -080053#ifdef TARGET_ARM
David Turner791d8612009-04-13 18:01:32 -070054#define SUPPORT_LEGACY_QEMUD 1
Jun Nakajima334ab472011-02-02 23:49:59 -080055#endif
56#ifdef TARGET_I386
57#define SUPPORT_LEGACY_QEMUD 0 /* no legacy support */
58#endif
David Turnerfbcbf422009-04-15 06:50:16 -070059#if SUPPORT_LEGACY_QEMUD
60#include "telephony/android_modem.h"
61#include "telephony/modem_driver.h"
62#endif
63
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070064/*
David Turner791d8612009-04-13 18:01:32 -070065 * This implements support for the 'qemud' multiplexing communication
66 * channel between clients running in the emulated system and 'services'
67 * provided by the emulator.
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070068 *
David Turner791d8612009-04-13 18:01:32 -070069 * For additional details, please read docs/ANDROID-QEMUD.TXT
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070070 *
The Android Open Source Project9877e2e2009-03-18 17:39:44 -070071 */
72
73/*
74 * IMPLEMENTATION DETAILS:
75 *
76 * We use one charpipe to connect the emulated serial port to the 'QemudSerial'
77 * object. This object is used to receive data from the serial port, and
78 * unframe messages (i.e. extract payload length + channel id from header,
79 * then the payload itself), before sending them to a generic receiver.
80 *
81 * The QemudSerial object can also be used to send messages to the daemon
82 * through the serial port (see qemud_serial_send())
83 *
84 * The multiplexer is connected to one or more 'service' objects.
85 * are themselves connected through a charpipe to an emulated device or
86 * control sub-module in the emulator.
87 *
88 * tty <==charpipe==> QemudSerial ---> QemudMultiplexer ----> QemudClient
89 * ^ |
90 * | |
91 * +--------------------------------------+
92 *
93 */
94
95/** HANDLING INCOMING DATA FRAMES
96 **/
97
David Turner791d8612009-04-13 18:01:32 -070098/* A QemudSink is just a handly data structure that is used to
99 * read a fixed amount of bytes into a buffer
100 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700101typedef struct QemudSink {
Ot ten Thije871da2a2010-09-20 10:29:22 +0100102 int used; /* number of bytes already used */
103 int size; /* total number of bytes in buff */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700104 uint8_t* buff;
105} QemudSink;
106
Ot ten Thije871da2a2010-09-20 10:29:22 +0100107/* save the state of a QemudSink to a snapshot.
108 *
109 * The buffer pointer is not saved, since it usually points to buffer
110 * fields in other structs, which have save functions themselves. It
111 * is up to the caller to make sure the buffer is correctly saved and
112 * restored.
113 */
114static void
115qemud_sink_save(QEMUFile* f, QemudSink* s)
116{
117 qemu_put_be32(f, s->used);
118 qemu_put_be32(f, s->size);
119}
120
121/* load the state of a QemudSink from a snapshot.
122 */
123static int
124qemud_sink_load(QEMUFile* f, QemudSink* s)
125{
126 s->used = qemu_get_be32(f);
127 s->size = qemu_get_be32(f);
128 return 0;
129}
130
131
David Turner791d8612009-04-13 18:01:32 -0700132/* reset a QemudSink, i.e. provide a new destination buffer address
133 * and its size in bytes.
134 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700135static void
136qemud_sink_reset( QemudSink* ss, int size, uint8_t* buffer )
137{
Ot ten Thije871da2a2010-09-20 10:29:22 +0100138 ss->used = 0;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700139 ss->size = size;
140 ss->buff = buffer;
141}
142
David Turner791d8612009-04-13 18:01:32 -0700143/* try to fill the sink by reading bytes from the source buffer
144 * '*pmsg' which contains '*plen' bytes
145 *
146 * this functions updates '*pmsg' and '*plen', and returns
147 * 1 if the sink's destination buffer is full, or 0 otherwise.
148 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700149static int
150qemud_sink_fill( QemudSink* ss, const uint8_t* *pmsg, int *plen)
151{
Ot ten Thije871da2a2010-09-20 10:29:22 +0100152 int avail = ss->size - ss->used;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700153
154 if (avail <= 0)
155 return 1;
156
157 if (avail > *plen)
158 avail = *plen;
159
Ot ten Thije871da2a2010-09-20 10:29:22 +0100160 memcpy(ss->buff + ss->used, *pmsg, avail);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700161 *pmsg += avail;
162 *plen -= avail;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100163 ss->used += avail;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700164
Ot ten Thije871da2a2010-09-20 10:29:22 +0100165 return (ss->used == ss->size);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700166}
167
David Turner791d8612009-04-13 18:01:32 -0700168/* returns the number of bytes needed to fill a sink's destination
169 * buffer.
170 */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700171static int
172qemud_sink_needed( QemudSink* ss )
173{
Ot ten Thije871da2a2010-09-20 10:29:22 +0100174 return ss->size - ss->used;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700175}
176
177/** HANDLING SERIAL PORT CONNECTION
178 **/
179
180/* The QemudSerial object receives data from the serial port charpipe.
181 * It parses the header to extract the channel id and payload length,
182 * then the message itself.
183 *
184 * Incoming messages are sent to a generic receiver identified by
185 * the 'recv_opaque' and 'recv_func' parameters to qemud_serial_init()
186 *
187 * It also provides qemud_serial_send() which can be used to send
188 * messages back through the serial port.
189 */
190
191#define HEADER_SIZE 6
192
193#define LENGTH_OFFSET 2
194#define LENGTH_SIZE 4
195
196#define CHANNEL_OFFSET 0
197#define CHANNEL_SIZE 2
198
David Turner791d8612009-04-13 18:01:32 -0700199#if SUPPORT_LEGACY_QEMUD
200typedef enum {
201 QEMUD_VERSION_UNKNOWN,
202 QEMUD_VERSION_LEGACY,
203 QEMUD_VERSION_NORMAL
204} QemudVersion;
205
206# define LEGACY_LENGTH_OFFSET 0
207# define LEGACY_CHANNEL_OFFSET 4
208#endif
209
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700210/* length of the framed header */
211#define FRAME_HEADER_SIZE 4
212
213#define BUFFER_SIZE MAX_SERIAL_PAYLOAD
214
215/* out of convenience, the incoming message is zero-terminated
216 * and can be modified by the receiver (e.g. for tokenization).
217 */
218typedef void (*QemudSerialReceive)( void* opaque, int channel, uint8_t* msg, int msglen);
219
220typedef struct QemudSerial {
221 CharDriverState* cs; /* serial charpipe endpoint */
222
223 /* managing incoming packets from the serial port */
224 ABool need_header;
225 int overflow;
226 int in_size;
227 int in_channel;
David Turner791d8612009-04-13 18:01:32 -0700228#if SUPPORT_LEGACY_QEMUD
229 QemudVersion version;
230#endif
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700231 QemudSink header[1];
232 QemudSink payload[1];
233 uint8_t data0[MAX_SERIAL_PAYLOAD+1];
234
235 /* receiver */
236 QemudSerialReceive recv_func; /* receiver callback */
237 void* recv_opaque; /* receiver user-specific data */
238} QemudSerial;
239
240
Ot ten Thije871da2a2010-09-20 10:29:22 +0100241/* Save the state of a QemudSerial to a snapshot file.
242 */
243static void
244qemud_serial_save(QEMUFile* f, QemudSerial* s)
245{
246 /* cs, recv_func and recv_opaque are not saved, as these are assigned only
247 * during emulator init. A load within a session can re-use the values
248 * already assigned, a newly launched emulator has freshly assigned values.
249 */
250
251 /* state of incoming packets from the serial port */
252 qemu_put_be32(f, s->need_header);
253 qemu_put_be32(f, s->overflow);
254 qemu_put_be32(f, s->in_size);
255 qemu_put_be32(f, s->in_channel);
256#if SUPPORT_LEGACY_QEMUD
257 qemu_put_be32(f, s->version);
258#endif
259 qemud_sink_save(f, s->header);
260 qemud_sink_save(f, s->payload);
261 qemu_put_be32(f, MAX_SERIAL_PAYLOAD+1);
262 qemu_put_buffer(f, s->data0, MAX_SERIAL_PAYLOAD+1);
263}
264
265/* Load the state of a QemudSerial from a snapshot file.
266 */
267static int
268qemud_serial_load(QEMUFile* f, QemudSerial* s)
269{
270 /* state of incoming packets from the serial port */
271 s->need_header = qemu_get_be32(f);
272 s->overflow = qemu_get_be32(f);
273 s->in_size = qemu_get_be32(f);
274 s->in_channel = qemu_get_be32(f);
275#if SUPPORT_LEGACY_QEMUD
276 s->version = qemu_get_be32(f);
277#endif
278 qemud_sink_load(f, s->header);
279 qemud_sink_load(f, s->payload);
280
281 /* s->header and s->payload are only ever connected to s->data0 */
282 s->header->buff = s->payload->buff = s->data0;
283
284 int len = qemu_get_be32(f);
285 if (len - 1 > MAX_SERIAL_PAYLOAD) {
286 D("%s: load failed: size of saved payload buffer (%d) exceeds "
287 "current maximum (%d)\n",
288 __FUNCTION__, len - 1, MAX_SERIAL_PAYLOAD);
289 return -EIO;
290 }
291 int ret;
292 if ((ret = qemu_get_buffer(f, s->data0, len)) != len) {
293 D("%s: failed to load serial buffer contents (tried reading %d bytes, got %d)\n",
294 __FUNCTION__, len, ret);
295 return -EIO;
296 }
297
298 return 0;
299}
300
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700301/* called by the charpipe to see how much bytes can be
302 * read from the serial port.
303 */
304static int
305qemud_serial_can_read( void* opaque )
306{
307 QemudSerial* s = opaque;
308
309 if (s->overflow > 0) {
310 return s->overflow;
311 }
312
313 /* if in_size is 0, we're reading the header */
314 if (s->need_header)
315 return qemud_sink_needed(s->header);
316
317 /* otherwise, we're reading the payload */
318 return qemud_sink_needed(s->payload);
319}
320
321/* called by the charpipe to read data from the serial
322 * port. 'len' cannot be more than the value returned
323 * by 'qemud_serial_can_read'.
324 */
325static void
326qemud_serial_read( void* opaque, const uint8_t* from, int len )
327{
328 QemudSerial* s = opaque;
329
330 T("%s: received %3d bytes: '%s'", __FUNCTION__, len, quote_bytes((const void*)from, len));
331
332 while (len > 0) {
333 int avail;
334
335 /* skip overflow bytes */
336 if (s->overflow > 0) {
337 avail = s->overflow;
338 if (avail > len)
339 avail = len;
340
341 from += avail;
342 len -= avail;
343 continue;
344 }
345
346 /* read header if needed */
347 if (s->need_header) {
348 if (!qemud_sink_fill(s->header, (const uint8_t**)&from, &len))
349 break;
350
David Turner791d8612009-04-13 18:01:32 -0700351#if SUPPORT_LEGACY_QEMUD
352 if (s->version == QEMUD_VERSION_UNKNOWN) {
353 /* if we receive "001200" as the first header, then we
354 * detected a legacy qemud daemon. See the comments
355 * in qemud_serial_send_legacy_probe() for details.
356 */
357 if ( !memcmp(s->data0, "001200", 6) ) {
358 D("%s: legacy qemud detected.", __FUNCTION__);
359 s->version = QEMUD_VERSION_LEGACY;
David Turnerfbcbf422009-04-15 06:50:16 -0700360 /* tell the modem to use legacy emulation mode */
361 amodem_set_legacy(android_modem);
David Turner791d8612009-04-13 18:01:32 -0700362 } else {
363 D("%s: normal qemud detected.", __FUNCTION__);
364 s->version = QEMUD_VERSION_NORMAL;
365 }
366 }
367
368 if (s->version == QEMUD_VERSION_LEGACY) {
369 s->in_size = hex2int( s->data0 + LEGACY_LENGTH_OFFSET, LENGTH_SIZE );
370 s->in_channel = hex2int( s->data0 + LEGACY_CHANNEL_OFFSET, CHANNEL_SIZE );
371 } else {
372 s->in_size = hex2int( s->data0 + LENGTH_OFFSET, LENGTH_SIZE );
373 s->in_channel = hex2int( s->data0 + CHANNEL_OFFSET, CHANNEL_SIZE );
374 }
375#else
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700376 /* extract payload length + channel id */
377 s->in_size = hex2int( s->data0 + LENGTH_OFFSET, LENGTH_SIZE );
378 s->in_channel = hex2int( s->data0 + CHANNEL_OFFSET, CHANNEL_SIZE );
David Turner791d8612009-04-13 18:01:32 -0700379#endif
Ot ten Thije871da2a2010-09-20 10:29:22 +0100380 s->header->used = 0;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700381
382 if (s->in_size <= 0 || s->in_channel < 0) {
383 D("%s: bad header: '%.*s'", __FUNCTION__, HEADER_SIZE, s->data0);
384 continue;
385 }
386
387 if (s->in_size > MAX_SERIAL_PAYLOAD) {
388 D("%s: ignoring huge serial packet: length=%d channel=%1",
389 __FUNCTION__, s->in_size, s->in_channel);
390 s->overflow = s->in_size;
391 continue;
392 }
393
394 /* prepare 'in_data' for payload */
395 s->need_header = 0;
396 qemud_sink_reset(s->payload, s->in_size, s->data0);
397 }
398
399 /* read payload bytes */
400 if (!qemud_sink_fill(s->payload, &from, &len))
401 break;
402
403 /* zero-terminate payload, then send it to receiver */
404 s->payload->buff[s->payload->size] = 0;
405 D("%s: channel=%2d len=%3d '%s'", __FUNCTION__,
406 s->in_channel, s->payload->size,
407 quote_bytes((const void*)s->payload->buff, s->payload->size));
408
409 s->recv_func( s->recv_opaque, s->in_channel, s->payload->buff, s->payload->size );
410
411 /* prepare for new header */
412 s->need_header = 1;
413 }
414}
415
David Turner791d8612009-04-13 18:01:32 -0700416
417#if SUPPORT_LEGACY_QEMUD
418static void
419qemud_serial_send_legacy_probe( QemudSerial* s )
420{
421 /* we're going to send a specially crafted packet to the qemud
422 * daemon, this will help us determine whether we're talking
423 * to a legacy or a normal daemon.
424 *
425 * the trick is to known that a legacy daemon uses the following
426 * header:
427 *
428 * <length><channel><payload>
429 *
430 * while the normal one uses:
431 *
432 * <channel><length><payload>
433 *
434 * where <channel> is a 2-hexchar string, and <length> a 4-hexchar
435 * string.
436 *
437 * if we send a header of "000100", it is interpreted:
438 *
439 * - as the header of a 1-byte payload by the legacy daemon
440 * - as the header of a 256-byte payload by the normal one.
441 *
442 * we're going to send something that looks like:
443 *
444 * "000100" + "X" +
445 * "000b00" + "connect:gsm" +
446 * "000b00" + "connect:gps" +
447 * "000f00" + "connect:control" +
448 * "00c210" + "0"*194
449 *
450 * the normal daemon will interpret this as a 256-byte payload
451 * for channel 0, with garbage content ("X000b00conn...") which
452 * will be silently ignored.
453 *
454 * on the other hand, the legacy daemon will see it as a
455 * series of packets:
456 *
457 * one message "X" on channel 0, which will force the daemon
458 * to send back "001200ko:unknown command" as its first answer.
459 *
460 * three "connect:<xxx>" messages used to receive the channel
461 * numbers of the three legacy services implemented by the daemon.
462 *
463 * a garbage packet of 194 zeroes for channel 16, which will be
464 * silently ignored.
465 */
466 uint8_t tab[194];
467
468 memset(tab, 0, sizeof(tab));
469 qemu_chr_write(s->cs, (uint8_t*)"000100X", 7);
470 qemu_chr_write(s->cs, (uint8_t*)"000b00connect:gsm", 17);
471 qemu_chr_write(s->cs, (uint8_t*)"000b00connect:gps", 17);
472 qemu_chr_write(s->cs, (uint8_t*)"000f00connect:control", 21);
473 qemu_chr_write(s->cs, (uint8_t*)"00c210", 6);
474 qemu_chr_write(s->cs, tab, sizeof(tab));
475}
476#endif /* SUPPORT_LEGACY_QEMUD */
477
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700478/* intialize a QemudSerial object with a charpipe endpoint
479 * and a receiver.
480 */
481static void
482qemud_serial_init( QemudSerial* s,
483 CharDriverState* cs,
484 QemudSerialReceive recv_func,
485 void* recv_opaque )
486{
487 s->cs = cs;
488 s->recv_func = recv_func;
489 s->recv_opaque = recv_opaque;
490 s->need_header = 1;
491 s->overflow = 0;
492
493 qemud_sink_reset( s->header, HEADER_SIZE, s->data0 );
494 s->in_size = 0;
495 s->in_channel = -1;
496
David Turner791d8612009-04-13 18:01:32 -0700497#if SUPPORT_LEGACY_QEMUD
498 s->version = QEMUD_VERSION_UNKNOWN;
499 qemud_serial_send_legacy_probe(s);
500#endif
501
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700502 qemu_chr_add_handlers( cs,
503 qemud_serial_can_read,
504 qemud_serial_read,
505 NULL,
506 s );
507}
508
509/* send a message to the serial port. This will add the necessary
510 * header.
511 */
512static void
513qemud_serial_send( QemudSerial* s,
514 int channel,
515 ABool framing,
516 const uint8_t* msg,
517 int msglen )
518{
519 uint8_t header[HEADER_SIZE];
520 uint8_t frame[FRAME_HEADER_SIZE];
521 int avail, len = msglen;
522
523 if (msglen <= 0 || channel < 0)
524 return;
525
526 D("%s: channel=%2d len=%3d '%s'",
527 __FUNCTION__, channel, msglen,
528 quote_bytes((const void*)msg, msglen));
529
530 if (framing) {
531 len += FRAME_HEADER_SIZE;
532 }
533
534 /* packetize the payload for the serial MTU */
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100535 while (len > 0)
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700536 {
537 avail = len;
538 if (avail > MAX_SERIAL_PAYLOAD)
539 avail = MAX_SERIAL_PAYLOAD;
540
541 /* write this packet's header */
David Turner791d8612009-04-13 18:01:32 -0700542#if SUPPORT_LEGACY_QEMUD
543 if (s->version == QEMUD_VERSION_LEGACY) {
544 int2hex(header + LEGACY_LENGTH_OFFSET, LENGTH_SIZE, avail);
545 int2hex(header + LEGACY_CHANNEL_OFFSET, CHANNEL_SIZE, channel);
546 } else {
547 int2hex(header + LENGTH_OFFSET, LENGTH_SIZE, avail);
548 int2hex(header + CHANNEL_OFFSET, CHANNEL_SIZE, channel);
549 }
550#else
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700551 int2hex(header + LENGTH_OFFSET, LENGTH_SIZE, avail);
552 int2hex(header + CHANNEL_OFFSET, CHANNEL_SIZE, channel);
David Turner791d8612009-04-13 18:01:32 -0700553#endif
554 T("%s: '%.*s'", __FUNCTION__, HEADER_SIZE, header);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700555 qemu_chr_write(s->cs, header, HEADER_SIZE);
556
557 /* insert frame header when needed */
558 if (framing) {
559 int2hex(frame, FRAME_HEADER_SIZE, msglen);
David Turner791d8612009-04-13 18:01:32 -0700560 T("%s: '%.*s'", __FUNCTION__, FRAME_HEADER_SIZE, frame);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700561 qemu_chr_write(s->cs, frame, FRAME_HEADER_SIZE);
562 avail -= FRAME_HEADER_SIZE;
563 len -= FRAME_HEADER_SIZE;
564 framing = 0;
565 }
566
567 /* write message content */
David Turner791d8612009-04-13 18:01:32 -0700568 T("%s: '%.*s'", __FUNCTION__, avail, msg);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700569 qemu_chr_write(s->cs, msg, avail);
570 msg += avail;
571 len -= avail;
572 }
573}
574
575/** CLIENTS
576 **/
577
578/* A QemudClient models a single client as seen by the emulator.
579 * Each client has its own channel id, and belongs to a given
580 * QemudService (see below).
581 *
582 * There is a global list of clients used to multiplex incoming
583 * messages from the channel id (see qemud_multiplexer_serial_recv()).
584 *
585 */
586
587struct QemudClient {
588 int channel;
589 QemudSerial* serial;
590 void* clie_opaque;
591 QemudClientRecv clie_recv;
592 QemudClientClose clie_close;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100593 QemudClientSave clie_save;
594 QemudClientLoad clie_load;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700595 QemudService* service;
596 QemudClient* next_serv; /* next in same service */
597 QemudClient* next;
598 QemudClient** pref;
599
600 /* framing support */
601 int framing;
602 ABool need_header;
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100603 ABool closing;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700604 QemudSink header[1];
605 uint8_t header0[FRAME_HEADER_SIZE];
606 QemudSink payload[1];
607};
608
609static void qemud_service_remove_client( QemudService* service,
610 QemudClient* client );
611
612/* remove a QemudClient from global list */
613static void
614qemud_client_remove( QemudClient* c )
615{
616 c->pref[0] = c->next;
617 if (c->next)
618 c->next->pref = c->pref;
619
620 c->next = NULL;
621 c->pref = &c->next;
622}
623
624/* add a QemudClient to global list */
625static void
626qemud_client_prepend( QemudClient* c, QemudClient** plist )
627{
628 c->next = *plist;
629 c->pref = plist;
630 *plist = c;
631 if (c->next)
632 c->next->pref = &c->next;
633}
634
635/* receive a new message from a client, and dispatch it to
636 * the real service implementation.
637 */
638static void
639qemud_client_recv( void* opaque, uint8_t* msg, int msglen )
640{
641 QemudClient* c = opaque;
642
643 /* no framing, things are simple */
644 if (!c->framing) {
645 if (c->clie_recv)
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200646 c->clie_recv( c->clie_opaque, msg, msglen, c );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700647 return;
648 }
649
650 /* framing */
651
652#if 1
653 /* special case, in 99% of cases, everything is in
654 * the incoming message, and we can do all we need
655 * directly without dynamic allocation.
656 */
657 if (msglen > FRAME_HEADER_SIZE &&
658 c->need_header == 1 &&
659 qemud_sink_needed(c->header) == 0)
660 {
661 int len = hex2int( msg, FRAME_HEADER_SIZE );
662
663 if (len >= 0 && msglen == len + FRAME_HEADER_SIZE) {
664 if (c->clie_recv)
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100665 c->clie_recv( c->clie_opaque,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700666 msg+FRAME_HEADER_SIZE,
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200667 msglen-FRAME_HEADER_SIZE, c );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700668 return;
669 }
670 }
671#endif
672
673 while (msglen > 0) {
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700674 uint8_t *data;
675
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700676 /* read the header */
677 if (c->need_header) {
678 int frame_size;
679 uint8_t* data;
680
681 if (!qemud_sink_fill(c->header, (const uint8_t**)&msg, &msglen))
682 break;
683
684 frame_size = hex2int(c->header0, 4);
685 if (frame_size == 0) {
686 D("%s: ignoring empty frame", __FUNCTION__);
687 continue;
688 }
689 if (frame_size < 0) {
690 D("%s: ignoring corrupted frame header '.*s'",
691 __FUNCTION__, FRAME_HEADER_SIZE, c->header0 );
692 continue;
693 }
694
695 AARRAY_NEW(data, frame_size+1); /* +1 for terminating zero */
696 qemud_sink_reset(c->payload, frame_size, data);
697 c->need_header = 0;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100698 c->header->used = 0;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700699 }
700
701 /* read the payload */
702 if (!qemud_sink_fill(c->payload, (const uint8_t**)&msg, &msglen))
703 break;
704
705 c->payload->buff[c->payload->size] = 0;
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700706 c->need_header = 1;
707 data = c->payload->buff;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700708
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700709 /* Technically, calling 'clie_recv' can destroy client object 'c'
710 * if it decides to close the connection, so ensure we don't
711 * use/dereference it after the call. */
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700712 if (c->clie_recv)
David 'Digit' Turner318e4f22009-05-25 18:01:03 +0200713 c->clie_recv( c->clie_opaque, c->payload->buff, c->payload->size, c );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700714
David 'Digit' Turner83f82212010-06-25 12:46:24 -0700715 AFREE(data);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700716 }
717}
718
719/* disconnect a client. this automatically frees the QemudClient.
720 * note that this also removes the client from the global list
721 * and from its service's list, if any.
722 */
723static void
724qemud_client_disconnect( void* opaque )
725{
726 QemudClient* c = opaque;
727
David 'Digit' Turnerbb1f4322011-03-21 17:50:20 +0100728 if (c->closing) { /* recursive call, exit immediately */
729 return;
730 }
731 c->closing = 1;
732
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700733 /* remove from current list */
734 qemud_client_remove(c);
735
736 /* send a disconnect command to the daemon */
737 if (c->channel > 0) {
738 char tmp[128], *p=tmp, *end=p+sizeof(tmp);
David Turnerfff1ae52009-04-05 14:22:28 -0700739 p = bufprint(tmp, end, "disconnect:%02x", c->channel);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700740 qemud_serial_send(c->serial, 0, 0, (uint8_t*)tmp, p-tmp);
741 }
742
743 /* call the client close callback */
744 if (c->clie_close) {
745 c->clie_close(c->clie_opaque);
746 c->clie_close = NULL;
747 }
748 c->clie_recv = NULL;
749
750 /* remove from service list, if any */
751 if (c->service) {
752 qemud_service_remove_client(c->service, c);
753 c->service = NULL;
754 }
755
756 AFREE(c);
757}
758
759/* allocate a new QemudClient object */
760static QemudClient*
761qemud_client_alloc( int channel_id,
762 void* clie_opaque,
763 QemudClientRecv clie_recv,
764 QemudClientClose clie_close,
Ot ten Thije871da2a2010-09-20 10:29:22 +0100765 QemudClientSave clie_save,
766 QemudClientLoad clie_load,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700767 QemudSerial* serial,
768 QemudClient** pclients )
769{
770 QemudClient* c;
771
772 ANEW0(c);
773
774 c->serial = serial;
775 c->channel = channel_id;
776 c->clie_opaque = clie_opaque;
777 c->clie_recv = clie_recv;
778 c->clie_close = clie_close;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100779 c->clie_save = clie_save;
780 c->clie_load = clie_load;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700781
782 c->framing = 0;
783 c->need_header = 1;
784 qemud_sink_reset(c->header, FRAME_HEADER_SIZE, c->header0);
785
786 qemud_client_prepend(c, pclients);
787
788 return c;
789}
790
Ot ten Thije871da2a2010-09-20 10:29:22 +0100791/* forward */
792static void qemud_service_save_name( QEMUFile* f, QemudService* s );
793static char* qemud_service_load_name( QEMUFile* f );
794static QemudService* qemud_service_find( QemudService* service_list,
795 const char* service_name );
796static QemudClient* qemud_service_connect_client( QemudService *sv,
797 int channel_id );
798
799/* Saves the client state needed to re-establish connections on load.
800 */
801static void
802qemud_client_save(QEMUFile* f, QemudClient* c)
803{
804 /* save generic information */
805 qemud_service_save_name(f, c->service);
806 qemu_put_be32(f, c->channel);
807
808 /* save client-specific state */
809 if (c->clie_save)
810 c->clie_save(f, c, c->clie_opaque);
811
812 /* save framing configuration */
813 qemu_put_be32(f, c->framing);
814 if (c->framing) {
815 qemu_put_be32(f, c->need_header);
816 /* header sink always connected to c->header0, no need to save */
817 qemu_put_be32(f, FRAME_HEADER_SIZE);
818 qemu_put_buffer(f, c->header0, FRAME_HEADER_SIZE);
819 /* payload sink */
820 qemud_sink_save(f, c->payload);
821 qemu_put_buffer(f, c->payload->buff, c->payload->size);
822 }
823}
824
825/* Loads client state from file, then starts a new client connected to the
826 * corresponding service.
827 */
828static int
829qemud_client_load(QEMUFile* f, QemudService* current_services )
830{
831 char *service_name = qemud_service_load_name(f);
832 if (service_name == NULL)
833 return -EIO;
834
835 /* get current service instance */
836 QemudService *sv = qemud_service_find(current_services, service_name);
837 if (sv == NULL) {
838 D("%s: load failed: unknown service \"%s\"\n",
839 __FUNCTION__, service_name);
840 return -EIO;
841 }
842
843 /* get channel id */
844 int channel = qemu_get_be32(f);
845 if (channel == 0) {
846 D("%s: illegal snapshot: client for control channel must no be saved\n",
847 __FUNCTION__);
848 return -EIO;
849 }
850
851 /* re-connect client */
852 QemudClient* c = qemud_service_connect_client(sv, channel);
853 if(c == NULL)
854 return -EIO;
855
856 /* load client-specific state */
857 int ret;
858 if (c->clie_load)
859 if ((ret = c->clie_load(f, c, c->clie_opaque)))
860 return ret; /* load failure */
861
862 /* load framing configuration */
863 c->framing = qemu_get_be32(f);
864 if (c->framing) {
865
866 /* header buffer */
867 c->need_header = qemu_get_be32(f);
868 int header_size = qemu_get_be32(f);
869 if (header_size > FRAME_HEADER_SIZE) {
870 D("%s: load failed: payload buffer requires %d bytes, %d available\n",
871 __FUNCTION__, header_size, FRAME_HEADER_SIZE);
872 return -EIO;
873 }
874 int ret;
875 if ((ret = qemu_get_buffer(f, c->header0, header_size)) != header_size) {
876 D("%s: frame header buffer load failed: expected %d bytes, got %d\n",
877 __FUNCTION__, header_size, ret);
878 return -EIO;
879 }
880
881 /* payload sink */
882 if ((ret = qemud_sink_load(f, c->payload)))
883 return ret;
884
885 /* replace payload buffer by saved data */
886 if (c->payload->buff) {
887 AFREE(c->payload->buff);
888 }
889 AARRAY_NEW(c->payload->buff, c->payload->size+1); /* +1 for terminating zero */
890 if ((ret = qemu_get_buffer(f, c->payload->buff, c->payload->size)) != c->payload->size) {
891 D("%s: frame payload buffer load failed: expected %d bytes, got %d\n",
892 __FUNCTION__, c->payload->size, ret);
893 AFREE(c->payload->buff);
894 return -EIO;
895 }
896 }
897
898 return 0;
899}
900
901
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700902/** SERVICES
903 **/
904
905/* A QemudService models a _named_ service facility implemented
906 * by the emulator, that clients in the emulated system can connect
907 * to.
908 *
909 * Each service can have a limit on the number of clients they
910 * accept (this number if unlimited if 'max_clients' is 0).
911 *
912 * Each service maintains a list of active QemudClients and
913 * can also be used to create new QemudClient objects through
914 * its 'serv_opaque' and 'serv_connect' fields.
915 */
916struct QemudService {
917 const char* name;
918 int max_clients;
919 int num_clients;
920 QemudClient* clients;
921 QemudServiceConnect serv_connect;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100922 QemudServiceSave serv_save;
923 QemudServiceLoad serv_load;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700924 void* serv_opaque;
925 QemudService* next;
926};
927
928/* Create a new QemudService object */
929static QemudService*
930qemud_service_new( const char* name,
931 int max_clients,
932 void* serv_opaque,
933 QemudServiceConnect serv_connect,
Ot ten Thije871da2a2010-09-20 10:29:22 +0100934 QemudServiceSave serv_save,
935 QemudServiceLoad serv_load,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700936 QemudService** pservices )
937{
938 QemudService* s;
939
940 ANEW0(s);
941 s->name = ASTRDUP(name);
942 s->max_clients = max_clients;
943 s->num_clients = 0;
944 s->clients = NULL;
945
946 s->serv_opaque = serv_opaque;
947 s->serv_connect = serv_connect;
Ot ten Thije871da2a2010-09-20 10:29:22 +0100948 s->serv_save = serv_save;
949 s->serv_load = serv_load;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -0700950
951 s->next = *pservices;
952 *pservices = s;
953
954 return s;
955}
956
957/* used internally to populate a QemudService object with a
958 * new QemudClient */
959static void
960qemud_service_add_client( QemudService* s, QemudClient* c )
961{
962 c->service = s;
963 c->next_serv = s->clients;
964 s->clients = c;
965 s->num_clients += 1;
966}
967
968/* used internally to remove a QemudClient from a QemudService */
969static void
970qemud_service_remove_client( QemudService* s, QemudClient* c )
971{
972 QemudClient** pnode = &s->clients;
973 QemudClient* node;
974
975 /* remove from clients linked-list */
976 for (;;) {
977 node = *pnode;
978 if (node == NULL) {
979 D("%s: could not find client %d for service '%s'",
980 __FUNCTION__, c->channel, s->name);
981 return;
982 }
983 if (node == c)
984 break;
985 pnode = &node->next_serv;
986 }
987
988 *pnode = node->next_serv;
989 s->num_clients -= 1;
990}
991
Ot ten Thije871da2a2010-09-20 10:29:22 +0100992/* ask the service to create a new QemudClient. Note that we
993 * assume that this calls qemud_client_new() which will add
994 * the client to the service's list automatically.
995 *
996 * returns the client or NULL if an error occurred
997 */
998static QemudClient*
999qemud_service_connect_client(QemudService *sv, int channel_id)
1000{
1001 QemudClient* client = sv->serv_connect( sv->serv_opaque, sv, channel_id );
1002 if (client == NULL) {
1003 D("%s: registration failed for '%s' service",
1004 __FUNCTION__, sv->name);
1005 return NULL;
1006 }
1007
1008 D("%s: registered client channel %d for '%s' service",
1009 __FUNCTION__, channel_id, sv->name);
1010 return client;
1011}
1012
1013/* find a registered service by name.
1014 */
1015static QemudService*
1016qemud_service_find( QemudService* service_list, const char* service_name)
1017{
1018 QemudService* sv = NULL;
1019 for (sv = service_list; sv != NULL; sv = sv->next) {
1020 if (!strcmp(sv->name, service_name)) {
1021 break;
1022 }
1023 }
1024 return sv;
1025}
1026
1027/* Save the name of the given service.
1028 */
1029static void
1030qemud_service_save_name(QEMUFile* f, QemudService* s)
1031{
1032 int len = strlen(s->name) + 1; // include '\0' terminator
1033 qemu_put_be32(f, len);
1034 qemu_put_buffer(f, (const uint8_t *) s->name, len);
1035}
1036
1037/* Load the name of a service. Returns a pointer to the loaded name, or NULL
1038 * on failure.
1039 */
1040static char*
1041qemud_service_load_name( QEMUFile* f )
1042{
1043 int ret;
1044 int name_len = qemu_get_be32(f);
1045 char *service_name = android_alloc(name_len);
1046 if ((ret = qemu_get_buffer(f, (uint8_t*)service_name, name_len) != name_len)) {
1047 D("%s: service name load failed: expected %d bytes, got %d\n",
1048 __FUNCTION__, name_len, ret);
1049 AFREE(service_name);
1050 return NULL;
1051 }
1052 if (service_name[name_len - 1] != '\0') {
1053 char last = service_name[name_len - 1];
1054 service_name[name_len - 1] = '\0'; /* make buffer contents printable */
1055 D("%s: service name load failed: expecting NULL-terminated string, but "
1056 "last char is '%c' (buffer contents: '%s%c')\n",
1057 __FUNCTION__, name_len, last, service_name, last);
1058 AFREE(service_name);
1059 return NULL;
1060 }
1061
1062 return service_name;
1063}
1064
1065/* Saves state of a service.
1066 */
1067static void
1068qemud_service_save(QEMUFile* f, QemudService* s)
1069{
1070 qemud_service_save_name(f, s);
1071 qemu_put_be32(f, s->max_clients);
1072 qemu_put_be32(f, s->num_clients);
1073
1074 if (s->serv_save)
1075 s->serv_save(f, s, s->serv_opaque);
1076}
1077
1078/* Loads service state from file, then updates the currently running instance
1079 * of that service to mirror the loaded state. If the service is not running,
1080 * the load process is aborted.
1081 *
1082 * Parameter 'current_services' should be the list of active services.
1083 */
1084static int
1085qemud_service_load( QEMUFile* f, QemudService* current_services )
1086{
1087 char* service_name = qemud_service_load_name(f);
1088 if (service_name == NULL)
1089 return -EIO;
1090
1091 /* get current service instance */
1092 QemudService *sv = qemud_service_find(current_services, service_name);
1093 if (sv == NULL) {
1094 D("%s: loading failed: service \"%s\" not available\n",
1095 __FUNCTION__, service_name);
1096 return -EIO;
1097 }
1098
1099 /* reconfigure service as required */
1100 sv->max_clients = qemu_get_be32(f);
1101 sv->num_clients = qemu_get_be32(f);
1102
1103 /* load service specific data */
1104 int ret;
1105 if (sv->serv_load)
1106 if ((ret = sv->serv_load(f, sv, sv->serv_opaque)))
1107 return ret; /* load failure */
1108
1109 return 0;
1110}
1111
1112
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001113/** MULTIPLEXER
1114 **/
1115
1116/* A QemudMultiplexer object maintains the global state of the
1117 * qemud service facility. It holds a QemudSerial object to
1118 * maintain the state of the serial port connection.
1119 *
1120 * The QemudMultiplexer receives all incoming messages from
1121 * the serial port, and dispatches them to the appropriate
1122 * QemudClient.
1123 *
1124 * It also has a global list of clients, and a global list of
1125 * services.
1126 *
1127 * Finally, the QemudMultiplexer has a special QemudClient used
1128 * to handle channel 0, i.e. the control channel used to handle
1129 * connections and disconnections of clients.
1130 */
1131typedef struct QemudMultiplexer QemudMultiplexer;
1132
1133struct QemudMultiplexer {
1134 QemudSerial serial[1];
1135 QemudClient* clients;
1136 QemudService* services;
1137};
1138
1139/* this is the serial_recv callback that is called
1140 * whenever an incoming message arrives through the serial port
1141 */
1142static void
1143qemud_multiplexer_serial_recv( void* opaque,
1144 int channel,
1145 uint8_t* msg,
1146 int msglen )
1147{
1148 QemudMultiplexer* m = opaque;
1149 QemudClient* c = m->clients;
1150
1151 /* dispatch to an existing client if possible
1152 * note that channel 0 is handled by a special
1153 * QemudClient that is setup in qemud_multiplexer_init()
1154 */
1155 for ( ; c != NULL; c = c->next ) {
1156 if (c->channel == channel) {
1157 qemud_client_recv(c, msg, msglen);
1158 return;
1159 }
1160 }
1161
1162 D("%s: ignoring %d bytes for unknown channel %d",
1163 __FUNCTION__, msglen, channel);
1164}
1165
1166/* handle a new connection attempt. This returns 0 on
1167 * success, -1 if the service name is unknown, or -2
1168 * if the service's maximum number of clients has been
1169 * reached.
1170 */
1171static int
1172qemud_multiplexer_connect( QemudMultiplexer* m,
1173 const char* service_name,
1174 int channel_id )
1175{
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001176 /* find the corresponding registered service by name */
Ot ten Thije871da2a2010-09-20 10:29:22 +01001177 QemudService* sv = qemud_service_find(m->services, service_name);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001178 if (sv == NULL) {
1179 D("%s: no registered '%s' service", __FUNCTION__, service_name);
1180 return -1;
1181 }
1182
1183 /* check service's client count */
1184 if (sv->max_clients > 0 && sv->num_clients >= sv->max_clients) {
1185 D("%s: registration failed for '%s' service: too many clients (%d)",
1186 __FUNCTION__, service_name, sv->num_clients);
1187 return -2;
1188 }
1189
Ot ten Thije871da2a2010-09-20 10:29:22 +01001190 /* connect a new client to the service on the given channel */
1191 if (qemud_service_connect_client(sv, channel_id) == NULL)
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001192 return -1;
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001193
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001194 return 0;
1195}
1196
1197/* disconnect a given client from its channel id */
1198static void
1199qemud_multiplexer_disconnect( QemudMultiplexer* m,
1200 int channel )
1201{
1202 QemudClient* c;
1203
1204 /* find the client by its channel id, then disconnect it */
1205 for (c = m->clients; c; c = c->next) {
1206 if (c->channel == channel) {
1207 D("%s: disconnecting client %d",
1208 __FUNCTION__, channel);
1209 /* note thatt this removes the client from
1210 * m->clients automatically.
1211 */
1212 c->channel = -1; /* no need to send disconnect:<id> */
1213 qemud_client_disconnect(c);
1214 return;
1215 }
1216 }
1217 D("%s: disconnecting unknown channel %d",
1218 __FUNCTION__, channel);
1219}
1220
Ot ten Thije871da2a2010-09-20 10:29:22 +01001221/* disconnects all channels, except for the control channel, without informing
1222 * the daemon in the guest that disconnection has occurred.
1223 *
1224 * Used to silently kill clients when restoring emulator state snapshots.
1225 */
1226static void
1227qemud_multiplexer_disconnect_noncontrol( QemudMultiplexer* m )
1228{
1229 QemudClient* c;
1230 QemudClient* next = m->clients;
1231
1232 while (next) {
1233 c = next;
1234 next = c->next; /* disconnect frees c, remember next in advance */
1235
1236 if (c->channel > 0) { /* skip control channel */
1237 D("%s: disconnecting client %d",
1238 __FUNCTION__, c->channel);
1239 D("%s: disconnecting client %d\n",
1240 __FUNCTION__, c->channel);
1241 c->channel = -1; /* do not send disconnect:<id> */
1242 qemud_client_disconnect(c);
1243 }
1244 }
1245}
1246
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001247/* handle control messages. This is used as the receive
1248 * callback for the special QemudClient setup to manage
1249 * channel 0.
1250 *
1251 * note that the message is zero-terminated for convenience
1252 * (i.e. msg[msglen] is a valid memory read that returns '\0')
1253 */
1254static void
David 'Digit' Turner318e4f22009-05-25 18:01:03 +02001255qemud_multiplexer_control_recv( void* opaque,
1256 uint8_t* msg,
1257 int msglen,
1258 QemudClient* client )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001259{
1260 QemudMultiplexer* mult = opaque;
1261 uint8_t* msgend = msg + msglen;
1262 char tmp[64], *p=tmp, *end=p+sizeof(tmp);
1263
1264 /* handle connection attempts.
1265 * the client message must be "connect:<service-name>:<id>"
David Turnerfff1ae52009-04-05 14:22:28 -07001266 * where <id> is a 2-char hexadecimal string, which must be > 0
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001267 */
1268 if (msglen > 8 && !memcmp(msg, "connect:", 8))
1269 {
1270 const char* service_name = (const char*)msg + 8;
1271 int channel, ret;
1272 char* q;
1273
1274 q = strchr(service_name, ':');
David Turnerfff1ae52009-04-05 14:22:28 -07001275 if (q == NULL || q+3 != (char*)msgend) {
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001276 D("%s: malformed connect message: '%.*s' (offset=%d)",
1277 __FUNCTION__, msglen, (const char*)msg, q ? q-(char*)msg : -1);
1278 return;
1279 }
1280 *q++ = 0; /* zero-terminate service name */
David Turnerfff1ae52009-04-05 14:22:28 -07001281 channel = hex2int((uint8_t*)q, 2);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001282 if (channel <= 0) {
1283 D("%s: malformed channel id '%.*s",
David Turnerfff1ae52009-04-05 14:22:28 -07001284 __FUNCTION__, 2, q);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001285 return;
1286 }
1287
1288 ret = qemud_multiplexer_connect(mult, service_name, channel);
1289 /* the answer can be one of:
1290 * ok:connect:<id>
1291 * ko:connect:<id>:<reason-for-failure>
1292 */
1293 if (ret < 0) {
1294 if (ret == -1) {
1295 /* could not connect */
David Turnerfff1ae52009-04-05 14:22:28 -07001296 p = bufprint(tmp, end, "ko:connect:%02x:unknown service", channel);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001297 } else {
David Turnerfff1ae52009-04-05 14:22:28 -07001298 p = bufprint(tmp, end, "ko:connect:%02x:service busy", channel);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001299 }
1300 }
1301 else {
David Turnerfff1ae52009-04-05 14:22:28 -07001302 p = bufprint(tmp, end, "ok:connect:%02x", channel);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001303 }
1304 qemud_serial_send(mult->serial, 0, 0, (uint8_t*)tmp, p-tmp);
1305 return;
1306 }
1307
1308 /* handle client disconnections,
1309 * this message arrives when the client has closed the connection.
David Turnerfff1ae52009-04-05 14:22:28 -07001310 * format: "disconnect:<id>" where <id> is a 2-hex channel id > 0
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001311 */
David Turnerfff1ae52009-04-05 14:22:28 -07001312 if (msglen == 13 && !memcmp(msg, "disconnect:", 11)) {
1313 int channel_id = hex2int(msg+11, 2);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001314 if (channel_id <= 0) {
1315 D("%s: malformed disconnect channel id: '%.*s'",
David Turnerfff1ae52009-04-05 14:22:28 -07001316 __FUNCTION__, 2, msg+11);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001317 return;
1318 }
1319 qemud_multiplexer_disconnect(mult, channel_id);
1320 return;
1321 }
1322
David Turner791d8612009-04-13 18:01:32 -07001323#if SUPPORT_LEGACY_QEMUD
1324 /* an ok:connect:<service>:<id> message can be received if we're
1325 * talking to a legacy qemud daemon, i.e. one running in a 1.0 or
1326 * 1.1 system image.
1327 *
1328 * we should treat is as a normal "connect:" attempt, except that
1329 * we must not send back any acknowledgment.
1330 */
1331 if (msglen > 11 && !memcmp(msg, "ok:connect:", 11)) {
1332 const char* service_name = (const char*)msg + 11;
1333 char* q = strchr(service_name, ':');
1334 int channel;
1335
1336 if (q == NULL || q+3 != (char*)msgend) {
1337 D("%s: malformed legacy connect message: '%.*s' (offset=%d)",
1338 __FUNCTION__, msglen, (const char*)msg, q ? q-(char*)msg : -1);
1339 return;
1340 }
1341 *q++ = 0; /* zero-terminate service name */
1342 channel = hex2int((uint8_t*)q, 2);
1343 if (channel <= 0) {
1344 D("%s: malformed legacy channel id '%.*s",
1345 __FUNCTION__, 2, q);
1346 return;
1347 }
1348
1349 switch (mult->serial->version) {
1350 case QEMUD_VERSION_UNKNOWN:
1351 mult->serial->version = QEMUD_VERSION_LEGACY;
1352 D("%s: legacy qemud daemon detected.", __FUNCTION__);
1353 break;
1354
1355 case QEMUD_VERSION_LEGACY:
1356 /* nothing unusual */
1357 break;
1358
1359 default:
1360 D("%s: weird, ignoring legacy qemud control message: '%.*s'",
1361 __FUNCTION__, msglen, msg);
1362 return;
1363 }
1364
1365 /* "hw-control" was called "control" in 1.0/1.1 */
1366 if (!strcmp(service_name,"control"))
1367 service_name = "hw-control";
1368
1369 qemud_multiplexer_connect(mult, service_name, channel);
1370 return;
1371 }
1372
1373 /* anything else, don't answer for legacy */
1374 if (mult->serial->version == QEMUD_VERSION_LEGACY)
1375 return;
1376#endif /* SUPPORT_LEGACY_QEMUD */
1377
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001378 /* anything else is a problem */
1379 p = bufprint(tmp, end, "ko:unknown command");
1380 qemud_serial_send(mult->serial, 0, 0, (uint8_t*)tmp, p-tmp);
1381}
1382
1383/* initialize the global QemudMultiplexer.
1384 */
1385static void
1386qemud_multiplexer_init( QemudMultiplexer* mult,
1387 CharDriverState* serial_cs )
1388{
1389 QemudClient* control;
1390
1391 /* initialize serial handler */
1392 qemud_serial_init( mult->serial,
1393 serial_cs,
1394 qemud_multiplexer_serial_recv,
1395 mult );
1396
1397 /* setup listener for channel 0 */
1398 control = qemud_client_alloc( 0,
1399 mult,
1400 qemud_multiplexer_control_recv,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001401 NULL, NULL, NULL,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001402 mult->serial,
1403 &mult->clients );
1404}
1405
1406/* the global multiplexer state */
1407static QemudMultiplexer _multiplexer[1];
1408
1409/** HIGH-LEVEL API
1410 **/
1411
1412/* this function must be used in the serv_connect callback
1413 * of a given QemudService object (see qemud_service_register()
1414 * below). It is used to register a new QemudClient to acknowledge
1415 * a new client connection.
1416 *
1417 * 'clie_opaque', 'clie_recv' and 'clie_close' are used to
1418 * send incoming client messages to the corresponding service
1419 * implementation, or notify the service that a client has
1420 * disconnected.
1421 */
1422QemudClient*
1423qemud_client_new( QemudService* service,
1424 int channelId,
1425 void* clie_opaque,
1426 QemudClientRecv clie_recv,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001427 QemudClientClose clie_close,
1428 QemudClientSave clie_save,
1429 QemudClientLoad clie_load )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001430{
1431 QemudMultiplexer* m = _multiplexer;
1432 QemudClient* c = qemud_client_alloc( channelId,
1433 clie_opaque,
1434 clie_recv,
1435 clie_close,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001436 clie_save,
1437 clie_load,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001438 m->serial,
1439 &m->clients );
1440
1441 qemud_service_add_client(service, c);
1442 return c;
1443}
1444
1445/* this can be used by a service implementation to send an answer
1446 * or message to a specific client.
1447 */
1448void
1449qemud_client_send ( QemudClient* client, const uint8_t* msg, int msglen )
1450{
1451 qemud_serial_send(client->serial, client->channel, client->framing != 0, msg, msglen);
1452}
1453
1454/* enable framing for this client. When TRUE, this will
1455 * use internally a simple 4-hexchar header before each
1456 * message exchanged through the serial port.
1457 */
1458void
1459qemud_client_set_framing( QemudClient* client, int framing )
1460{
1461 /* release dynamic buffer if we're disabling framing */
1462 if (client->framing) {
1463 if (!client->need_header) {
1464 AFREE(client->payload->buff);
1465 client->need_header = 1;
1466 }
1467 }
1468 client->framing = !!framing;
1469}
1470
1471/* this can be used by a service implementation to close a
1472 * specific client connection.
1473 */
1474void
1475qemud_client_close( QemudClient* client )
1476{
1477 qemud_client_disconnect(client);
1478}
1479
1480
Ot ten Thije871da2a2010-09-20 10:29:22 +01001481/** SNAPSHOT SUPPORT
1482 **/
1483
1484/* Saves the number of clients.
1485 */
1486static void
1487qemud_client_save_count(QEMUFile* f, QemudClient* c)
1488{
1489 unsigned int client_count = 0;
1490 for( ; c; c = c->next) // walk over linked list
1491 if (c->channel > 0) // skip control channel, which is not saved
1492 client_count++;
1493
1494 qemu_put_be32(f, client_count);
1495}
1496
1497/* Saves the number of services currently available.
1498 */
1499static void
1500qemud_service_save_count(QEMUFile* f, QemudService* s)
1501{
1502 unsigned int service_count = 0;
1503 for( ; s; s = s->next ) // walk over linked list
1504 service_count++;
1505
1506 qemu_put_be32(f, service_count);
1507}
1508
1509/* Save QemuD state to snapshot.
1510 *
1511 * The control channel has no state of its own, other than the local variables
1512 * in qemud_multiplexer_control_recv. We can therefore safely skip saving it,
1513 * which spares us dealing with the exception of a client not connected to a
1514 * service.
1515 */
1516static void
1517qemud_save(QEMUFile* f, void* opaque)
1518{
1519 QemudMultiplexer *m = opaque;
1520
1521 qemud_serial_save(f, m->serial);
1522
1523 /* save service states */
1524 qemud_service_save_count(f, m->services);
1525 QemudService *s;
1526 for (s = m->services; s; s = s->next)
1527 qemud_service_save(f, s);
1528
1529 /* save client channels */
1530 qemud_client_save_count(f, m->clients);
1531 QemudClient *c;
1532 for (c = m->clients; c; c = c->next) {
1533 if (c->channel > 0) { /* skip control channel client */
1534 qemud_client_save(f, c);
1535 }
1536 }
1537
1538}
1539
1540
1541/* Checks whether the same services are available at this point as when the
1542 * snapshot was made.
1543 */
1544static int
1545qemud_load_services( QEMUFile* f, QemudService* current_services )
1546{
1547 int i, ret;
1548 int service_count = qemu_get_be32(f);
1549 for (i = 0; i < service_count; i++) {
1550 if ((ret = qemud_service_load(f, current_services)))
1551 return ret;
1552 }
1553
1554 return 0;
1555}
1556
1557/* Removes all active non-control clients, then creates new ones with state
1558 * taken from the snapshot.
1559 *
1560 * We do not send "disconnect" commands, over the channel. If we did, we might
1561 * stop clients in the restored guest, resulting in an incorrect restore.
1562 *
1563 * Instead, we silently replace the clients that were running before the
1564 * restore with new clients, whose state we copy from the snapshot. Since
1565 * everything is multiplexed over one link, only the multiplexer notices the
1566 * changes, there is no communication with the guest.
1567 */
1568static int
1569qemud_load_clients(QEMUFile* f, QemudMultiplexer* m )
1570{
1571 /* Remove all clients, except on the control channel.*/
1572 qemud_multiplexer_disconnect_noncontrol(m);
1573
1574 /* Load clients from snapshot */
1575 int client_count = qemu_get_be32(f);
1576 int i, ret;
1577 for (i = 0; i < client_count; i++) {
1578 if ((ret = qemud_client_load(f, m->services))) {
1579 return ret;
1580 }
1581 }
1582
1583 return 0;
1584}
1585
1586/* Load QemuD state from file.
1587 */
1588static int
1589qemud_load(QEMUFile *f, void* opaque, int version)
1590{
1591 QemudMultiplexer *m = opaque;
1592
1593 int ret;
1594 if (version != QEMUD_SAVE_VERSION)
1595 return -1;
1596
1597 if ((ret = qemud_serial_load(f, m->serial)))
1598 return ret;
1599 if ((ret = qemud_load_services(f, m->services)))
1600 return ret;
1601 if ((ret = qemud_load_clients(f, m)))
1602 return ret;
1603
1604 return 0;
1605}
1606
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001607
1608/* this is the end of the serial charpipe that must be passed
1609 * to the emulated tty implementation. The other end of the
1610 * charpipe must be passed to qemud_multiplexer_init().
1611 */
1612static CharDriverState* android_qemud_cs;
1613
1614extern void
1615android_qemud_init( void )
1616{
1617 CharDriverState* cs;
1618
1619 if (android_qemud_cs != NULL)
1620 return;
1621
1622 if (qemu_chr_open_charpipe( &android_qemud_cs, &cs ) < 0) {
1623 derror( "%s: can't create charpipe to serial port",
1624 __FUNCTION__ );
1625 exit(1);
1626 }
1627
1628 qemud_multiplexer_init(_multiplexer, cs);
Ot ten Thije871da2a2010-09-20 10:29:22 +01001629
1630 register_savevm( "qemud", 0, QEMUD_SAVE_VERSION,
1631 qemud_save, qemud_load, _multiplexer);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001632}
1633
1634/* return the serial charpipe endpoint that must be used
1635 * by the emulated tty implementation.
1636 */
1637CharDriverState* android_qemud_get_cs( void )
1638{
1639 if (android_qemud_cs == NULL)
1640 android_qemud_init();
1641
1642 return android_qemud_cs;
1643}
1644
1645/* this function is used to register a new named qemud-based
1646 * service. You must provide 'serv_opaque' and 'serv_connect'
1647 * which will be called whenever a new client tries to connect
1648 * to the services.
1649 *
1650 * 'serv_connect' shall return NULL if the connection is refused,
1651 * or a handle to a new QemudClient otherwise. The latter can be
1652 * created through qemud_client_new() defined above.
1653 *
1654 * 'max_clients' is the maximum number of clients accepted by
1655 * the service concurrently. If this value is 0, then any number
1656 * of clients can connect.
1657 */
1658QemudService*
1659qemud_service_register( const char* service_name,
1660 int max_clients,
1661 void* serv_opaque,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001662 QemudServiceConnect serv_connect,
1663 QemudServiceSave serv_save,
1664 QemudServiceLoad serv_load )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001665{
1666 QemudMultiplexer* m = _multiplexer;
1667 QemudService* sv;
1668
1669 if (android_qemud_cs == NULL)
1670 android_qemud_init();
1671
1672 sv = qemud_service_new(service_name,
1673 max_clients,
1674 serv_opaque,
1675 serv_connect,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001676 serv_save,
1677 serv_load,
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001678 &m->services);
1679
1680 return sv;
1681}
1682
1683/* broadcast a given message to all clients of a given QemudService
1684 */
1685extern void
1686qemud_service_broadcast( QemudService* sv,
1687 const uint8_t* msg,
1688 int msglen )
1689{
1690 QemudClient* c;
1691
1692 for (c = sv->clients; c; c = c->next_serv)
1693 qemud_client_send(c, msg, msglen);
1694}
1695
1696
1697
1698/*
1699 * The following code is used for backwards compatibility reasons.
1700 * It allows you to implement a given qemud-based service through
1701 * a charpipe.
1702 *
1703 * In other words, this implements a QemudService and corresponding
1704 * QemudClient that connects a qemud client running in the emulated
1705 * system, to a CharDriverState object implemented through a charpipe.
1706 *
1707 * QemudCharClient <===charpipe====> (char driver user)
1708 *
1709 * For example, this is used to implement the "gsm" service when the
1710 * modem emulation is provided through an external serial device.
1711 *
1712 * A QemudCharService can have only one client by definition.
1713 * There is no QemudCharClient object because we can store a single
1714 * CharDriverState handle in the 'opaque' field for simplicity.
1715 */
1716
1717typedef struct {
1718 QemudService* service;
1719 CharDriverState* cs;
1720} QemudCharService;
1721
1722/* called whenever a new message arrives from a qemud client.
1723 * this simply sends the message through the charpipe to the user.
1724 */
1725static void
David 'Digit' Turner318e4f22009-05-25 18:01:03 +02001726_qemud_char_client_recv( void* opaque, uint8_t* msg, int msglen,
1727 QemudClient* client )
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001728{
1729 CharDriverState* cs = opaque;
1730 qemu_chr_write(cs, msg, msglen);
1731}
1732
1733/* we don't expect clients of char. services to exit. Just
1734 * print an error to signal an unexpected situation. We should
1735 * be able to recover from these though, so don't panic.
1736 */
1737static void
1738_qemud_char_client_close( void* opaque )
1739{
1740 derror("unexpected qemud char. channel close");
1741}
1742
1743
1744/* called by the charpipe to know how much data can be read from
1745 * the user. Since we send everything directly to the serial port
1746 * we can return an arbitrary number.
1747 */
1748static int
1749_qemud_char_service_can_read( void* opaque )
1750{
1751 return 8192; /* whatever */
1752}
1753
1754/* called to read data from the charpipe and send it to the client.
1755 * used qemud_service_broadcast() even if there is a single client
1756 * because we don't need a QemudCharClient object this way.
1757 */
1758static void
1759_qemud_char_service_read( void* opaque, const uint8_t* from, int len )
1760{
1761 QemudService* sv = opaque;
1762 qemud_service_broadcast( sv, from, len );
1763}
1764
1765/* called when a qemud client tries to connect to a char. service.
1766 * we simply create a new client and open the charpipe to receive
1767 * data from it.
1768 */
1769static QemudClient*
1770_qemud_char_service_connect( void* opaque, QemudService* sv, int channel )
1771{
1772 CharDriverState* cs = opaque;
1773 QemudClient* c = qemud_client_new( sv, channel,
1774 cs,
1775 _qemud_char_client_recv,
Ot ten Thije871da2a2010-09-20 10:29:22 +01001776 _qemud_char_client_close,
1777 NULL, NULL );
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001778
1779 /* now we can open the gates :-) */
1780 qemu_chr_add_handlers( cs,
1781 _qemud_char_service_can_read,
1782 _qemud_char_service_read,
1783 NULL,
1784 sv );
1785
1786 return c;
1787}
1788
1789/* returns a charpipe endpoint that can be used by an emulated
1790 * device or external serial port to implement a char. service
1791 */
1792int
1793android_qemud_get_channel( const char* name, CharDriverState* *pcs )
1794{
1795 CharDriverState* cs;
1796
1797 if (qemu_chr_open_charpipe(&cs, pcs) < 0) {
1798 derror("can't open charpipe for '%s' qemud service", name);
1799 exit(2);
1800 }
Ot ten Thije871da2a2010-09-20 10:29:22 +01001801 qemud_service_register(name, 1, cs, _qemud_char_service_connect, NULL, NULL);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001802 return 0;
1803}
1804
1805/* set the character driver state for a given qemud communication channel. this
1806 * is used to attach the channel to an external char driver device directly.
1807 * returns 0 on success, -1 on error
1808 */
1809int
1810android_qemud_set_channel( const char* name, CharDriverState* peer_cs )
1811{
David Turnerfff1ae52009-04-05 14:22:28 -07001812 CharDriverState* char_buffer = qemu_chr_open_buffer(peer_cs);
1813
1814 if (char_buffer == NULL)
1815 return -1;
1816
Ot ten Thije871da2a2010-09-20 10:29:22 +01001817 qemud_service_register(name, 1, char_buffer, _qemud_char_service_connect,
1818 NULL, NULL);
The Android Open Source Project9877e2e2009-03-18 17:39:44 -07001819 return 0;
1820}