1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright 2011 Google LLC
3*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker */
5*61046927SAndroid Build Coastguard Worker #include "QemuPipeStream.h"
6*61046927SAndroid Build Coastguard Worker
7*61046927SAndroid Build Coastguard Worker #include <errno.h>
8*61046927SAndroid Build Coastguard Worker #include <qemu_pipe_bp.h>
9*61046927SAndroid Build Coastguard Worker #include <stdio.h>
10*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
11*61046927SAndroid Build Coastguard Worker #include <string.h>
12*61046927SAndroid Build Coastguard Worker #include <unistd.h>
13*61046927SAndroid Build Coastguard Worker
14*61046927SAndroid Build Coastguard Worker #include "util/log.h"
15*61046927SAndroid Build Coastguard Worker
16*61046927SAndroid Build Coastguard Worker static const size_t kReadSize = 512 * 1024;
17*61046927SAndroid Build Coastguard Worker static const size_t kWriteOffset = kReadSize;
18*61046927SAndroid Build Coastguard Worker
QemuPipeStream(size_t bufSize)19*61046927SAndroid Build Coastguard Worker QemuPipeStream::QemuPipeStream(size_t bufSize)
20*61046927SAndroid Build Coastguard Worker : IOStream(bufSize), m_sock(-1), m_bufsize(bufSize), m_buf(NULL), m_read(0), m_readLeft(0) {}
21*61046927SAndroid Build Coastguard Worker
QemuPipeStream(QEMU_PIPE_HANDLE sock,size_t bufSize)22*61046927SAndroid Build Coastguard Worker QemuPipeStream::QemuPipeStream(QEMU_PIPE_HANDLE sock, size_t bufSize)
23*61046927SAndroid Build Coastguard Worker : IOStream(bufSize), m_sock(sock), m_bufsize(bufSize), m_buf(NULL), m_read(0), m_readLeft(0) {}
24*61046927SAndroid Build Coastguard Worker
~QemuPipeStream()25*61046927SAndroid Build Coastguard Worker QemuPipeStream::~QemuPipeStream() {
26*61046927SAndroid Build Coastguard Worker if (valid()) {
27*61046927SAndroid Build Coastguard Worker flush();
28*61046927SAndroid Build Coastguard Worker qemu_pipe_close((QEMU_PIPE_HANDLE)m_sock);
29*61046927SAndroid Build Coastguard Worker }
30*61046927SAndroid Build Coastguard Worker if (m_buf != NULL) {
31*61046927SAndroid Build Coastguard Worker free(m_buf);
32*61046927SAndroid Build Coastguard Worker }
33*61046927SAndroid Build Coastguard Worker }
34*61046927SAndroid Build Coastguard Worker
connect(const char * serviceName)35*61046927SAndroid Build Coastguard Worker int QemuPipeStream::connect(const char* serviceName) {
36*61046927SAndroid Build Coastguard Worker m_sock = (int)qemu_pipe_open("opengles");
37*61046927SAndroid Build Coastguard Worker if (!valid()) {
38*61046927SAndroid Build Coastguard Worker mesa_loge("%s: failed to connect to opengles pipe", __FUNCTION__);
39*61046927SAndroid Build Coastguard Worker qemu_pipe_print_error(m_sock);
40*61046927SAndroid Build Coastguard Worker return -1;
41*61046927SAndroid Build Coastguard Worker }
42*61046927SAndroid Build Coastguard Worker return 0;
43*61046927SAndroid Build Coastguard Worker }
44*61046927SAndroid Build Coastguard Worker
processPipeInit()45*61046927SAndroid Build Coastguard Worker uint64_t QemuPipeStream::processPipeInit() {
46*61046927SAndroid Build Coastguard Worker QEMU_PIPE_HANDLE processPipe = qemu_pipe_open("GLProcessPipe");
47*61046927SAndroid Build Coastguard Worker
48*61046927SAndroid Build Coastguard Worker uint64_t procUID = 0;
49*61046927SAndroid Build Coastguard Worker if (!qemu_pipe_valid(processPipe)) {
50*61046927SAndroid Build Coastguard Worker processPipe = 0;
51*61046927SAndroid Build Coastguard Worker mesa_logi("Process pipe failed");
52*61046927SAndroid Build Coastguard Worker return 0;
53*61046927SAndroid Build Coastguard Worker }
54*61046927SAndroid Build Coastguard Worker
55*61046927SAndroid Build Coastguard Worker // Send a confirmation int to the host
56*61046927SAndroid Build Coastguard Worker int32_t confirmInt = 100;
57*61046927SAndroid Build Coastguard Worker if (qemu_pipe_write_fully(processPipe, &confirmInt, sizeof(confirmInt))) { // failed
58*61046927SAndroid Build Coastguard Worker qemu_pipe_close(processPipe);
59*61046927SAndroid Build Coastguard Worker processPipe = 0;
60*61046927SAndroid Build Coastguard Worker mesa_logi("Process pipe failed");
61*61046927SAndroid Build Coastguard Worker return 0;
62*61046927SAndroid Build Coastguard Worker }
63*61046927SAndroid Build Coastguard Worker
64*61046927SAndroid Build Coastguard Worker // Ask the host for per-process unique ID
65*61046927SAndroid Build Coastguard Worker if (qemu_pipe_read_fully(processPipe, &procUID, sizeof(procUID))) {
66*61046927SAndroid Build Coastguard Worker qemu_pipe_close(processPipe);
67*61046927SAndroid Build Coastguard Worker processPipe = 0;
68*61046927SAndroid Build Coastguard Worker procUID = 0;
69*61046927SAndroid Build Coastguard Worker mesa_logi("Process pipe failed");
70*61046927SAndroid Build Coastguard Worker return 0;
71*61046927SAndroid Build Coastguard Worker }
72*61046927SAndroid Build Coastguard Worker
73*61046927SAndroid Build Coastguard Worker return procUID;
74*61046927SAndroid Build Coastguard Worker }
75*61046927SAndroid Build Coastguard Worker
allocBuffer(size_t minSize)76*61046927SAndroid Build Coastguard Worker void* QemuPipeStream::allocBuffer(size_t minSize) {
77*61046927SAndroid Build Coastguard Worker // Add dedicated read buffer space at the front of the buffer.
78*61046927SAndroid Build Coastguard Worker minSize += kReadSize;
79*61046927SAndroid Build Coastguard Worker
80*61046927SAndroid Build Coastguard Worker size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize);
81*61046927SAndroid Build Coastguard Worker if (!m_buf) {
82*61046927SAndroid Build Coastguard Worker m_buf = (unsigned char*)malloc(allocSize);
83*61046927SAndroid Build Coastguard Worker } else if (m_bufsize < allocSize) {
84*61046927SAndroid Build Coastguard Worker unsigned char* p = (unsigned char*)realloc(m_buf, allocSize);
85*61046927SAndroid Build Coastguard Worker if (p != NULL) {
86*61046927SAndroid Build Coastguard Worker m_buf = p;
87*61046927SAndroid Build Coastguard Worker m_bufsize = allocSize;
88*61046927SAndroid Build Coastguard Worker } else {
89*61046927SAndroid Build Coastguard Worker mesa_loge("realloc (%zu) failed\n", allocSize);
90*61046927SAndroid Build Coastguard Worker free(m_buf);
91*61046927SAndroid Build Coastguard Worker m_buf = NULL;
92*61046927SAndroid Build Coastguard Worker m_bufsize = 0;
93*61046927SAndroid Build Coastguard Worker }
94*61046927SAndroid Build Coastguard Worker }
95*61046927SAndroid Build Coastguard Worker
96*61046927SAndroid Build Coastguard Worker return m_buf + kWriteOffset;
97*61046927SAndroid Build Coastguard Worker };
98*61046927SAndroid Build Coastguard Worker
commitBuffer(size_t size)99*61046927SAndroid Build Coastguard Worker int QemuPipeStream::commitBuffer(size_t size) {
100*61046927SAndroid Build Coastguard Worker if (size == 0) return 0;
101*61046927SAndroid Build Coastguard Worker return writeFully(m_buf + kWriteOffset, size);
102*61046927SAndroid Build Coastguard Worker }
103*61046927SAndroid Build Coastguard Worker
writeFully(const void * buf,size_t len)104*61046927SAndroid Build Coastguard Worker int QemuPipeStream::writeFully(const void* buf, size_t len) {
105*61046927SAndroid Build Coastguard Worker return qemu_pipe_write_fully(m_sock, buf, len);
106*61046927SAndroid Build Coastguard Worker }
107*61046927SAndroid Build Coastguard Worker
readFully(void * buf,size_t len)108*61046927SAndroid Build Coastguard Worker const unsigned char* QemuPipeStream::readFully(void* buf, size_t len) {
109*61046927SAndroid Build Coastguard Worker return commitBufferAndReadFully(0, buf, len);
110*61046927SAndroid Build Coastguard Worker }
111*61046927SAndroid Build Coastguard Worker
commitBufferAndReadFully(size_t writeSize,void * userReadBufPtr,size_t totalReadSize)112*61046927SAndroid Build Coastguard Worker const unsigned char* QemuPipeStream::commitBufferAndReadFully(size_t writeSize,
113*61046927SAndroid Build Coastguard Worker void* userReadBufPtr,
114*61046927SAndroid Build Coastguard Worker size_t totalReadSize) {
115*61046927SAndroid Build Coastguard Worker unsigned char* userReadBuf = static_cast<unsigned char*>(userReadBufPtr);
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Worker if (!valid()) return NULL;
118*61046927SAndroid Build Coastguard Worker
119*61046927SAndroid Build Coastguard Worker if (!userReadBuf) {
120*61046927SAndroid Build Coastguard Worker if (totalReadSize > 0) {
121*61046927SAndroid Build Coastguard Worker mesa_loge(
122*61046927SAndroid Build Coastguard Worker "QemuPipeStream::commitBufferAndReadFully failed, userReadBuf=NULL, totalReadSize "
123*61046927SAndroid Build Coastguard Worker "%zu, lethal"
124*61046927SAndroid Build Coastguard Worker " error, exiting.",
125*61046927SAndroid Build Coastguard Worker totalReadSize);
126*61046927SAndroid Build Coastguard Worker abort();
127*61046927SAndroid Build Coastguard Worker }
128*61046927SAndroid Build Coastguard Worker if (!writeSize) {
129*61046927SAndroid Build Coastguard Worker return NULL;
130*61046927SAndroid Build Coastguard Worker }
131*61046927SAndroid Build Coastguard Worker }
132*61046927SAndroid Build Coastguard Worker
133*61046927SAndroid Build Coastguard Worker // Advance buffered read if not yet consumed.
134*61046927SAndroid Build Coastguard Worker size_t remaining = totalReadSize;
135*61046927SAndroid Build Coastguard Worker size_t bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
136*61046927SAndroid Build Coastguard Worker if (bufferedReadSize) {
137*61046927SAndroid Build Coastguard Worker memcpy(userReadBuf, m_buf + (m_read - m_readLeft), bufferedReadSize);
138*61046927SAndroid Build Coastguard Worker remaining -= bufferedReadSize;
139*61046927SAndroid Build Coastguard Worker m_readLeft -= bufferedReadSize;
140*61046927SAndroid Build Coastguard Worker }
141*61046927SAndroid Build Coastguard Worker
142*61046927SAndroid Build Coastguard Worker // Early out if nothing left to do.
143*61046927SAndroid Build Coastguard Worker if (!writeSize && !remaining) {
144*61046927SAndroid Build Coastguard Worker return userReadBuf;
145*61046927SAndroid Build Coastguard Worker }
146*61046927SAndroid Build Coastguard Worker
147*61046927SAndroid Build Coastguard Worker writeFully(m_buf + kWriteOffset, writeSize);
148*61046927SAndroid Build Coastguard Worker
149*61046927SAndroid Build Coastguard Worker // Now done writing. Early out if no reading left to do.
150*61046927SAndroid Build Coastguard Worker if (!remaining) {
151*61046927SAndroid Build Coastguard Worker return userReadBuf;
152*61046927SAndroid Build Coastguard Worker }
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker // Read up to kReadSize bytes if all buffered read has been consumed.
155*61046927SAndroid Build Coastguard Worker size_t maxRead = m_readLeft ? 0 : kReadSize;
156*61046927SAndroid Build Coastguard Worker
157*61046927SAndroid Build Coastguard Worker ssize_t actual = 0;
158*61046927SAndroid Build Coastguard Worker
159*61046927SAndroid Build Coastguard Worker if (maxRead) {
160*61046927SAndroid Build Coastguard Worker actual = qemu_pipe_read(m_sock, m_buf, maxRead);
161*61046927SAndroid Build Coastguard Worker // Updated buffered read size.
162*61046927SAndroid Build Coastguard Worker if (actual > 0) {
163*61046927SAndroid Build Coastguard Worker m_read = m_readLeft = actual;
164*61046927SAndroid Build Coastguard Worker }
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker if (actual == 0) {
167*61046927SAndroid Build Coastguard Worker mesa_logi("%s: end of pipe", __FUNCTION__);
168*61046927SAndroid Build Coastguard Worker return NULL;
169*61046927SAndroid Build Coastguard Worker }
170*61046927SAndroid Build Coastguard Worker }
171*61046927SAndroid Build Coastguard Worker
172*61046927SAndroid Build Coastguard Worker // Consume buffered read and read more if necessary.
173*61046927SAndroid Build Coastguard Worker while (remaining) {
174*61046927SAndroid Build Coastguard Worker bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
175*61046927SAndroid Build Coastguard Worker if (bufferedReadSize) {
176*61046927SAndroid Build Coastguard Worker memcpy(userReadBuf + (totalReadSize - remaining), m_buf + (m_read - m_readLeft),
177*61046927SAndroid Build Coastguard Worker bufferedReadSize);
178*61046927SAndroid Build Coastguard Worker remaining -= bufferedReadSize;
179*61046927SAndroid Build Coastguard Worker m_readLeft -= bufferedReadSize;
180*61046927SAndroid Build Coastguard Worker continue;
181*61046927SAndroid Build Coastguard Worker }
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker actual = qemu_pipe_read(m_sock, m_buf, kReadSize);
184*61046927SAndroid Build Coastguard Worker
185*61046927SAndroid Build Coastguard Worker if (actual == 0) {
186*61046927SAndroid Build Coastguard Worker mesa_logi("%s: Failed reading from pipe: %d", __FUNCTION__, errno);
187*61046927SAndroid Build Coastguard Worker return NULL;
188*61046927SAndroid Build Coastguard Worker }
189*61046927SAndroid Build Coastguard Worker
190*61046927SAndroid Build Coastguard Worker if (actual > 0) {
191*61046927SAndroid Build Coastguard Worker m_read = m_readLeft = actual;
192*61046927SAndroid Build Coastguard Worker continue;
193*61046927SAndroid Build Coastguard Worker }
194*61046927SAndroid Build Coastguard Worker
195*61046927SAndroid Build Coastguard Worker if (!qemu_pipe_try_again(actual)) {
196*61046927SAndroid Build Coastguard Worker mesa_logi("%s: Error reading from pipe: %d", __FUNCTION__, errno);
197*61046927SAndroid Build Coastguard Worker return NULL;
198*61046927SAndroid Build Coastguard Worker }
199*61046927SAndroid Build Coastguard Worker }
200*61046927SAndroid Build Coastguard Worker
201*61046927SAndroid Build Coastguard Worker return userReadBuf;
202*61046927SAndroid Build Coastguard Worker }
203*61046927SAndroid Build Coastguard Worker
read(void * buf,size_t * inout_len)204*61046927SAndroid Build Coastguard Worker const unsigned char* QemuPipeStream::read(void* buf, size_t* inout_len) {
205*61046927SAndroid Build Coastguard Worker if (!valid()) return NULL;
206*61046927SAndroid Build Coastguard Worker if (!buf) {
207*61046927SAndroid Build Coastguard Worker mesa_loge("QemuPipeStream::read failed, buf=NULL");
208*61046927SAndroid Build Coastguard Worker return NULL; // do not allow NULL buf in that implementation
209*61046927SAndroid Build Coastguard Worker }
210*61046927SAndroid Build Coastguard Worker
211*61046927SAndroid Build Coastguard Worker int n = recv(buf, *inout_len);
212*61046927SAndroid Build Coastguard Worker
213*61046927SAndroid Build Coastguard Worker if (n > 0) {
214*61046927SAndroid Build Coastguard Worker *inout_len = n;
215*61046927SAndroid Build Coastguard Worker return (const unsigned char*)buf;
216*61046927SAndroid Build Coastguard Worker }
217*61046927SAndroid Build Coastguard Worker
218*61046927SAndroid Build Coastguard Worker return NULL;
219*61046927SAndroid Build Coastguard Worker }
220*61046927SAndroid Build Coastguard Worker
valid()221*61046927SAndroid Build Coastguard Worker bool QemuPipeStream::valid() { return qemu_pipe_valid(m_sock); }
222*61046927SAndroid Build Coastguard Worker
recv(void * buf,size_t len)223*61046927SAndroid Build Coastguard Worker int QemuPipeStream::recv(void* buf, size_t len) {
224*61046927SAndroid Build Coastguard Worker if (!valid()) return int(ERR_INVALID_SOCKET);
225*61046927SAndroid Build Coastguard Worker char* p = (char*)buf;
226*61046927SAndroid Build Coastguard Worker int ret = 0;
227*61046927SAndroid Build Coastguard Worker while (len > 0) {
228*61046927SAndroid Build Coastguard Worker int res = qemu_pipe_read(m_sock, p, len);
229*61046927SAndroid Build Coastguard Worker if (res > 0) {
230*61046927SAndroid Build Coastguard Worker p += res;
231*61046927SAndroid Build Coastguard Worker ret += res;
232*61046927SAndroid Build Coastguard Worker len -= res;
233*61046927SAndroid Build Coastguard Worker continue;
234*61046927SAndroid Build Coastguard Worker }
235*61046927SAndroid Build Coastguard Worker if (res == 0) { /* EOF */
236*61046927SAndroid Build Coastguard Worker break;
237*61046927SAndroid Build Coastguard Worker }
238*61046927SAndroid Build Coastguard Worker if (qemu_pipe_try_again(res)) {
239*61046927SAndroid Build Coastguard Worker continue;
240*61046927SAndroid Build Coastguard Worker }
241*61046927SAndroid Build Coastguard Worker
242*61046927SAndroid Build Coastguard Worker /* A real error */
243*61046927SAndroid Build Coastguard Worker if (ret == 0) ret = -1;
244*61046927SAndroid Build Coastguard Worker break;
245*61046927SAndroid Build Coastguard Worker }
246*61046927SAndroid Build Coastguard Worker return ret;
247*61046927SAndroid Build Coastguard Worker }
248