blob: 6a5e5e461fed1520217dec645e7cbaef9228f243 [file] [log] [blame]
Nick Pelly92a75412009-05-19 19:22:42 -07001/*
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) {
Nick Pelly111bfce2009-05-22 09:09:34 -0700242 if (pfd[0].revents & POLLOUT) {
Nick Pelly92a75412009-05-19 19:22:42 -0700243 /* 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}