1 /* 2 * Copyright (C) 2010 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 17 /* 18 * Contains helper routines dealing with syncronous access to a non-blocking 19 * sokets. 20 */ 21 22 #include "qemu-common.h" 23 #include "errno.h" 24 #include "iolooper.h" 25 #include "sockets.h" 26 #include "android/utils/debug.h" 27 #include "android/sync-utils.h" 28 #include "android/utils/system.h" 29 30 #define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0) 31 32 struct SyncSocket { 33 // Helper for performing synchronous I/O on the socket. 34 IoLooper* iolooper; 35 36 /* Opened socket handle. */ 37 int fd; 38 }; 39 40 SyncSocket* 41 syncsocket_init(int fd) 42 { 43 SyncSocket* sync_socket; 44 ANEW0(sync_socket); 45 46 socket_set_nonblock(fd); 47 sync_socket->iolooper = iolooper_new(); 48 sync_socket->fd = fd; 49 50 return sync_socket; 51 } 52 53 SyncSocket* 54 syncsocket_connect(int fd, SockAddress* sockaddr, int timeout) 55 { 56 IoLooper* looper; 57 int connect_status; 58 SyncSocket* sync_socket = NULL; 59 60 socket_set_nonblock(fd); 61 62 for(;;) { 63 connect_status = socket_connect(fd, sockaddr); 64 if (connect_status >= 0) { 65 // Connected. Create IoLooper for the helper. 66 looper = iolooper_new(); 67 break; 68 } 69 70 if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) { 71 // Connection is in progress. Wait till it's finished. 72 looper = iolooper_new(); 73 iolooper_add_write(looper, fd); 74 connect_status = iolooper_wait(looper, timeout); 75 if (connect_status > 0) { 76 iolooper_del_write(looper, fd); 77 break; 78 } else { 79 iolooper_free(looper); 80 return NULL; 81 } 82 } else if (errno != EINTR) { 83 return NULL; 84 } 85 } 86 87 // We're now connected. Lets initialize SyncSocket instance 88 // for this connection. 89 sync_socket = malloc(sizeof(SyncSocket)); 90 if (sync_socket == NULL) { 91 derror("PANIC: not enough memory\n"); 92 exit(1); 93 } 94 95 sync_socket->iolooper = looper; 96 sync_socket->fd = fd; 97 98 return sync_socket; 99 } 100 101 void 102 syncsocket_close(SyncSocket* ssocket) 103 { 104 if (ssocket != NULL && ssocket->fd >= 0) { 105 if (ssocket->iolooper != NULL) { 106 iolooper_reset(ssocket->iolooper); 107 } 108 socket_close(ssocket->fd); 109 ssocket->fd = -1; 110 } 111 } 112 113 void 114 syncsocket_free(SyncSocket* ssocket) 115 { 116 if (ssocket != NULL) { 117 if (ssocket->iolooper != NULL) { 118 iolooper_free(ssocket->iolooper); 119 } 120 free(ssocket); 121 } 122 } 123 124 int 125 syncsocket_start_read(SyncSocket* ssocket) 126 { 127 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) { 128 errno = EINVAL; 129 return -1; 130 } 131 iolooper_add_read(ssocket->iolooper, ssocket->fd); 132 return 0; 133 } 134 135 int 136 syncsocket_stop_read(SyncSocket* ssocket) 137 { 138 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) { 139 errno = EINVAL; 140 return -1; 141 } 142 iolooper_del_read(ssocket->iolooper, ssocket->fd); 143 return 0; 144 } 145 146 int 147 syncsocket_start_write(SyncSocket* ssocket) 148 { 149 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) { 150 errno = EINVAL; 151 return -1; 152 } 153 iolooper_add_write(ssocket->iolooper, ssocket->fd); 154 return 0; 155 } 156 157 int 158 syncsocket_stop_write(SyncSocket* ssocket) 159 { 160 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) { 161 errno = EINVAL; 162 return -1; 163 } 164 iolooper_del_write(ssocket->iolooper, ssocket->fd); 165 return 0; 166 } 167 168 ssize_t 169 syncsocket_read_absolute(SyncSocket* ssocket, 170 void* buf, 171 size_t size, 172 int64_t deadline) 173 { 174 int ret; 175 176 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) { 177 errno = EINVAL; 178 return -1; 179 } 180 181 ret = iolooper_wait_absolute(ssocket->iolooper, deadline); 182 if (ret > 0) { 183 if (!iolooper_is_read(ssocket->iolooper, ssocket->fd)) { 184 D("%s: Internal error, iolooper_is_read() not set!", __FUNCTION__); 185 return -1; 186 } 187 do { 188 ret = socket_recv(ssocket->fd, buf, size); 189 } while( ret < 0 && errno == EINTR); 190 } else if (ret == 0) { 191 // Timed out 192 errno = ETIMEDOUT; 193 ret = -1; 194 } 195 return ret; 196 } 197 198 ssize_t 199 syncsocket_read(SyncSocket* ssocket, void* buf, size_t size, int timeout) 200 { 201 return syncsocket_read_absolute(ssocket, buf, size, iolooper_now() + timeout); 202 } 203 204 ssize_t 205 syncsocket_write_absolute(SyncSocket* ssocket, 206 const void* buf, 207 size_t size, 208 int64_t deadline) 209 { 210 int ret; 211 size_t written = 0; 212 213 if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) { 214 errno = EINVAL; 215 return -1; 216 } 217 218 do { 219 ret = iolooper_wait_absolute(ssocket->iolooper, deadline); 220 if (ret < 0) { 221 return ret; 222 } else if (ret == 0) { 223 // Timeout. 224 errno = ETIMEDOUT; 225 return -1; 226 } 227 if (!iolooper_is_write(ssocket->iolooper, ssocket->fd)) { 228 D("%s: Internal error, iolooper_is_write() not set!", __FUNCTION__); 229 return -1; 230 } 231 232 do { 233 ret = socket_send(ssocket->fd, (const char*)buf + written, size - written); 234 } while( ret < 0 && errno == EINTR); 235 236 if (ret > 0) { 237 written += ret; 238 } else if (ret < 0) { 239 if (errno != EAGAIN && errno != EWOULDBLOCK) { 240 return -1; 241 } 242 } else { 243 // Disconnected. 244 errno = ECONNRESET; 245 return -1; 246 } 247 } while (written < size); 248 return (int)written; 249 } 250 251 ssize_t 252 syncsocket_write(SyncSocket* ssocket, const void* buf, size_t size, int timeout) 253 { 254 return syncsocket_write_absolute(ssocket, buf, size, iolooper_now() + timeout); 255 } 256 257 ssize_t 258 syncsocket_read_line_absolute(SyncSocket* ssocket, 259 char* buffer, 260 size_t size, 261 int64_t deadline) 262 { 263 size_t read_chars = 0; 264 265 while (read_chars < size) { 266 char ch; 267 int ret = syncsocket_read_absolute(ssocket, &ch, 1, deadline); 268 if (ret <= 0) { 269 return ret; 270 } 271 buffer[read_chars++] = ch; 272 if (ch == '\n') { 273 return read_chars; 274 } 275 } 276 277 /* Not enough room in the input buffer!*/ 278 errno = ENOMEM; 279 return -1; 280 } 281 282 ssize_t 283 syncsocket_read_line(SyncSocket* ssocket, char* buffer, size_t size, int timeout) 284 { 285 return syncsocket_read_line_absolute(ssocket, buffer, size, 286 iolooper_now() + timeout); 287 } 288 289 int 290 syncsocket_get_socket(SyncSocket* ssocket) 291 { 292 return (ssocket != NULL) ? ssocket->fd : -1; 293 } 294