1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "QemuPipeStream.h"
17 #include "qemu_pipe.h"
18
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24
QemuPipeStream(size_t bufSize)25 QemuPipeStream::QemuPipeStream(size_t bufSize) :
26 IOStream(bufSize),
27 m_sock(-1),
28 m_bufsize(bufSize),
29 m_buf(NULL)
30 {
31 }
32
QemuPipeStream(int sock,size_t bufSize)33 QemuPipeStream::QemuPipeStream(int sock, size_t bufSize) :
34 IOStream(bufSize),
35 m_sock(sock),
36 m_bufsize(bufSize),
37 m_buf(NULL)
38 {
39 }
40
~QemuPipeStream()41 QemuPipeStream::~QemuPipeStream()
42 {
43 if (m_sock >= 0) {
44 flush();
45 ::close(m_sock);
46 }
47 if (m_buf != NULL) {
48 free(m_buf);
49 }
50 }
51
52
connect(void)53 int QemuPipeStream::connect(void)
54 {
55 m_sock = qemu_pipe_open("opengles");
56 if (!valid()) {
57 ALOGE("%s: failed with fd %d errno %d", __FUNCTION__, m_sock, errno);
58 return -1;
59 }
60 return 0;
61 }
62
allocBuffer(size_t minSize)63 void *QemuPipeStream::allocBuffer(size_t minSize)
64 {
65 size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize);
66 if (!m_buf) {
67 m_buf = (unsigned char *)malloc(allocSize);
68 }
69 else if (m_bufsize < allocSize) {
70 unsigned char *p = (unsigned char *)realloc(m_buf, allocSize);
71 if (p != NULL) {
72 m_buf = p;
73 m_bufsize = allocSize;
74 } else {
75 ERR("realloc (%d) failed\n", allocSize);
76 free(m_buf);
77 m_buf = NULL;
78 m_bufsize = 0;
79 }
80 }
81
82 return m_buf;
83 };
84
commitBuffer(size_t size)85 int QemuPipeStream::commitBuffer(size_t size)
86 {
87 return writeFully(m_buf, size);
88 }
89
writeFully(const void * buf,size_t len)90 int QemuPipeStream::writeFully(const void *buf, size_t len)
91 {
92 //DBG(">> QemuPipeStream::writeFully %d\n", len);
93 if (!valid()) return -1;
94 if (!buf) {
95 if (len>0) {
96 // If len is non-zero, buf must not be NULL. Otherwise the pipe would be
97 // in a corrupted state, which is lethal for the emulator.
98 ERR("QemuPipeStream::writeFully failed, buf=NULL, len %d,"
99 " lethal error, exiting", len);
100 abort();
101 }
102 return 0;
103 }
104
105 size_t res = len;
106 int retval = 0;
107
108 while (res > 0) {
109 ssize_t stat = ::write(m_sock, (const char *)(buf) + (len - res), res);
110 if (stat > 0) {
111 res -= stat;
112 continue;
113 }
114 if (stat == 0) { /* EOF */
115 ERR("QemuPipeStream::writeFully failed: premature EOF\n");
116 retval = -1;
117 break;
118 }
119 if (errno == EINTR) {
120 continue;
121 }
122 retval = stat;
123 ERR("QemuPipeStream::writeFully failed: %s, lethal error, exiting.\n",
124 strerror(errno));
125 abort();
126 }
127 //DBG("<< QemuPipeStream::writeFully %d\n", len );
128 return retval;
129 }
130
getSocket() const131 int QemuPipeStream::getSocket() const {
132 return m_sock;
133 }
134
readFully(void * buf,size_t len)135 const unsigned char *QemuPipeStream::readFully(void *buf, size_t len)
136 {
137 //DBG(">> QemuPipeStream::readFully %d\n", len);
138 if (!valid()) return NULL;
139 if (!buf) {
140 if (len > 0) {
141 // If len is non-zero, buf must not be NULL. Otherwise the pipe would be
142 // in a corrupted state, which is lethal for the emulator.
143 ERR("QemuPipeStream::readFully failed, buf=NULL, len %zu, lethal"
144 " error, exiting.", len);
145 abort();
146 }
147 return NULL; // do not allow NULL buf in that implementation
148 }
149 size_t res = len;
150 while (res > 0) {
151 ssize_t stat = ::read(m_sock, (char *)(buf) + len - res, res);
152 if (stat == 0) {
153 // client shutdown;
154 return NULL;
155 } else if (stat < 0) {
156 if (errno == EINTR) {
157 continue;
158 } else {
159 ERR("QemuPipeStream::readFully failed (buf %p, len %zu"
160 ", res %zu): %s, lethal error, exiting.", buf, len, res,
161 strerror(errno));
162 abort();
163 }
164 } else {
165 res -= stat;
166 }
167 }
168 //DBG("<< QemuPipeStream::readFully %d\n", len);
169 return (const unsigned char *)buf;
170 }
171
read(void * buf,size_t * inout_len)172 const unsigned char *QemuPipeStream::read( void *buf, size_t *inout_len)
173 {
174 //DBG(">> QemuPipeStream::read %d\n", *inout_len);
175 if (!valid()) return NULL;
176 if (!buf) {
177 ERR("QemuPipeStream::read failed, buf=NULL");
178 return NULL; // do not allow NULL buf in that implementation
179 }
180
181 int n = recv(buf, *inout_len);
182
183 if (n > 0) {
184 *inout_len = n;
185 return (const unsigned char *)buf;
186 }
187
188 //DBG("<< QemuPipeStream::read %d\n", *inout_len);
189 return NULL;
190 }
191
recv(void * buf,size_t len)192 int QemuPipeStream::recv(void *buf, size_t len)
193 {
194 if (!valid()) return int(ERR_INVALID_SOCKET);
195 char* p = (char *)buf;
196 int ret = 0;
197 while(len > 0) {
198 int res = ::read(m_sock, p, len);
199 if (res > 0) {
200 p += res;
201 ret += res;
202 len -= res;
203 continue;
204 }
205 if (res == 0) { /* EOF */
206 break;
207 }
208 if (errno == EINTR)
209 continue;
210
211 /* A real error */
212 if (ret == 0)
213 ret = -1;
214 break;
215 }
216 return ret;
217 }
218