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