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 <errno.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <unistd.h> 21 #include <string.h> 22 23 #ifndef _WIN32 24 #include <netinet/in.h> 25 #include <netinet/tcp.h> 26 #include <sys/un.h> 27 #else 28 #include <ws2tcpip.h> 29 #endif 30 31 SocketStream::SocketStream(size_t bufSize) : 32 IOStream(bufSize), 33 m_sock(-1), 34 m_bufsize(bufSize), 35 m_buf(NULL) 36 { 37 } 38 39 SocketStream::SocketStream(int sock, size_t bufSize) : 40 IOStream(bufSize), 41 m_sock(sock), 42 m_bufsize(bufSize), 43 m_buf(NULL) 44 { 45 } 46 47 SocketStream::~SocketStream() 48 { 49 if (m_sock >= 0) { 50 #ifdef _WIN32 51 closesocket(m_sock); 52 #else 53 ::close(m_sock); 54 #endif 55 m_sock = -1; 56 } 57 if (m_buf != NULL) { 58 free(m_buf); 59 m_buf = NULL; 60 } 61 } 62 63 64 void *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 86 int SocketStream::commitBuffer(size_t size) 87 { 88 return writeFully(m_buf, size); 89 } 90 91 int 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 113 const unsigned char *SocketStream::readFully(void *buf, size_t len) 114 { 115 if (!valid()) return NULL; 116 if (!buf) { 117 return NULL; // do not allow NULL buf in that implementation 118 } 119 size_t res = len; 120 while (res > 0) { 121 ssize_t stat = ::recv(m_sock, (char *)(buf) + len - res, res, 0); 122 if (stat > 0) { 123 res -= stat; 124 continue; 125 } 126 if (stat == 0 || errno != EINTR) { // client shutdown or error 127 return NULL; 128 } 129 } 130 return (const unsigned char *)buf; 131 } 132 133 const unsigned char *SocketStream::read( void *buf, size_t *inout_len) 134 { 135 if (!valid()) return NULL; 136 if (!buf) { 137 return NULL; // do not allow NULL buf in that implementation 138 } 139 140 int n; 141 do { 142 n = this->recv(buf, *inout_len); 143 } while( n < 0 && errno == EINTR ); 144 145 if (n > 0) { 146 *inout_len = n; 147 return (const unsigned char *)buf; 148 } 149 150 return NULL; 151 } 152 153 int SocketStream::recv(void *buf, size_t len) 154 { 155 if (!valid()) return int(ERR_INVALID_SOCKET); 156 int res = 0; 157 while(true) { 158 res = ::recv(m_sock, (char *)buf, len, 0); 159 if (res < 0) { 160 if (errno == EINTR) { 161 continue; 162 } 163 } 164 break; 165 } 166 return res; 167 } 168