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 "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