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 "SocketStream.h" 17#include <cutils/sockets.h> 18#include <errno.h> 19#include <stdio.h> 20#include <stdlib.h> 21#include <unistd.h> 22#include <string.h> 23 24#ifndef _WIN32 25#include <netinet/in.h> 26#include <netinet/tcp.h> 27#include <sys/un.h> 28#else 29#include <ws2tcpip.h> 30#endif 31 32SocketStream::SocketStream(size_t bufSize) : 33 IOStream(bufSize), 34 m_sock(-1), 35 m_bufsize(bufSize), 36 m_buf(NULL) 37{ 38} 39 40SocketStream::SocketStream(int sock, size_t bufSize) : 41 IOStream(bufSize), 42 m_sock(sock), 43 m_bufsize(bufSize), 44 m_buf(NULL) 45{ 46} 47 48SocketStream::~SocketStream() 49{ 50 if (m_sock >= 0) { 51#ifdef _WIN32 52 closesocket(m_sock); 53#else 54 ::close(m_sock); 55#endif 56 } 57 if (m_buf != NULL) { 58 free(m_buf); 59 m_buf = NULL; 60 } 61} 62 63 64void *SocketStream::allocBuffer(size_t minSize) 65{ 66 size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize); 67 if (!m_buf) { 68 m_buf = (unsigned char *)malloc(allocSize); 69 } 70 else if (m_bufsize < allocSize) { 71 unsigned char *p = (unsigned char *)realloc(m_buf, allocSize); 72 if (p != NULL) { 73 m_buf = p; 74 m_bufsize = allocSize; 75 } else { 76 ERR("%s: realloc (%zu) failed\n", __FUNCTION__, allocSize); 77 free(m_buf); 78 m_buf = NULL; 79 m_bufsize = 0; 80 } 81 } 82 83 return m_buf; 84}; 85 86int SocketStream::commitBuffer(size_t size) 87{ 88 return writeFully(m_buf, size); 89} 90 91int SocketStream::writeFully(const void* buffer, size_t size) 92{ 93 if (!valid()) return -1; 94 95 size_t res = size; 96 int retval = 0; 97 98 while (res > 0) { 99 ssize_t stat = ::send(m_sock, (const char *)buffer + (size - res), res, 0); 100 if (stat < 0) { 101 if (errno != EINTR) { 102 retval = stat; 103 ERR("%s: failed: %s\n", __FUNCTION__, strerror(errno)); 104 break; 105 } 106 } else { 107 res -= stat; 108 } 109 } 110 return retval; 111} 112 113const unsigned char *SocketStream::readFully(void *buf, size_t len) 114{ 115 const unsigned char* ret = NULL; 116 if (!valid()) return NULL; 117 if (!buf) { 118 return NULL; // do not allow NULL buf in that implementation 119 } 120 size_t res = len; 121 while (res > 0) { 122 ssize_t stat = ::recv(m_sock, (char *)(buf) + len - res, res, 0); 123 if (stat > 0) { 124 res -= stat; 125 continue; 126 } 127 if (stat == 0 || errno != EINTR) { // client shutdown or error 128 return NULL; 129 } 130 } 131 return (const unsigned char *)buf; 132} 133 134const unsigned char *SocketStream::read( void *buf, size_t *inout_len) 135{ 136 if (!valid()) return NULL; 137 if (!buf) { 138 return NULL; // do not allow NULL buf in that implementation 139 } 140 141 int n; 142 do { 143 n = recv(buf, *inout_len); 144 } while( n < 0 && errno == EINTR ); 145 146 if (n > 0) { 147 *inout_len = n; 148 return (const unsigned char *)buf; 149 } 150 151 return NULL; 152} 153 154int SocketStream::recv(void *buf, size_t len) 155{ 156 if (!valid()) return int(ERR_INVALID_SOCKET); 157 int res = 0; 158 while(true) { 159 res = ::recv(m_sock, (char *)buf, len, 0); 160 if (res < 0) { 161 if (errno == EINTR) { 162 continue; 163 } 164 } 165 break; 166 } 167 return res; 168} 169