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 <hardware/qemu_pipe.h> 18 #include <errno.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <unistd.h> 22 #include <string.h> 23 24 QemuPipeStream::QemuPipeStream(size_t bufSize) : 25 IOStream(bufSize), 26 m_sock(-1), 27 m_bufsize(bufSize), 28 m_buf(NULL) 29 { 30 } 31 32 QemuPipeStream::QemuPipeStream(int sock, size_t bufSize) : 33 IOStream(bufSize), 34 m_sock(sock), 35 m_bufsize(bufSize), 36 m_buf(NULL) 37 { 38 } 39 40 QemuPipeStream::~QemuPipeStream() 41 { 42 if (m_sock >= 0) { 43 flush(); 44 ::close(m_sock); 45 } 46 if (m_buf != NULL) { 47 free(m_buf); 48 } 49 } 50 51 52 int QemuPipeStream::connect(void) 53 { 54 m_sock = qemu_pipe_open("opengles"); 55 if (!valid()) return -1; 56 return 0; 57 } 58 59 void *QemuPipeStream::allocBuffer(size_t minSize) 60 { 61 size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize); 62 if (!m_buf) { 63 m_buf = (unsigned char *)malloc(allocSize); 64 } 65 else if (m_bufsize < allocSize) { 66 unsigned char *p = (unsigned char *)realloc(m_buf, allocSize); 67 if (p != NULL) { 68 m_buf = p; 69 m_bufsize = allocSize; 70 } else { 71 ERR("realloc (%d) failed\n", allocSize); 72 free(m_buf); 73 m_buf = NULL; 74 m_bufsize = 0; 75 } 76 } 77 78 return m_buf; 79 }; 80 81 int QemuPipeStream::commitBuffer(size_t size) 82 { 83 return writeFully(m_buf, size); 84 } 85 86 int QemuPipeStream::writeFully(const void *buf, size_t len) 87 { 88 //DBG(">> QemuPipeStream::writeFully %d\n", len); 89 if (!valid()) return -1; 90 if (!buf) { 91 if (len>0) { 92 // If len is non-zero, buf must not be NULL. Otherwise the pipe would be 93 // in a corrupted state, which is lethal for the emulator. 94 ERR("QemuPipeStream::writeFully failed, buf=NULL, len %d," 95 " lethal error, exiting", len); 96 abort(); 97 } 98 return 0; 99 } 100 101 size_t res = len; 102 int retval = 0; 103 104 while (res > 0) { 105 ssize_t stat = ::write(m_sock, (const char *)(buf) + (len - res), res); 106 if (stat > 0) { 107 res -= stat; 108 continue; 109 } 110 if (stat == 0) { /* EOF */ 111 ERR("QemuPipeStream::writeFully failed: premature EOF\n"); 112 retval = -1; 113 break; 114 } 115 if (errno == EINTR) { 116 continue; 117 } 118 retval = stat; 119 ERR("QemuPipeStream::writeFully failed: %s, lethal error, exiting.\n", 120 strerror(errno)); 121 abort(); 122 } 123 //DBG("<< QemuPipeStream::writeFully %d\n", len ); 124 return retval; 125 } 126 127 const unsigned char *QemuPipeStream::readFully(void *buf, size_t len) 128 { 129 //DBG(">> QemuPipeStream::readFully %d\n", len); 130 if (!valid()) return NULL; 131 if (!buf) { 132 if (len > 0) { 133 // If len is non-zero, buf must not be NULL. Otherwise the pipe would be 134 // in a corrupted state, which is lethal for the emulator. 135 ERR("QemuPipeStream::readFully failed, buf=NULL, len %zu, lethal" 136 " error, exiting.", len); 137 abort(); 138 } 139 return NULL; // do not allow NULL buf in that implementation 140 } 141 size_t res = len; 142 while (res > 0) { 143 ssize_t stat = ::read(m_sock, (char *)(buf) + len - res, res); 144 if (stat == 0) { 145 // client shutdown; 146 return NULL; 147 } else if (stat < 0) { 148 if (errno == EINTR) { 149 continue; 150 } else { 151 ERR("QemuPipeStream::readFully failed (buf %p, len %zu" 152 ", res %zu): %s, lethal error, exiting.", buf, len, res, 153 strerror(errno)); 154 abort(); 155 } 156 } else { 157 res -= stat; 158 } 159 } 160 //DBG("<< QemuPipeStream::readFully %d\n", len); 161 return (const unsigned char *)buf; 162 } 163 164 const unsigned char *QemuPipeStream::read( void *buf, size_t *inout_len) 165 { 166 //DBG(">> QemuPipeStream::read %d\n", *inout_len); 167 if (!valid()) return NULL; 168 if (!buf) { 169 ERR("QemuPipeStream::read failed, buf=NULL"); 170 return NULL; // do not allow NULL buf in that implementation 171 } 172 173 int n = recv(buf, *inout_len); 174 175 if (n > 0) { 176 *inout_len = n; 177 return (const unsigned char *)buf; 178 } 179 180 //DBG("<< QemuPipeStream::read %d\n", *inout_len); 181 return NULL; 182 } 183 184 int QemuPipeStream::recv(void *buf, size_t len) 185 { 186 if (!valid()) return int(ERR_INVALID_SOCKET); 187 char* p = (char *)buf; 188 int ret = 0; 189 while(len > 0) { 190 int res = ::read(m_sock, p, len); 191 if (res > 0) { 192 p += res; 193 ret += res; 194 len -= res; 195 continue; 196 } 197 if (res == 0) { /* EOF */ 198 break; 199 } 200 if (errno == EINTR) 201 continue; 202 203 /* A real error */ 204 if (ret == 0) 205 ret = -1; 206 break; 207 } 208 return ret; 209 } 210