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