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 "iolooper.h"
     25 #include "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 if (errno != EINTR) {
     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         do {
    188             ret = socket_recv(ssocket->fd, buf, size);
    189         } while( ret < 0 && errno == EINTR);
    190     } else if (ret == 0) {
    191         // Timed out
    192         errno = ETIMEDOUT;
    193         ret = -1;
    194     }
    195     return ret;
    196 }
    197 
    198 ssize_t
    199 syncsocket_read(SyncSocket* ssocket, void* buf, size_t size, int timeout)
    200 {
    201     return syncsocket_read_absolute(ssocket, buf, size, iolooper_now() + timeout);
    202 }
    203 
    204 ssize_t
    205 syncsocket_write_absolute(SyncSocket* ssocket,
    206                           const void* buf,
    207                           size_t size,
    208                           int64_t deadline)
    209 {
    210     int ret;
    211     size_t written = 0;
    212 
    213     if (ssocket == NULL || ssocket->fd < 0 || ssocket->iolooper == NULL) {
    214         errno = EINVAL;
    215         return -1;
    216     }
    217 
    218     do {
    219         ret = iolooper_wait_absolute(ssocket->iolooper, deadline);
    220         if (ret < 0) {
    221             return ret;
    222         } else if (ret == 0) {
    223             // Timeout.
    224             errno = ETIMEDOUT;
    225             return -1;
    226         }
    227         if (!iolooper_is_write(ssocket->iolooper, ssocket->fd)) {
    228             D("%s: Internal error, iolooper_is_write() not set!", __FUNCTION__);
    229             return -1;
    230         }
    231 
    232         do {
    233             ret = socket_send(ssocket->fd, (const char*)buf + written, size - written);
    234         } while( ret < 0 && errno == EINTR);
    235 
    236         if (ret > 0) {
    237             written += ret;
    238         } else if (ret < 0) {
    239             if (errno != EAGAIN && errno != EWOULDBLOCK) {
    240                 return -1;
    241             }
    242         } else {
    243             // Disconnected.
    244             errno = ECONNRESET;
    245             return -1;
    246         }
    247     } while (written < size);
    248     return (int)written;
    249 }
    250 
    251 ssize_t
    252 syncsocket_write(SyncSocket* ssocket, const void* buf, size_t size, int timeout)
    253 {
    254     return syncsocket_write_absolute(ssocket, buf, size, iolooper_now() + timeout);
    255 }
    256 
    257 ssize_t
    258 syncsocket_read_line_absolute(SyncSocket* ssocket,
    259                               char* buffer,
    260                               size_t size,
    261                               int64_t deadline)
    262 {
    263     size_t read_chars = 0;
    264 
    265     while (read_chars < size) {
    266         char ch;
    267         int ret = syncsocket_read_absolute(ssocket, &ch, 1, deadline);
    268         if (ret <= 0) {
    269             return ret;
    270         }
    271         buffer[read_chars++] = ch;
    272         if (ch == '\n') {
    273             return read_chars;
    274         }
    275     }
    276 
    277     /* Not enough room in the input buffer!*/
    278     errno = ENOMEM;
    279     return -1;
    280 }
    281 
    282 ssize_t
    283 syncsocket_read_line(SyncSocket* ssocket, char* buffer, size_t size, int timeout)
    284 {
    285     return syncsocket_read_line_absolute(ssocket, buffer, size,
    286                                          iolooper_now() + timeout);
    287 }
    288 
    289 int
    290 syncsocket_get_socket(SyncSocket* ssocket)
    291 {
    292     return (ssocket != NULL) ? ssocket->fd : -1;
    293 }
    294