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 25QemuPipeStream::QemuPipeStream(size_t bufSize) : 26 IOStream(bufSize), 27 m_sock(-1), 28 m_bufsize(bufSize), 29 m_buf(NULL) 30{ 31} 32 33QemuPipeStream::QemuPipeStream(int sock, size_t bufSize) : 34 IOStream(bufSize), 35 m_sock(sock), 36 m_bufsize(bufSize), 37 m_buf(NULL) 38{ 39} 40 41QemuPipeStream::~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 53int 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 63void *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 85int QemuPipeStream::commitBuffer(size_t size) 86{ 87 return writeFully(m_buf, size); 88} 89 90int 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 131int QemuPipeStream::getSocket() const { 132 return m_sock; 133} 134 135const 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 172const 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 192int 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