• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
asocket_init(int fd)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  
asocket_connect(struct asocket * s,const struct sockaddr * addr,socklen_t addrlen,int timeout)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  
asocket_accept(struct asocket * s,struct sockaddr * addr,socklen_t * addrlen,int timeout)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  
asocket_read(struct asocket * s,void * buf,size_t count,int timeout)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  
asocket_write(struct asocket * s,const void * buf,size_t count,int timeout)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  
asocket_abort(struct asocket * s)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  
asocket_destroy(struct asocket * s)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