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