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 
     17 /*
     18  * Contains helper routines dealing with syncronous access to a non-blocking
     19  * sokets.
     20  */
     21 
     22 #include "qemu-common.h"
     23 #include "errno.h"
     24 #include "android/iolooper.h"
     25 #include "android/sockets.h"
     26 #include "android/utils/debug.h"
     27 #include "android/sync-utils.h"
     28 #include "android/utils/system.h"
     29 
     30 #define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
     31 
     32 struct SyncSocket {
     33     // Helper for performing synchronous I/O on the socket.
     34     IoLooper* iolooper;
     35 
     36     /* Opened socket handle. */
     37     int fd;
     38 };
     39 
     40 SyncSocket*
     41 syncsocket_init(int fd)
     42 {
     43     SyncSocket* sync_socket;
     44     ANEW0(sync_socket);
     45 
     46     socket_set_nonblock(fd);
     47     sync_socket->iolooper = iolooper_new();
     48     sync_socket->fd = fd;
     49 
     50     return sync_socket;
     51 }
     52 
     53 SyncSocket*
     54 syncsocket_connect(int fd, SockAddress* sockaddr, int timeout)
     55 {
     56     IoLooper* looper;
     57     int connect_status;
     58     SyncSocket* sync_socket = NULL;
     59 
     60     socket_set_nonblock(fd);
     61 
     62     for(;;) {
     63         connect_status = socket_connect(fd, sockaddr);
     64         if (connect_status >= 0) {
     65             // Connected. Create IoLooper for the helper.
     66             looper = iolooper_new();
     67             break;
     68         }
     69 
     70         if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) {
     71             // Connection is in progress. Wait till it's finished.
     72             looper = iolooper_new();
     73             iolooper_add_write(looper, fd);
     74             connect_status = iolooper_wait(looper, timeout);
     75             if (connect_status > 0) {
     76                 iolooper_del_write(looper, fd);
     77                 break;
     78             } else {
     79                 iolooper_free(looper);
     80                 return NULL;
     81             }
     82         } else {
     83             return NULL;
     84         }
     85     }
     86 
     87     // We're now connected. Lets initialize SyncSocket instance
     88     // for this connection.
     89     sync_socket = malloc(sizeof(SyncSocket));
     90     if (sync_socket == NULL) {
     91         derror("PANIC: not enough memory\n");
     92         exit(1);
     93     }
     94 
     95     sync_socket->iolooper = looper;
     96     sync_socket->fd = fd;
     97 
     98     return sync_socket;
     99 }
    100 
    101 void
    102 syncsocket_close(SyncSocket* ssocket)
    103 {
    104     if (ssocket != NULL && ssocket->fd >= 0) {
    105         if (ssocket->iolooper != NULL) {
    106             iolooper_reset(ssocket->iolooper);
    107         }
    108         socket_close(ssocket->fd);
    109         ssocket->fd = -1;
    110     }
    111 }
    112 
    113 void
    114 syncsocket_free(SyncSocket* ssocket)
    115 {
    116     if (ssocket != NULL) {
    117         if (ssocket->iolooper != NULL) {
    118             iolooper_free(ssocket->iolooper);
    119         }
    120         free(ssocket);
    121     }
    122 }
    123 
    124 int
    125 syncsocket_start_read(SyncSocket* ssocket)
    126 {
    127     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
    128         errno = EINVAL;
    129         return -1;
    130     }
    131     iolooper_add_read(ssocket->iolooper, ssocket->fd);
    132     return 0;
    133 }
    134 
    135 int
    136 syncsocket_stop_read(SyncSocket* ssocket)
    137 {
    138     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
    139         errno = EINVAL;
    140         return -1;
    141     }
    142     iolooper_del_read(ssocket->iolooper, ssocket->fd);
    143     return 0;
    144 }
    145 
    146 int
    147 syncsocket_start_write(SyncSocket* ssocket)
    148 {
    149     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
    150         errno = EINVAL;
    151         return -1;
    152     }
    153     iolooper_add_write(ssocket->iolooper, ssocket->fd);
    154     return 0;
    155 }
    156 
    157 int
    158 syncsocket_stop_write(SyncSocket* ssocket)
    159 {
    160     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
    161         errno = EINVAL;
    162         return -1;
    163     }
    164     iolooper_del_write(ssocket->iolooper, ssocket->fd);
    165     return 0;
    166 }
    167 
    168 ssize_t
    169 syncsocket_read_absolute(SyncSocket* ssocket,
    170                          void* buf,
    171                          size_t size,
    172                          int64_t deadline)
    173 {
    174     int ret;
    175 
    176     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
    177         errno = EINVAL;
    178         return -1;
    179     }
    180 
    181     ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
    182     if (ret > 0) {
    183         if (!iolooper_is_read(ssocket->iolooper, ssocket->fd)) {
    184             D("%s: Internal error, iolooper_is_read() not set!", __FUNCTION__);
    185             return -1;
    186         }
    187         ret = socket_recv(ssocket->fd, buf, size);
    188     } else if (ret == 0) {
    189         // Timed out
    190         errno = ETIMEDOUT;
    191         ret = -1;
    192     }
    193     return ret;
    194 }
    195 
    196 ssize_t
    197 syncsocket_read(SyncSocket* ssocket, void* buf, size_t size, int timeout)
    198 {
    199     return syncsocket_read_absolute(ssocket, buf, size, iolooper_now() + timeout);
    200 }
    201 
    202 ssize_t
    203 syncsocket_write_absolute(SyncSocket* ssocket,
    204                           const void* buf,
    205                           size_t size,
    206                           int64_t deadline)
    207 {
    208     int ret;
    209     size_t written = 0;
    210 
    211     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
    212         errno = EINVAL;
    213         return -1;
    214     }
    215 
    216     do {
    217         ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
    218         if (ret < 0) {
    219             return ret;
    220         } else if (ret == 0) {
    221             // Timeout.
    222             errno = ETIMEDOUT;
    223             return -1;
    224         }
    225         if (!iolooper_is_write(ssocket->iolooper, ssocket->fd)) {
    226             D("%s: Internal error, iolooper_is_write() not set!", __FUNCTION__);
    227             return -1;
    228         }
    229 
    230         ret = socket_send(ssocket->fd, (const char*)buf + written, size - written);
    231         if (ret > 0) {
    232             written += ret;
    233         } else if (ret < 0) {
    234             if (errno != EAGAIN && errno != EWOULDBLOCK) {
    235                 return -1;
    236             }
    237         } else {
    238             // Disconnected.
    239             errno = ECONNRESET;
    240             return -1;
    241         }
    242     } while (written < size);
    243     return (int)written;
    244 }
    245 
    246 ssize_t
    247 syncsocket_write(SyncSocket* ssocket, const void* buf, size_t size, int timeout)
    248 {
    249     return syncsocket_write_absolute(ssocket, buf, size, iolooper_now() + timeout);
    250 }
    251 
    252 ssize_t
    253 syncsocket_read_line_absolute(SyncSocket* ssocket,
    254                               char* buffer,
    255                               size_t size,
    256                               int64_t deadline)
    257 {
    258     size_t read_chars = 0;
    259 
    260     while (read_chars < size) {
    261         char ch;
    262         int ret = syncsocket_read_absolute(ssocket, &ch, 1, deadline);
    263         if (ret <= 0) {
    264             return ret;
    265         }
    266         buffer[read_chars++] = ch;
    267         if (ch == '\n') {
    268             return read_chars;
    269         }
    270     }
    271 
    272     /* Not enough room in the input buffer!*/
    273     errno = ENOMEM;
    274     return -1;
    275 }
    276 
    277 ssize_t
    278 syncsocket_read_line(SyncSocket* ssocket, char* buffer, size_t size, int timeout)
    279 {
    280     return syncsocket_read_line_absolute(ssocket, buffer, size,
    281                                          iolooper_now() + timeout);
    282 }
    283 
    284 int
    285 syncsocket_get_socket(SyncSocket* ssocket)
    286 {
    287     return (ssocket != NULL) ? ssocket->fd : -1;
    288 }
    289