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