Home | History | Annotate | Download | only in android
      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