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