abort_socket.c revision 111bfcefc3cf0f14ad607a56fcf5d076131833a9
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
26struct 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
59int 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
119int 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
166int 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
211int 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
257void 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
270void 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