1 /*
   2  * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <sys/param.h>
  29 #include <signal.h>
  30 #include <pthread.h>
  31 #include <sys/types.h>
  32 #include <sys/socket.h>
  33 #include <sys/select.h>
  34 #include <sys/time.h>
  35 #include <sys/resource.h>
  36 #include <sys/uio.h>
  37 #include <unistd.h>
  38 #include <errno.h>
  39 #include <sys/poll.h>
  40 
  41 /*
  42  * Stack allocated by thread when doing blocking operation
  43  */
  44 typedef struct threadEntry {
  45     pthread_t thr;                      /* this thread */
  46     struct threadEntry *next;           /* next thread */
  47     int intr;                           /* interrupted */
  48 } threadEntry_t;
  49 
  50 /*
  51  * Heap allocated during initialized - one entry per fd
  52  */
  53 typedef struct {
  54     pthread_mutex_t lock;               /* fd lock */
  55     threadEntry_t *threads;             /* threads blocked on fd */
  56 } fdEntry_t;
  57 
  58 /*
  59  * Signal to unblock thread
  60  */
  61 static int sigWakeup = SIGIO;
  62 
  63 /*
  64  * The fd table and the number of file descriptors
  65  */
  66 static fdEntry_t *fdTable;
  67 static int fdCount;
  68 
  69 /*
  70  * This limit applies if getlimit() returns unlimited.
  71  * Unfortunately, this means if someone wants a higher limit
  72  * then they have to set an explicit limit, higher than this,
  73  * which is probably counter-intuitive.
  74  */
  75 #define MAX_FD_COUNT 4096
  76 
  77 /*
  78  * Null signal handler
  79  */
  80 static void sig_wakeup(int sig) {
  81 }
  82 
  83 /*
  84  * Initialization routine (executed when library is loaded)
  85  * Allocate fd tables and sets up signal handler.
  86  */
  87 static void __attribute((constructor)) init() {
  88     struct rlimit nbr_files;
  89     sigset_t sigset;
  90     struct sigaction sa;
  91     int i;
  92 
  93     /*
  94      * Allocate table based on the maximum number of
  95      * file descriptors.
  96      */
  97     getrlimit(RLIMIT_NOFILE, &nbr_files);
  98     if (nbr_files.rlim_max == RLIM_INFINITY) {
  99         fdCount = MAX_FD_COUNT;
 100     } else {
 101         fdCount = nbr_files.rlim_max;
 102     }
 103     fdTable = (fdEntry_t *)calloc(fdCount, sizeof(fdEntry_t));
 104     if (fdTable == NULL) {
 105         fprintf(stderr, "library initialization failed - "
 106                 "unable to allocate file descriptor table - out of memory");
 107         abort();
 108     }
 109     for (i=0; i<fdCount; i++) {
 110         pthread_mutex_init(&fdTable[i].lock, NULL);
 111     }
 112 
 113     /*
 114      * Setup the signal handler
 115      */
 116     sa.sa_handler = sig_wakeup;
 117     sa.sa_flags   = 0;
 118     sigemptyset(&sa.sa_mask);
 119     sigaction(sigWakeup, &sa, NULL);
 120 
 121     sigemptyset(&sigset);
 122     sigaddset(&sigset, sigWakeup);
 123     sigprocmask(SIG_UNBLOCK, &sigset, NULL);
 124 }
 125 
 126 /*
 127  * Return the fd table for this fd or NULL is fd out
 128  * of range.
 129  */
 130 static inline fdEntry_t *getFdEntry(int fd)
 131 {
 132     if (fd < 0 || fd >= fdCount) {
 133         return NULL;
 134     }
 135     return &fdTable[fd];
 136 }
 137 
 138 /*
 139  * Start a blocking operation :-
 140  *    Insert thread onto thread list for the fd.
 141  */
 142 static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self)
 143 {
 144     self->thr = pthread_self();
 145     self->intr = 0;
 146 
 147     pthread_mutex_lock(&(fdEntry->lock));
 148     {
 149         self->next = fdEntry->threads;
 150         fdEntry->threads = self;
 151     }
 152     pthread_mutex_unlock(&(fdEntry->lock));
 153 }
 154 
 155 /*
 156  * End a blocking operation :-
 157  *     Remove thread from thread list for the fd
 158  *     If fd has been interrupted then set errno to EBADF
 159  */
 160 static inline void endOp
 161     (fdEntry_t *fdEntry, threadEntry_t *self)
 162 {
 163     int orig_errno = errno;
 164     pthread_mutex_lock(&(fdEntry->lock));
 165     {
 166         threadEntry_t *curr, *prev=NULL;
 167         curr = fdEntry->threads;
 168         while (curr != NULL) {
 169             if (curr == self) {
 170                 if (curr->intr) {
 171                     orig_errno = EBADF;
 172                 }
 173                 if (prev == NULL) {
 174                     fdEntry->threads = curr->next;
 175                 } else {
 176                     prev->next = curr->next;
 177                 }
 178                 break;
 179             }
 180             prev = curr;
 181             curr = curr->next;
 182         }
 183     }
 184     pthread_mutex_unlock(&(fdEntry->lock));
 185     errno = orig_errno;
 186 }
 187 
 188 /*
 189  * Close or dup2 a file descriptor ensuring that all threads blocked on
 190  * the file descriptor are notified via a wakeup signal.
 191  *
 192  *      fd1 < 0    => close(fd2)
 193  *      fd1 >= 0   => dup2(fd1, fd2)
 194  *
 195  * Returns -1 with errno set if operation fails.
 196  */
 197 static int closefd(int fd1, int fd2) {
 198     int rv, orig_errno;
 199     fdEntry_t *fdEntry = getFdEntry(fd2);
 200     if (fdEntry == NULL) {
 201         errno = EBADF;
 202         return -1;
 203     }
 204 
 205     /*
 206      * Lock the fd to hold-off additional I/O on this fd.
 207      */
 208     pthread_mutex_lock(&(fdEntry->lock));
 209 
 210     {
 211         /*
 212          * Send a wakeup signal to all threads blocked on this
 213          * file descriptor.
 214          */
 215         threadEntry_t *curr = fdEntry->threads;
 216         while (curr != NULL) {
 217             curr->intr = 1;
 218             pthread_kill( curr->thr, sigWakeup );
 219             curr = curr->next;
 220         }
 221 
 222         /*
 223          * And close/dup the file descriptor
 224          * (restart if interrupted by signal)
 225          */
 226         do {
 227             if (fd1 < 0) {
 228                 rv = close(fd2);
 229             } else {
 230                 rv = dup2(fd1, fd2);
 231             }
 232         } while (rv == -1 && errno == EINTR);
 233 
 234     }
 235 
 236     /*
 237      * Unlock without destroying errno
 238      */
 239     orig_errno = errno;
 240     pthread_mutex_unlock(&(fdEntry->lock));
 241     errno = orig_errno;
 242 
 243     return rv;
 244 }
 245 
 246 /*
 247  * Wrapper for dup2 - same semantics as dup2 system call except
 248  * that any threads blocked in an I/O system call on fd2 will be
 249  * preempted and return -1/EBADF;
 250  */
 251 int NET_Dup2(int fd, int fd2) {
 252     if (fd < 0) {
 253         errno = EBADF;
 254         return -1;
 255     }
 256     return closefd(fd, fd2);
 257 }
 258 
 259 /*
 260  * Wrapper for close - same semantics as close system call
 261  * except that any threads blocked in an I/O on fd will be
 262  * preempted and the I/O system call will return -1/EBADF.
 263  */
 264 int NET_SocketClose(int fd) {
 265     return closefd(-1, fd);
 266 }
 267 
 268 /************** Basic I/O operations here ***************/
 269 
 270 /*
 271  * Macro to perform a blocking IO operation. Restarts
 272  * automatically if interrupted by signal (other than
 273  * our wakeup signal)
 274  */
 275 #define BLOCKING_IO_RETURN_INT(FD, FUNC) {      \
 276     int ret;                                    \
 277     threadEntry_t self;                         \
 278     fdEntry_t *fdEntry = getFdEntry(FD);        \
 279     if (fdEntry == NULL) {                      \
 280         errno = EBADF;                          \
 281         return -1;                              \
 282     }                                           \
 283     do {                                        \
 284         startOp(fdEntry, &self);                \
 285         ret = FUNC;                             \
 286         endOp(fdEntry, &self);                  \
 287     } while (ret == -1 && errno == EINTR);      \
 288     return ret;                                 \
 289 }
 290 
 291 int NET_Read(int s, void* buf, size_t len) {
 292     BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );
 293 }
 294 
 295 int NET_ReadV(int s, const struct iovec * vector, int count) {
 296     BLOCKING_IO_RETURN_INT( s, readv(s, vector, count) );
 297 }
 298 
 299 int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
 300        struct sockaddr *from, socklen_t *fromlen) {
 301     BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) );
 302 }
 303 
 304 int NET_Send(int s, void *msg, int len, unsigned int flags) {
 305     BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) );
 306 }
 307 
 308 int NET_WriteV(int s, const struct iovec * vector, int count) {
 309     BLOCKING_IO_RETURN_INT( s, writev(s, vector, count) );
 310 }
 311 
 312 int NET_SendTo(int s, const void *msg, int len,  unsigned  int
 313        flags, const struct sockaddr *to, int tolen) {
 314     BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) );
 315 }
 316 
 317 int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
 318     BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) );
 319 }
 320 
 321 int NET_Connect(int s, struct sockaddr *addr, int addrlen) {
 322     BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) );
 323 }
 324 
 325 int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
 326     BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) );
 327 }
 328 
 329 /*
 330  * Wrapper for select(s, timeout). We are using select() on Mac OS due to Bug 7131399.
 331  * Auto restarts with adjusted timeout if interrupted by
 332  * signal other than our wakeup signal.
 333  */
 334 int NET_Timeout(int s, long timeout) {
 335     long prevtime = 0, newtime;
 336     struct timeval t, *tp = &t;
 337     fd_set fds;
 338     fd_set* fdsp = NULL;
 339     int allocated = 0;
 340     threadEntry_t self;
 341     fdEntry_t *fdEntry = getFdEntry(s);
 342 
 343     /*
 344      * Check that fd hasn't been closed.
 345      */
 346     if (fdEntry == NULL) {
 347         errno = EBADF;
 348         return -1;
 349     }
 350 
 351     /*
 352      * Pick up current time as may need to adjust timeout
 353      */
 354     if (timeout > 0) {
 355         /* Timed */
 356         struct timeval now;
 357         gettimeofday(&now, NULL);
 358         prevtime = now.tv_sec * 1000  +  now.tv_usec / 1000;
 359         t.tv_sec = timeout / 1000;
 360         t.tv_usec = (timeout % 1000) * 1000;
 361     } else if (timeout < 0) {
 362         /* Blocking */
 363         tp = 0;
 364     } else {
 365         /* Poll */
 366         t.tv_sec = 0;
 367         t.tv_usec = 0;
 368     }
 369 
 370     if (s < FD_SETSIZE) {
 371         fdsp = &fds;
 372         FD_ZERO(fdsp);
 373     } else {
 374         int length = (howmany(s+1, NFDBITS)) * sizeof(int);
 375         fdsp = (fd_set *) calloc(1, length);
 376         if (fdsp == NULL) {
 377             return -1;   // errno will be set to ENOMEM
 378         }
 379         allocated = 1;
 380     }
 381     FD_SET(s, fdsp);
 382 
 383     for(;;) {
 384         int rv;
 385 
 386         /*
 387          * call select on the fd. If interrupted by our wakeup signal
 388          * errno will be set to EBADF.
 389          */
 390 
 391         startOp(fdEntry, &self);
 392         rv = select(s+1, fdsp, 0, 0, tp);
 393         endOp(fdEntry, &self);
 394 
 395         /*
 396          * If interrupted then adjust timeout. If timeout
 397          * has expired return 0 (indicating timeout expired).
 398          */
 399         if (rv < 0 && errno == EINTR) {
 400             if (timeout > 0) {
 401                 struct timeval now;
 402                 gettimeofday(&now, NULL);
 403                 newtime = now.tv_sec * 1000  +  now.tv_usec / 1000;
 404                 timeout -= newtime - prevtime;
 405                 if (timeout <= 0) {
 406                     if (allocated != 0)
 407                         free(fdsp);
 408                     return 0;
 409                 }
 410                 prevtime = newtime;
 411                 t.tv_sec = timeout / 1000;
 412                 t.tv_usec = (timeout % 1000) * 1000;
 413             }
 414         } else {
 415             if (allocated != 0)
 416                 free(fdsp);
 417             return rv;
 418         }
 419 
 420     }
 421 }