19877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* Copyright (C) 2007-2008 The Android Open Source Project
29877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project**
39877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project** This software is licensed under the terms of the GNU General Public
49877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project** License version 2, as published by the Free Software Foundation, and
59877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project** may be copied, distributed, and modified under those terms.
69877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project**
79877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project** This program is distributed in the hope that it will be useful,
89877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project** but WITHOUT ANY WARRANTY; without even the implied warranty of
99877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project** GNU General Public License for more details.
119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project*/
129877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#include "android/hw-qemud.h"
139877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#include "android/utils/debug.h"
149877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#include "android/utils/misc.h"
159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#include "android/utils/system.h"
169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#include "android/utils/bufprint.h"
1777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine#include "android/looper.h"
18871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije#include "hw/hw.h"
19f5bc01c356e1fa924ed07aadf589b3663873593eDavid 'Digit' Turner#include "hw/android/goldfish/pipe.h"
20e7216d82dbaa19892ad62b07402d512234559a6eDavid 'Digit' Turner#include "sysemu/char.h"
21e1e03df288d5a44bfbffbd86588395c7cbbc27dfDavid 'Digit' Turner#include "android/charpipe.h"
22e1e03df288d5a44bfbffbd86588395c7cbbc27dfDavid 'Digit' Turner#include "android/cbuffer.h"
233e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner#include "utils/panic.h"
249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
257ffddd66de46c27c4e24d9af9b47fc0b9a8da8d1Vladimir Chtchetkine#define  D(...)    VERBOSE_PRINT(qemud,__VA_ARGS__)
269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  D_ACTIVE  VERBOSE_CHECK(qemud)
279877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
289877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* the T(...) macro is used to dump traffic */
299877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  T_ACTIVE   0
309877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#if T_ACTIVE
329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  T(...)    VERBOSE_PRINT(qemud,__VA_ARGS__)
339877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#else
349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  T(...)    ((void)0)
359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#endif
369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* max serial MTU. Don't change this without modifying
389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * development/emulator/qemud/qemud.c as well.
399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  MAX_SERIAL_PAYLOAD        4000
419877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* max framed data payload. Must be < (1 << 16)
439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  MAX_FRAME_PAYLOAD  65535
459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
46871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Version number of snapshots code. Increment whenever the data saved
47871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * or the layout in which it is saved is changed.
48871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
49d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine#define QEMUD_SAVE_VERSION 2
50871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
51a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner#ifndef min
524c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine#define min(a, b) (((a) < (b)) ? (a) : (b))
53a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner#endif
549877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
55791d86195fedca3a8cba5d7fa3e3610302361a78David Turner/* define SUPPORT_LEGACY_QEMUD to 1 if you want to support
56791d86195fedca3a8cba5d7fa3e3610302361a78David Turner * talking to a legacy qemud daemon. See docs/ANDROID-QEMUD.TXT
57791d86195fedca3a8cba5d7fa3e3610302361a78David Turner * for details.
58791d86195fedca3a8cba5d7fa3e3610302361a78David Turner */
59334ab475d2f27dbf6fbf836c2d4fb86dbb02a15cJun Nakajima#ifdef TARGET_ARM
60791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#define  SUPPORT_LEGACY_QEMUD  1
61334ab475d2f27dbf6fbf836c2d4fb86dbb02a15cJun Nakajima#endif
62334ab475d2f27dbf6fbf836c2d4fb86dbb02a15cJun Nakajima#ifdef TARGET_I386
63334ab475d2f27dbf6fbf836c2d4fb86dbb02a15cJun Nakajima#define  SUPPORT_LEGACY_QEMUD  0 /* no legacy support */
64334ab475d2f27dbf6fbf836c2d4fb86dbb02a15cJun Nakajima#endif
65fbcbf4201b9b56b72e9a06d292ae94360dd66b9eDavid Turner#if SUPPORT_LEGACY_QEMUD
66fbcbf4201b9b56b72e9a06d292ae94360dd66b9eDavid Turner#include "telephony/android_modem.h"
67fbcbf4201b9b56b72e9a06d292ae94360dd66b9eDavid Turner#include "telephony/modem_driver.h"
68fbcbf4201b9b56b72e9a06d292ae94360dd66b9eDavid Turner#endif
69fbcbf4201b9b56b72e9a06d292ae94360dd66b9eDavid Turner
709877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/*
71791d86195fedca3a8cba5d7fa3e3610302361a78David Turner *  This implements support for the 'qemud' multiplexing communication
72791d86195fedca3a8cba5d7fa3e3610302361a78David Turner *  channel between clients running in the emulated system and 'services'
73791d86195fedca3a8cba5d7fa3e3610302361a78David Turner *  provided by the emulator.
749877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
75791d86195fedca3a8cba5d7fa3e3610302361a78David Turner *  For additional details, please read docs/ANDROID-QEMUD.TXT
769877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
779877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/*
809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * IMPLEMENTATION DETAILS:
819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
829877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * We use one charpipe to connect the emulated serial port to the 'QemudSerial'
839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * object. This object is used to receive data from the serial port, and
849877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * unframe messages (i.e. extract payload length + channel id from header,
859877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * then the payload itself), before sending them to a generic receiver.
869877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
879877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * The QemudSerial object can also be used to send messages to the daemon
889877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * through the serial port (see qemud_serial_send())
899877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
909877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * The multiplexer is connected to one or more 'service' objects.
919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * are themselves connected through a charpipe to an emulated device or
929877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * control sub-module in the emulator.
939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
949877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *  tty <==charpipe==> QemudSerial ---> QemudMultiplexer ----> QemudClient
959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *                          ^                                      |
969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *                          |                                      |
979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *                          +--------------------------------------+
989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
1009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/** HANDLING INCOMING DATA FRAMES
1029877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project **/
1039877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
104791d86195fedca3a8cba5d7fa3e3610302361a78David Turner/* A QemudSink is just a handly data structure that is used to
105791d86195fedca3a8cba5d7fa3e3610302361a78David Turner * read a fixed amount of bytes into a buffer
106791d86195fedca3a8cba5d7fa3e3610302361a78David Turner */
1079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projecttypedef struct QemudSink {
108871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int       used;  /* number of bytes already used */
109871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int       size;  /* total number of bytes in buff */
1109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    uint8_t*  buff;
1119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project} QemudSink;
1129877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
113871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* save the state of a QemudSink to a snapshot.
114871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije *
115871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * The buffer pointer is not saved, since it usually points to buffer
116871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * fields in other structs, which have save functions themselves. It
117871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * is up to the caller to make sure the buffer is correctly saved and
118871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * restored.
119871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
120871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic void
121871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_sink_save(QEMUFile* f, QemudSink* s)
122871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
123871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, s->used);
124871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, s->size);
125871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
126871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
127871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* load the state of a QemudSink from a snapshot.
128871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
129871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic int
130871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_sink_load(QEMUFile* f, QemudSink* s)
131871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
132871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    s->used = qemu_get_be32(f);
133871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    s->size = qemu_get_be32(f);
134871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return 0;
135871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
136871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
137871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
138791d86195fedca3a8cba5d7fa3e3610302361a78David Turner/* reset a QemudSink, i.e. provide a new destination buffer address
139791d86195fedca3a8cba5d7fa3e3610302361a78David Turner * and its size in bytes.
140791d86195fedca3a8cba5d7fa3e3610302361a78David Turner */
1419877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
1429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_sink_reset( QemudSink*  ss, int  size, uint8_t*  buffer )
1439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
144871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    ss->used = 0;
1459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    ss->size = size;
1469877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    ss->buff = buffer;
1479877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
1489877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
149791d86195fedca3a8cba5d7fa3e3610302361a78David Turner/* try to fill the sink by reading bytes from the source buffer
150791d86195fedca3a8cba5d7fa3e3610302361a78David Turner * '*pmsg' which contains '*plen' bytes
151791d86195fedca3a8cba5d7fa3e3610302361a78David Turner *
152791d86195fedca3a8cba5d7fa3e3610302361a78David Turner * this functions updates '*pmsg' and '*plen', and returns
153791d86195fedca3a8cba5d7fa3e3610302361a78David Turner * 1 if the sink's destination buffer is full, or 0 otherwise.
154791d86195fedca3a8cba5d7fa3e3610302361a78David Turner */
1559877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic int
1569877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_sink_fill( QemudSink*  ss, const uint8_t* *pmsg, int  *plen)
1579877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
158871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int  avail = ss->size - ss->used;
1599877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1609877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (avail <= 0)
1619877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return 1;
1629877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1639877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (avail > *plen)
1649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        avail = *plen;
1659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
166871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    memcpy(ss->buff + ss->used, *pmsg, avail);
1679877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    *pmsg += avail;
1689877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    *plen -= avail;
169871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    ss->used += avail;
1709877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
171871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return (ss->used == ss->size);
1729877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
1739877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
174791d86195fedca3a8cba5d7fa3e3610302361a78David Turner/* returns the number of bytes needed to fill a sink's destination
175791d86195fedca3a8cba5d7fa3e3610302361a78David Turner * buffer.
176791d86195fedca3a8cba5d7fa3e3610302361a78David Turner */
1779877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic int
1789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_sink_needed( QemudSink*  ss )
1799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
180871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return ss->size - ss->used;
1819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
1829877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/** HANDLING SERIAL PORT CONNECTION
1849877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project **/
1859877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1869877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* The QemudSerial object receives data from the serial port charpipe.
1879877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * It parses the header to extract the channel id and payload length,
1889877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * then the message itself.
1899877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
1909877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * Incoming messages are sent to a generic receiver identified by
1919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * the 'recv_opaque' and 'recv_func' parameters to qemud_serial_init()
1929877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
1939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * It also provides qemud_serial_send() which can be used to send
1949877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * messages back through the serial port.
1959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
1969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  HEADER_SIZE    6
1989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  LENGTH_OFFSET  2
2009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  LENGTH_SIZE    4
2019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
2029877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  CHANNEL_OFFSET 0
2039877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  CHANNEL_SIZE   2
2049877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
205791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#if SUPPORT_LEGACY_QEMUD
206791d86195fedca3a8cba5d7fa3e3610302361a78David Turnertypedef enum {
207791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    QEMUD_VERSION_UNKNOWN,
208791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    QEMUD_VERSION_LEGACY,
209791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    QEMUD_VERSION_NORMAL
210791d86195fedca3a8cba5d7fa3e3610302361a78David Turner} QemudVersion;
211791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
212791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#  define  LEGACY_LENGTH_OFFSET   0
213791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#  define  LEGACY_CHANNEL_OFFSET  4
214791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#endif
215791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
2169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* length of the framed header */
2179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  FRAME_HEADER_SIZE  4
2189877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
2199877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#define  BUFFER_SIZE    MAX_SERIAL_PAYLOAD
2209877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
2219877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* out of convenience, the incoming message is zero-terminated
2229877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * and can be modified by the receiver (e.g. for tokenization).
2239877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
2249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projecttypedef void  (*QemudSerialReceive)( void*  opaque, int  channel, uint8_t*  msg, int  msglen);
2259877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
2269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projecttypedef struct QemudSerial {
2279877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    CharDriverState*  cs;  /* serial charpipe endpoint */
2289877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
2299877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* managing incoming packets from the serial port */
2309877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    ABool         need_header;
2319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    int           overflow;
2329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    int           in_size;
2339877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    int           in_channel;
234791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#if SUPPORT_LEGACY_QEMUD
235791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    QemudVersion  version;
236791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#endif
2379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudSink     header[1];
2389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudSink     payload[1];
2399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    uint8_t       data0[MAX_SERIAL_PAYLOAD+1];
2409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
2419877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* receiver */
2429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudSerialReceive  recv_func;    /* receiver callback */
2439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    void*               recv_opaque;  /* receiver user-specific data */
2449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project} QemudSerial;
2459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
2469877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
247871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Save the state of a QemudSerial to a snapshot file.
248871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
249871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic void
250871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_serial_save(QEMUFile* f, QemudSerial* s)
251871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
252871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* cs, recv_func and recv_opaque are not saved, as these are assigned only
253871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije     * during emulator init. A load within a session can re-use the values
254871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije     * already assigned, a newly launched emulator has freshly assigned values.
255871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije     */
256871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
257871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* state of incoming packets from the serial port */
258871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, s->need_header);
259871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, s->overflow);
260871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, s->in_size);
261871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, s->in_channel);
262871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije#if SUPPORT_LEGACY_QEMUD
263871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, s->version);
264871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije#endif
265871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_sink_save(f, s->header);
266871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_sink_save(f, s->payload);
267871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, MAX_SERIAL_PAYLOAD+1);
268871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_buffer(f, s->data0, MAX_SERIAL_PAYLOAD+1);
269871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
270871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
271871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Load the state of a QemudSerial from a snapshot file.
272871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
273871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic int
274871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_serial_load(QEMUFile* f, QemudSerial* s)
275871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
276871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* state of incoming packets from the serial port */
277871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    s->need_header = qemu_get_be32(f);
278871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    s->overflow    = qemu_get_be32(f);
279871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    s->in_size     = qemu_get_be32(f);
280871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    s->in_channel  = qemu_get_be32(f);
281871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije#if SUPPORT_LEGACY_QEMUD
282871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    s->version = qemu_get_be32(f);
283871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije#endif
284871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_sink_load(f, s->header);
285871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_sink_load(f, s->payload);
286871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
287871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* s->header and s->payload are only ever connected to s->data0 */
288871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    s->header->buff = s->payload->buff = s->data0;
289871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
290871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int len = qemu_get_be32(f);
291871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (len - 1 > MAX_SERIAL_PAYLOAD) {
292871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        D("%s: load failed: size of saved payload buffer (%d) exceeds "
293871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije          "current maximum (%d)\n",
294871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije          __FUNCTION__, len - 1, MAX_SERIAL_PAYLOAD);
295871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return -EIO;
296871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
297871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int ret;
298871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if ((ret = qemu_get_buffer(f, s->data0, len)) != len) {
299871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        D("%s: failed to load serial buffer contents (tried reading %d bytes, got %d)\n",
300871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije          __FUNCTION__, len, ret);
301871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return -EIO;
302871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
303871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
304871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return 0;
305871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
306871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
3079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* called by the charpipe to see how much bytes can be
3089877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * read from the serial port.
3099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
3109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic int
3119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_serial_can_read( void*  opaque )
3129877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
3139877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudSerial*  s = opaque;
3149877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (s->overflow > 0) {
3169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return s->overflow;
3179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
3189877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3199877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* if in_size is 0, we're reading the header */
3209877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (s->need_header)
3219877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return qemud_sink_needed(s->header);
3229877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3239877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* otherwise, we're reading the payload */
3249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return qemud_sink_needed(s->payload);
3259877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
3269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3279877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* called by the charpipe to read data from the serial
3289877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * port. 'len' cannot be more than the value returned
3299877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * by 'qemud_serial_can_read'.
3309877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
3319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
3329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_serial_read( void*  opaque, const uint8_t*  from, int  len )
3339877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
3349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudSerial*  s = opaque;
3359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    T("%s: received %3d bytes: '%s'", __FUNCTION__, len, quote_bytes((const void*)from, len));
3379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    while (len > 0) {
3399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        int  avail;
3409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3419877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* skip overflow bytes */
3429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (s->overflow > 0) {
3439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            avail = s->overflow;
3449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            if (avail > len)
3459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                avail = len;
3469877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3479877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            from += avail;
3489877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            len  -= avail;
3499877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            continue;
3509877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
3519877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3529877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* read header if needed */
3539877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (s->need_header) {
3549877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            if (!qemud_sink_fill(s->header, (const uint8_t**)&from, &len))
3559877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                break;
3569877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
357791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#if SUPPORT_LEGACY_QEMUD
358791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            if (s->version == QEMUD_VERSION_UNKNOWN) {
359791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                /* if we receive "001200" as the first header, then we
360791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                 * detected a legacy qemud daemon. See the comments
361791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                 * in qemud_serial_send_legacy_probe() for details.
362791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                 */
363791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                if ( !memcmp(s->data0, "001200", 6) ) {
364791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                    D("%s: legacy qemud detected.", __FUNCTION__);
365791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                    s->version = QEMUD_VERSION_LEGACY;
366fbcbf4201b9b56b72e9a06d292ae94360dd66b9eDavid Turner                    /* tell the modem to use legacy emulation mode */
367fbcbf4201b9b56b72e9a06d292ae94360dd66b9eDavid Turner                    amodem_set_legacy(android_modem);
368791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                } else {
369791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                    D("%s: normal qemud detected.", __FUNCTION__);
370791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                    s->version = QEMUD_VERSION_NORMAL;
371791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                }
372791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            }
373791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
374791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            if (s->version == QEMUD_VERSION_LEGACY) {
375791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                s->in_size     = hex2int( s->data0 + LEGACY_LENGTH_OFFSET,  LENGTH_SIZE );
376791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                s->in_channel  = hex2int( s->data0 + LEGACY_CHANNEL_OFFSET, CHANNEL_SIZE );
377791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            } else {
378791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                s->in_size     = hex2int( s->data0 + LENGTH_OFFSET,  LENGTH_SIZE );
379791d86195fedca3a8cba5d7fa3e3610302361a78David Turner                s->in_channel  = hex2int( s->data0 + CHANNEL_OFFSET, CHANNEL_SIZE );
380791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            }
381791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#else
3829877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            /* extract payload length + channel id */
3839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            s->in_size     = hex2int( s->data0 + LENGTH_OFFSET,  LENGTH_SIZE );
3849877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            s->in_channel  = hex2int( s->data0 + CHANNEL_OFFSET, CHANNEL_SIZE );
385791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#endif
386871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            s->header->used = 0;
3879877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3889877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            if (s->in_size <= 0 || s->in_channel < 0) {
3899877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                D("%s: bad header: '%.*s'", __FUNCTION__, HEADER_SIZE, s->data0);
3909877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                continue;
3919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            }
3929877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
3939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            if (s->in_size > MAX_SERIAL_PAYLOAD) {
3949877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                D("%s: ignoring huge serial packet: length=%d channel=%1",
3959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                  __FUNCTION__, s->in_size, s->in_channel);
3969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                s->overflow = s->in_size;
3979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                continue;
3989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            }
3999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
4009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            /* prepare 'in_data' for payload */
4019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            s->need_header = 0;
4029877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            qemud_sink_reset(s->payload, s->in_size, s->data0);
4039877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
4049877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
4059877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* read payload bytes */
4069877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (!qemud_sink_fill(s->payload, &from, &len))
4079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            break;
4089877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
4099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* zero-terminate payload, then send it to receiver */
4109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        s->payload->buff[s->payload->size] = 0;
4119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        D("%s: channel=%2d len=%3d '%s'", __FUNCTION__,
4129877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project          s->in_channel, s->payload->size,
4139877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project          quote_bytes((const void*)s->payload->buff, s->payload->size));
4149877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
4159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        s->recv_func( s->recv_opaque, s->in_channel, s->payload->buff, s->payload->size );
4169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
4179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* prepare for new header */
4189877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        s->need_header = 1;
4199877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
4209877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
4219877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
422791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
423791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#if SUPPORT_LEGACY_QEMUD
424791d86195fedca3a8cba5d7fa3e3610302361a78David Turnerstatic void
425791d86195fedca3a8cba5d7fa3e3610302361a78David Turnerqemud_serial_send_legacy_probe( QemudSerial*  s )
426791d86195fedca3a8cba5d7fa3e3610302361a78David Turner{
427791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    /* we're going to send a specially crafted packet to the qemud
428791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * daemon, this will help us determine whether we're talking
429791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * to a legacy or a normal daemon.
430791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
431791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * the trick is to known that a legacy daemon uses the following
432791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * header:
433791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
434791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *    <length><channel><payload>
435791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
436791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * while the normal one uses:
437791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
438791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *    <channel><length><payload>
439791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
440791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * where <channel> is a 2-hexchar string, and <length> a 4-hexchar
441791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * string.
442791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
443791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * if we send a header of "000100", it is interpreted:
444791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
445791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * - as the header of a 1-byte payload by the legacy daemon
446791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * - as the header of a 256-byte payload by the normal one.
447791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
448791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * we're going to send something that looks like:
449791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
450791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   "000100" + "X" +
451791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   "000b00" + "connect:gsm" +
452791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   "000b00" + "connect:gps" +
453791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   "000f00" + "connect:control" +
454791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   "00c210" + "0"*194
455791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
456791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * the normal daemon will interpret this as a 256-byte payload
457791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * for channel 0, with garbage content ("X000b00conn...") which
458791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * will be silently ignored.
459791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
460791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * on the other hand, the legacy daemon will see it as a
461791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * series of packets:
462791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
463791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   one message "X" on channel 0, which will force the daemon
464791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   to send back "001200ko:unknown command" as its first answer.
465791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
466791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   three "connect:<xxx>" messages used to receive the channel
467791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   numbers of the three legacy services implemented by the daemon.
468791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
469791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   a garbage packet of 194 zeroes for channel 16, which will be
470791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *   silently ignored.
471791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     */
472791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    uint8_t  tab[194];
473791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
474791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    memset(tab, 0, sizeof(tab));
475791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    qemu_chr_write(s->cs, (uint8_t*)"000100X", 7);
476791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    qemu_chr_write(s->cs, (uint8_t*)"000b00connect:gsm", 17);
477791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    qemu_chr_write(s->cs, (uint8_t*)"000b00connect:gps", 17);
478791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    qemu_chr_write(s->cs, (uint8_t*)"000f00connect:control", 21);
479791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    qemu_chr_write(s->cs, (uint8_t*)"00c210", 6);
480791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    qemu_chr_write(s->cs, tab, sizeof(tab));
481791d86195fedca3a8cba5d7fa3e3610302361a78David Turner}
482791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#endif /* SUPPORT_LEGACY_QEMUD */
483791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
4849877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* intialize a QemudSerial object with a charpipe endpoint
4859877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * and a receiver.
4869877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
4879877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
4889877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_serial_init( QemudSerial*        s,
4899877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   CharDriverState*    cs,
4909877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   QemudSerialReceive  recv_func,
4919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   void*               recv_opaque )
4929877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
4939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->cs           = cs;
4949877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->recv_func    = recv_func;
4959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->recv_opaque  = recv_opaque;
4969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->need_header  = 1;
4979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->overflow     = 0;
4989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
4999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemud_sink_reset( s->header, HEADER_SIZE, s->data0 );
5009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->in_size      = 0;
5019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->in_channel   = -1;
5029877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
503791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#if SUPPORT_LEGACY_QEMUD
504791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    s->version = QEMUD_VERSION_UNKNOWN;
505791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    qemud_serial_send_legacy_probe(s);
506791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#endif
507791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
5089877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemu_chr_add_handlers( cs,
5099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                           qemud_serial_can_read,
5109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                           qemud_serial_read,
5119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                           NULL,
5129877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                           s );
5139877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
5149877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
5159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* send a message to the serial port. This will add the necessary
5169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * header.
5179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
5189877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
5199877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_serial_send( QemudSerial*    s,
5209877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   int             channel,
5219877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   ABool           framing,
5229877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   const uint8_t*  msg,
5239877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   int             msglen )
5249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
5259877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    uint8_t   header[HEADER_SIZE];
5269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    uint8_t   frame[FRAME_HEADER_SIZE];
5279877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    int       avail, len = msglen;
5289877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
5299877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (msglen <= 0 || channel < 0)
5309877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return;
5319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
5329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    D("%s: channel=%2d len=%3d '%s'",
5339877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project      __FUNCTION__, channel, msglen,
5349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project      quote_bytes((const void*)msg, msglen));
5359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
5369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (framing) {
5379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        len += FRAME_HEADER_SIZE;
5389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
5399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
5409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* packetize the payload for the serial MTU */
541bb1f432421288dae208c7189356643023ccbffbcDavid 'Digit' Turner    while (len > 0)
5429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    {
5439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        avail = len;
5449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (avail > MAX_SERIAL_PAYLOAD)
5459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            avail = MAX_SERIAL_PAYLOAD;
5469877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
5479877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* write this packet's header */
548791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#if SUPPORT_LEGACY_QEMUD
549791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        if (s->version == QEMUD_VERSION_LEGACY) {
550791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            int2hex(header + LEGACY_LENGTH_OFFSET,  LENGTH_SIZE,  avail);
551791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            int2hex(header + LEGACY_CHANNEL_OFFSET, CHANNEL_SIZE, channel);
552791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        } else {
553791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            int2hex(header + LENGTH_OFFSET,  LENGTH_SIZE,  avail);
554791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            int2hex(header + CHANNEL_OFFSET, CHANNEL_SIZE, channel);
555791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        }
556791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#else
5579877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        int2hex(header + LENGTH_OFFSET,  LENGTH_SIZE,  avail);
5589877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        int2hex(header + CHANNEL_OFFSET, CHANNEL_SIZE, channel);
559791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#endif
560791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        T("%s: '%.*s'", __FUNCTION__, HEADER_SIZE, header);
5619877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        qemu_chr_write(s->cs, header, HEADER_SIZE);
5629877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
5639877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* insert frame header when needed */
5649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (framing) {
5659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            int2hex(frame, FRAME_HEADER_SIZE, msglen);
566791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            T("%s: '%.*s'", __FUNCTION__, FRAME_HEADER_SIZE, frame);
5679877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            qemu_chr_write(s->cs, frame, FRAME_HEADER_SIZE);
5689877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            avail  -= FRAME_HEADER_SIZE;
5699877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            len    -= FRAME_HEADER_SIZE;
5709877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            framing = 0;
5719877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
5729877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
5739877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* write message content */
574791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        T("%s: '%.*s'", __FUNCTION__, avail, msg);
5759877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        qemu_chr_write(s->cs, msg, avail);
5769877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        msg += avail;
5779877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        len -= avail;
5789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
5799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
5809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
5819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/** CLIENTS
5829877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project **/
5839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
58477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* Descriptor for a data buffer pending to be sent to a qemud pipe client.
58577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine *
58677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * When a service decides to send data to the client, there could be cases when
58777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * client is not ready to read them. In this case there is no GoldfishPipeBuffer
58877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * available to write service's data to, So, we need to cache that data into the
58977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * client descriptor, and "send" them over to the client in _qemudPipe_recvBuffers
59077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * callback. Pending service data is stored in the client descriptor as a list
59177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * of QemudPipeMessage instances.
59277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
59377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinetypedef struct QemudPipeMessage QemudPipeMessage;
59477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestruct QemudPipeMessage {
59577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Message to send. */
59677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    uint8_t*            message;
59777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Message size. */
59877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    size_t              size;
59977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Offset in the message buffer of the chunk, that has not been sent
60077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine     * to the pipe yet. */
60177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    size_t              offset;
60277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Links next message in the client. */
60377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudPipeMessage*   next;
60477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine};
60577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
60677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
6079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* A QemudClient models a single client as seen by the emulator.
60877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * Each client has its own channel id (for the serial qemud), or pipe descriptor
60977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * (for the pipe based qemud), and belongs to a given QemudService (see below).
6109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
61177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * There is a global list of serial clients used to multiplex incoming
61277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * messages from the channel id (see qemud_multiplexer_serial_recv()). Pipe
61377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * clients don't need multiplexing, because they are communicated via qemud pipes
61477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * that are unique for each client.
6159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
6169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
6179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
61877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* Defines type of the client: pipe, or serial.
61977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
62077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinetypedef enum QemudProtocol {
62177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Client is communicating via pipe. */
62277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QEMUD_PROTOCOL_PIPE,
62377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Client is communicating via serial port. */
62477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QEMUD_PROTOCOL_SERIAL
62577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine} QemudProtocol;
62677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
627593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine/* Descriptor for a QEMUD pipe connection.
628593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine *
629593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine * Every time a client connects to the QEMUD via pipe, an instance of this
630593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine * structure is created to represent a connection used by new pipe client.
631593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine */
632593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkinetypedef struct QemudPipe {
633593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    /* Pipe descriptor. */
634593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    void*           hwpipe;
635593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    /* Looper used for I/O */
636593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    void*           looper;
637593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    /* Service for this pipe. */
638593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    QemudService*   service;
639593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    /* Client for this pipe. */
640593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    QemudClient*    client;
641593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine} QemudPipe;
642593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine
6439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstruct QemudClient {
64477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Defines protocol, used by the client. */
64577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudProtocol     protocol;
64677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
64777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Fields that are common for all protocols. */
6484c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    char*             param;
6499877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    void*             clie_opaque;
6509877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClientRecv   clie_recv;
6519877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClientClose  clie_close;
652871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudClientSave   clie_save;
653871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudClientLoad   clie_load;
6549877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudService*     service;
6559877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*      next_serv; /* next in same service */
6569877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*      next;
6579877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient**     pref;
6589877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
6599877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* framing support */
6609877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    int               framing;
6619877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    ABool             need_header;
662bb1f432421288dae208c7189356643023ccbffbcDavid 'Digit' Turner    ABool             closing;
6639877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudSink         header[1];
6649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    uint8_t           header0[FRAME_HEADER_SIZE];
6659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudSink         payload[1];
66677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
66777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Fields that are protocol-specific. */
66877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    union {
66977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* Serial-specific fields. */
67077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        struct {
67177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            int                 channel;
67277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            QemudSerial*        serial;
67377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        } Serial;
67477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* Pipe-specific fields. */
67577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        struct {
676593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine            QemudPipe*          qemud_pipe;
67777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            QemudPipeMessage*   messages;
67877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        } Pipe;
67977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    } ProtocolSelector;
6809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project};
6819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
68277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic ABool
68377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_is_pipe_client(QemudClient* client)
68477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
68577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    return (client-> protocol == QEMUD_PROTOCOL_PIPE) ? true : false;
68677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
68777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
6889877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void  qemud_service_remove_client( QemudService*  service,
6899877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                                          QemudClient*   client );
6909877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
6919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* remove a QemudClient from global list */
6929877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
6939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_client_remove( QemudClient*  c )
6949877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
6959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->pref[0] = c->next;
6969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (c->next)
6979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        c->next->pref = c->pref;
6989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
6999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->next = NULL;
7009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->pref = &c->next;
7019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
7029877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7039877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* add a QemudClient to global list */
7049877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
7059877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_client_prepend( QemudClient*  c, QemudClient** plist )
7069877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
7079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->next = *plist;
7089877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->pref = plist;
7099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    *plist  = c;
7109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (c->next)
7119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        c->next->pref = &c->next;
7129877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
7139877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7149877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* receive a new message from a client, and dispatch it to
7159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * the real service implementation.
7169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
7179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
7189877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_client_recv( void*  opaque, uint8_t*  msg, int  msglen )
7199877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
7209877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*  c = opaque;
7219877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7229877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* no framing, things are simple */
7239877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (!c->framing) {
7249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (c->clie_recv)
725318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner            c->clie_recv( c->clie_opaque, msg, msglen, c );
7269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return;
7279877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
7289877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7299877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* framing */
7309877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#if 1
7329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* special case, in 99% of cases, everything is in
7339877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project     * the incoming message, and we can do all we need
7349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project     * directly without dynamic allocation.
7359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project     */
7369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (msglen > FRAME_HEADER_SIZE   &&
7379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        c->need_header == 1          &&
7389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        qemud_sink_needed(c->header) == 0)
7399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    {
7409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        int  len = hex2int( msg, FRAME_HEADER_SIZE );
7419877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (len >= 0 && msglen == len + FRAME_HEADER_SIZE) {
7439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            if (c->clie_recv)
744bb1f432421288dae208c7189356643023ccbffbcDavid 'Digit' Turner                c->clie_recv( c->clie_opaque,
7459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                              msg+FRAME_HEADER_SIZE,
746318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                              msglen-FRAME_HEADER_SIZE, c );
7479877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            return;
7489877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
7499877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
7509877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project#endif
7519877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7529877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    while (msglen > 0) {
75383f82216024e9b5623d9f2b3b90e9c2e954412e9David 'Digit' Turner        uint8_t *data;
75483f82216024e9b5623d9f2b3b90e9c2e954412e9David 'Digit' Turner
7559877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* read the header */
7569877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (c->need_header) {
7579877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            int       frame_size;
7589877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            uint8_t*  data;
7599877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7609877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            if (!qemud_sink_fill(c->header, (const uint8_t**)&msg, &msglen))
7619877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                break;
7629877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7639877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            frame_size = hex2int(c->header0, 4);
7649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            if (frame_size == 0) {
7659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                D("%s: ignoring empty frame", __FUNCTION__);
7669877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                continue;
7679877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            }
7689877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            if (frame_size < 0) {
7699877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                D("%s: ignoring corrupted frame header '.*s'",
7709877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                  __FUNCTION__, FRAME_HEADER_SIZE, c->header0 );
7719877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                continue;
7729877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            }
7739877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7749877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            AARRAY_NEW(data, frame_size+1);  /* +1 for terminating zero */
7759877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            qemud_sink_reset(c->payload, frame_size, data);
7769877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            c->need_header = 0;
777871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            c->header->used = 0;
7789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
7799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* read the payload */
7819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (!qemud_sink_fill(c->payload, (const uint8_t**)&msg, &msglen))
7829877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            break;
7839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
7849877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        c->payload->buff[c->payload->size] = 0;
78583f82216024e9b5623d9f2b3b90e9c2e954412e9David 'Digit' Turner        c->need_header = 1;
78683f82216024e9b5623d9f2b3b90e9c2e954412e9David 'Digit' Turner        data = c->payload->buff;
7879877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
78883f82216024e9b5623d9f2b3b90e9c2e954412e9David 'Digit' Turner        /* Technically, calling 'clie_recv' can destroy client object 'c'
78983f82216024e9b5623d9f2b3b90e9c2e954412e9David 'Digit' Turner         * if it decides to close the connection, so ensure we don't
79083f82216024e9b5623d9f2b3b90e9c2e954412e9David 'Digit' Turner         * use/dereference it after the call. */
7919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (c->clie_recv)
792318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner            c->clie_recv( c->clie_opaque, c->payload->buff, c->payload->size, c );
7939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
79483f82216024e9b5623d9f2b3b90e9c2e954412e9David 'Digit' Turner        AFREE(data);
7959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
7969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
7979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
79877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* Sends data to a pipe-based client.
79977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
80077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic void
80177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_qemud_pipe_send(QemudClient*  client, const uint8_t*  msg, int  msglen);
80277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
8034c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine/* Frees memory allocated for the qemud client.
8044c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine */
8054c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkinestatic void
8064c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine_qemud_client_free(QemudClient* c)
8074c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine{
8084c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    if ( c != NULL) {
8094c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        if (_is_pipe_client(c)) {
8104c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine            /* Free outstanding messages. */
8114c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine            QemudPipeMessage** msg_list = &c->ProtocolSelector.Pipe.messages;
8124c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine            while (*msg_list != NULL) {
8134c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                QemudPipeMessage* to_free = *msg_list;
8144c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                *msg_list = to_free->next;
8154c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                free(to_free);
8164c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine            }
8174c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        }
8184c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        if (c->param != NULL) {
8194c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine            free(c->param);
8204c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        }
8214c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        AFREE(c);
8224c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    }
8234c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine}
8244c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine
8259877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* disconnect a client. this automatically frees the QemudClient.
8269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * note that this also removes the client from the global list
8279877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * and from its service's list, if any.
828ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine * Param:
829ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine *  opaque - QemuClient instance
830ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine *  guest_close - For pipe clients control whether or not the disconnect is
831ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine *      caused by guest closing the pipe handle (in which case 1 is passed in
832ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine *      this parameter). For serial clients this parameter is ignored.
8339877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
8349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
835ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkineqemud_client_disconnect( void*  opaque, int guest_close )
8369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
8379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*  c = opaque;
8389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
839bb1f432421288dae208c7189356643023ccbffbcDavid 'Digit' Turner    if (c->closing) {  /* recursive call, exit immediately */
840bb1f432421288dae208c7189356643023ccbffbcDavid 'Digit' Turner        return;
841bb1f432421288dae208c7189356643023ccbffbcDavid 'Digit' Turner    }
842ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine
843ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine    if (_is_pipe_client(c) && !guest_close) {
844ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine        /* This is emulator component (rather than the guest) closing a pipe
845ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine         * client. Since pipe clients are controlled strictly by the guest, we
846ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine         * don't actually close the client here, but notify the guest about the
847ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine         * client being disconnected. Then we will do the real client close when
848ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine         * the guest explicitly closes the pipe, in which case this routine will
849ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine         * be called from the _qemudPipe_closeFromGuest callback with guest_close
850ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine         * set to 1. */
851ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine        char  tmp[128], *p=tmp, *end=p+sizeof(tmp);
852ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine        p = bufprint(tmp, end, "disconnect:00");
853ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine        _qemud_pipe_send(c, (uint8_t*)tmp, p-tmp);
854ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine        return;
855ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine    }
856ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine
857bb1f432421288dae208c7189356643023ccbffbcDavid 'Digit' Turner    c->closing = 1;
858bb1f432421288dae208c7189356643023ccbffbcDavid 'Digit' Turner
8599877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* remove from current list */
8609877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemud_client_remove(c);
8619877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
86277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (_is_pipe_client(c)) {
863593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        /* We must NULL the client reference in the QemuPipe for this connection,
864593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine         * so if a sudden receive request comes after client has been closed, we
865593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine         * don't blow up. */
866593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        c->ProtocolSelector.Pipe.qemud_pipe->client = NULL;
86777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    } else if (c->ProtocolSelector.Serial.channel > 0) {
868ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine        /* send a disconnect command to the daemon */
86977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        char  tmp[128], *p=tmp, *end=p+sizeof(tmp);
87077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        p = bufprint(tmp, end, "disconnect:%02x",
87177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                     c->ProtocolSelector.Serial.channel);
87277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        qemud_serial_send(c->ProtocolSelector.Serial.serial, 0, 0, (uint8_t*)tmp, p-tmp);
8739877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
8749877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
8759877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* call the client close callback */
8769877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (c->clie_close) {
8779877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        c->clie_close(c->clie_opaque);
8789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        c->clie_close = NULL;
8799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
8809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->clie_recv = NULL;
8819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
8829877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* remove from service list, if any */
8839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (c->service) {
8849877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        qemud_service_remove_client(c->service, c);
8859877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        c->service = NULL;
8869877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
8879877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
8884c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    _qemud_client_free(c);
8899877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
8909877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
89177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* allocate a new QemudClient object
89277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * NOTE: channel_id valie is used as a selector between serial and pipe clients.
89377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * Since channel_id < 0 is an invalid value for a serial client, it would
89477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * indicate that creating client is a pipe client. */
8959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic QemudClient*
8969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_client_alloc( int               channel_id,
8974c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                    const char*       client_param,
8989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                    void*             clie_opaque,
8999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                    QemudClientRecv   clie_recv,
9009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                    QemudClientClose  clie_close,
901871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                    QemudClientSave   clie_save,
902871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                    QemudClientLoad   clie_load,
9039877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                    QemudSerial*      serial,
9049877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                    QemudClient**     pclients )
9059877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
9069877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*  c;
9079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
9089877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    ANEW0(c);
9099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
91077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (channel_id < 0) {
91177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* Allocating a pipe client. */
91277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        c->protocol = QEMUD_PROTOCOL_PIPE;
91377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        c->ProtocolSelector.Pipe.messages   = NULL;
914593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        c->ProtocolSelector.Pipe.qemud_pipe = NULL;
91577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    } else {
91677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* Allocating a serial client. */
91777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        c->protocol = QEMUD_PROTOCOL_SERIAL;
91877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        c->ProtocolSelector.Serial.serial   = serial;
91977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        c->ProtocolSelector.Serial.channel  = channel_id;
92077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
9214c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    c->param       = client_param ? ASTRDUP(client_param) : NULL;
9229877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->clie_opaque = clie_opaque;
9239877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->clie_recv   = clie_recv;
9249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->clie_close  = clie_close;
925871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    c->clie_save   = clie_save;
926871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    c->clie_load   = clie_load;
92777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    c->service     = NULL;
92877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    c->next_serv   = NULL;
92977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    c->next        = NULL;
9309877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->framing     = 0;
9319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->need_header = 1;
9329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemud_sink_reset(c->header, FRAME_HEADER_SIZE, c->header0);
9339877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
9349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemud_client_prepend(c, pclients);
9359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
9369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return c;
9379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
9389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
939871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* forward */
940871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic void  qemud_service_save_name( QEMUFile* f, QemudService* s );
941871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic char* qemud_service_load_name( QEMUFile* f );
942871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic QemudService* qemud_service_find(  QemudService*  service_list,
943871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                                          const char*    service_name );
944871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic QemudClient*  qemud_service_connect_client(  QemudService  *sv,
9454c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                                                    int           channel_id,
9464c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                                                    const char* client_param);
947871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
948871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Saves the client state needed to re-establish connections on load.
9493e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner * Note that we save only serial clients here. The pipe clients will be
9503e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner * saved along with the pipe to which they are attached.
951871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
952871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic void
9533e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turnerqemud_serial_client_save(QEMUFile* f, QemudClient* c)
954871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
955871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* save generic information */
956871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_service_save_name(f, c->service);
9573e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemu_put_string(f, c->param);
9583e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemu_put_be32(f, c->ProtocolSelector.Serial.channel);
959871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
960871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* save client-specific state */
961871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (c->clie_save)
962871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        c->clie_save(f, c, c->clie_opaque);
963871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
964871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* save framing configuration */
965871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, c->framing);
966871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (c->framing) {
967871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        qemu_put_be32(f, c->need_header);
968871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        /* header sink always connected to c->header0, no need to save */
969871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        qemu_put_be32(f, FRAME_HEADER_SIZE);
970871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        qemu_put_buffer(f, c->header0, FRAME_HEADER_SIZE);
971871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        /* payload sink */
972871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        qemud_sink_save(f, c->payload);
973871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        qemu_put_buffer(f, c->payload->buff, c->payload->size);
974871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
975871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
976871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
977871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Loads client state from file, then starts a new client connected to the
978871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * corresponding service.
9793e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner * Note that we load only serial clients here. The pipe clients will be
9803e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner * loaded along with the pipe to which they were attached.
981871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
982871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic int
9833e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turnerqemud_serial_client_load(QEMUFile* f, QemudService* current_services, int version )
984871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
985871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    char *service_name = qemud_service_load_name(f);
986871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (service_name == NULL)
987871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return -EIO;
9883e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    char* param = qemu_get_string(f);
989871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* get current service instance */
990871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudService *sv = qemud_service_find(current_services, service_name);
991871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (sv == NULL) {
992871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        D("%s: load failed: unknown service \"%s\"\n",
993871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije          __FUNCTION__, service_name);
994871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return -EIO;
995871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
996871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
9973e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    int channel = qemu_get_be32(f);
998d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine
999871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (channel == 0) {
1000871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        D("%s: illegal snapshot: client for control channel must no be saved\n",
1001871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije          __FUNCTION__);
1002871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return -EIO;
1003871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1004871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1005871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* re-connect client */
10063e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    QemudClient* c = qemud_service_connect_client(sv, channel, param);
1007871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if(c == NULL)
1008871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return -EIO;
1009871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1010871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* load client-specific state */
1011871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int ret;
1012871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (c->clie_load)
1013871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        if ((ret = c->clie_load(f, c, c->clie_opaque)))
1014871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            return ret;  /* load failure */
1015871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1016871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* load framing configuration */
1017871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    c->framing = qemu_get_be32(f);
1018871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (c->framing) {
1019871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1020871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        /* header buffer */
1021871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        c->need_header = qemu_get_be32(f);
1022871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        int header_size = qemu_get_be32(f);
1023871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        if (header_size > FRAME_HEADER_SIZE) {
1024871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            D("%s: load failed: payload buffer requires %d bytes, %d available\n",
1025871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije              __FUNCTION__, header_size, FRAME_HEADER_SIZE);
1026871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            return -EIO;
1027871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        }
1028871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        int ret;
1029871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        if ((ret = qemu_get_buffer(f, c->header0, header_size)) != header_size) {
1030871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            D("%s: frame header buffer load failed: expected %d bytes, got %d\n",
1031871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije              __FUNCTION__, header_size, ret);
1032871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            return -EIO;
1033871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        }
1034871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1035871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        /* payload sink */
1036871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        if ((ret = qemud_sink_load(f, c->payload)))
1037871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            return ret;
1038871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1039871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        /* replace payload buffer by saved data */
1040871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        if (c->payload->buff) {
1041871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            AFREE(c->payload->buff);
1042871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        }
1043871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        AARRAY_NEW(c->payload->buff, c->payload->size+1);  /* +1 for terminating zero */
1044871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        if ((ret = qemu_get_buffer(f, c->payload->buff, c->payload->size)) != c->payload->size) {
1045871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            D("%s: frame payload buffer load failed: expected %d bytes, got %d\n",
1046871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije              __FUNCTION__, c->payload->size, ret);
1047871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            AFREE(c->payload->buff);
1048871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            return -EIO;
1049871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        }
1050871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1051871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1052871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return 0;
1053871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1054871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1055871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
10569877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/** SERVICES
10579877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project **/
10589877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
10599877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* A QemudService models a _named_ service facility implemented
10609877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * by the emulator, that clients in the emulated system can connect
10619877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * to.
10629877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
10639877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * Each service can have a limit on the number of clients they
10649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * accept (this number if unlimited if 'max_clients' is 0).
10659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
10669877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * Each service maintains a list of active QemudClients and
10679877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * can also be used to create new QemudClient objects through
10689877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * its 'serv_opaque' and 'serv_connect' fields.
10699877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
10709877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstruct QemudService {
10719877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    const char*          name;
10729877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    int                  max_clients;
10739877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    int                  num_clients;
10749877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*         clients;
10759877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudServiceConnect  serv_connect;
1076871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudServiceSave     serv_save;
1077871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudServiceLoad     serv_load;
10789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    void*                serv_opaque;
10799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudService*        next;
10809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project};
10819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
10829877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* Create a new QemudService object */
10839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic QemudService*
10849877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_service_new( const char*          name,
10859877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   int                  max_clients,
10869877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   void*                serv_opaque,
10879877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   QemudServiceConnect  serv_connect,
1088871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                   QemudServiceSave     serv_save,
1089871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                   QemudServiceLoad     serv_load,
10909877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                   QemudService**       pservices )
10919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
10929877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudService*  s;
10939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
10949877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    ANEW0(s);
10959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->name        = ASTRDUP(name);
10969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->max_clients = max_clients;
10979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->num_clients = 0;
10989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->clients     = NULL;
10999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
11009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->serv_opaque  = serv_opaque;
11019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->serv_connect = serv_connect;
1102871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    s->serv_save = serv_save;
1103871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    s->serv_load = serv_load;
11049877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
11059877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->next    = *pservices;
11069877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    *pservices = s;
11079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
11089877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return s;
11099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
11109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
11119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* used internally to populate a QemudService object with a
11129877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * new QemudClient */
11139877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
11149877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_service_add_client( QemudService*  s, QemudClient*  c )
11159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
11169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->service      = s;
11179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    c->next_serv    = s->clients;
11189877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->clients      = c;
11199877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->num_clients += 1;
11209877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
11219877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
11229877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* used internally to remove a QemudClient from a QemudService */
11239877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
11249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_service_remove_client( QemudService*  s, QemudClient*  c )
11259877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
11269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient**  pnode = &s->clients;
11279877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*   node;
11289877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
11299877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* remove from clients linked-list */
11309877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    for (;;) {
11319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        node = *pnode;
11329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (node == NULL) {
113377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            D("%s: could not find client for service '%s'",
113477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine              __FUNCTION__, s->name);
11359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            return;
11369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
11379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (node == c)
11389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            break;
11399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        pnode = &node->next_serv;
11409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
11419877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
11429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    *pnode          = node->next_serv;
11439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    s->num_clients -= 1;
11449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
11459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1146871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* ask the service to create a new QemudClient. Note that we
1147871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * assume that this calls qemud_client_new() which will add
1148871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * the client to the service's list automatically.
1149871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije *
1150871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * returns the client or NULL if an error occurred
1151871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1152871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic QemudClient*
11534c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkineqemud_service_connect_client(QemudService *sv,
11544c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                             int channel_id,
11554c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                             const char* client_param)
1156871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
11574c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    QemudClient* client =
11584c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        sv->serv_connect( sv->serv_opaque, sv, channel_id, client_param );
1159871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (client == NULL) {
1160871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        D("%s: registration failed for '%s' service",
1161871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije          __FUNCTION__, sv->name);
1162871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return NULL;
1163871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1164871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    D("%s: registered client channel %d for '%s' service",
1165871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije      __FUNCTION__, channel_id, sv->name);
1166871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return client;
1167871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1168871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1169871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* find a registered service by name.
1170871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1171871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic QemudService*
1172871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_service_find( QemudService*  service_list, const char*  service_name)
1173871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1174871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudService*  sv = NULL;
1175871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    for (sv = service_list; sv != NULL; sv = sv->next) {
1176871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        if (!strcmp(sv->name, service_name)) {
1177871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            break;
1178871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        }
1179871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1180871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return sv;
1181871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1182871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1183871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Save the name of the given service.
1184871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1185871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic void
1186871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_service_save_name(QEMUFile* f, QemudService* s)
1187871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1188871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int len = strlen(s->name) + 1;  // include '\0' terminator
1189871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, len);
1190871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_buffer(f, (const uint8_t *) s->name, len);
1191871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1192871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1193871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Load the name of a service. Returns a pointer to the loaded name, or NULL
1194871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * on failure.
1195871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1196871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic char*
1197871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_service_load_name( QEMUFile*  f )
1198871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1199871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int ret;
1200871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int name_len = qemu_get_be32(f);
1201871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    char *service_name = android_alloc(name_len);
1202871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if ((ret = qemu_get_buffer(f, (uint8_t*)service_name, name_len) != name_len)) {
1203871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        D("%s: service name load failed: expected %d bytes, got %d\n",
1204871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije          __FUNCTION__, name_len, ret);
1205871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        AFREE(service_name);
1206871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return NULL;
1207871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1208871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (service_name[name_len - 1] != '\0') {
1209871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        char last = service_name[name_len - 1];
1210871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        service_name[name_len - 1] = '\0';  /* make buffer contents printable */
1211871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        D("%s: service name load failed: expecting NULL-terminated string, but "
1212871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije          "last char is '%c' (buffer contents: '%s%c')\n",
1213871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije          __FUNCTION__, name_len, last, service_name, last);
1214871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        AFREE(service_name);
1215871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return NULL;
1216871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1217871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1218871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return service_name;
1219871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1220871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1221871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Saves state of a service.
1222871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1223871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic void
1224871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_service_save(QEMUFile* f, QemudService* s)
1225871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1226871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_service_save_name(f, s);
1227871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, s->max_clients);
1228871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, s->num_clients);
1229871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1230871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (s->serv_save)
1231871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        s->serv_save(f, s, s->serv_opaque);
1232871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1233871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1234871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Loads service state from file, then updates the currently running instance
1235871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * of that service to mirror the loaded state. If the service is not running,
1236871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * the load process is aborted.
1237871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije *
1238871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * Parameter 'current_services' should be the list of active services.
1239871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1240871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic int
1241871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_service_load(  QEMUFile*  f, QemudService*  current_services  )
1242871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1243871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    char* service_name = qemud_service_load_name(f);
1244871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (service_name == NULL)
1245871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return -EIO;
1246871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1247871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* get current service instance */
1248871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudService *sv = qemud_service_find(current_services, service_name);
1249871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (sv == NULL) {
1250871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        D("%s: loading failed: service \"%s\" not available\n",
1251871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije          __FUNCTION__, service_name);
1252871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return -EIO;
1253871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1254871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1255871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* reconfigure service as required */
1256871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    sv->max_clients = qemu_get_be32(f);
1257871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    sv->num_clients = qemu_get_be32(f);
1258871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1259871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* load service specific data */
1260871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int ret;
1261871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if (sv->serv_load)
1262871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        if ((ret = sv->serv_load(f, sv, sv->serv_opaque)))
1263871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            return ret;  /* load failure */
1264871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1265871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return 0;
1266871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1267871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1268871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
12699877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/** MULTIPLEXER
12709877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project **/
12719877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
12729877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* A QemudMultiplexer object maintains the global state of the
12739877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * qemud service facility. It holds a QemudSerial object to
12749877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * maintain the state of the serial port connection.
12759877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
12769877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * The QemudMultiplexer receives all incoming messages from
12779877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * the serial port, and dispatches them to the appropriate
12789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * QemudClient.
12799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
12809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * It also has a global list of clients, and a global list of
12819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * services.
12829877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
12839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * Finally, the QemudMultiplexer has a special QemudClient used
12849877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * to handle channel 0, i.e. the control channel used to handle
12859877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * connections and disconnections of clients.
12869877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
12879877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projecttypedef struct QemudMultiplexer  QemudMultiplexer;
12889877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
12899877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstruct QemudMultiplexer {
12909877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudSerial    serial[1];
12919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*   clients;
12929877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudService*  services;
12939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project};
12949877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
12959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* this is the serial_recv callback that is called
12969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * whenever an incoming message arrives through the serial port
12979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
12989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
12999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_multiplexer_serial_recv( void*     opaque,
13009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                               int       channel,
13019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                               uint8_t*  msg,
13029877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                               int       msglen )
13039877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
13049877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudMultiplexer*  m = opaque;
13059877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*       c = m->clients;
13069877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
13079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* dispatch to an existing client if possible
13089877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project     * note that channel 0 is handled by a special
13099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project     * QemudClient that is setup in qemud_multiplexer_init()
13109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project     */
13119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    for ( ; c != NULL; c = c->next ) {
131277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel == channel) {
13139877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            qemud_client_recv(c, msg, msglen);
13149877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            return;
13159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
13169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
13179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
13189877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    D("%s: ignoring %d bytes for unknown channel %d",
13199877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project      __FUNCTION__, msglen, channel);
13209877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
13219877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
13229877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* handle a new connection attempt. This returns 0 on
13239877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * success, -1 if the service name is unknown, or -2
13249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * if the service's maximum number of clients has been
13259877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * reached.
13269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
13279877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic int
13289877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_multiplexer_connect( QemudMultiplexer*  m,
13299877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                           const char*        service_name,
13309877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                           int                channel_id )
13319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
13329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* find the corresponding registered service by name */
1333871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudService*  sv = qemud_service_find(m->services, service_name);
13349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (sv == NULL) {
13359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        D("%s: no registered '%s' service", __FUNCTION__, service_name);
13369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return -1;
13379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
13389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
13399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* check service's client count */
13409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (sv->max_clients > 0 && sv->num_clients >= sv->max_clients) {
13419877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        D("%s: registration failed for '%s' service: too many clients (%d)",
13429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project          __FUNCTION__, service_name, sv->num_clients);
13439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return -2;
13449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
13459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1346871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* connect a new client to the service on the given channel */
13474c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    if (qemud_service_connect_client(sv, channel_id, NULL) == NULL)
13489877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return -1;
13499877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
13509877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return 0;
13519877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
13529877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
13539877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* disconnect a given client from its channel id */
13549877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
13559877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_multiplexer_disconnect( QemudMultiplexer*  m,
13569877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                              int                channel )
13579877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
13589877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*  c;
13599877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
13609877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* find the client by its channel id, then disconnect it */
13619877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    for (c = m->clients; c; c = c->next) {
136277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel == channel) {
13639877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            D("%s: disconnecting client %d",
13649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project              __FUNCTION__, channel);
13659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            /* note thatt this removes the client from
13669877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project             * m->clients automatically.
13679877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project             */
136877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            c->ProtocolSelector.Serial.channel = -1; /* no need to send disconnect:<id> */
1369ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine            qemud_client_disconnect(c, 0);
13709877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            return;
13719877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
13729877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
13739877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    D("%s: disconnecting unknown channel %d",
13749877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project      __FUNCTION__, channel);
13759877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
13769877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1377871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* disconnects all channels, except for the control channel, without informing
1378871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * the daemon in the guest that disconnection has occurred.
1379871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije *
1380871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * Used to silently kill clients when restoring emulator state snapshots.
1381871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1382871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic void
1383871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_multiplexer_disconnect_noncontrol( QemudMultiplexer*  m )
1384871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1385871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudClient* c;
1386871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudClient* next = m->clients;
1387871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1388871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    while (next) {
1389871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        c = next;
1390871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        next = c->next;  /* disconnect frees c, remember next in advance */
1391871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
139277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0) {
139377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            /* skip control channel */
1394871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            D("%s: disconnecting client %d",
139577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine              __FUNCTION__, c->ProtocolSelector.Serial.channel);
1396871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            D("%s: disconnecting client %d\n",
139777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine              __FUNCTION__, c->ProtocolSelector.Serial.channel);
139877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            c->ProtocolSelector.Serial.channel = -1; /* do not send disconnect:<id> */
1399ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine            qemud_client_disconnect(c, 0);
1400871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        }
1401871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1402871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1403871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
14049877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* handle control messages. This is used as the receive
14059877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * callback for the special QemudClient setup to manage
14069877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * channel 0.
14079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
14089877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * note that the message is zero-terminated for convenience
14099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * (i.e. msg[msglen] is a valid memory read that returns '\0')
14109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
14119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
1412318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turnerqemud_multiplexer_control_recv( void*         opaque,
1413318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                                uint8_t*      msg,
1414318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                                int           msglen,
1415318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                                QemudClient*  client )
14169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
14179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudMultiplexer*  mult   = opaque;
14189877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    uint8_t*           msgend = msg + msglen;
14199877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    char               tmp[64], *p=tmp, *end=p+sizeof(tmp);
14209877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
14219877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* handle connection attempts.
14229877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project     * the client message must be "connect:<service-name>:<id>"
1423fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner     * where <id> is a 2-char hexadecimal string, which must be > 0
14249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project     */
14259877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (msglen > 8 && !memcmp(msg, "connect:", 8))
14269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    {
14279877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        const char*    service_name = (const char*)msg + 8;
14289877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        int            channel, ret;
14299877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        char*          q;
14309877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
14319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        q = strchr(service_name, ':');
1432fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner        if (q == NULL || q+3 != (char*)msgend) {
14339877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            D("%s: malformed connect message: '%.*s' (offset=%d)",
14349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project              __FUNCTION__, msglen, (const char*)msg, q ? q-(char*)msg : -1);
14359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            return;
14369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
14379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        *q++ = 0;  /* zero-terminate service name */
1438fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner        channel = hex2int((uint8_t*)q, 2);
14399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (channel <= 0) {
14409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            D("%s: malformed channel id '%.*s",
1441fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner              __FUNCTION__, 2, q);
14429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            return;
14439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
14449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
14459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        ret = qemud_multiplexer_connect(mult, service_name, channel);
14469877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        /* the answer can be one of:
14479877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project         *    ok:connect:<id>
14489877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project         *    ko:connect:<id>:<reason-for-failure>
14499877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project         */
14509877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (ret < 0) {
14519877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            if (ret == -1) {
14529877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                /* could not connect */
1453fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner                p = bufprint(tmp, end, "ko:connect:%02x:unknown service", channel);
14549877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            } else {
1455fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner                p = bufprint(tmp, end, "ko:connect:%02x:service busy", channel);
14569877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            }
14579877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
14589877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        else {
1459fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner            p = bufprint(tmp, end, "ok:connect:%02x", channel);
14609877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
14619877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        qemud_serial_send(mult->serial, 0, 0, (uint8_t*)tmp, p-tmp);
14629877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return;
14639877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
14649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
14659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* handle client disconnections,
14669877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project     * this message arrives when the client has closed the connection.
1467fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner     * format: "disconnect:<id>" where <id> is a 2-hex channel id > 0
14689877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project     */
1469fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner    if (msglen == 13 && !memcmp(msg, "disconnect:", 11)) {
1470fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner        int  channel_id = hex2int(msg+11, 2);
14719877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (channel_id <= 0) {
14729877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            D("%s: malformed disconnect channel id: '%.*s'",
1473fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner              __FUNCTION__, 2, msg+11);
14749877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            return;
14759877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
14769877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        qemud_multiplexer_disconnect(mult, channel_id);
14779877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return;
14789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
14799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1480791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#if SUPPORT_LEGACY_QEMUD
1481791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    /* an ok:connect:<service>:<id> message can be received if we're
1482791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * talking to a legacy qemud daemon, i.e. one running in a 1.0 or
1483791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * 1.1 system image.
1484791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     *
1485791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * we should treat is as a normal "connect:" attempt, except that
1486791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     * we must not send back any acknowledgment.
1487791d86195fedca3a8cba5d7fa3e3610302361a78David Turner     */
1488791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    if (msglen > 11 && !memcmp(msg, "ok:connect:", 11)) {
1489791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        const char*  service_name = (const char*)msg + 11;
1490791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        char*        q            = strchr(service_name, ':');
1491791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        int          channel;
1492791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
1493791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        if (q == NULL || q+3 != (char*)msgend) {
1494791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            D("%s: malformed legacy connect message: '%.*s' (offset=%d)",
1495791d86195fedca3a8cba5d7fa3e3610302361a78David Turner              __FUNCTION__, msglen, (const char*)msg, q ? q-(char*)msg : -1);
1496791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            return;
1497791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        }
1498791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        *q++ = 0;  /* zero-terminate service name */
1499791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        channel = hex2int((uint8_t*)q, 2);
1500791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        if (channel <= 0) {
1501791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            D("%s: malformed legacy channel id '%.*s",
1502791d86195fedca3a8cba5d7fa3e3610302361a78David Turner              __FUNCTION__, 2, q);
1503791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            return;
1504791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        }
1505791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
1506791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        switch (mult->serial->version) {
1507791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        case QEMUD_VERSION_UNKNOWN:
1508791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            mult->serial->version = QEMUD_VERSION_LEGACY;
1509791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            D("%s: legacy qemud daemon detected.", __FUNCTION__);
1510791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            break;
1511791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
1512791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        case QEMUD_VERSION_LEGACY:
1513791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            /* nothing unusual */
1514791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            break;
1515791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
1516791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        default:
1517791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            D("%s: weird, ignoring legacy qemud control message: '%.*s'",
1518791d86195fedca3a8cba5d7fa3e3610302361a78David Turner              __FUNCTION__, msglen, msg);
1519791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            return;
1520791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        }
1521791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
1522791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        /* "hw-control" was called "control" in 1.0/1.1 */
1523791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        if (!strcmp(service_name,"control"))
1524791d86195fedca3a8cba5d7fa3e3610302361a78David Turner            service_name = "hw-control";
1525791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
1526791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        qemud_multiplexer_connect(mult, service_name, channel);
1527791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        return;
1528791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    }
1529791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
1530791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    /* anything else, don't answer for legacy */
1531791d86195fedca3a8cba5d7fa3e3610302361a78David Turner    if (mult->serial->version == QEMUD_VERSION_LEGACY)
1532791d86195fedca3a8cba5d7fa3e3610302361a78David Turner        return;
1533791d86195fedca3a8cba5d7fa3e3610302361a78David Turner#endif /* SUPPORT_LEGACY_QEMUD */
1534791d86195fedca3a8cba5d7fa3e3610302361a78David Turner
15359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* anything else is a problem */
15369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    p = bufprint(tmp, end, "ko:unknown command");
15379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemud_serial_send(mult->serial, 0, 0, (uint8_t*)tmp, p-tmp);
15389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
15399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
15409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* initialize the global QemudMultiplexer.
15419877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
15429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
15439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_multiplexer_init( QemudMultiplexer*  mult,
15449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                        CharDriverState*   serial_cs )
15459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
15469877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* initialize serial handler */
15479877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemud_serial_init( mult->serial,
15489877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                       serial_cs,
15499877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                       qemud_multiplexer_serial_recv,
15509877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                       mult );
15519877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
15529877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* setup listener for channel 0 */
1553a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner    qemud_client_alloc(0,
1554a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner                       NULL,
1555a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner                       mult,
1556a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner                       qemud_multiplexer_control_recv,
1557a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner                       NULL, NULL, NULL,
1558a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner                       mult->serial,
1559a2c14f947951612b45024095afd2210aa7368773David 'Digit' Turner                       &mult->clients );
15609877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
15619877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
15629877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* the global multiplexer state */
15639877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic QemudMultiplexer  _multiplexer[1];
15649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
15659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/** HIGH-LEVEL API
15669877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project **/
15679877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
15689877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* this function must be used in the serv_connect callback
15699877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * of a given QemudService object (see qemud_service_register()
15709877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * below). It is used to register a new QemudClient to acknowledge
15719877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * a new client connection.
15729877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
15739877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * 'clie_opaque', 'clie_recv' and 'clie_close' are used to
15749877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * send incoming client messages to the corresponding service
15759877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * implementation, or notify the service that a client has
15769877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * disconnected.
15779877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
15789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source ProjectQemudClient*
15799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_client_new( QemudService*     service,
15809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                  int               channelId,
15814c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                  const char*       client_param,
15829877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                  void*             clie_opaque,
15839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                  QemudClientRecv   clie_recv,
1584871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                  QemudClientClose  clie_close,
1585871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                  QemudClientSave   clie_save,
1586871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                  QemudClientLoad   clie_load )
15879877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
15889877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudMultiplexer*  m = _multiplexer;
15899877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*       c = qemud_client_alloc( channelId,
15904c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine                                               client_param,
15919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                                               clie_opaque,
15929877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                                               clie_recv,
15939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                                               clie_close,
1594871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                                               clie_save,
1595871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                                               clie_load,
15969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                                               m->serial,
15979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                                               &m->clients );
15989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
15999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemud_service_add_client(service, c);
16009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return c;
16019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
16029877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
160377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* Caches a service message into the client's descriptor.
160477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine *
160577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * See comments on QemudPipeMessage structure for more info.
160677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
160777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic void
160877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_qemud_pipe_cache_buffer(QemudClient* client, const uint8_t*  msg, int  msglen)
160977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
161077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudPipeMessage* buf;
161177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudPipeMessage** ins_at = &client->ProtocolSelector.Pipe.messages;
161277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
161377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Allocate descriptor big enough to contain message as well. */
161477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    buf = (QemudPipeMessage*)malloc(msglen + sizeof(QemudPipeMessage));
161577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (buf != NULL) {
161677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* Message starts right after the descriptor. */
161777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        buf->message = (uint8_t*)buf + sizeof(QemudPipeMessage);
161877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        buf->size = msglen;
161977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        memcpy(buf->message, msg, msglen);
162077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        buf->offset = 0;
162177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        buf->next = NULL;
162277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        while (*ins_at != NULL) {
162377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            ins_at = &(*ins_at)->next;
162477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        }
162577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        *ins_at = buf;
162677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* Notify the pipe that there is data to read. */
1627593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        goldfish_pipe_wake(client->ProtocolSelector.Pipe.qemud_pipe->hwpipe,
1628593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine                           PIPE_WAKE_READ);
162977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
163077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
163177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
163277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* Sends service message to the client.
163377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
163477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic void
163577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_qemud_pipe_send(QemudClient*  client, const uint8_t*  msg, int  msglen)
163677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
163777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    uint8_t   frame[FRAME_HEADER_SIZE];
163877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    int       avail, len = msglen;
163977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    int framing = client->framing;
164077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
164177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (msglen <= 0)
164277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        return;
164377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
164477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    D("%s: len=%3d '%s'",
164577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine      __FUNCTION__, msglen, quote_bytes((const void*)msg, msglen));
164677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
164777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (framing) {
164877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        len += FRAME_HEADER_SIZE;
164977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
165077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
165177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* packetize the payload for the serial MTU */
165277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    while (len > 0)
165377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    {
165477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        avail = len;
165577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        if (avail > MAX_SERIAL_PAYLOAD)
165677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            avail = MAX_SERIAL_PAYLOAD;
165777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
165877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* insert frame header when needed */
165977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        if (framing) {
166077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            int2hex(frame, FRAME_HEADER_SIZE, msglen);
166177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            T("%s: '%.*s'", __FUNCTION__, FRAME_HEADER_SIZE, frame);
166277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            _qemud_pipe_cache_buffer(client, frame, FRAME_HEADER_SIZE);
166377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            avail  -= FRAME_HEADER_SIZE;
166477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            len    -= FRAME_HEADER_SIZE;
166577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            framing = 0;
166677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        }
166777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
166877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* write message content */
166977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        T("%s: '%.*s'", __FUNCTION__, avail, msg);
167077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        _qemud_pipe_cache_buffer(client, msg, avail);
167177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        msg += avail;
167277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        len -= avail;
167377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
167477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
167577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
16769877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* this can be used by a service implementation to send an answer
16779877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * or message to a specific client.
16789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
16799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectvoid
16809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_client_send ( QemudClient*  client, const uint8_t*  msg, int  msglen )
16819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
168277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (_is_pipe_client(client)) {
168377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        _qemud_pipe_send(client, msg, msglen);
168477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    } else {
168577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        qemud_serial_send(client->ProtocolSelector.Serial.serial,
168677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                          client->ProtocolSelector.Serial.channel,
168777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                          client->framing != 0, msg, msglen);
168877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
16899877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
16909877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
16919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* enable framing for this client. When TRUE, this will
16929877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * use internally a simple 4-hexchar header before each
16939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * message exchanged through the serial port.
16949877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
16959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectvoid
16969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_client_set_framing( QemudClient*  client, int  framing )
16979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
16989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* release dynamic buffer if we're disabling framing */
16999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (client->framing) {
17009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        if (!client->need_header) {
17019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            AFREE(client->payload->buff);
17029877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project            client->need_header = 1;
17039877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        }
17049877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
17059877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    client->framing = !!framing;
17069877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
17079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
17089877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* this can be used by a service implementation to close a
17099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * specific client connection.
17109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
17119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectvoid
17129877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_client_close( QemudClient*  client )
17139877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
1714ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine    qemud_client_disconnect(client, 0);
17159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
17169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
17179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
1718871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/** SNAPSHOT SUPPORT
1719871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije **/
1720871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1721871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Saves the number of clients.
1722871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1723871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic void
1724871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_client_save_count(QEMUFile* f, QemudClient* c)
1725871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1726871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    unsigned int client_count = 0;
1727871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    for( ; c; c = c->next)   // walk over linked list
17283e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        /* skip control channel, which is not saved, and pipe channels that
17293e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner         * are saved along with the pipe. */
17303e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0)
1731871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            client_count++;
1732871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1733871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, client_count);
1734871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1735871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1736871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Saves the number of services currently available.
1737871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1738871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic void
1739871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_service_save_count(QEMUFile* f, QemudService* s)
1740871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1741871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    unsigned int service_count = 0;
1742871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    for( ; s; s = s->next )  // walk over linked list
1743871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        service_count++;
1744871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1745871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemu_put_be32(f, service_count);
1746871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1747871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1748871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Save QemuD state to snapshot.
1749871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije *
1750871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * The control channel has no state of its own, other than the local variables
1751871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * in qemud_multiplexer_control_recv. We can therefore safely skip saving it,
1752871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * which spares us dealing with the exception of a client not connected to a
1753871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * service.
1754871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1755871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic void
1756871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_save(QEMUFile* f, void* opaque)
1757871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1758871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudMultiplexer *m = opaque;
1759871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1760871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_serial_save(f, m->serial);
1761871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1762871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* save service states */
1763871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_service_save_count(f, m->services);
1764871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudService *s;
1765871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    for (s = m->services; s; s = s->next)
1766871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        qemud_service_save(f, s);
1767871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1768871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* save client channels */
1769871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_client_save_count(f, m->clients);
1770871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudClient *c;
1771871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    for (c = m->clients; c; c = c->next) {
17723e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        /* skip control channel, and pipe clients */
17733e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        if (!_is_pipe_client(c) && c->ProtocolSelector.Serial.channel > 0) {
17743e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            qemud_serial_client_save(f, c);
1775871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        }
1776871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1777871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1778871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1779871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1780871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1781871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Checks whether the same services are available at this point as when the
1782871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * snapshot was made.
1783871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1784871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic int
1785871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_load_services( QEMUFile*  f, QemudService*  current_services )
1786871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1787871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int i, ret;
1788871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int service_count = qemu_get_be32(f);
1789871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    for (i = 0; i < service_count; i++) {
1790871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        if ((ret = qemud_service_load(f, current_services)))
1791871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            return ret;
1792871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1793871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1794871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return 0;
1795871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1796871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1797871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Removes all active non-control clients, then creates new ones with state
1798871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * taken from the snapshot.
1799871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije *
1800871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * We do not send "disconnect" commands, over the channel. If we did, we might
1801871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * stop clients in the restored guest, resulting in an incorrect restore.
1802871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije *
1803871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * Instead, we silently replace the clients that were running before the
1804871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * restore with new clients, whose state we copy from the snapshot. Since
1805871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * everything is multiplexed over one link, only the multiplexer notices the
1806871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije * changes, there is no communication with the guest.
1807871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1808871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic int
1809d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkineqemud_load_clients(QEMUFile* f, QemudMultiplexer* m, int version )
1810871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1811871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* Remove all clients, except on the control channel.*/
1812871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_multiplexer_disconnect_noncontrol(m);
1813871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1814871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    /* Load clients from snapshot */
1815871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int client_count = qemu_get_be32(f);
1816871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int i, ret;
1817871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    for (i = 0; i < client_count; i++) {
18183e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        if ((ret = qemud_serial_client_load(f, m->services, version))) {
1819871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije            return ret;
1820871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        }
1821871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    }
1822871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1823871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return 0;
1824871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1825871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1826871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije/* Load QemuD state from file.
1827871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije */
1828871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijestatic int
1829871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thijeqemud_load(QEMUFile *f, void* opaque, int version)
1830871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije{
1831871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    QemudMultiplexer *m = opaque;
1832871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1833871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    int ret;
1834871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1835871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if ((ret = qemud_serial_load(f, m->serial)))
1836871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return ret;
1837871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    if ((ret = qemud_load_services(f, m->services)))
1838871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return ret;
1839d0e2872813e1d37e8233befdfd13a4d6cb0d7431Vladimir Chtchetkine    if ((ret = qemud_load_clients(f, m, version)))
1840871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije        return ret;
1841871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
1842871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    return 0;
1843871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije}
1844871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
184577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/*------------------------------------------------------------------------------
184677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine *
184777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * QEMUD PIPE service callbacks
184877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine *
184977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * ----------------------------------------------------------------------------*/
185077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
18513e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner/* Saves pending pipe message to the snapshot file. */
18523e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turnerstatic void
18533e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner_save_pipe_message(QEMUFile* f, QemudPipeMessage* msg)
18543e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner{
18553e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemu_put_be32(f, msg->size);
18563e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemu_put_be32(f, msg->offset);
18573e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemu_put_buffer(f, msg->message, msg->size);
18583e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner}
18593e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
18603e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner/* Loads pending pipe messages from the snapshot file.
18613e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner * Return:
18623e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner *  List of pending pipe messages loaded from snapshot, or NULL if snapshot didn't
18633e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner *  contain saved messages.
18643e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner */
18653e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turnerstatic QemudPipeMessage*
18663e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner_load_pipe_message(QEMUFile* f)
18673e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner{
18683e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    QemudPipeMessage* ret = NULL;
18693e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    QemudPipeMessage** next = &ret;
18703e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
18713e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    uint32_t size = qemu_get_be32(f);
18723e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    while (size != 0) {
18733e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        QemudPipeMessage* wrk;
18743e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        ANEW0(wrk);
18753e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        *next = wrk;
18763e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        wrk->size = size;
18773e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        wrk->offset = qemu_get_be32(f);
18783e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        wrk->message = malloc(wrk->size);
18793e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        if (wrk->message == NULL) {
18803e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            APANIC("Unable to allocate buffer for pipe's pending message.");
18813e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        }
18823e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        qemu_get_buffer(f, wrk->message, wrk->size);
18833e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        next = &wrk->next;
18843e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        *next = NULL;
18853e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        size = qemu_get_be32(f);
18863e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    }
18873e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
18883e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    return ret;
18893e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner}
18903e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
189177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* This is a callback that gets invoked when guest is connecting to the service.
189277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine *
189377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * Here we will create a new client as well as pipe descriptor representing new
189477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine * connection.
189577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
189677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic void*
189777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_qemudPipe_init(void* hwpipe, void* _looper, const char* args)
189877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
189977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudMultiplexer *m = _multiplexer;
190077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudService* sv = m->services;
190177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudClient* client;
190277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudPipe* pipe = NULL;
19034c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    char service_name[512];
19044c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    const char* client_args;
19054c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    size_t srv_name_len;
190677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
190777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* 'args' passed in this callback represents name of the service the guest is
190877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine     * connecting to. It can't be NULL. */
190977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (args == NULL) {
191077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        D("%s: Missing address!", __FUNCTION__);
191177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        return NULL;
191277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
191377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
19144c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    /* 'args' contain service name, and optional parameters for the client that
19154c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine     * is about to be created in this call. The parameters are separated from the
19164c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine     * service name wit ':'. Separate service name from the client param. */
19174c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    client_args = strchr(args, ':');
19184c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    if (client_args != NULL) {
19194c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        srv_name_len = min(client_args - args, sizeof(service_name) - 1);
19204c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        client_args++;  // Past the ':'
19214c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        if (*client_args == '\0') {
19224c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine            /* No actual parameters. */
19234c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine            client_args = NULL;
19244c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        }
19254c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    } else {
19264c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        srv_name_len = min(strlen(args), sizeof(service_name) - 1);
19274c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    }
19284c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    memcpy(service_name, args, srv_name_len);
19294c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    service_name[srv_name_len] = '\0';
19304c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine
193177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Lookup registered service by its name. */
19324c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    while (sv != NULL && strcmp(sv->name, service_name)) {
193377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        sv = sv->next;
193477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
193577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (sv == NULL) {
19364c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine        D("%s: Service '%s' has not been registered!", __FUNCTION__, service_name);
193777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        return NULL;
193877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
193977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
194077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Create a client for this connection. -1 as a channel ID signals that this
194177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine     * is a pipe client. */
19424c414820910ba8553cab7ff30188575f972a9896Vladimir Chtchetkine    client = qemud_service_connect_client(sv, -1, client_args);
194377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (client != NULL) {
194477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        ANEW0(pipe);
194577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        pipe->hwpipe = hwpipe;
194677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        pipe->looper = _looper;
194777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        pipe->service = sv;
194877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        pipe->client = client;
1949593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        client->ProtocolSelector.Pipe.qemud_pipe = pipe;
195077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
195177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
195277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    return pipe;
195377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
195477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
195577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* Called when the guest wants to close the channel.
195677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine*/
195777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic void
195877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_qemudPipe_closeFromGuest( void* opaque )
195977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
196077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudPipe* pipe = opaque;
196177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudClient*  client = pipe->client;
196277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    D("%s", __FUNCTION__);
1963593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    if (client != NULL) {
1964ef71cb8b3f97b6c985bda997759ce2113cdb893eVladimir Chtchetkine        qemud_client_disconnect(client, 1);
1965593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    } else {
1966593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        D("%s: Unexpected NULL client", __FUNCTION__);
1967593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    }
196877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
196977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
197077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* Called when the guest has sent some data to the client.
197177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
197277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic int
197377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_qemudPipe_sendBuffers(void* opaque,
197477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                       const GoldfishPipeBuffer* buffers,
197577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                       int numBuffers)
197677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
197777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudPipe* pipe = opaque;
197877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudClient*  client = pipe->client;
197977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    size_t transferred = 0;
198077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
1981593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    if (client == NULL) {
1982593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        D("%s: Unexpected NULL client", __FUNCTION__);
1983593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        return -1;
1984593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    }
1985593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine
198677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (numBuffers == 1) {
198777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* Simple case: all data are in one buffer. */
198877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        D("%s: %s", __FUNCTION__, quote_bytes((char*)buffers->data, buffers->size));
198977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        qemud_client_recv(client, buffers->data, buffers->size);
199077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        transferred = buffers->size;
199177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    } else {
199277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* If there are multiple buffers involved, collect all data in one buffer
199377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine         * before calling the high level client. */
199477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        uint8_t* msg, *wrk;
199577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        int n;
199677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        for (n = 0; n < numBuffers; n++) {
199777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            transferred += buffers[n].size;
199877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        }
199977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        msg = malloc(transferred);
200077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        wrk = msg;
200177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        for (n = 0; n < numBuffers; n++) {
200277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            memcpy(wrk, buffers[n].data, buffers[n].size);
200377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            wrk += buffers[n].size;
200477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        }
200577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        D("%s: %s", __FUNCTION__, quote_bytes((char*)msg, transferred));
200677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        qemud_client_recv(client, msg, transferred);
200777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        free(msg);
200877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
200977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
201077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    return transferred;
201177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
201277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
201377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* Called when the guest is reading data from the client.
201477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
201577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic int
201677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_qemudPipe_recvBuffers(void* opaque, GoldfishPipeBuffer* buffers, int numBuffers)
201777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
201877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudPipe* pipe = opaque;
201977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudClient*  client = pipe->client;
2020593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    QemudPipeMessage** msg_list;
202177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    GoldfishPipeBuffer* buff = buffers;
202277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    GoldfishPipeBuffer* endbuff = buffers + numBuffers;
202377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    size_t sent_bytes = 0;
202477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    size_t off_in_buff = 0;
202577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
2026593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    if (client == NULL) {
2027593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        D("%s: Unexpected NULL client", __FUNCTION__);
2028593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        return -1;
2029593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    }
2030593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine
2031593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    msg_list = &client->ProtocolSelector.Pipe.messages;
203277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (*msg_list == NULL) {
203377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* No data to send. Let it block until we wake it up with
203477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine         * PIPE_WAKE_READ when service sends data to the client. */
203577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        return PIPE_ERROR_AGAIN;
203677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
203777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
203877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* Fill in goldfish buffers while they are still available, and there are
203977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine     * messages in the client's message list. */
204077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    while (buff != endbuff && *msg_list != NULL) {
204177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        QemudPipeMessage* msg = *msg_list;
204277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* Message data fiting the current pipe's buffer. */
20431875d374acc7412b8b0aacaff073c8080d532924Vladimir Chtchetkine        size_t to_copy = min(msg->size - msg->offset, buff->size - off_in_buff);
204477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        memcpy(buff->data + off_in_buff, msg->message + msg->offset, to_copy);
204577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        /* Update offsets. */
204677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        off_in_buff += to_copy;
204777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        msg->offset += to_copy;
204877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        sent_bytes += to_copy;
204977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        if (msg->size == msg->offset) {
205077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            /* We're done with the current message. Go to the next one. */
205177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            *msg_list = msg->next;
205277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            free(msg);
205377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        }
205477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        if (off_in_buff == buff->size) {
205577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            /* Current pipe buffer is full. Continue with the next one. */
205677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine            buff++;
20571875d374acc7412b8b0aacaff073c8080d532924Vladimir Chtchetkine            off_in_buff = 0;
205877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        }
205977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
206077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
206177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    D("%s: -> %u (of %u)", __FUNCTION__, sent_bytes, buffers->size);
206277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
206377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    return sent_bytes;
206477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
206577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
206677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic unsigned
206777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_qemudPipe_poll(void* opaque)
206877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
206977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudPipe* pipe = opaque;
207077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudClient*  client = pipe->client;
2071593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    unsigned ret = 0;
2072593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine
2073593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    if (client != NULL) {
2074fd16505ce923202f0abe74bfe7c3ba110d325ebeVladimir Chtchetkine        ret |= PIPE_POLL_OUT;
2075593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        if (client->ProtocolSelector.Pipe.messages != NULL) {
2076fd16505ce923202f0abe74bfe7c3ba110d325ebeVladimir Chtchetkine            ret |= PIPE_POLL_IN;
2077593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        }
2078593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine    } else {
2079593853248510bda1bdb064780ef6046f3a50e582Vladimir Chtchetkine        D("%s: Unexpected NULL client", __FUNCTION__);
208077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
208177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
208277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    return ret;
208377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
208477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
208577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic void
208677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_qemudPipe_wakeOn(void* opaque, int flags)
208777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
208877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    D("%s: -> %X", __FUNCTION__, flags);
208977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
209077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
20913e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turnerstatic void
20923e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner_qemudPipe_save(void* opaque, QEMUFile* f )
20933e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner{
20943e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    QemudPipe* qemud_pipe = (QemudPipe*)opaque;
20953e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    QemudClient* c = qemud_pipe->client;
20963e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    QemudPipeMessage* msg = c->ProtocolSelector.Pipe.messages;
20973e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
20983e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* save generic information */
20993e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemud_service_save_name(f, c->service);
21003e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemu_put_string(f, c->param);
21013e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21023e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* Save pending messages. */
21033e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    while (msg != NULL) {
21043e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        _save_pipe_message(f, msg);
21053e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        msg = msg->next;
21063e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    }
21073e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* End of pending messages. */
21083e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemu_put_be32(f, 0);
21093e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21103e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* save client-specific state */
21113e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    if (c->clie_save)
21123e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        c->clie_save(f, c, c->clie_opaque);
21133e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21143e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* save framing configuration */
21153e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemu_put_be32(f, c->framing);
21163e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    if (c->framing) {
21173e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        qemu_put_be32(f, c->need_header);
21183e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        /* header sink always connected to c->header0, no need to save */
21193e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        qemu_put_be32(f, FRAME_HEADER_SIZE);
21203e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        qemu_put_buffer(f, c->header0, FRAME_HEADER_SIZE);
21213e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        /* payload sink */
21223e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        qemud_sink_save(f, c->payload);
21233e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        qemu_put_buffer(f, c->payload->buff, c->payload->size);
21243e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    }
21253e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner}
21263e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21273e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turnerstatic void*
21283e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner_qemudPipe_load(void* hwpipe, void* pipeOpaque, const char* args, QEMUFile* f)
21293e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner{
21303e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    QemudPipe* qemud_pipe = NULL;
21313e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    char* param;
21323e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    char *service_name = qemud_service_load_name(f);
21333e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    if (service_name == NULL)
21343e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        return NULL;
21353e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* get service instance for the loading client*/
21363e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    QemudService *sv = qemud_service_find(_multiplexer->services, service_name);
21373e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    if (sv == NULL) {
21383e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        D("%s: load failed: unknown service \"%s\"\n",
21393e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner          __FUNCTION__, service_name);
21403e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        return NULL;
21413e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    }
21423e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21433e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* Load saved parameters. */
21443e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    param = qemu_get_string(f);
21453e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21463e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* re-connect client */
21473e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    QemudClient* c = qemud_service_connect_client(sv, -1, param);
21483e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    if(c == NULL)
21493e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        return NULL;
21503e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21513e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* Load pending messages. */
21523e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    c->ProtocolSelector.Pipe.messages = _load_pipe_message(f);
21533e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21543e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* load client-specific state */
21553e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    if (c->clie_load && c->clie_load(f, c, c->clie_opaque)) {
21563e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        /* load failure */
21573e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        return NULL;
21583e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    }
21593e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21603e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* load framing configuration */
21613e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    c->framing = qemu_get_be32(f);
21623e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    if (c->framing) {
21633e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21643e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        /* header buffer */
21653e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        c->need_header = qemu_get_be32(f);
21663e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        int header_size = qemu_get_be32(f);
21673e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        if (header_size > FRAME_HEADER_SIZE) {
21683e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            D("%s: load failed: payload buffer requires %d bytes, %d available\n",
21693e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner              __FUNCTION__, header_size, FRAME_HEADER_SIZE);
21703e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            return NULL;
21713e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        }
21723e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        int ret;
21733e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        if ((ret = qemu_get_buffer(f, c->header0, header_size)) != header_size) {
21743e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            D("%s: frame header buffer load failed: expected %d bytes, got %d\n",
21753e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner              __FUNCTION__, header_size, ret);
21763e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            return NULL;
21773e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        }
21783e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21793e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        /* payload sink */
21803e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        if ((ret = qemud_sink_load(f, c->payload)))
21813e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            return NULL;
21823e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21833e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        /* replace payload buffer by saved data */
21843e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        if (c->payload->buff) {
21853e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            AFREE(c->payload->buff);
21863e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        }
21873e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        AARRAY_NEW(c->payload->buff, c->payload->size+1);  /* +1 for terminating zero */
21883e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        if ((ret = qemu_get_buffer(f, c->payload->buff, c->payload->size)) != c->payload->size) {
21893e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            D("%s: frame payload buffer load failed: expected %d bytes, got %d\n",
21903e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner              __FUNCTION__, c->payload->size, ret);
21913e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            AFREE(c->payload->buff);
21923e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner            return NULL;
21933e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner        }
21943e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    }
21953e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
21963e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    /* Associate the client with the pipe. */
21973e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    ANEW0(qemud_pipe);
21983e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemud_pipe->hwpipe = hwpipe;
21993e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemud_pipe->looper = pipeOpaque;
22003e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemud_pipe->service = sv;
22013e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    qemud_pipe->client = c;
22023e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    c->ProtocolSelector.Pipe.qemud_pipe = qemud_pipe;
22033e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
22043e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    return qemud_pipe;
22053e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner}
22063e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner
220777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* QEMUD pipe functions.
220877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
220977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic const GoldfishPipeFuncs _qemudPipe_funcs = {
221077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    _qemudPipe_init,
221177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    _qemudPipe_closeFromGuest,
221277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    _qemudPipe_sendBuffers,
221377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    _qemudPipe_recvBuffers,
221477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    _qemudPipe_poll,
221577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    _qemudPipe_wakeOn,
22163e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    _qemudPipe_save,
22173e92c2d49cb0e8752ce8c9a3c879c84ac3299061David 'Digit' Turner    _qemudPipe_load,
221877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine};
221977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
222077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* Initializes QEMUD pipe interface.
222177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
222277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic void
222377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_android_qemud_pipe_init(void)
222477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
222577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    static ABool _qemud_pipe_initialized = false;
222677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
222777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    if (!_qemud_pipe_initialized) {
222877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        goldfish_pipe_add_type( "qemud", looper_newCore(), &_qemudPipe_funcs );
222977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine        _qemud_pipe_initialized = true;
223077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    }
223177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
22329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
22339877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* this is the end of the serial charpipe that must be passed
22349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * to the emulated tty implementation. The other end of the
22359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * charpipe must be passed to qemud_multiplexer_init().
22369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
22379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic CharDriverState*  android_qemud_cs;
22389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
223977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine/* Initializes QEMUD serial interface.
224077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine */
224177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkinestatic void
224277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine_android_qemud_serial_init(void)
22439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
22449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    CharDriverState*    cs;
22459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
22469877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (android_qemud_cs != NULL)
22479877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        return;
22489877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
22499877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (qemu_chr_open_charpipe( &android_qemud_cs, &cs ) < 0) {
22509877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        derror( "%s: can't create charpipe to serial port",
22519877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                __FUNCTION__ );
22529877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        exit(1);
22539877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
22549877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
22559877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemud_multiplexer_init(_multiplexer, cs);
2256871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije
22575cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner    register_savevm(NULL,
22585cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    "qemud",
22595cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    0,
22605cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    QEMUD_SAVE_VERSION,
22615cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    qemud_save,
22625cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    qemud_load,
22635cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    _multiplexer);
22649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
22659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
226677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkineextern void
226777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkineandroid_qemud_init( void )
226877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine{
226977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    D("%s", __FUNCTION__);
227077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    /* We don't know in advance whether the guest system supports qemud pipes,
227177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine     * so we will initialize both qemud machineries, the legacy (over serial
227277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine     * port), and the new one (over qemu pipe). Then we let the guest to connect
227377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine     * via one, or the other. */
227477e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    _android_qemud_serial_init();
227577e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    _android_qemud_pipe_init();
227677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine}
227777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine
22789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* return the serial charpipe endpoint that must be used
22799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * by the emulated tty implementation.
22809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
22819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source ProjectCharDriverState*  android_qemud_get_cs( void )
22829877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
22839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (android_qemud_cs == NULL)
22849877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        android_qemud_init();
22859877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
22869877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return android_qemud_cs;
22879877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
22889877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
22899877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* this function is used to register a new named qemud-based
22909877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * service. You must provide 'serv_opaque' and 'serv_connect'
22919877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * which will be called whenever a new client tries to connect
22929877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * to the services.
22939877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
22949877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * 'serv_connect' shall return NULL if the connection is refused,
22959877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * or a handle to a new QemudClient otherwise. The latter can be
22969877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * created through qemud_client_new() defined above.
22979877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
22989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * 'max_clients' is the maximum number of clients accepted by
22999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * the service concurrently. If this value is 0, then any number
23009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * of clients can connect.
23019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
23029877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source ProjectQemudService*
23039877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_service_register( const char*          service_name,
23049877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                        int                  max_clients,
23059877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                        void*                serv_opaque,
2306871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                        QemudServiceConnect  serv_connect,
2307871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                        QemudServiceSave     serv_save,
2308871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                        QemudServiceLoad     serv_load )
23099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
23109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudService*      sv;
231177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    QemudMultiplexer*  m  = _multiplexer;
23129877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
231377e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    android_qemud_init();
23149877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
23159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    sv = qemud_service_new(service_name,
231677e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                           max_clients,
231777e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                           serv_opaque,
231877e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                           serv_connect,
231977e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                           serv_save,
232077e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                           serv_load,
232177e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine                           &m->services);
232277e61ceb3ecd53d6c4de9631c9450b6183d9244bVladimir Chtchetkine    D("Registered QEMUD service %s", service_name);
23239877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return sv;
23249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
23259877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
23269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* broadcast a given message to all clients of a given QemudService
23279877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
23289877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectextern void
23299877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectqemud_service_broadcast( QemudService*  sv,
23309877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                         const uint8_t*  msg,
23319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                         int             msglen )
23329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
23339877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudClient*  c;
23349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
23359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    for (c = sv->clients; c; c = c->next_serv)
23369877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        qemud_client_send(c, msg, msglen);
23379877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
23389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
23399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
23409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
23419877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/*
23429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * The following code is used for backwards compatibility reasons.
23439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * It allows you to implement a given qemud-based service through
23449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * a charpipe.
23459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
23469877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * In other words, this implements a QemudService and corresponding
23479877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * QemudClient that connects a qemud client running in the emulated
23489877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * system, to a CharDriverState object implemented through a charpipe.
23499877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
23509877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *   QemudCharClient <===charpipe====> (char driver user)
23519877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
23529877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * For example, this is used to implement the "gsm" service when the
23539877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * modem emulation is provided through an external serial device.
23549877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project *
23559877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * A QemudCharService can have only one client by definition.
23569877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * There is no QemudCharClient object because we can store a single
23579877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * CharDriverState handle in the 'opaque' field for simplicity.
23589877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
23599877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
23609877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projecttypedef struct {
23619877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudService*     service;
23629877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    CharDriverState*  cs;
23639877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project} QemudCharService;
23649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
23659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* called whenever a new message arrives from a qemud client.
23669877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * this simply sends the message through the charpipe to the user.
23679877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
23689877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
2369318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner_qemud_char_client_recv( void*  opaque, uint8_t*  msg, int  msglen,
2370318e4f294c181df33cf2541763904565b29bcccbDavid 'Digit' Turner                         QemudClient*  client )
23719877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
23729877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    CharDriverState*  cs = opaque;
23739877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemu_chr_write(cs, msg, msglen);
23749877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
23759877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
23769877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* we don't expect clients of char. services to exit. Just
23779877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * print an error to signal an unexpected situation. We should
23789877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * be able to recover from these though, so don't panic.
23799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
23809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
23819877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project_qemud_char_client_close( void*  opaque )
23825297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine
23839877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
23845297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine    QemudClient* client = opaque;
23855297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine
23865297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine    /* At this point modem driver still uses char pipe to communicate with
23875297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine     * hw-qemud, while communication with the guest is done over qemu pipe.
23885297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine     * So, when guest disconnects from the qemu pipe, and emulator-side client
23895297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine     * goes through the disconnection process, this routine is called, since it
23905297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine     * has been set to called during service registration. Unless modem driver
23915297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine     * is changed to drop char pipe communication, this routine will be called
23925297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine     * due to guest disconnection. As long as the client was a qemu pipe - based
23935297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine     * client, it's fine, since we don't really need to do anything in this case.
23945297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine     */
23955297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine    if (!_is_pipe_client(client)) {
23965297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine        derror("unexpected qemud char. channel close");
23975297e197c131258f3b115d1fc4ab608224b39bb9Vladimir Chtchetkine    }
23989877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
23999877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
24009877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
24019877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* called by the charpipe to know how much data can be read from
24029877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * the user. Since we send everything directly to the serial port
24039877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * we can return an arbitrary number.
24049877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
24059877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic int
24069877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project_qemud_char_service_can_read( void*  opaque )
24079877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
24089877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return 8192;  /* whatever */
24099877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
24109877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
24119877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* called to read data from the charpipe and send it to the client.
24129877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * used qemud_service_broadcast() even if there is a single client
24139877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * because we don't need a QemudCharClient object this way.
24149877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
24159877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic void
24169877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project_qemud_char_service_read( void*  opaque, const uint8_t*  from, int  len )
24179877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
24189877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    QemudService*  sv = opaque;
24199877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemud_service_broadcast( sv, from, len );
24209877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
24219877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
24229877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* called when a qemud client tries to connect to a char. service.
24239877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * we simply create a new client and open the charpipe to receive
24249877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * data from it.
24259877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
24269877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectstatic QemudClient*
24271875d374acc7412b8b0aacaff073c8080d532924Vladimir Chtchetkine_qemud_char_service_connect(void*          opaque,
24281875d374acc7412b8b0aacaff073c8080d532924Vladimir Chtchetkine                            QemudService*  sv,
24291875d374acc7412b8b0aacaff073c8080d532924Vladimir Chtchetkine                            int            channel,
24301875d374acc7412b8b0aacaff073c8080d532924Vladimir Chtchetkine                            const char*    client_param )
24319877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
24329877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    CharDriverState*   cs = opaque;
24331875d374acc7412b8b0aacaff073c8080d532924Vladimir Chtchetkine    QemudClient*       c  = qemud_client_new( sv, channel, client_param,
24349877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                                              cs,
24359877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                                              _qemud_char_client_recv,
2436871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                                              _qemud_char_client_close,
2437871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                                              NULL, NULL );
24389877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
24399877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    /* now we can open the gates :-) */
24409877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    qemu_chr_add_handlers( cs,
24419877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                           _qemud_char_service_can_read,
24429877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                           _qemud_char_service_read,
24439877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                           NULL,
24449877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project                           sv );
24459877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
24469877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return c;
24479877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
24489877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
24499877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* returns a charpipe endpoint that can be used by an emulated
24509877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * device or external serial port to implement a char. service
24519877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
24529877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectint
24539877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectandroid_qemud_get_channel( const char*  name, CharDriverState* *pcs )
24549877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
24559877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    CharDriverState*   cs;
24569877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
24579877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    if (qemu_chr_open_charpipe(&cs, pcs) < 0) {
24589877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        derror("can't open charpipe for '%s' qemud service", name);
24599877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project        exit(2);
24609877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    }
2461871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_service_register(name, 1, cs, _qemud_char_service_connect, NULL, NULL);
24629877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return 0;
24639877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
24649877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project
24659877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project/* set the character driver state for a given qemud communication channel. this
24669877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * is used to attach the channel to an external char driver device directly.
24679877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project * returns 0 on success, -1 on error
24689877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project */
24699877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectint
24709877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Projectandroid_qemud_set_channel( const char*  name, CharDriverState*  peer_cs )
24719877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project{
2472fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner    CharDriverState*  char_buffer = qemu_chr_open_buffer(peer_cs);
2473fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner
2474fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner    if (char_buffer == NULL)
2475fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner        return -1;
2476fff1ae51e389c25e2b19cd087c5e19cd27d40163David Turner
2477871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije    qemud_service_register(name, 1, char_buffer, _qemud_char_service_connect,
2478871da2aa80687142bec00ef7c1112253c76c32bbOt ten Thije                           NULL, NULL);
24799877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project    return 0;
24809877e2e3e3c2df64de306b48f80a4f5d0b028d95The Android Open Source Project}
2481