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 #include "android/async-utils.h" 17 #include "unistd.h" 18 19 void 20 asyncReader_init(AsyncReader* ar, 21 void* buffer, 22 size_t buffsize, 23 LoopIo* io) 24 { 25 ar->buffer = buffer; 26 ar->buffsize = buffsize; 27 ar->pos = 0; 28 ar->io = io; 29 if (buffsize > 0) 30 loopIo_wantRead(io); 31 } 32 33 AsyncStatus 34 asyncReader_read(AsyncReader* ar) 35 { 36 int ret; 37 38 if (ar->pos >= ar->buffsize) { 39 return ASYNC_COMPLETE; 40 } 41 42 do { 43 ret = socket_recv(ar->io->fd, ar->buffer + ar->pos, ar->buffsize - ar->pos); 44 if (ret == 0) { 45 /* disconnection ! */ 46 errno = ECONNRESET; 47 return ASYNC_ERROR; 48 } 49 if (ret < 0) { 50 if (errno == EINTR) /* loop on EINTR */ 51 continue; 52 if (errno == EWOULDBLOCK || errno == EAGAIN) { 53 loopIo_wantRead(ar->io); 54 return ASYNC_NEED_MORE; 55 } 56 return ASYNC_ERROR; 57 } 58 ar->pos += ret; 59 60 } while (ar->pos < ar->buffsize); 61 62 loopIo_dontWantRead(ar->io); 63 return ASYNC_COMPLETE; 64 } 65 66 void 67 asyncWriter_init(AsyncWriter* aw, 68 const void* buffer, 69 size_t buffsize, 70 LoopIo* io) 71 { 72 aw->buffer = buffer; 73 aw->buffsize = buffsize; 74 aw->pos = 0; 75 aw->io = io; 76 if (buffsize > 0) 77 loopIo_wantWrite(io); 78 } 79 80 AsyncStatus 81 asyncWriter_write(AsyncWriter* aw) 82 { 83 int ret; 84 85 if (aw->pos >= aw->buffsize) { 86 return ASYNC_COMPLETE; 87 } 88 89 do { 90 ret = socket_send(aw->io->fd, aw->buffer + aw->pos, aw->buffsize - aw->pos); 91 if (ret == 0) { 92 /* disconnection ! */ 93 errno = ECONNRESET; 94 return ASYNC_ERROR; 95 } 96 if (ret < 0) { 97 if (errno == EINTR) /* loop on EINTR */ 98 continue; 99 if (errno == EWOULDBLOCK || errno == EAGAIN) { 100 return ASYNC_NEED_MORE; 101 } 102 return ASYNC_ERROR; 103 } 104 aw->pos += ret; 105 106 } while (aw->pos < aw->buffsize); 107 108 loopIo_dontWantWrite(aw->io); 109 return ASYNC_COMPLETE; 110 } 111 112 113 void 114 asyncLineReader_init(AsyncLineReader* alr, 115 void* buffer, 116 size_t buffsize, 117 LoopIo* io) 118 { 119 alr->buffer = buffer; 120 alr->buffsize = buffsize; 121 alr->pos = 0; 122 alr->io = io; 123 alr->eol = '\n'; 124 if (buffsize > 0) 125 loopIo_wantRead(io); 126 } 127 128 AsyncStatus 129 asyncLineReader_read(AsyncLineReader* alr) 130 { 131 int ret; 132 133 if (alr->pos >= alr->buffsize) { 134 errno = ENOMEM; 135 return ASYNC_ERROR; 136 } 137 138 do { 139 char ch; 140 ret = socket_recv(alr->io->fd, &ch, 1); 141 if (ret == 0) { 142 /* disconnection ! */ 143 errno = ECONNRESET; 144 return ASYNC_ERROR; 145 } 146 if (ret < 0) { 147 if (errno == EINTR) /* loop on EINTR */ 148 continue; 149 if (errno == EWOULDBLOCK || errno == EAGAIN) { 150 loopIo_wantRead(alr->io); 151 return ASYNC_NEED_MORE; 152 } 153 return ASYNC_ERROR; 154 } 155 alr->buffer[alr->pos++] = (uint8_t)ch; 156 if (ch == alr->eol) { 157 loopIo_dontWantRead(alr->io); 158 return ASYNC_COMPLETE; 159 } 160 } while (alr->pos < alr->buffsize); 161 162 /* Not enough room in the input buffer!*/ 163 loopIo_dontWantRead(alr->io); 164 errno = ENOMEM; 165 return ASYNC_ERROR; 166 } 167 168 const char* 169 asyncLineReader_getLineRaw(AsyncLineReader* alr, int *pLength) 170 { 171 if (alr->pos == 0 || alr->pos > alr->buffsize) 172 return NULL; 173 174 if (pLength != 0) 175 *pLength = alr->pos; 176 177 return (const char*) alr->buffer; 178 } 179 180 const char* 181 asyncLineReader_getLine(AsyncLineReader* alr) 182 { 183 /* Strip trailing \n if any */ 184 size_t pos = alr->pos; 185 char* buffer = (char*) alr->buffer; 186 187 if (pos == 0 || pos > alr->buffsize) 188 return NULL; 189 190 pos--; 191 192 /* Check that we have a proper terminator, and replace it with 0 */ 193 if (alr->eol == '\n') { 194 if (buffer[pos] != '\n') 195 return NULL; 196 197 buffer[pos] = '\0'; 198 199 /* Also strip \r\n */ 200 if (pos > 0 && buffer[--pos] == '\r') { 201 buffer[pos] = '\0'; 202 } 203 } 204 205 return (const char*) buffer; 206 } 207 208 209 enum { 210 CONNECT_ERROR = 0, 211 CONNECT_CONNECTING, 212 CONNECT_COMPLETED 213 }; 214 215 AsyncStatus 216 asyncConnector_init(AsyncConnector* ac, 217 const SockAddress* address, 218 LoopIo* io) 219 { 220 int ret; 221 ac->error = 0; 222 ac->io = io; 223 ret = socket_connect(io->fd, address); 224 if (ret == 0) { 225 ac->state = CONNECT_COMPLETED; 226 return ASYNC_COMPLETE; 227 } 228 if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) { 229 ac->state = CONNECT_CONNECTING; 230 /* The socket will be marked writable for select() when the 231 * connection is established, or when it is definitely 232 * refused / timed-out, for any reason. */ 233 loopIo_wantWrite(io); 234 return ASYNC_NEED_MORE; 235 } 236 ac->error = errno; 237 ac->state = CONNECT_ERROR; 238 return ASYNC_ERROR; 239 } 240 241 AsyncStatus 242 asyncConnector_run(AsyncConnector* ac) 243 { 244 switch (ac->state) { 245 case CONNECT_ERROR: 246 errno = ac->error; 247 return ASYNC_ERROR; 248 249 case CONNECT_CONNECTING: 250 loopIo_dontWantWrite(ac->io); 251 /* We need to read the socket error to determine if 252 * the connection was really succesful or not. This 253 * is optional, because in case of error a future 254 * socket_recv() or socket_send() will fail anyway, but this 255 * allows us to get a better error value as soon as 256 * possible. 257 */ 258 ac->error = socket_get_error(ac->io->fd); 259 if (ac->error == 0) { 260 ac->state = CONNECT_COMPLETED; 261 return ASYNC_COMPLETE; 262 } 263 ac->state = CONNECT_ERROR; 264 errno = ac->error; 265 return ASYNC_ERROR; 266 267 default: 268 return ASYNC_COMPLETE; 269 } 270 } 271 272 int 273 asyncConnector_stop(AsyncConnector* ac) 274 { 275 if (ac->state == CONNECT_CONNECTING) { 276 loopIo_dontWantWrite(ac->io); 277 ac->state = CONNECT_COMPLETED; 278 return 0; 279 } 280 return -1; 281 } 282