Home | History | Annotate | Download | only in libcutils
      1 /*
      2  * Copyright 2009, 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 #include <stdlib.h>
     18 #include <errno.h>
     19 #include <unistd.h>
     20 #include <fcntl.h>
     21 #include <sys/socket.h>
     22 #include <sys/poll.h>
     23 
     24 #include "cutils/abort_socket.h"
     25 
     26 struct asocket *asocket_init(int fd) {
     27     int abort_fd[2];
     28     int flags;
     29     struct asocket *s;
     30 
     31     /* set primary socket to non-blocking */
     32     flags = fcntl(fd, F_GETFL);
     33     if (flags == -1)
     34         return NULL;
     35     if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
     36         return NULL;
     37 
     38     /* create pipe with non-blocking write, so that asocket_close() cannot
     39        block */
     40     if (pipe(abort_fd))
     41         return NULL;
     42     flags = fcntl(abort_fd[1], F_GETFL);
     43     if (flags == -1)
     44         return NULL;
     45     if (fcntl(abort_fd[1], F_SETFL, flags | O_NONBLOCK))
     46         return NULL;
     47 
     48     s = malloc(sizeof(struct asocket));
     49     if (!s)
     50         return NULL;
     51 
     52     s->fd = fd;
     53     s->abort_fd[0] = abort_fd[0];
     54     s->abort_fd[1] = abort_fd[1];
     55 
     56     return s;
     57 }
     58 
     59 int asocket_connect(struct asocket *s, const struct sockaddr *addr,
     60         socklen_t addrlen, int timeout) {
     61 
     62     int ret;
     63 
     64     do {
     65         ret = connect(s->fd, addr, addrlen);
     66     } while (ret && errno == EINTR);
     67 
     68     if (ret && errno == EINPROGRESS) {
     69         /* ready to poll() */
     70         socklen_t retlen;
     71         struct pollfd pfd[2];
     72 
     73         pfd[0].fd = s->fd;
     74         pfd[0].events = POLLOUT;
     75         pfd[0].revents = 0;
     76         pfd[1].fd = s->abort_fd[0];
     77         pfd[1].events = POLLIN;
     78         pfd[1].revents = 0;
     79 
     80         do {
     81             ret = poll(pfd, 2, timeout);
     82         } while (ret < 0 && errno == EINTR);
     83 
     84         if (ret < 0)
     85             return -1;
     86         else if (ret == 0) {
     87             /* timeout */
     88             errno = ETIMEDOUT;
     89             return -1;
     90         }
     91 
     92         if (pfd[1].revents) {
     93             /* abort due to asocket_abort() */
     94             errno = ECANCELED;
     95             return -1;
     96         }
     97 
     98         if (pfd[0].revents) {
     99             if (pfd[0].revents & POLLOUT) {
    100                 /* connect call complete, read return code */
    101                 retlen = sizeof(ret);
    102                 if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen))
    103                     return -1;
    104                 /* got connect() return code */
    105                 if (ret) {
    106                     errno = ret;
    107                 }
    108             } else {
    109                 /* some error event on this fd */
    110                 errno = ECONNABORTED;
    111                 return -1;
    112             }
    113         }
    114     }
    115 
    116     return ret;
    117 }
    118 
    119 int asocket_accept(struct asocket *s, struct sockaddr *addr,
    120         socklen_t *addrlen, int timeout) {
    121 
    122     int ret;
    123     struct pollfd pfd[2];
    124 
    125     pfd[0].fd = s->fd;
    126     pfd[0].events = POLLIN;
    127     pfd[0].revents = 0;
    128     pfd[1].fd = s->abort_fd[0];
    129     pfd[1].events = POLLIN;
    130     pfd[1].revents = 0;
    131 
    132     do {
    133         ret = poll(pfd, 2, timeout);
    134     } while (ret < 0 && errno == EINTR);
    135 
    136     if (ret < 0)
    137         return -1;
    138     else if (ret == 0) {
    139         /* timeout */
    140         errno = ETIMEDOUT;
    141         return -1;
    142     }
    143 
    144     if (pfd[1].revents) {
    145         /* abort due to asocket_abort() */
    146         errno = ECANCELED;
    147         return -1;
    148     }
    149 
    150     if (pfd[0].revents) {
    151         if (pfd[0].revents & POLLIN) {
    152             /* ready to accept() without blocking */
    153             do {
    154                 ret = accept(s->fd, addr, addrlen);
    155             } while (ret < 0 && errno == EINTR);
    156         } else {
    157             /* some error event on this fd */
    158             errno = ECONNABORTED;
    159             return -1;
    160         }
    161     }
    162 
    163     return ret;
    164 }
    165 
    166 int asocket_read(struct asocket *s, void *buf, size_t count, int timeout) {
    167     int ret;
    168     struct pollfd pfd[2];
    169 
    170     pfd[0].fd = s->fd;
    171     pfd[0].events = POLLIN;
    172     pfd[0].revents = 0;
    173     pfd[1].fd = s->abort_fd[0];
    174     pfd[1].events = POLLIN;
    175     pfd[1].revents = 0;
    176 
    177     do {
    178         ret = poll(pfd, 2, timeout);
    179     } while (ret < 0 && errno == EINTR);
    180 
    181     if (ret < 0)
    182         return -1;
    183     else if (ret == 0) {
    184         /* timeout */
    185         errno = ETIMEDOUT;
    186         return -1;
    187     }
    188 
    189     if (pfd[1].revents) {
    190         /* abort due to asocket_abort() */
    191         errno = ECANCELED;
    192         return -1;
    193     }
    194 
    195     if (pfd[0].revents) {
    196         if (pfd[0].revents & POLLIN) {
    197             /* ready to read() without blocking */
    198             do {
    199                 ret = read(s->fd, buf, count);
    200             } while (ret < 0 && errno == EINTR);
    201         } else {
    202             /* some error event on this fd */
    203             errno = ECONNABORTED;
    204             return -1;
    205         }
    206     }
    207 
    208     return ret;
    209 }
    210 
    211 int asocket_write(struct asocket *s, const void *buf, size_t count,
    212         int timeout) {
    213     int ret;
    214     struct pollfd pfd[2];
    215 
    216     pfd[0].fd = s->fd;
    217     pfd[0].events = POLLOUT;
    218     pfd[0].revents = 0;
    219     pfd[1].fd = s->abort_fd[0];
    220     pfd[1].events = POLLIN;
    221     pfd[1].revents = 0;
    222 
    223     do {
    224         ret = poll(pfd, 2, timeout);
    225     } while (ret < 0 && errno == EINTR);
    226 
    227     if (ret < 0)
    228         return -1;
    229     else if (ret == 0) {
    230         /* timeout */
    231         errno = ETIMEDOUT;
    232         return -1;
    233     }
    234 
    235     if (pfd[1].revents) {
    236         /* abort due to asocket_abort() */
    237         errno = ECANCELED;
    238         return -1;
    239     }
    240 
    241     if (pfd[0].revents) {
    242         if (pfd[0].revents & POLLOUT) {
    243             /* ready to write() without blocking */
    244             do {
    245                 ret = write(s->fd, buf, count);
    246             } while (ret < 0 && errno == EINTR);
    247         } else {
    248             /* some error event on this fd */
    249             errno = ECONNABORTED;
    250             return -1;
    251         }
    252     }
    253 
    254     return ret;
    255 }
    256 
    257 void asocket_abort(struct asocket *s) {
    258     int ret;
    259     char buf = 0;
    260 
    261     /* Prevent further use of fd, without yet releasing the fd */
    262     shutdown(s->fd, SHUT_RDWR);
    263 
    264     /* wake up calls blocked at poll() */
    265     do {
    266         ret = write(s->abort_fd[1], &buf, 1);
    267     } while (ret < 0 && errno == EINTR);
    268 }
    269 
    270 void asocket_destroy(struct asocket *s) {
    271     struct asocket s_copy = *s;
    272 
    273     /* Clients should *not* be using these fd's after calling
    274        asocket_destroy(), but in case they do, set to -1 so they cannot use a
    275        stale fd */
    276     s->fd = -1;
    277     s->abort_fd[0] = -1;
    278     s->abort_fd[1] = -1;
    279 
    280     /* Call asocket_abort() in case there are still threads blocked on this
    281        socket. Clients should not rely on this behavior - it is racy because we
    282        are about to close() these sockets - clients should instead make sure
    283        all threads are done with the socket before calling asocket_destory().
    284      */
    285     asocket_abort(&s_copy);
    286 
    287     /* enough safety checks, close and release memory */
    288     close(s_copy.abort_fd[1]);
    289     close(s_copy.abort_fd[0]);
    290     close(s_copy.fd);
    291 
    292     free(s);
    293 }
    294