Coverage Report

Created: 2025-08-18 06:34

/src/nspr/pr/src/pthreads/ptio.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
/*
7
** File:   ptio.c
8
** Descritpion:  Implemenation of I/O methods for pthreads
9
*/
10
11
#if defined(_PR_PTHREADS)
12
13
#  if defined(_PR_POLL_WITH_SELECT)
14
#    if !(defined(HPUX) && defined(_USE_BIG_FDS))
15
/* set fd limit for select(), before including system header files */
16
#      define FD_SETSIZE (16 * 1024)
17
#    endif
18
#  endif
19
20
#  include <pthread.h>
21
#  include <string.h> /* for memset() */
22
#  include <sys/types.h>
23
#  include <dirent.h>
24
#  include <fcntl.h>
25
#  include <unistd.h>
26
#  include <sys/socket.h>
27
#  include <sys/stat.h>
28
#  include <sys/uio.h>
29
#  include <sys/file.h>
30
#  include <sys/ioctl.h>
31
#  if defined(DARWIN)
32
#    include <sys/utsname.h> /* for uname */
33
#  endif
34
#  if defined(SOLARIS)
35
#    include <sys/filio.h> /* to pick up FIONREAD */
36
#  endif
37
#  ifdef _PR_POLL_AVAILABLE
38
#    include <poll.h>
39
#  endif
40
#  ifdef AIX
41
/* To pick up sysconf() */
42
#    include <unistd.h>
43
#    include <dlfcn.h> /* for dlopen */
44
#  else
45
/* To pick up getrlimit() etc. */
46
#    include <sys/time.h>
47
#    include <sys/resource.h>
48
#  endif
49
50
#  ifdef SOLARIS
51
/*
52
 * Define HAVE_SENDFILEV if the system has the sendfilev() system call.
53
 * Code built this way won't run on a system without sendfilev().
54
 * We can define HAVE_SENDFILEV by default when the minimum release
55
 * of Solaris that NSPR supports has sendfilev().
56
 */
57
#    ifdef HAVE_SENDFILEV
58
59
#      include <sys/sendfile.h>
60
61
#      define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d))
62
63
#    else
64
65
#      include <dlfcn.h> /* for dlopen */
66
67
/*
68
 * Match the definitions in <sys/sendfile.h>.
69
 */
70
typedef struct sendfilevec {
71
  int sfv_fd;      /* input fd */
72
  uint_t sfv_flag; /* flags */
73
  off_t sfv_off;   /* offset to start reading from */
74
  size_t sfv_len;  /* amount of data */
75
} sendfilevec_t;
76
77
#      define SFV_FD_SELF (-2)
78
79
/*
80
 * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *);
81
 */
82
static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL;
83
84
#      define SOLARIS_SENDFILEV(a, b, c, d) \
85
        (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d))
86
87
#    endif /* HAVE_SENDFILEV */
88
#  endif   /* SOLARIS */
89
90
/*
91
 * The send_file() system call is available in AIX 4.3.2 or later.
92
 * If this file is compiled on an older AIX system, it attempts to
93
 * look up the send_file symbol at run time to determine whether
94
 * we can use the faster PR_SendFile/PR_TransmitFile implementation based on
95
 * send_file().  On AIX 4.3.2 or later, we can safely skip this
96
 * runtime function dispatching and just use the send_file based
97
 * implementation.
98
 */
99
#  ifdef AIX
100
#    ifdef SF_CLOSE
101
#      define HAVE_SEND_FILE
102
#    endif
103
104
#    ifdef HAVE_SEND_FILE
105
106
#      define AIX_SEND_FILE(a, b, c) send_file(a, b, c)
107
108
#    else                              /* HAVE_SEND_FILE */
109
110
/*
111
 * The following definitions match those in <sys/socket.h>
112
 * on AIX 4.3.2.
113
 */
114
115
/*
116
 * Structure for the send_file() system call
117
 */
118
struct sf_parms {
119
  /* --------- header parms ---------- */
120
  void* header_data;    /* Input/Output. Points to header buf */
121
  uint_t header_length; /* Input/Output. Length of the header */
122
  /* --------- file parms ------------ */
123
  int file_descriptor;            /* Input. File descriptor of the file */
124
  unsigned long long file_size;   /* Output. Size of the file */
125
  unsigned long long file_offset; /* Input/Output. Starting offset */
126
  long long file_bytes;           /* Input/Output. no. of bytes to send */
127
  /* --------- trailer parms --------- */
128
  void* trailer_data;    /* Input/Output. Points to trailer buf */
129
  uint_t trailer_length; /* Input/Output. Length of the trailer */
130
  /* --------- return info ----------- */
131
  unsigned long long bytes_sent; /* Output. no. of bytes sent */
132
};
133
134
/*
135
 * Flags for the send_file() system call
136
 */
137
#      define SF_CLOSE 0x00000001      /* close the socket after completion */
138
#      define SF_REUSE 0x00000002      /* reuse socket. not supported */
139
#      define SF_DONT_CACHE 0x00000004 /* don't apply network buffer cache */
140
#      define SF_SYNC_CACHE 0x00000008 /* sync/update network buffer cache */
141
142
/*
143
 * prototype: size_t send_file(int *, struct sf_parms *, uint_t);
144
 */
145
static ssize_t (*pt_aix_sendfile_fptr)() = NULL;
146
147
#      define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c)
148
149
#    endif /* HAVE_SEND_FILE */
150
#  endif   /* AIX */
151
152
#  ifdef LINUX
153
#    include <sys/sendfile.h>
154
#  endif
155
156
#  include "primpl.h"
157
158
#  if defined(LINUX) || defined(ANDROID)
159
#    include <netinet/in.h>
160
#  endif
161
162
#  ifdef DARWIN
163
#    include <netinet/in.h>
164
#    include <netinet/ip.h>
165
#  endif
166
167
#  ifdef HAVE_NETINET_TCP_H
168
#    include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
169
#  endif
170
171
#  ifdef LINUX
172
/* TCP_CORK is not defined in <netinet/tcp.h> on Red Hat Linux 6.0 */
173
#    ifndef TCP_CORK
174
#      define TCP_CORK 3
175
#    endif
176
#    ifndef MSG_FASTOPEN
177
#      define MSG_FASTOPEN 0x20000000
178
#    endif
179
#  endif
180
181
#  ifdef _PR_IPV6_V6ONLY_PROBE
182
static PRBool _pr_ipv6_v6only_on_by_default;
183
#  endif
184
185
#  if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11))
186
#    define _PRSelectFdSetArg_t int*
187
#  elif defined(AIX4_1)
188
#    define _PRSelectFdSetArg_t void*
189
#  elif (defined(AIX) && !defined(AIX4_1)) || defined(SOLARIS) ||   \
190
      defined(HPUX10_30) || defined(HPUX11) || defined(LINUX) ||    \
191
      defined(__GNU__) || defined(__GLIBC__) || defined(FREEBSD) || \
192
      defined(NETBSD) || defined(OPENBSD) || defined(NTO) ||        \
193
      defined(DARWIN) || defined(RISCOS)
194
#    define _PRSelectFdSetArg_t fd_set*
195
#  else
196
#    error "Cannot determine architecture"
197
#  endif
198
199
#  if defined(SOLARIS)
200
#    ifndef PROTO_SDP
201
/* on solaris, SDP is a new type of protocol */
202
#      define PROTO_SDP 257
203
#    endif
204
#    define _PR_HAVE_SDP
205
#  elif defined(LINUX)
206
#    ifndef AF_INET_SDP
207
/* on linux, SDP is a new type of address family */
208
0
#      define AF_INET_SDP 27
209
#    endif
210
#    define _PR_HAVE_SDP
211
#  endif /* LINUX */
212
213
static PRFileDesc* pt_SetMethods(PRIntn osfd, PRDescType type,
214
                                 PRBool isAcceptedSocket, PRBool imported);
215
216
static PRLock* _pr_flock_lock;  /* For PR_LockFile() etc. */
217
static PRCondVar* _pr_flock_cv; /* For PR_LockFile() etc. */
218
static PRLock* _pr_rename_lock; /* For PR_Rename() */
219
220
/**************************************************************************/
221
222
/* These two functions are only used in assertions. */
223
#  if defined(DEBUG)
224
225
0
PRBool IsValidNetAddr(const PRNetAddr* addr) {
226
0
  if ((addr != NULL) && (addr->raw.family != AF_UNIX) &&
227
0
      (addr->raw.family != PR_AF_INET6) && (addr->raw.family != AF_INET)) {
228
0
    return PR_FALSE;
229
0
  }
230
0
  return PR_TRUE;
231
0
}
232
233
0
static PRBool IsValidNetAddrLen(const PRNetAddr* addr, PRInt32 addr_len) {
234
  /*
235
   * The definition of the length of a Unix domain socket address
236
   * is not uniform, so we don't check it.
237
   */
238
0
  if ((addr != NULL) && (addr->raw.family != AF_UNIX) &&
239
0
      (PR_NETADDR_SIZE(addr) != addr_len)) {
240
#    if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
241
    /*
242
     * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
243
     * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
244
     * field and is 28 bytes.  It is possible for socket functions
245
     * to return an addr_len greater than sizeof(struct sockaddr_in6).
246
     * We need to allow that.  (Bugzilla bug #77264)
247
     */
248
    if ((PR_AF_INET6 == addr->raw.family) && (sizeof(addr->ipv6) == addr_len)) {
249
      return PR_TRUE;
250
    }
251
#    endif
252
0
    return PR_FALSE;
253
0
  }
254
0
  return PR_TRUE;
255
0
}
256
257
#  endif /* DEBUG */
258
259
/*****************************************************************************/
260
/************************* I/O Continuation machinery ************************/
261
/*****************************************************************************/
262
263
/*
264
 * The polling interval defines the maximum amount of time that a thread
265
 * might hang up before an interrupt is noticed.
266
 */
267
0
#  define PT_DEFAULT_POLL_MSEC 5000
268
#  if defined(_PR_POLL_WITH_SELECT)
269
#    define PT_DEFAULT_SELECT_SEC (PT_DEFAULT_POLL_MSEC / PR_MSEC_PER_SEC)
270
#    define PT_DEFAULT_SELECT_USEC \
271
      ((PT_DEFAULT_POLL_MSEC % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC)
272
#  endif
273
274
/*
275
 * pt_SockLen is the type for the length of a socket address
276
 * structure, used in the address length argument to bind,
277
 * connect, accept, getsockname, getpeername, etc.  Posix.1g
278
 * defines this type as socklen_t.  It is size_t or int on
279
 * most current systems.
280
 */
281
#  if defined(HAVE_SOCKLEN_T) || (defined(__GLIBC__) && __GLIBC__ >= 2)
282
typedef socklen_t pt_SockLen;
283
#  elif (defined(AIX) && !defined(AIX4_1))
284
typedef PRSize pt_SockLen;
285
#  else
286
typedef PRIntn pt_SockLen;
287
#  endif
288
289
typedef struct pt_Continuation pt_Continuation;
290
typedef PRBool (*ContinuationFn)(pt_Continuation* op, PRInt16 revents);
291
292
typedef enum pr_ContuationStatus {
293
  pt_continuation_pending,
294
  pt_continuation_done
295
} pr_ContuationStatus;
296
297
struct pt_Continuation {
298
  /* The building of the continuation operation */
299
  ContinuationFn function; /* what function to continue */
300
  union {
301
    PRIntn osfd;
302
  } arg1; /* #1 - the op's fd */
303
  union {
304
    void* buffer;
305
  } arg2; /* #2 - primary transfer buffer */
306
  union {
307
    PRSize amount;        /* #3 - size of 'buffer', or */
308
    pt_SockLen* addr_len; /*    - length of address */
309
#  ifdef HPUX11
310
    /*
311
     * For sendfile()
312
     */
313
    struct file_spec {
314
      off_t offset;   /* offset in file to send */
315
      size_t nbytes;  /* length of file data to send */
316
      size_t st_size; /* file size */
317
    } file_spec;
318
#  endif
319
  } arg3;
320
  union {
321
    PRIntn flags;
322
  } arg4; /* #4 - read/write flags */
323
  union {
324
    PRNetAddr* addr;
325
  } arg5; /* #5 - send/recv address */
326
327
#  ifdef HPUX11
328
  /*
329
   * For sendfile()
330
   */
331
  int filedesc;       /* descriptor of file to send */
332
  int nbytes_to_send; /* size of header and file */
333
#  endif              /* HPUX11 */
334
335
#  ifdef SOLARIS
336
  /*
337
   * For sendfilev()
338
   */
339
  int nbytes_to_send; /* size of header and file */
340
#  endif              /* SOLARIS */
341
342
#  ifdef LINUX
343
  /*
344
   * For sendfile()
345
   */
346
  int in_fd; /* descriptor of file to send */
347
  off_t offset;
348
  size_t count;
349
#  endif /* LINUX */
350
351
  PRIntervalTime timeout; /* client (relative) timeout */
352
353
  PRInt16 event; /* flags for poll()'s events */
354
355
  /*
356
  ** The representation and notification of the results of the operation.
357
  ** These function can either return an int return code or a pointer to
358
  ** some object.
359
  */
360
  union {
361
    PRSize code;
362
    void* object;
363
  } result;
364
365
  PRIntn syserrno;            /* in case it failed, why (errno) */
366
  pr_ContuationStatus status; /* the status of the operation */
367
};
368
369
#  if defined(DEBUG)
370
371
PTDebug pt_debug; /* this is shared between several modules */
372
373
0
PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc* debug_out, const char* msg) {
374
0
  PTDebug stats;
375
0
  char buffer[100];
376
0
  PRExplodedTime tod;
377
0
  PRInt64 elapsed, aMil;
378
0
  stats = pt_debug; /* a copy */
379
0
  PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod);
380
0
  (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
381
382
0
  LL_SUB(elapsed, PR_Now(), stats.timeStarted);
383
0
  LL_I2L(aMil, 1000000);
384
0
  LL_DIV(elapsed, elapsed, aMil);
385
386
0
  if (NULL != msg) {
387
0
    PR_fprintf(debug_out, "%s", msg);
388
0
  }
389
0
  PR_fprintf(debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed);
390
0
  PR_fprintf(debug_out, "\tlocks [created: %u, destroyed: %u]\n",
391
0
             stats.locks_created, stats.locks_destroyed);
392
0
  PR_fprintf(debug_out, "\tlocks [acquired: %u, released: %u]\n",
393
0
             stats.locks_acquired, stats.locks_released);
394
0
  PR_fprintf(debug_out, "\tcvars [created: %u, destroyed: %u]\n",
395
0
             stats.cvars_created, stats.cvars_destroyed);
396
0
  PR_fprintf(debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n",
397
0
             stats.cvars_notified, stats.delayed_cv_deletes);
398
0
} /* PT_FPrintStats */
399
400
#  else
401
402
PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc* debug_out, const char* msg) {
403
  /* do nothing */
404
} /* PT_FPrintStats */
405
406
#  endif /* DEBUG */
407
408
#  if defined(_PR_POLL_WITH_SELECT)
409
/*
410
 * HPUX report the POLLHUP event for a socket when the
411
 * shutdown(SHUT_WR) operation is called for the remote end, even though
412
 * the socket is still writeable. Use select(), instead of poll(), to
413
 * workaround this problem.
414
 */
415
static void pt_poll_now_with_select(pt_Continuation* op) {
416
  PRInt32 msecs;
417
  fd_set rd, wr, *rdp, *wrp;
418
  struct timeval tv;
419
  PRIntervalTime epoch, now, elapsed, remaining;
420
  PRBool wait_for_remaining;
421
  PRThread* self = PR_GetCurrentThread();
422
423
  PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
424
  PR_ASSERT(op->arg1.osfd < FD_SETSIZE);
425
426
  switch (op->timeout) {
427
    case PR_INTERVAL_NO_TIMEOUT:
428
      tv.tv_sec = PT_DEFAULT_SELECT_SEC;
429
      tv.tv_usec = PT_DEFAULT_SELECT_USEC;
430
      do {
431
        PRIntn rv;
432
433
        if (op->event & POLLIN) {
434
          FD_ZERO(&rd);
435
          FD_SET(op->arg1.osfd, &rd);
436
          rdp = &rd;
437
        } else {
438
          rdp = NULL;
439
        }
440
        if (op->event & POLLOUT) {
441
          FD_ZERO(&wr);
442
          FD_SET(op->arg1.osfd, &wr);
443
          wrp = &wr;
444
        } else {
445
          wrp = NULL;
446
        }
447
448
        rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
449
450
        if (_PT_THREAD_INTERRUPTED(self)) {
451
          self->state &= ~PT_THREAD_ABORTED;
452
          op->result.code = -1;
453
          op->syserrno = EINTR;
454
          op->status = pt_continuation_done;
455
          return;
456
        }
457
458
        if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN))) {
459
          continue; /* go around the loop again */
460
        }
461
462
        if (rv > 0) {
463
          PRInt16 revents = 0;
464
465
          if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd)) {
466
            revents |= POLLIN;
467
          }
468
          if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr)) {
469
            revents |= POLLOUT;
470
          }
471
472
          if (op->function(op, revents)) {
473
            op->status = pt_continuation_done;
474
          }
475
        } else if (rv == -1) {
476
          op->result.code = -1;
477
          op->syserrno = errno;
478
          op->status = pt_continuation_done;
479
        }
480
        /* else, select timed out */
481
      } while (pt_continuation_done != op->status);
482
      break;
483
    default:
484
      now = epoch = PR_IntervalNow();
485
      remaining = op->timeout;
486
      do {
487
        PRIntn rv;
488
489
        if (op->event & POLLIN) {
490
          FD_ZERO(&rd);
491
          FD_SET(op->arg1.osfd, &rd);
492
          rdp = &rd;
493
        } else {
494
          rdp = NULL;
495
        }
496
        if (op->event & POLLOUT) {
497
          FD_ZERO(&wr);
498
          FD_SET(op->arg1.osfd, &wr);
499
          wrp = &wr;
500
        } else {
501
          wrp = NULL;
502
        }
503
504
        wait_for_remaining = PR_TRUE;
505
        msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
506
        if (msecs > PT_DEFAULT_POLL_MSEC) {
507
          wait_for_remaining = PR_FALSE;
508
          msecs = PT_DEFAULT_POLL_MSEC;
509
        }
510
        tv.tv_sec = msecs / PR_MSEC_PER_SEC;
511
        tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
512
        rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
513
514
        if (_PT_THREAD_INTERRUPTED(self)) {
515
          self->state &= ~PT_THREAD_ABORTED;
516
          op->result.code = -1;
517
          op->syserrno = EINTR;
518
          op->status = pt_continuation_done;
519
          return;
520
        }
521
522
        if (rv > 0) {
523
          PRInt16 revents = 0;
524
525
          if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd)) {
526
            revents |= POLLIN;
527
          }
528
          if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr)) {
529
            revents |= POLLOUT;
530
          }
531
532
          if (op->function(op, revents)) {
533
            op->status = pt_continuation_done;
534
          }
535
536
        } else if ((rv == 0) || ((errno == EINTR) || (errno == EAGAIN))) {
537
          if (rv == 0) { /* select timed out */
538
            if (wait_for_remaining) {
539
              now += remaining;
540
            } else {
541
              now += PR_MillisecondsToInterval(msecs);
542
            }
543
          } else {
544
            now = PR_IntervalNow();
545
          }
546
          elapsed = (PRIntervalTime)(now - epoch);
547
          if (elapsed >= op->timeout) {
548
            op->result.code = -1;
549
            op->syserrno = ETIMEDOUT;
550
            op->status = pt_continuation_done;
551
          } else {
552
            remaining = op->timeout - elapsed;
553
          }
554
        } else {
555
          op->result.code = -1;
556
          op->syserrno = errno;
557
          op->status = pt_continuation_done;
558
        }
559
      } while (pt_continuation_done != op->status);
560
      break;
561
  }
562
563
} /* pt_poll_now_with_select */
564
565
#  endif /* _PR_POLL_WITH_SELECT */
566
567
0
static void pt_poll_now(pt_Continuation* op) {
568
0
  PRInt32 msecs;
569
0
  PRIntervalTime epoch, now, elapsed, remaining;
570
0
  PRBool wait_for_remaining;
571
0
  PRThread* self = PR_GetCurrentThread();
572
573
0
  PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
574
#  if defined(_PR_POLL_WITH_SELECT)
575
  /*
576
   * If the fd is small enough call the select-based poll operation
577
   */
578
  if (op->arg1.osfd < FD_SETSIZE) {
579
    pt_poll_now_with_select(op);
580
    return;
581
  }
582
#  endif
583
584
0
  switch (op->timeout) {
585
0
    case PR_INTERVAL_NO_TIMEOUT:
586
0
      msecs = PT_DEFAULT_POLL_MSEC;
587
0
      do {
588
0
        PRIntn rv;
589
0
        struct pollfd tmp_pfd;
590
591
0
        tmp_pfd.revents = 0;
592
0
        tmp_pfd.fd = op->arg1.osfd;
593
0
        tmp_pfd.events = op->event;
594
595
0
        rv = poll(&tmp_pfd, 1, msecs);
596
597
0
        if (_PT_THREAD_INTERRUPTED(self)) {
598
0
          self->state &= ~PT_THREAD_ABORTED;
599
0
          op->result.code = -1;
600
0
          op->syserrno = EINTR;
601
0
          op->status = pt_continuation_done;
602
0
          return;
603
0
        }
604
605
0
        if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN))) {
606
0
          continue; /* go around the loop again */
607
0
        }
608
609
0
        if (rv > 0) {
610
0
          PRInt16 events = tmp_pfd.events;
611
0
          PRInt16 revents = tmp_pfd.revents;
612
613
0
          if ((revents & POLLNVAL) /* busted in all cases */
614
0
              || ((events & POLLOUT) && (revents & POLLHUP)))
615
          /* write op & hup */
616
0
          {
617
0
            op->result.code = -1;
618
0
            if (POLLNVAL & revents) {
619
0
              op->syserrno = EBADF;
620
0
            } else if (POLLHUP & revents) {
621
0
              op->syserrno = EPIPE;
622
0
            }
623
0
            op->status = pt_continuation_done;
624
0
          } else {
625
0
            if (op->function(op, revents)) {
626
0
              op->status = pt_continuation_done;
627
0
            }
628
0
          }
629
0
        } else if (rv == -1) {
630
0
          op->result.code = -1;
631
0
          op->syserrno = errno;
632
0
          op->status = pt_continuation_done;
633
0
        }
634
        /* else, poll timed out */
635
0
      } while (pt_continuation_done != op->status);
636
0
      break;
637
0
    default:
638
0
      now = epoch = PR_IntervalNow();
639
0
      remaining = op->timeout;
640
0
      do {
641
0
        PRIntn rv;
642
0
        struct pollfd tmp_pfd;
643
644
0
        tmp_pfd.revents = 0;
645
0
        tmp_pfd.fd = op->arg1.osfd;
646
0
        tmp_pfd.events = op->event;
647
648
0
        wait_for_remaining = PR_TRUE;
649
0
        msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
650
0
        if (msecs > PT_DEFAULT_POLL_MSEC) {
651
0
          wait_for_remaining = PR_FALSE;
652
0
          msecs = PT_DEFAULT_POLL_MSEC;
653
0
        }
654
0
        rv = poll(&tmp_pfd, 1, msecs);
655
656
0
        if (_PT_THREAD_INTERRUPTED(self)) {
657
0
          self->state &= ~PT_THREAD_ABORTED;
658
0
          op->result.code = -1;
659
0
          op->syserrno = EINTR;
660
0
          op->status = pt_continuation_done;
661
0
          return;
662
0
        }
663
664
0
        if (rv > 0) {
665
0
          PRInt16 events = tmp_pfd.events;
666
0
          PRInt16 revents = tmp_pfd.revents;
667
668
0
          if ((revents & POLLNVAL) /* busted in all cases */
669
0
              || ((events & POLLOUT) && (revents & POLLHUP)))
670
          /* write op & hup */
671
0
          {
672
0
            op->result.code = -1;
673
0
            if (POLLNVAL & revents) {
674
0
              op->syserrno = EBADF;
675
0
            } else if (POLLHUP & revents) {
676
0
              op->syserrno = EPIPE;
677
0
            }
678
0
            op->status = pt_continuation_done;
679
0
          } else {
680
0
            if (op->function(op, revents)) {
681
0
              op->status = pt_continuation_done;
682
0
            }
683
0
          }
684
0
        } else if ((rv == 0) || ((errno == EINTR) || (errno == EAGAIN))) {
685
0
          if (rv == 0) /* poll timed out */
686
0
          {
687
0
            if (wait_for_remaining) {
688
0
              now += remaining;
689
0
            } else {
690
0
              now += PR_MillisecondsToInterval(msecs);
691
0
            }
692
0
          } else {
693
0
            now = PR_IntervalNow();
694
0
          }
695
0
          elapsed = (PRIntervalTime)(now - epoch);
696
0
          if (elapsed >= op->timeout) {
697
0
            op->result.code = -1;
698
0
            op->syserrno = ETIMEDOUT;
699
0
            op->status = pt_continuation_done;
700
0
          } else {
701
0
            remaining = op->timeout - elapsed;
702
0
          }
703
0
        } else {
704
0
          op->result.code = -1;
705
0
          op->syserrno = errno;
706
0
          op->status = pt_continuation_done;
707
0
        }
708
0
      } while (pt_continuation_done != op->status);
709
0
      break;
710
0
  }
711
712
0
} /* pt_poll_now */
713
714
0
static PRIntn pt_Continue(pt_Continuation* op) {
715
0
  op->status = pt_continuation_pending; /* set default value */
716
  /*
717
   * let each thread call poll directly
718
   */
719
0
  pt_poll_now(op);
720
0
  PR_ASSERT(pt_continuation_done == op->status);
721
0
  return op->result.code;
722
0
} /* pt_Continue */
723
724
/*****************************************************************************/
725
/*********************** specific continuation functions *********************/
726
/*****************************************************************************/
727
0
static PRBool pt_connect_cont(pt_Continuation* op, PRInt16 revents) {
728
0
  op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd);
729
0
  if (op->syserrno != 0) {
730
0
    op->result.code = -1;
731
0
  } else {
732
0
    op->result.code = 0;
733
0
  }
734
0
  return PR_TRUE; /* this one is cooked */
735
0
} /* pt_connect_cont */
736
737
0
static PRBool pt_accept_cont(pt_Continuation* op, PRInt16 revents) {
738
0
  op->syserrno = 0;
739
0
  op->result.code = accept(op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len);
740
0
  if (-1 == op->result.code) {
741
0
    op->syserrno = errno;
742
0
    if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno) {
743
0
      return PR_FALSE; /* do nothing - this one ain't finished */
744
0
    }
745
0
  }
746
0
  return PR_TRUE;
747
0
} /* pt_accept_cont */
748
749
0
static PRBool pt_read_cont(pt_Continuation* op, PRInt16 revents) {
750
  /*
751
   * Any number of bytes will complete the operation. It need
752
   * not (and probably will not) satisfy the request. The only
753
   * error we continue is EWOULDBLOCK|EAGAIN.
754
   */
755
0
  op->result.code = read(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
756
0
  op->syserrno = errno;
757
0
  return ((-1 == op->result.code) &&
758
0
          (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno))
759
0
             ? PR_FALSE
760
0
             : PR_TRUE;
761
0
} /* pt_read_cont */
762
763
0
static PRBool pt_recv_cont(pt_Continuation* op, PRInt16 revents) {
764
  /*
765
   * Any number of bytes will complete the operation. It need
766
   * not (and probably will not) satisfy the request. The only
767
   * error we continue is EWOULDBLOCK|EAGAIN.
768
   */
769
#  if defined(SOLARIS)
770
  if (0 == op->arg4.flags)
771
    op->result.code = read(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
772
  else
773
    op->result.code =
774
        recv(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
775
#  else
776
0
  op->result.code =
777
0
      recv(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
778
0
#  endif
779
0
  op->syserrno = errno;
780
0
  return ((-1 == op->result.code) &&
781
0
          (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno))
782
0
             ? PR_FALSE
783
0
             : PR_TRUE;
784
0
} /* pt_recv_cont */
785
786
0
static PRBool pt_send_cont(pt_Continuation* op, PRInt16 revents) {
787
0
  PRIntn bytes;
788
#  if defined(SOLARIS)
789
  PRInt32 tmp_amount = op->arg3.amount;
790
#  endif
791
  /*
792
   * We want to write the entire amount out, no matter how many
793
   * tries it takes. Keep advancing the buffer and the decrementing
794
   * the amount until the amount goes away. Return the total bytes
795
   * (which should be the original amount) when finished (or an
796
   * error).
797
   */
798
#  if defined(SOLARIS)
799
retry:
800
  bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount);
801
#  else
802
0
  bytes = send(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
803
0
#  endif
804
0
  op->syserrno = errno;
805
806
#  if defined(SOLARIS)
807
  /*
808
   * The write system call has been reported to return the ERANGE error
809
   * on occasion. Try to write in smaller chunks to workaround this bug.
810
   */
811
  if ((bytes == -1) && (op->syserrno == ERANGE)) {
812
    if (tmp_amount > 1) {
813
      tmp_amount = tmp_amount / 2; /* half the bytes */
814
      goto retry;
815
    }
816
  }
817
#  endif
818
819
0
  if (bytes >= 0) /* this is progress */
820
0
  {
821
0
    char* bp = (char*)op->arg2.buffer;
822
0
    bp += bytes; /* adjust the buffer pointer */
823
0
    op->arg2.buffer = bp;
824
0
    op->result.code += bytes; /* accumulate the number sent */
825
0
    op->arg3.amount -= bytes; /* and reduce the required count */
826
0
    return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
827
0
  }
828
0
  if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) {
829
0
    op->result.code = -1;
830
0
    return PR_TRUE;
831
0
  } else {
832
0
    return PR_FALSE;
833
0
  }
834
0
} /* pt_send_cont */
835
836
0
static PRBool pt_write_cont(pt_Continuation* op, PRInt16 revents) {
837
0
  PRIntn bytes;
838
  /*
839
   * We want to write the entire amount out, no matter how many
840
   * tries it takes. Keep advancing the buffer and the decrementing
841
   * the amount until the amount goes away. Return the total bytes
842
   * (which should be the original amount) when finished (or an
843
   * error).
844
   */
845
0
  bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
846
0
  op->syserrno = errno;
847
0
  if (bytes >= 0) /* this is progress */
848
0
  {
849
0
    char* bp = (char*)op->arg2.buffer;
850
0
    bp += bytes; /* adjust the buffer pointer */
851
0
    op->arg2.buffer = bp;
852
0
    op->result.code += bytes; /* accumulate the number sent */
853
0
    op->arg3.amount -= bytes; /* and reduce the required count */
854
0
    return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
855
0
  }
856
0
  if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) {
857
0
    op->result.code = -1;
858
0
    return PR_TRUE;
859
0
  } else {
860
0
    return PR_FALSE;
861
0
  }
862
0
} /* pt_write_cont */
863
864
0
static PRBool pt_writev_cont(pt_Continuation* op, PRInt16 revents) {
865
0
  PRIntn bytes;
866
0
  struct iovec* iov = (struct iovec*)op->arg2.buffer;
867
  /*
868
   * Same rules as write, but continuing seems to be a bit more
869
   * complicated. As the number of bytes sent grows, we have to
870
   * redefine the vector we're pointing at. We might have to
871
   * modify an individual vector parms or we might have to eliminate
872
   * a pair altogether.
873
   */
874
0
  bytes = writev(op->arg1.osfd, iov, op->arg3.amount);
875
0
  op->syserrno = errno;
876
0
  if (bytes >= 0) /* this is progress */
877
0
  {
878
0
    PRIntn iov_index;
879
0
    op->result.code += bytes; /* accumulate the number sent */
880
0
    for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index) {
881
      /* how much progress did we make in the i/o vector? */
882
0
      if (bytes < iov[iov_index].iov_len) {
883
        /* this element's not done yet */
884
0
        char** bp = (char**)&(iov[iov_index].iov_base);
885
0
        iov[iov_index].iov_len -= bytes; /* there's that much left */
886
0
        *bp += bytes;                    /* starting there */
887
0
        break;                           /* go off and do that */
888
0
      }
889
0
      bytes -= iov[iov_index].iov_len; /* that element's consumed */
890
0
    }
891
0
    op->arg2.buffer = &iov[iov_index]; /* new start of array */
892
0
    op->arg3.amount -= iov_index;      /* and array length */
893
0
    return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
894
0
  }
895
0
  if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) {
896
0
    op->result.code = -1;
897
0
    return PR_TRUE;
898
0
  } else {
899
0
    return PR_FALSE;
900
0
  }
901
0
} /* pt_writev_cont */
902
903
0
static PRBool pt_sendto_cont(pt_Continuation* op, PRInt16 revents) {
904
0
  PRIntn bytes =
905
0
      sendto(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
906
0
             (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr));
907
0
  op->syserrno = errno;
908
0
  if (bytes >= 0) /* this is progress */
909
0
  {
910
0
    char* bp = (char*)op->arg2.buffer;
911
0
    bp += bytes; /* adjust the buffer pointer */
912
0
    op->arg2.buffer = bp;
913
0
    op->result.code += bytes; /* accumulate the number sent */
914
0
    op->arg3.amount -= bytes; /* and reduce the required count */
915
0
    return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
916
0
  }
917
0
  if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno)) {
918
0
    op->result.code = -1;
919
0
    return PR_TRUE;
920
0
  } else {
921
0
    return PR_FALSE;
922
0
  }
923
0
} /* pt_sendto_cont */
924
925
0
static PRBool pt_recvfrom_cont(pt_Continuation* op, PRInt16 revents) {
926
0
  pt_SockLen addr_len = sizeof(PRNetAddr);
927
0
  op->result.code =
928
0
      recvfrom(op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
929
0
               (struct sockaddr*)op->arg5.addr, &addr_len);
930
0
  op->syserrno = errno;
931
0
  return ((-1 == op->result.code) &&
932
0
          (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno))
933
0
             ? PR_FALSE
934
0
             : PR_TRUE;
935
0
} /* pt_recvfrom_cont */
936
937
#  ifdef AIX
938
static PRBool pt_aix_sendfile_cont(pt_Continuation* op, PRInt16 revents) {
939
  struct sf_parms* sf_struct = (struct sf_parms*)op->arg2.buffer;
940
  ssize_t rv;
941
  unsigned long long saved_file_offset;
942
  long long saved_file_bytes;
943
944
  saved_file_offset = sf_struct->file_offset;
945
  saved_file_bytes = sf_struct->file_bytes;
946
  sf_struct->bytes_sent = 0;
947
948
  if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0))
949
    PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <=
950
              sf_struct->file_size);
951
  rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags);
952
  op->syserrno = errno;
953
954
  if (rv != -1) {
955
    op->result.code += sf_struct->bytes_sent;
956
    /*
957
     * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
958
     * being updated. So, 'file_bytes' is maintained by NSPR to
959
     * avoid conflict when this bug is fixed in AIX, in the future.
960
     */
961
    if (saved_file_bytes != -1) {
962
      saved_file_bytes -= (sf_struct->file_offset - saved_file_offset);
963
    }
964
    sf_struct->file_bytes = saved_file_bytes;
965
  } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
966
    op->result.code = -1;
967
  } else {
968
    return PR_FALSE;
969
  }
970
971
  if (rv == 1) { /* more data to send */
972
    return PR_FALSE;
973
  }
974
975
  return PR_TRUE;
976
}
977
#  endif /* AIX */
978
979
#  ifdef HPUX11
980
static PRBool pt_hpux_sendfile_cont(pt_Continuation* op, PRInt16 revents) {
981
  struct iovec* hdtrl = (struct iovec*)op->arg2.buffer;
982
  int count;
983
984
  count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset,
985
                   op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags);
986
  PR_ASSERT(count <= op->nbytes_to_send);
987
  op->syserrno = errno;
988
989
  if (count != -1) {
990
    op->result.code += count;
991
  } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
992
    op->result.code = -1;
993
  } else {
994
    return PR_FALSE;
995
  }
996
  if (count != -1 && count < op->nbytes_to_send) {
997
    if (count < hdtrl[0].iov_len) {
998
      /* header not sent */
999
1000
      hdtrl[0].iov_base = ((char*)hdtrl[0].iov_base) + count;
1001
      hdtrl[0].iov_len -= count;
1002
1003
    } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) {
1004
      /* header sent, file not sent */
1005
      PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len;
1006
1007
      hdtrl[0].iov_base = NULL;
1008
      hdtrl[0].iov_len = 0;
1009
1010
      op->arg3.file_spec.offset += file_nbytes_sent;
1011
      op->arg3.file_spec.nbytes -= file_nbytes_sent;
1012
    } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes +
1013
                        hdtrl[1].iov_len)) {
1014
      PRUint32 trailer_nbytes_sent =
1015
          count - (hdtrl[0].iov_len + op->arg3.file_spec.nbytes);
1016
1017
      /* header sent, file sent, trailer not sent */
1018
1019
      hdtrl[0].iov_base = NULL;
1020
      hdtrl[0].iov_len = 0;
1021
      /*
1022
       * set file offset and len so that no more file data is
1023
       * sent
1024
       */
1025
      op->arg3.file_spec.offset = op->arg3.file_spec.st_size;
1026
      op->arg3.file_spec.nbytes = 0;
1027
1028
      hdtrl[1].iov_base = ((char*)hdtrl[1].iov_base) + trailer_nbytes_sent;
1029
      hdtrl[1].iov_len -= trailer_nbytes_sent;
1030
    }
1031
    op->nbytes_to_send -= count;
1032
    return PR_FALSE;
1033
  }
1034
1035
  return PR_TRUE;
1036
}
1037
#  endif /* HPUX11 */
1038
1039
#  ifdef SOLARIS
1040
static PRBool pt_solaris_sendfile_cont(pt_Continuation* op, PRInt16 revents) {
1041
  struct sendfilevec* vec = (struct sendfilevec*)op->arg2.buffer;
1042
  size_t xferred;
1043
  ssize_t count;
1044
1045
  count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred);
1046
  op->syserrno = errno;
1047
  PR_ASSERT((count == -1) || (count == xferred));
1048
1049
  if (count == -1) {
1050
    if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN &&
1051
        op->syserrno != EINTR) {
1052
      op->result.code = -1;
1053
      return PR_TRUE;
1054
    }
1055
    count = xferred;
1056
  } else if (count == 0) {
1057
    /*
1058
     * We are now at EOF. The file was truncated. Solaris sendfile is
1059
     * supposed to return 0 and no error in this case, though some versions
1060
     * may return -1 and EINVAL .
1061
     */
1062
    op->result.code = -1;
1063
    op->syserrno = 0; /* will be treated as EOF */
1064
    return PR_TRUE;
1065
  }
1066
  PR_ASSERT(count <= op->nbytes_to_send);
1067
1068
  op->result.code += count;
1069
  if (count < op->nbytes_to_send) {
1070
    op->nbytes_to_send -= count;
1071
1072
    while (count >= vec->sfv_len) {
1073
      count -= vec->sfv_len;
1074
      vec++;
1075
      op->arg3.amount--;
1076
    }
1077
    PR_ASSERT(op->arg3.amount > 0);
1078
1079
    vec->sfv_off += count;
1080
    vec->sfv_len -= count;
1081
    PR_ASSERT(vec->sfv_len > 0);
1082
    op->arg2.buffer = vec;
1083
1084
    return PR_FALSE;
1085
  }
1086
1087
  return PR_TRUE;
1088
}
1089
#  endif /* SOLARIS */
1090
1091
#  ifdef LINUX
1092
0
static PRBool pt_linux_sendfile_cont(pt_Continuation* op, PRInt16 revents) {
1093
0
  ssize_t rv;
1094
0
  off_t oldoffset;
1095
1096
0
  oldoffset = op->offset;
1097
0
  rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count);
1098
0
  op->syserrno = errno;
1099
1100
0
  if (rv == -1) {
1101
0
    if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
1102
0
      op->result.code = -1;
1103
0
      return PR_TRUE;
1104
0
    }
1105
0
    rv = 0;
1106
0
  }
1107
0
  PR_ASSERT(rv == op->offset - oldoffset);
1108
0
  op->result.code += rv;
1109
0
  if (rv < op->count) {
1110
0
    op->count -= rv;
1111
0
    return PR_FALSE;
1112
0
  }
1113
0
  return PR_TRUE;
1114
0
}
1115
#  endif /* LINUX */
1116
1117
1
void _PR_InitIO(void) {
1118
1
#  if defined(DEBUG)
1119
1
  memset(&pt_debug, 0, sizeof(PTDebug));
1120
1
  pt_debug.timeStarted = PR_Now();
1121
1
#  endif
1122
1123
1
  _pr_flock_lock = PR_NewLock();
1124
1
  PR_ASSERT(NULL != _pr_flock_lock);
1125
1
  _pr_flock_cv = PR_NewCondVar(_pr_flock_lock);
1126
1
  PR_ASSERT(NULL != _pr_flock_cv);
1127
1
  _pr_rename_lock = PR_NewLock();
1128
1
  PR_ASSERT(NULL != _pr_rename_lock);
1129
1130
1
  _PR_InitFdCache(); /* do that */
1131
1132
1
  _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE);
1133
1
  _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE);
1134
1
  _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE);
1135
1
  PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr);
1136
1137
#  ifdef _PR_IPV6_V6ONLY_PROBE
1138
  /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option
1139
   * is turned on by default, contrary to what RFC 3493, Section
1140
   * 5.3 says.  So we have to turn it off.  Find out whether we
1141
   * are running on such a system.
1142
   */
1143
  {
1144
    int osfd;
1145
    osfd = socket(AF_INET6, SOCK_STREAM, 0);
1146
    if (osfd != -1) {
1147
      int on;
1148
      socklen_t optlen = sizeof(on);
1149
      if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, &optlen) == 0) {
1150
        _pr_ipv6_v6only_on_by_default = on;
1151
      }
1152
      close(osfd);
1153
    }
1154
  }
1155
#  endif
1156
1
} /* _PR_InitIO */
1157
1158
0
void _PR_CleanupIO(void) {
1159
0
  _PR_Putfd(_pr_stdin);
1160
0
  _pr_stdin = NULL;
1161
0
  _PR_Putfd(_pr_stdout);
1162
0
  _pr_stdout = NULL;
1163
0
  _PR_Putfd(_pr_stderr);
1164
0
  _pr_stderr = NULL;
1165
1166
0
  _PR_CleanupFdCache();
1167
1168
0
  if (_pr_flock_cv) {
1169
0
    PR_DestroyCondVar(_pr_flock_cv);
1170
0
    _pr_flock_cv = NULL;
1171
0
  }
1172
0
  if (_pr_flock_lock) {
1173
0
    PR_DestroyLock(_pr_flock_lock);
1174
0
    _pr_flock_lock = NULL;
1175
0
  }
1176
0
  if (_pr_rename_lock) {
1177
0
    PR_DestroyLock(_pr_rename_lock);
1178
0
    _pr_rename_lock = NULL;
1179
0
  }
1180
0
} /* _PR_CleanupIO */
1181
1182
0
PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd) {
1183
0
  PRFileDesc* result = NULL;
1184
0
  PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError);
1185
1186
0
  if (!_pr_initialized) {
1187
0
    _PR_ImplicitInitialization();
1188
0
  }
1189
1190
0
  switch (osfd) {
1191
0
    case PR_StandardInput:
1192
0
      result = _pr_stdin;
1193
0
      break;
1194
0
    case PR_StandardOutput:
1195
0
      result = _pr_stdout;
1196
0
      break;
1197
0
    case PR_StandardError:
1198
0
      result = _pr_stderr;
1199
0
      break;
1200
0
    default:
1201
0
      (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1202
0
  }
1203
0
  return result;
1204
0
} /* PR_GetSpecialFD */
1205
1206
/*****************************************************************************/
1207
/***************************** I/O private methods ***************************/
1208
/*****************************************************************************/
1209
1210
0
static PRBool pt_TestAbort(void) {
1211
0
  PRThread* me = PR_GetCurrentThread();
1212
0
  if (_PT_THREAD_INTERRUPTED(me)) {
1213
0
    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
1214
0
    me->state &= ~PT_THREAD_ABORTED;
1215
0
    return PR_TRUE;
1216
0
  }
1217
0
  return PR_FALSE;
1218
0
} /* pt_TestAbort */
1219
1220
0
static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno) {
1221
0
  switch (syserrno) {
1222
0
    case EINTR:
1223
0
      PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
1224
0
      break;
1225
0
    case ETIMEDOUT:
1226
0
      PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
1227
0
      break;
1228
0
    default:
1229
0
      mapper(syserrno);
1230
0
  }
1231
0
} /* pt_MapError */
1232
1233
0
static PRStatus pt_Close(PRFileDesc* fd) {
1234
0
  if ((NULL == fd) || (NULL == fd->secret) ||
1235
0
      ((_PR_FILEDESC_OPEN != fd->secret->state) &&
1236
0
       (_PR_FILEDESC_CLOSED != fd->secret->state))) {
1237
0
    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
1238
0
    return PR_FAILURE;
1239
0
  }
1240
0
  if (pt_TestAbort()) {
1241
0
    return PR_FAILURE;
1242
0
  }
1243
1244
0
  if (_PR_FILEDESC_OPEN == fd->secret->state) {
1245
0
    if (-1 == close(fd->secret->md.osfd)) {
1246
0
      pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
1247
0
      return PR_FAILURE;
1248
0
    }
1249
0
    fd->secret->state = _PR_FILEDESC_CLOSED;
1250
0
  }
1251
0
  _PR_Putfd(fd);
1252
0
  return PR_SUCCESS;
1253
0
} /* pt_Close */
1254
1255
0
static PRInt32 pt_Read(PRFileDesc* fd, void* buf, PRInt32 amount) {
1256
0
  PRInt32 syserrno, bytes = -1;
1257
1258
0
  if (pt_TestAbort()) {
1259
0
    return bytes;
1260
0
  }
1261
1262
0
  bytes = read(fd->secret->md.osfd, buf, amount);
1263
0
  syserrno = errno;
1264
1265
0
  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
1266
0
      (!fd->secret->nonblocking)) {
1267
0
    pt_Continuation op;
1268
0
    op.arg1.osfd = fd->secret->md.osfd;
1269
0
    op.arg2.buffer = buf;
1270
0
    op.arg3.amount = amount;
1271
0
    op.timeout = PR_INTERVAL_NO_TIMEOUT;
1272
0
    op.function = pt_read_cont;
1273
0
    op.event = POLLIN | POLLPRI;
1274
0
    bytes = pt_Continue(&op);
1275
0
    syserrno = op.syserrno;
1276
0
  }
1277
0
  if (bytes < 0) {
1278
0
    pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno);
1279
0
  }
1280
0
  return bytes;
1281
0
} /* pt_Read */
1282
1283
0
static PRInt32 pt_Write(PRFileDesc* fd, const void* buf, PRInt32 amount) {
1284
0
  PRInt32 syserrno, bytes = -1;
1285
0
  PRBool fNeedContinue = PR_FALSE;
1286
1287
0
  if (pt_TestAbort()) {
1288
0
    return bytes;
1289
0
  }
1290
1291
0
  bytes = write(fd->secret->md.osfd, buf, amount);
1292
0
  syserrno = errno;
1293
1294
0
  if ((bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking)) {
1295
0
    buf = (char*)buf + bytes;
1296
0
    amount -= bytes;
1297
0
    fNeedContinue = PR_TRUE;
1298
0
  }
1299
0
  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
1300
0
      (!fd->secret->nonblocking)) {
1301
0
    bytes = 0;
1302
0
    fNeedContinue = PR_TRUE;
1303
0
  }
1304
1305
0
  if (fNeedContinue == PR_TRUE) {
1306
0
    pt_Continuation op;
1307
0
    op.arg1.osfd = fd->secret->md.osfd;
1308
0
    op.arg2.buffer = (void*)buf;
1309
0
    op.arg3.amount = amount;
1310
0
    op.timeout = PR_INTERVAL_NO_TIMEOUT;
1311
0
    op.result.code = bytes; /* initialize the number sent */
1312
0
    op.function = pt_write_cont;
1313
0
    op.event = POLLOUT | POLLPRI;
1314
0
    bytes = pt_Continue(&op);
1315
0
    syserrno = op.syserrno;
1316
0
  }
1317
0
  if (bytes == -1) {
1318
0
    pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
1319
0
  }
1320
0
  return bytes;
1321
0
} /* pt_Write */
1322
1323
static PRInt32 pt_Writev(PRFileDesc* fd, const PRIOVec* iov, PRInt32 iov_len,
1324
0
                         PRIntervalTime timeout) {
1325
0
  PRIntn iov_index;
1326
0
  PRBool fNeedContinue = PR_FALSE;
1327
0
  PRInt32 syserrno, bytes, rv = -1;
1328
0
  struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov;
1329
0
  int osiov_len;
1330
1331
0
  if (pt_TestAbort()) {
1332
0
    return rv;
1333
0
  }
1334
1335
  /* Ensured by PR_Writev */
1336
0
  PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE);
1337
1338
  /*
1339
   * We can't pass iov to writev because PRIOVec and struct iovec
1340
   * may not be binary compatible.  Make osiov a copy of iov and
1341
   * pass osiov to writev.  We can modify osiov if we need to
1342
   * continue the operation.
1343
   */
1344
0
  osiov = osiov_local;
1345
0
  osiov_len = iov_len;
1346
0
  for (iov_index = 0; iov_index < osiov_len; iov_index++) {
1347
0
    osiov[iov_index].iov_base = iov[iov_index].iov_base;
1348
0
    osiov[iov_index].iov_len = iov[iov_index].iov_len;
1349
0
  }
1350
1351
0
  rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len);
1352
0
  syserrno = errno;
1353
1354
0
  if (!fd->secret->nonblocking) {
1355
0
    if (bytes >= 0) {
1356
      /*
1357
       * If we moved some bytes, how does that implicate the
1358
       * i/o vector list?  In other words, exactly where are
1359
       * we within that array?  What are the parameters for
1360
       * resumption?  Maybe we're done!
1361
       */
1362
0
      for (; osiov_len > 0; osiov++, osiov_len--) {
1363
0
        if (bytes < osiov->iov_len) {
1364
          /* this one's not done yet */
1365
0
          osiov->iov_base = (char*)osiov->iov_base + bytes;
1366
0
          osiov->iov_len -= bytes;
1367
0
          break; /* go off and do that */
1368
0
        }
1369
0
        bytes -= osiov->iov_len; /* this one's done cooked */
1370
0
      }
1371
0
      PR_ASSERT(osiov_len > 0 || bytes == 0);
1372
0
      if (osiov_len > 0) {
1373
0
        if (PR_INTERVAL_NO_WAIT == timeout) {
1374
0
          rv = -1;
1375
0
          syserrno = ETIMEDOUT;
1376
0
        } else {
1377
0
          fNeedContinue = PR_TRUE;
1378
0
        }
1379
0
      }
1380
0
    } else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN) {
1381
0
      if (PR_INTERVAL_NO_WAIT == timeout) {
1382
0
        syserrno = ETIMEDOUT;
1383
0
      } else {
1384
0
        rv = 0;
1385
0
        fNeedContinue = PR_TRUE;
1386
0
      }
1387
0
    }
1388
0
  }
1389
1390
0
  if (fNeedContinue == PR_TRUE) {
1391
0
    pt_Continuation op;
1392
1393
0
    op.arg1.osfd = fd->secret->md.osfd;
1394
0
    op.arg2.buffer = (void*)osiov;
1395
0
    op.arg3.amount = osiov_len;
1396
0
    op.timeout = timeout;
1397
0
    op.result.code = rv;
1398
0
    op.function = pt_writev_cont;
1399
0
    op.event = POLLOUT | POLLPRI;
1400
0
    rv = pt_Continue(&op);
1401
0
    syserrno = op.syserrno;
1402
0
  }
1403
0
  if (rv == -1) {
1404
0
    pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
1405
0
  }
1406
0
  return rv;
1407
0
} /* pt_Writev */
1408
1409
0
static PRInt32 pt_Seek(PRFileDesc* fd, PRInt32 offset, PRSeekWhence whence) {
1410
0
  return _PR_MD_LSEEK(fd, offset, whence);
1411
0
} /* pt_Seek */
1412
1413
0
static PRInt64 pt_Seek64(PRFileDesc* fd, PRInt64 offset, PRSeekWhence whence) {
1414
0
  return _PR_MD_LSEEK64(fd, offset, whence);
1415
0
} /* pt_Seek64 */
1416
1417
0
static PRInt32 pt_Available_f(PRFileDesc* fd) {
1418
0
  PRInt32 result, cur, end;
1419
1420
0
  cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR);
1421
1422
0
  if (cur >= 0) {
1423
0
    end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END);
1424
0
  }
1425
1426
0
  if ((cur < 0) || (end < 0)) {
1427
0
    return -1;
1428
0
  }
1429
1430
0
  result = end - cur;
1431
0
  _PR_MD_LSEEK(fd, cur, PR_SEEK_SET);
1432
1433
0
  return result;
1434
0
} /* pt_Available_f */
1435
1436
0
static PRInt64 pt_Available64_f(PRFileDesc* fd) {
1437
0
  PRInt64 result, cur, end;
1438
0
  PRInt64 minus_one;
1439
1440
0
  LL_I2L(minus_one, -1);
1441
0
  cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR);
1442
1443
0
  if (LL_GE_ZERO(cur)) {
1444
0
    end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END);
1445
0
  }
1446
1447
0
  if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) {
1448
0
    return minus_one;
1449
0
  }
1450
1451
0
  LL_SUB(result, end, cur);
1452
0
  (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET);
1453
1454
0
  return result;
1455
0
} /* pt_Available64_f */
1456
1457
0
static PRInt32 pt_Available_s(PRFileDesc* fd) {
1458
0
  PRInt32 rv, bytes = -1;
1459
0
  if (pt_TestAbort()) {
1460
0
    return bytes;
1461
0
  }
1462
1463
0
  rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes);
1464
1465
0
  if (rv == -1) {
1466
0
    pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno);
1467
0
  }
1468
0
  return bytes;
1469
0
} /* pt_Available_s */
1470
1471
0
static PRInt64 pt_Available64_s(PRFileDesc* fd) {
1472
0
  PRInt64 rv;
1473
0
  LL_I2L(rv, pt_Available_s(fd));
1474
0
  return rv;
1475
0
} /* pt_Available64_s */
1476
1477
0
static PRStatus pt_FileInfo(PRFileDesc* fd, PRFileInfo* info) {
1478
0
  PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info);
1479
0
  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
1480
0
} /* pt_FileInfo */
1481
1482
0
static PRStatus pt_FileInfo64(PRFileDesc* fd, PRFileInfo64* info) {
1483
0
  PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info);
1484
0
  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
1485
0
} /* pt_FileInfo64 */
1486
1487
0
static PRStatus pt_Synch(PRFileDesc* fd) {
1488
0
  return (NULL == fd) ? PR_FAILURE : PR_SUCCESS;
1489
0
} /* pt_Synch */
1490
1491
0
static PRStatus pt_Fsync(PRFileDesc* fd) {
1492
0
  PRIntn rv = -1;
1493
0
  if (pt_TestAbort()) {
1494
0
    return PR_FAILURE;
1495
0
  }
1496
1497
0
  rv = fsync(fd->secret->md.osfd);
1498
0
  if (rv < 0) {
1499
0
    pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno);
1500
0
    return PR_FAILURE;
1501
0
  }
1502
0
  return PR_SUCCESS;
1503
0
} /* pt_Fsync */
1504
1505
static PRStatus pt_Connect(PRFileDesc* fd, const PRNetAddr* addr,
1506
0
                           PRIntervalTime timeout) {
1507
0
  PRIntn rv = -1, syserrno;
1508
0
  pt_SockLen addr_len;
1509
0
  const PRNetAddr* addrp = addr;
1510
0
#  if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
1511
0
  PRNetAddr addrCopy;
1512
0
#  endif
1513
#  ifdef _PR_HAVE_SOCKADDR_LEN
1514
  PRUint16 md_af = addr->raw.family;
1515
#  endif
1516
1517
0
  if (pt_TestAbort()) {
1518
0
    return PR_FAILURE;
1519
0
  }
1520
1521
0
  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1522
0
  addr_len = PR_NETADDR_SIZE(addr);
1523
0
#  ifdef _PR_INET6
1524
0
  if (addr->raw.family == PR_AF_INET6) {
1525
#    ifdef _PR_HAVE_SOCKADDR_LEN
1526
    md_af = AF_INET6;
1527
#    else
1528
0
    addrCopy = *addr;
1529
0
    addrCopy.raw.family = AF_INET6;
1530
0
    addrp = &addrCopy;
1531
0
#    endif
1532
0
  }
1533
0
#  endif
1534
1535
#  ifdef _PR_HAVE_SOCKADDR_LEN
1536
  addrCopy = *addr;
1537
  ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
1538
  ((struct sockaddr*)&addrCopy)->sa_family = md_af;
1539
  addrp = &addrCopy;
1540
#  endif
1541
0
  rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
1542
0
  syserrno = errno;
1543
0
  if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking)) {
1544
0
    if (PR_INTERVAL_NO_WAIT == timeout) {
1545
0
      syserrno = ETIMEDOUT;
1546
0
    } else {
1547
0
      pt_Continuation op;
1548
0
      op.arg1.osfd = fd->secret->md.osfd;
1549
0
      op.arg2.buffer = (void*)addrp;
1550
0
      op.arg3.amount = addr_len;
1551
0
      op.timeout = timeout;
1552
0
      op.function = pt_connect_cont;
1553
0
      op.event = POLLOUT | POLLPRI;
1554
0
      rv = pt_Continue(&op);
1555
0
      syserrno = op.syserrno;
1556
0
    }
1557
0
  }
1558
0
  if (-1 == rv) {
1559
0
    pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno);
1560
0
    return PR_FAILURE;
1561
0
  }
1562
0
  return PR_SUCCESS;
1563
0
} /* pt_Connect */
1564
1565
0
static PRStatus pt_ConnectContinue(PRFileDesc* fd, PRInt16 out_flags) {
1566
0
  int err;
1567
0
  PRInt32 osfd;
1568
1569
0
  if (out_flags & PR_POLL_NVAL) {
1570
0
    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
1571
0
    return PR_FAILURE;
1572
0
  }
1573
0
  if ((out_flags &
1574
0
       (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR | PR_POLL_HUP)) == 0) {
1575
0
    PR_ASSERT(out_flags == 0);
1576
0
    PR_SetError(PR_IN_PROGRESS_ERROR, 0);
1577
0
    return PR_FAILURE;
1578
0
  }
1579
1580
0
  osfd = fd->secret->md.osfd;
1581
1582
0
  err = _MD_unix_get_nonblocking_connect_error(osfd);
1583
0
  if (err != 0) {
1584
0
    _PR_MD_MAP_CONNECT_ERROR(err);
1585
0
    return PR_FAILURE;
1586
0
  }
1587
0
  return PR_SUCCESS;
1588
0
} /* pt_ConnectContinue */
1589
1590
0
PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc* pd) {
1591
  /* Find the NSPR layer and invoke its connectcontinue method */
1592
0
  PRFileDesc* bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
1593
1594
0
  if (NULL == bottom) {
1595
0
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1596
0
    return PR_FAILURE;
1597
0
  }
1598
0
  return pt_ConnectContinue(bottom, pd->out_flags);
1599
0
} /* PR_GetConnectStatus */
1600
1601
static PRFileDesc* pt_Accept(PRFileDesc* fd, PRNetAddr* addr,
1602
0
                             PRIntervalTime timeout) {
1603
0
  PRFileDesc* newfd = NULL;
1604
0
  PRIntn syserrno, osfd = -1;
1605
0
  pt_SockLen addr_len = sizeof(PRNetAddr);
1606
1607
0
  if (pt_TestAbort()) {
1608
0
    return newfd;
1609
0
  }
1610
1611
#  ifdef _PR_STRICT_ADDR_LEN
1612
  if (addr) {
1613
    /*
1614
     * Set addr->raw.family just so that we can use the
1615
     * PR_NETADDR_SIZE macro.
1616
     */
1617
    addr->raw.family = fd->secret->af;
1618
    addr_len = PR_NETADDR_SIZE(addr);
1619
  }
1620
#  endif
1621
1622
0
  osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
1623
0
  syserrno = errno;
1624
1625
0
  if (osfd == -1) {
1626
0
    if (fd->secret->nonblocking) {
1627
0
      goto failed;
1628
0
    }
1629
1630
0
    if (EWOULDBLOCK != syserrno && EAGAIN != syserrno &&
1631
0
        ECONNABORTED != syserrno) {
1632
0
      goto failed;
1633
0
    } else {
1634
0
      if (PR_INTERVAL_NO_WAIT == timeout) {
1635
0
        syserrno = ETIMEDOUT;
1636
0
      } else {
1637
0
        pt_Continuation op;
1638
0
        op.arg1.osfd = fd->secret->md.osfd;
1639
0
        op.arg2.buffer = addr;
1640
0
        op.arg3.addr_len = &addr_len;
1641
0
        op.timeout = timeout;
1642
0
        op.function = pt_accept_cont;
1643
0
        op.event = POLLIN | POLLPRI;
1644
0
        osfd = pt_Continue(&op);
1645
0
        syserrno = op.syserrno;
1646
0
      }
1647
0
      if (osfd < 0) {
1648
0
        goto failed;
1649
0
      }
1650
0
    }
1651
0
  }
1652
#  ifdef _PR_HAVE_SOCKADDR_LEN
1653
  /* ignore the sa_len field of struct sockaddr */
1654
  if (addr) {
1655
    addr->raw.family = ((struct sockaddr*)addr)->sa_family;
1656
  }
1657
#  endif /* _PR_HAVE_SOCKADDR_LEN */
1658
0
#  ifdef _PR_INET6
1659
0
  if (addr && (AF_INET6 == addr->raw.family)) {
1660
0
    addr->raw.family = PR_AF_INET6;
1661
0
  }
1662
0
#  endif
1663
0
  newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE);
1664
0
  if (newfd == NULL) {
1665
0
    close(osfd); /* $$$ whoops! this doesn't work $$$ */
1666
0
  } else {
1667
0
    PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1668
0
    PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
1669
0
#  ifdef LINUX
1670
    /*
1671
     * On Linux, experiments showed that the accepted sockets
1672
     * inherit the TCP_NODELAY socket option of the listening
1673
     * socket.
1674
     */
1675
0
    newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay;
1676
0
#  endif
1677
0
  }
1678
0
  return newfd;
1679
1680
0
failed:
1681
0
  pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno);
1682
0
  return NULL;
1683
0
} /* pt_Accept */
1684
1685
0
static PRStatus pt_Bind(PRFileDesc* fd, const PRNetAddr* addr) {
1686
0
  PRIntn rv;
1687
0
  pt_SockLen addr_len;
1688
0
  const PRNetAddr* addrp = addr;
1689
0
#  if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
1690
0
  PRNetAddr addrCopy;
1691
0
#  endif
1692
#  ifdef _PR_HAVE_SOCKADDR_LEN
1693
  PRUint16 md_af = addr->raw.family;
1694
#  endif
1695
1696
0
  if (pt_TestAbort()) {
1697
0
    return PR_FAILURE;
1698
0
  }
1699
1700
0
  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1701
0
  if (addr->raw.family == AF_UNIX) {
1702
    /* Disallow relative pathnames */
1703
0
    if (addr->local.path[0] != '/'
1704
0
#  if defined(LINUX)
1705
        /* Linux has abstract socket address support */
1706
0
        && addr->local.path[0] != 0
1707
0
#  endif
1708
0
    ) {
1709
0
      PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1710
0
      return PR_FAILURE;
1711
0
    }
1712
0
  }
1713
1714
0
#  ifdef _PR_INET6
1715
0
  if (addr->raw.family == PR_AF_INET6) {
1716
#    ifdef _PR_HAVE_SOCKADDR_LEN
1717
    md_af = AF_INET6;
1718
#    else
1719
0
    addrCopy = *addr;
1720
0
    addrCopy.raw.family = AF_INET6;
1721
0
    addrp = &addrCopy;
1722
0
#    endif
1723
0
  }
1724
0
#  endif
1725
1726
0
  addr_len = PR_NETADDR_SIZE(addr);
1727
#  ifdef _PR_HAVE_SOCKADDR_LEN
1728
  addrCopy = *addr;
1729
  ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
1730
  ((struct sockaddr*)&addrCopy)->sa_family = md_af;
1731
  addrp = &addrCopy;
1732
#  endif
1733
0
  rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
1734
1735
0
  if (rv == -1) {
1736
0
    pt_MapError(_PR_MD_MAP_BIND_ERROR, errno);
1737
0
    return PR_FAILURE;
1738
0
  }
1739
0
  return PR_SUCCESS;
1740
0
} /* pt_Bind */
1741
1742
0
static PRStatus pt_Listen(PRFileDesc* fd, PRIntn backlog) {
1743
0
  PRIntn rv;
1744
1745
0
  if (pt_TestAbort()) {
1746
0
    return PR_FAILURE;
1747
0
  }
1748
1749
0
  rv = listen(fd->secret->md.osfd, backlog);
1750
0
  if (rv == -1) {
1751
0
    pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno);
1752
0
    return PR_FAILURE;
1753
0
  }
1754
0
  return PR_SUCCESS;
1755
0
} /* pt_Listen */
1756
1757
0
static PRStatus pt_Shutdown(PRFileDesc* fd, PRIntn how) {
1758
0
  PRIntn rv = -1;
1759
0
  if (pt_TestAbort()) {
1760
0
    return PR_FAILURE;
1761
0
  }
1762
1763
0
  rv = shutdown(fd->secret->md.osfd, how);
1764
1765
0
  if (rv == -1) {
1766
0
    pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno);
1767
0
    return PR_FAILURE;
1768
0
  }
1769
0
  return PR_SUCCESS;
1770
0
} /* pt_Shutdown */
1771
1772
0
static PRInt16 pt_Poll(PRFileDesc* fd, PRInt16 in_flags, PRInt16* out_flags) {
1773
0
  *out_flags = 0;
1774
0
  return in_flags;
1775
0
} /* pt_Poll */
1776
1777
static PRInt32 pt_Recv(PRFileDesc* fd, void* buf, PRInt32 amount, PRIntn flags,
1778
0
                       PRIntervalTime timeout) {
1779
0
  PRInt32 syserrno, bytes = -1;
1780
0
  PRIntn osflags;
1781
1782
0
  if (0 == flags) {
1783
0
    osflags = 0;
1784
0
  } else if (PR_MSG_PEEK == flags) {
1785
0
    osflags = MSG_PEEK;
1786
0
  } else {
1787
0
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1788
0
    return bytes;
1789
0
  }
1790
1791
0
  if (pt_TestAbort()) {
1792
0
    return bytes;
1793
0
  }
1794
1795
  /* recv() is a much slower call on pre-2.6 Solaris than read(). */
1796
#  if defined(SOLARIS)
1797
  if (0 == osflags) {
1798
    bytes = read(fd->secret->md.osfd, buf, amount);
1799
  } else {
1800
    bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
1801
  }
1802
#  else
1803
0
  bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
1804
0
#  endif
1805
0
  syserrno = errno;
1806
1807
0
  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
1808
0
      (!fd->secret->nonblocking)) {
1809
0
    if (PR_INTERVAL_NO_WAIT == timeout) {
1810
0
      syserrno = ETIMEDOUT;
1811
0
    } else {
1812
0
      pt_Continuation op;
1813
0
      op.arg1.osfd = fd->secret->md.osfd;
1814
0
      op.arg2.buffer = buf;
1815
0
      op.arg3.amount = amount;
1816
0
      op.arg4.flags = osflags;
1817
0
      op.timeout = timeout;
1818
0
      op.function = pt_recv_cont;
1819
0
      op.event = POLLIN | POLLPRI;
1820
0
      bytes = pt_Continue(&op);
1821
0
      syserrno = op.syserrno;
1822
0
    }
1823
0
  }
1824
0
  if (bytes < 0) {
1825
0
    pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno);
1826
0
  }
1827
0
  return bytes;
1828
0
} /* pt_Recv */
1829
1830
0
static PRInt32 pt_SocketRead(PRFileDesc* fd, void* buf, PRInt32 amount) {
1831
0
  return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
1832
0
} /* pt_SocketRead */
1833
1834
static PRInt32 pt_Send(PRFileDesc* fd, const void* buf, PRInt32 amount,
1835
0
                       PRIntn flags, PRIntervalTime timeout) {
1836
0
  PRInt32 syserrno, bytes = -1;
1837
0
  PRBool fNeedContinue = PR_FALSE;
1838
#  if defined(SOLARIS)
1839
  PRInt32 tmp_amount = amount;
1840
#  endif
1841
1842
0
  if (pt_TestAbort()) {
1843
0
    return bytes;
1844
0
  }
1845
1846
  /*
1847
   * On pre-2.6 Solaris, send() is much slower than write().
1848
   * On 2.6 and beyond, with in-kernel sockets, send() and
1849
   * write() are fairly equivalent in performance.
1850
   */
1851
#  if defined(SOLARIS)
1852
  PR_ASSERT(0 == flags);
1853
retry:
1854
  bytes = write(fd->secret->md.osfd, buf, tmp_amount);
1855
#  else
1856
0
  bytes = send(fd->secret->md.osfd, buf, amount, flags);
1857
0
#  endif
1858
0
  syserrno = errno;
1859
1860
#  if defined(SOLARIS)
1861
  /*
1862
   * The write system call has been reported to return the ERANGE error
1863
   * on occasion. Try to write in smaller chunks to workaround this bug.
1864
   */
1865
  if ((bytes == -1) && (syserrno == ERANGE)) {
1866
    if (tmp_amount > 1) {
1867
      tmp_amount = tmp_amount / 2; /* half the bytes */
1868
      goto retry;
1869
    }
1870
  }
1871
#  endif
1872
1873
0
  if ((bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking)) {
1874
0
    if (PR_INTERVAL_NO_WAIT == timeout) {
1875
0
      bytes = -1;
1876
0
      syserrno = ETIMEDOUT;
1877
0
    } else {
1878
0
      buf = (char*)buf + bytes;
1879
0
      amount -= bytes;
1880
0
      fNeedContinue = PR_TRUE;
1881
0
    }
1882
0
  }
1883
0
  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
1884
0
      (!fd->secret->nonblocking)) {
1885
0
    if (PR_INTERVAL_NO_WAIT == timeout) {
1886
0
      syserrno = ETIMEDOUT;
1887
0
    } else {
1888
0
      bytes = 0;
1889
0
      fNeedContinue = PR_TRUE;
1890
0
    }
1891
0
  }
1892
1893
0
  if (fNeedContinue == PR_TRUE) {
1894
0
    pt_Continuation op;
1895
0
    op.arg1.osfd = fd->secret->md.osfd;
1896
0
    op.arg2.buffer = (void*)buf;
1897
0
    op.arg3.amount = amount;
1898
0
    op.arg4.flags = flags;
1899
0
    op.timeout = timeout;
1900
0
    op.result.code = bytes; /* initialize the number sent */
1901
0
    op.function = pt_send_cont;
1902
0
    op.event = POLLOUT | POLLPRI;
1903
0
    bytes = pt_Continue(&op);
1904
0
    syserrno = op.syserrno;
1905
0
  }
1906
0
  if (bytes == -1) {
1907
0
    pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno);
1908
0
  }
1909
0
  return bytes;
1910
0
} /* pt_Send */
1911
1912
0
static PRInt32 pt_SocketWrite(PRFileDesc* fd, const void* buf, PRInt32 amount) {
1913
0
  return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
1914
0
} /* pt_SocketWrite */
1915
1916
static PRInt32 pt_SendTo(PRFileDesc* fd, const void* buf, PRInt32 amount,
1917
                         PRIntn flags, const PRNetAddr* addr,
1918
0
                         PRIntervalTime timeout) {
1919
0
  PRInt32 syserrno, bytes = -1;
1920
0
  PRBool fNeedContinue = PR_FALSE;
1921
0
  pt_SockLen addr_len;
1922
0
  const PRNetAddr* addrp = addr;
1923
0
#  if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
1924
0
  PRNetAddr addrCopy;
1925
0
#  endif
1926
#  ifdef _PR_HAVE_SOCKADDR_LEN
1927
  PRUint16 md_af = addr->raw.family;
1928
#  endif
1929
1930
0
  if (pt_TestAbort()) {
1931
0
    return bytes;
1932
0
  }
1933
1934
0
  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1935
0
#  ifdef _PR_INET6
1936
0
  if (addr->raw.family == PR_AF_INET6) {
1937
#    ifdef _PR_HAVE_SOCKADDR_LEN
1938
    md_af = AF_INET6;
1939
#    else
1940
0
    addrCopy = *addr;
1941
0
    addrCopy.raw.family = AF_INET6;
1942
0
    addrp = &addrCopy;
1943
0
#    endif
1944
0
  }
1945
0
#  endif
1946
1947
0
  addr_len = PR_NETADDR_SIZE(addr);
1948
#  ifdef _PR_HAVE_SOCKADDR_LEN
1949
  addrCopy = *addr;
1950
  ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
1951
  ((struct sockaddr*)&addrCopy)->sa_family = md_af;
1952
  addrp = &addrCopy;
1953
#  endif
1954
0
  bytes = sendto(fd->secret->md.osfd, buf, amount, flags,
1955
0
                 (struct sockaddr*)addrp, addr_len);
1956
0
  syserrno = errno;
1957
0
  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
1958
0
      (!fd->secret->nonblocking)) {
1959
0
    if (PR_INTERVAL_NO_WAIT == timeout) {
1960
0
      syserrno = ETIMEDOUT;
1961
0
    } else {
1962
0
      fNeedContinue = PR_TRUE;
1963
0
    }
1964
0
  }
1965
0
  if (fNeedContinue == PR_TRUE) {
1966
0
    pt_Continuation op;
1967
0
    op.arg1.osfd = fd->secret->md.osfd;
1968
0
    op.arg2.buffer = (void*)buf;
1969
0
    op.arg3.amount = amount;
1970
0
    op.arg4.flags = flags;
1971
0
    op.arg5.addr = (PRNetAddr*)addrp;
1972
0
    op.timeout = timeout;
1973
0
    op.result.code = 0; /* initialize the number sent */
1974
0
    op.function = pt_sendto_cont;
1975
0
    op.event = POLLOUT | POLLPRI;
1976
0
    bytes = pt_Continue(&op);
1977
0
    syserrno = op.syserrno;
1978
0
  }
1979
0
  if (bytes < 0) {
1980
0
    pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
1981
0
  }
1982
0
  return bytes;
1983
0
} /* pt_SendTo */
1984
1985
#  if defined(LINUX) || defined(DARWIN)
1986
/* Linux uses SendTo to send data during TCP Fast Open. OSX uses connectx, but
1987
 * we will make it imitate the Linux's interface. */
1988
static PRInt32 pt_TCP_SendTo(PRFileDesc* fd, const void* buf, PRInt32 amount,
1989
                             PRIntn flags, const PRNetAddr* addr,
1990
0
                             PRIntervalTime timeout) {
1991
0
#    if defined(LINUX) || HAS_CONNECTX
1992
0
  PRInt32 syserrno, bytes = -1;
1993
0
  PRBool fNeedContinue = PR_FALSE;
1994
0
  pt_SockLen addr_len;
1995
0
  const PRNetAddr* addrp = addr;
1996
0
#      if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
1997
0
  PRNetAddr addrCopy;
1998
0
#      endif
1999
#      ifdef _PR_HAVE_SOCKADDR_LEN
2000
  PRUint16 md_af = addr->raw.family;
2001
#      endif
2002
2003
0
  if (pt_TestAbort()) {
2004
0
    return bytes;
2005
0
  }
2006
2007
0
  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
2008
0
  addr_len = PR_NETADDR_SIZE(addr);
2009
0
#      if defined(_PR_INET6)
2010
0
  if (addr->raw.family == PR_AF_INET6) {
2011
#        ifdef _PR_HAVE_SOCKADDR_LEN
2012
    md_af = AF_INET6;
2013
#        else
2014
    /* If _PR_INET6 is defined and it is PR_AF_INET6 we set family
2015
     * to AF_INET6. */
2016
0
    addrCopy = *addr;
2017
0
    addrCopy.raw.family = AF_INET6;
2018
0
    addrp = &addrCopy;
2019
0
#        endif
2020
0
  }
2021
0
#      endif
2022
2023
#      ifdef _PR_HAVE_SOCKADDR_LEN
2024
  /* if _PR_HAVE_SOCKADDR_LEN is defined and it is PR_AF_INET6 we set family
2025
   * to AF_INET6 and we set address length. */
2026
  addrCopy = *addr;
2027
  ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
2028
  ((struct sockaddr*)&addrCopy)->sa_family = md_af;
2029
  addrp = &addrCopy;
2030
#      endif
2031
2032
0
#      ifndef HAS_CONNECTX
2033
0
  bytes = sendto(fd->secret->md.osfd, buf, amount, MSG_FASTOPEN,
2034
0
                 (struct sockaddr*)addrp, addr_len);
2035
#      else
2036
  sa_endpoints_t endpoints;
2037
  endpoints.sae_srcif = 0;
2038
  endpoints.sae_srcaddr = NULL;
2039
  endpoints.sae_srcaddrlen = 0;
2040
  endpoints.sae_dstaddr = (struct sockaddr*)addrp;
2041
  endpoints.sae_dstaddrlen = addr_len;
2042
  struct iovec iov[1];
2043
  iov[0].iov_base = buf;
2044
  iov[0].iov_len = amount;
2045
  PRInt32 rv = connectx(fd->secret->md.osfd, &endpoints, SAE_ASSOCID_ANY,
2046
                        CONNECT_DATA_IDEMPOTENT, iov, 1, &bytes, NULL);
2047
#      endif
2048
0
  syserrno = errno;
2049
0
  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
2050
0
      (!fd->secret->nonblocking)) {
2051
0
    if (PR_INTERVAL_NO_WAIT == timeout) {
2052
0
      syserrno = ETIMEDOUT;
2053
0
    } else {
2054
0
      fNeedContinue = PR_TRUE;
2055
0
    }
2056
0
  }
2057
0
  if (fNeedContinue == PR_TRUE) {
2058
0
    pt_Continuation op;
2059
0
    op.arg1.osfd = fd->secret->md.osfd;
2060
0
    op.arg2.buffer = (void*)buf;
2061
0
    op.arg3.amount = amount;
2062
0
    op.arg4.flags = flags;
2063
0
    op.arg5.addr = (PRNetAddr*)addrp;
2064
0
    op.timeout = timeout;
2065
0
    op.result.code = 0; /* initialize the number sent */
2066
0
    op.function = pt_sendto_cont;
2067
0
    op.event = POLLOUT | POLLPRI;
2068
0
    bytes = pt_Continue(&op);
2069
0
    syserrno = op.syserrno;
2070
0
  }
2071
0
  if (bytes < 0) {
2072
0
    pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
2073
0
  }
2074
0
  return bytes;
2075
#    else /* !HAS_CONNECTX */
2076
  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2077
  return -1;
2078
#    endif
2079
0
} /* pt_TCP_SendTo */
2080
#  endif /* LINUX || DARWIN */
2081
2082
static PRInt32 pt_RecvFrom(PRFileDesc* fd, void* buf, PRInt32 amount,
2083
                           PRIntn flags, PRNetAddr* addr,
2084
0
                           PRIntervalTime timeout) {
2085
0
  PRBool fNeedContinue = PR_FALSE;
2086
0
  PRInt32 syserrno, bytes = -1;
2087
0
  pt_SockLen addr_len = sizeof(PRNetAddr);
2088
2089
0
  if (pt_TestAbort()) {
2090
0
    return bytes;
2091
0
  }
2092
2093
0
  bytes = recvfrom(fd->secret->md.osfd, buf, amount, flags,
2094
0
                   (struct sockaddr*)addr, &addr_len);
2095
0
  syserrno = errno;
2096
2097
0
  if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN) &&
2098
0
      (!fd->secret->nonblocking)) {
2099
0
    if (PR_INTERVAL_NO_WAIT == timeout) {
2100
0
      syserrno = ETIMEDOUT;
2101
0
    } else {
2102
0
      fNeedContinue = PR_TRUE;
2103
0
    }
2104
0
  }
2105
2106
0
  if (fNeedContinue == PR_TRUE) {
2107
0
    pt_Continuation op;
2108
0
    op.arg1.osfd = fd->secret->md.osfd;
2109
0
    op.arg2.buffer = buf;
2110
0
    op.arg3.amount = amount;
2111
0
    op.arg4.flags = flags;
2112
0
    op.arg5.addr = addr;
2113
0
    op.timeout = timeout;
2114
0
    op.function = pt_recvfrom_cont;
2115
0
    op.event = POLLIN | POLLPRI;
2116
0
    bytes = pt_Continue(&op);
2117
0
    syserrno = op.syserrno;
2118
0
  }
2119
0
  if (bytes >= 0) {
2120
#  ifdef _PR_HAVE_SOCKADDR_LEN
2121
    /* ignore the sa_len field of struct sockaddr */
2122
    if (addr) {
2123
      addr->raw.family = ((struct sockaddr*)addr)->sa_family;
2124
    }
2125
#  endif /* _PR_HAVE_SOCKADDR_LEN */
2126
0
#  ifdef _PR_INET6
2127
0
    if (addr && (AF_INET6 == addr->raw.family)) {
2128
0
      addr->raw.family = PR_AF_INET6;
2129
0
    }
2130
0
#  endif
2131
0
  } else {
2132
0
    pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno);
2133
0
  }
2134
0
  return bytes;
2135
0
} /* pt_RecvFrom */
2136
2137
#  ifdef AIX
2138
#    ifndef HAVE_SEND_FILE
2139
static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT;
2140
2141
static void pt_aix_sendfile_init_routine(void) {
2142
  void* handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
2143
  pt_aix_sendfile_fptr = (ssize_t(*)())dlsym(handle, "send_file");
2144
  dlclose(handle);
2145
}
2146
2147
/*
2148
 * pt_AIXDispatchSendFile
2149
 */
2150
static PRInt32 pt_AIXDispatchSendFile(PRFileDesc* sd, PRSendFileData* sfd,
2151
                                      PRTransmitFileFlags flags,
2152
                                      PRIntervalTime timeout) {
2153
  int rv;
2154
2155
  rv = pthread_once(&pt_aix_sendfile_once_block, pt_aix_sendfile_init_routine);
2156
  PR_ASSERT(0 == rv);
2157
  if (pt_aix_sendfile_fptr) {
2158
    return pt_AIXSendFile(sd, sfd, flags, timeout);
2159
  } else {
2160
    return PR_EmulateSendFile(sd, sfd, flags, timeout);
2161
  }
2162
}
2163
#    endif /* !HAVE_SEND_FILE */
2164
2165
/*
2166
 * pt_AIXSendFile
2167
 *
2168
 *    Send file sfd->fd across socket sd. If specified, header and trailer
2169
 *    buffers are sent before and after the file, respectively.
2170
 *
2171
 *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
2172
 *
2173
 *    return number of bytes sent or -1 on error
2174
 *
2175
 *      This implementation takes advantage of the send_file() system
2176
 *      call available in AIX 4.3.2.
2177
 */
2178
2179
static PRInt32 pt_AIXSendFile(PRFileDesc* sd, PRSendFileData* sfd,
2180
                              PRTransmitFileFlags flags,
2181
                              PRIntervalTime timeout) {
2182
  struct sf_parms sf_struct;
2183
  uint_t send_flags;
2184
  ssize_t rv;
2185
  int syserrno;
2186
  PRInt32 count;
2187
  unsigned long long saved_file_offset;
2188
  long long saved_file_bytes;
2189
2190
  sf_struct.header_data = (void*)sfd->header; /* cast away the 'const' */
2191
  sf_struct.header_length = sfd->hlen;
2192
  sf_struct.file_descriptor = sfd->fd->secret->md.osfd;
2193
  sf_struct.file_size = 0;
2194
  sf_struct.file_offset = sfd->file_offset;
2195
  if (sfd->file_nbytes == 0) {
2196
    sf_struct.file_bytes = -1;
2197
  } else {
2198
    sf_struct.file_bytes = sfd->file_nbytes;
2199
  }
2200
  sf_struct.trailer_data = (void*)sfd->trailer;
2201
  sf_struct.trailer_length = sfd->tlen;
2202
  sf_struct.bytes_sent = 0;
2203
2204
  saved_file_offset = sf_struct.file_offset;
2205
  saved_file_bytes = sf_struct.file_bytes;
2206
2207
  send_flags = 0; /* flags processed at the end */
2208
2209
  /* The first argument to send_file() is int*. */
2210
  PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd));
2211
  do {
2212
    rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags);
2213
  } while (rv == -1 && (syserrno = errno) == EINTR);
2214
2215
  if (rv == -1) {
2216
    if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
2217
      count = 0; /* Not a real error.  Need to continue. */
2218
    } else {
2219
      count = -1;
2220
    }
2221
  } else {
2222
    count = sf_struct.bytes_sent;
2223
    /*
2224
     * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
2225
     * being updated. So, 'file_bytes' is maintained by NSPR to
2226
     * avoid conflict when this bug is fixed in AIX, in the future.
2227
     */
2228
    if (saved_file_bytes != -1) {
2229
      saved_file_bytes -= (sf_struct.file_offset - saved_file_offset);
2230
    }
2231
    sf_struct.file_bytes = saved_file_bytes;
2232
  }
2233
2234
  if ((rv == 1) || ((rv == -1) && (count == 0))) {
2235
    pt_Continuation op;
2236
2237
    op.arg1.osfd = sd->secret->md.osfd;
2238
    op.arg2.buffer = &sf_struct;
2239
    op.arg4.flags = send_flags;
2240
    op.result.code = count;
2241
    op.timeout = timeout;
2242
    op.function = pt_aix_sendfile_cont;
2243
    op.event = POLLOUT | POLLPRI;
2244
    count = pt_Continue(&op);
2245
    syserrno = op.syserrno;
2246
  }
2247
2248
  if (count == -1) {
2249
    pt_MapError(_MD_aix_map_sendfile_error, syserrno);
2250
    return -1;
2251
  }
2252
  if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
2253
    PR_Close(sd);
2254
  }
2255
  PR_ASSERT(count ==
2256
            (sfd->hlen + sfd->tlen +
2257
             ((sfd->file_nbytes == 0) ? sf_struct.file_size - sfd->file_offset
2258
                                      : sfd->file_nbytes)));
2259
  return count;
2260
}
2261
#  endif /* AIX */
2262
2263
#  ifdef HPUX11
2264
/*
2265
 * pt_HPUXSendFile
2266
 *
2267
 *    Send file sfd->fd across socket sd. If specified, header and trailer
2268
 *    buffers are sent before and after the file, respectively.
2269
 *
2270
 *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
2271
 *
2272
 *    return number of bytes sent or -1 on error
2273
 *
2274
 *      This implementation takes advantage of the sendfile() system
2275
 *      call available in HP-UX B.11.00.
2276
 */
2277
2278
static PRInt32 pt_HPUXSendFile(PRFileDesc* sd, PRSendFileData* sfd,
2279
                               PRTransmitFileFlags flags,
2280
                               PRIntervalTime timeout) {
2281
  struct stat statbuf;
2282
  size_t nbytes_to_send, file_nbytes_to_send;
2283
  struct iovec hdtrl[2]; /* optional header and trailer buffers */
2284
  int send_flags;
2285
  PRInt32 count;
2286
  int syserrno;
2287
2288
  if (sfd->file_nbytes == 0) {
2289
    /* Get file size */
2290
    if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
2291
      _PR_MD_MAP_FSTAT_ERROR(errno);
2292
      return -1;
2293
    }
2294
    file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
2295
  } else {
2296
    file_nbytes_to_send = sfd->file_nbytes;
2297
  }
2298
  nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
2299
2300
  hdtrl[0].iov_base = (void*)sfd->header; /* cast away the 'const' */
2301
  hdtrl[0].iov_len = sfd->hlen;
2302
  hdtrl[1].iov_base = (void*)sfd->trailer;
2303
  hdtrl[1].iov_len = sfd->tlen;
2304
  /*
2305
   * SF_DISCONNECT seems to close the socket even if sendfile()
2306
   * only does a partial send on a nonblocking socket.  This
2307
   * would prevent the subsequent sendfile() calls on that socket
2308
   * from working.  So we don't use the SD_DISCONNECT flag.
2309
   */
2310
  send_flags = 0;
2311
2312
  do {
2313
    count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
2314
                     sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags);
2315
  } while (count == -1 && (syserrno = errno) == EINTR);
2316
2317
  if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) {
2318
    count = 0;
2319
  }
2320
  if (count != -1 && count < nbytes_to_send) {
2321
    pt_Continuation op;
2322
2323
    if (count < sfd->hlen) {
2324
      /* header not sent */
2325
2326
      hdtrl[0].iov_base = ((char*)sfd->header) + count;
2327
      hdtrl[0].iov_len = sfd->hlen - count;
2328
      op.arg3.file_spec.offset = sfd->file_offset;
2329
      op.arg3.file_spec.nbytes = file_nbytes_to_send;
2330
    } else if (count < (sfd->hlen + file_nbytes_to_send)) {
2331
      /* header sent, file not sent */
2332
2333
      hdtrl[0].iov_base = NULL;
2334
      hdtrl[0].iov_len = 0;
2335
2336
      op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen;
2337
      op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen);
2338
    } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) {
2339
      PRUint32 trailer_nbytes_sent;
2340
2341
      /* header sent, file sent, trailer not sent */
2342
2343
      hdtrl[0].iov_base = NULL;
2344
      hdtrl[0].iov_len = 0;
2345
      /*
2346
       * set file offset and len so that no more file data is
2347
       * sent
2348
       */
2349
      op.arg3.file_spec.offset = statbuf.st_size;
2350
      op.arg3.file_spec.nbytes = 0;
2351
2352
      trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send;
2353
      hdtrl[1].iov_base = ((char*)sfd->trailer) + trailer_nbytes_sent;
2354
      hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent;
2355
    }
2356
2357
    op.arg1.osfd = sd->secret->md.osfd;
2358
    op.filedesc = sfd->fd->secret->md.osfd;
2359
    op.arg2.buffer = hdtrl;
2360
    op.arg3.file_spec.st_size = statbuf.st_size;
2361
    op.arg4.flags = send_flags;
2362
    op.nbytes_to_send = nbytes_to_send - count;
2363
    op.result.code = count;
2364
    op.timeout = timeout;
2365
    op.function = pt_hpux_sendfile_cont;
2366
    op.event = POLLOUT | POLLPRI;
2367
    count = pt_Continue(&op);
2368
    syserrno = op.syserrno;
2369
  }
2370
2371
  if (count == -1) {
2372
    pt_MapError(_MD_hpux_map_sendfile_error, syserrno);
2373
    return -1;
2374
  }
2375
  if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
2376
    PR_Close(sd);
2377
  }
2378
  PR_ASSERT(count == nbytes_to_send);
2379
  return count;
2380
}
2381
2382
#  endif /* HPUX11 */
2383
2384
#  ifdef SOLARIS
2385
2386
/*
2387
 *    pt_SolarisSendFile
2388
 *
2389
 *    Send file sfd->fd across socket sd. If specified, header and trailer
2390
 *    buffers are sent before and after the file, respectively.
2391
 *
2392
 *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
2393
 *
2394
 *    return number of bytes sent or -1 on error
2395
 *
2396
 *    This implementation takes advantage of the sendfilev() system
2397
 *    call available in Solaris 8.
2398
 */
2399
2400
static PRInt32 pt_SolarisSendFile(PRFileDesc* sd, PRSendFileData* sfd,
2401
                                  PRTransmitFileFlags flags,
2402
                                  PRIntervalTime timeout) {
2403
  struct stat statbuf;
2404
  size_t nbytes_to_send, file_nbytes_to_send;
2405
  struct sendfilevec sfv_struct[3];
2406
  int sfvcnt = 0;
2407
  size_t xferred;
2408
  PRInt32 count;
2409
  int syserrno;
2410
2411
  if (sfd->file_nbytes == 0) {
2412
    /* Get file size */
2413
    if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
2414
      _PR_MD_MAP_FSTAT_ERROR(errno);
2415
      return -1;
2416
    }
2417
    file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
2418
  } else {
2419
    file_nbytes_to_send = sfd->file_nbytes;
2420
  }
2421
2422
  nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
2423
2424
  if (sfd->hlen != 0) {
2425
    sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
2426
    sfv_struct[sfvcnt].sfv_flag = 0;
2427
    sfv_struct[sfvcnt].sfv_off = (off_t)sfd->header;
2428
    sfv_struct[sfvcnt].sfv_len = sfd->hlen;
2429
    sfvcnt++;
2430
  }
2431
2432
  if (file_nbytes_to_send != 0) {
2433
    sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd;
2434
    sfv_struct[sfvcnt].sfv_flag = 0;
2435
    sfv_struct[sfvcnt].sfv_off = sfd->file_offset;
2436
    sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send;
2437
    sfvcnt++;
2438
  }
2439
2440
  if (sfd->tlen != 0) {
2441
    sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
2442
    sfv_struct[sfvcnt].sfv_flag = 0;
2443
    sfv_struct[sfvcnt].sfv_off = (off_t)sfd->trailer;
2444
    sfv_struct[sfvcnt].sfv_len = sfd->tlen;
2445
    sfvcnt++;
2446
  }
2447
2448
  if (0 == sfvcnt) {
2449
    count = 0;
2450
    goto done;
2451
  }
2452
2453
  /*
2454
   * Strictly speaking, we may have sent some bytes when the
2455
   * sendfilev() is interrupted and we should retry it from an
2456
   * updated offset.  We are not doing that here.
2457
   */
2458
  count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct, sfvcnt, &xferred);
2459
2460
  PR_ASSERT((count == -1) || (count == xferred));
2461
2462
  if (count == -1) {
2463
    syserrno = errno;
2464
    if (syserrno == EINTR || syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
2465
      count = xferred;
2466
    }
2467
  } else if (count == 0) {
2468
    /*
2469
     * We are now at EOF. The file was truncated. Solaris sendfile is
2470
     * supposed to return 0 and no error in this case, though some versions
2471
     * may return -1 and EINVAL .
2472
     */
2473
    count = -1;
2474
    syserrno = 0; /* will be treated as EOF */
2475
  }
2476
2477
  if (count != -1 && count < nbytes_to_send) {
2478
    pt_Continuation op;
2479
    struct sendfilevec* vec = sfv_struct;
2480
    PRInt32 rem = count;
2481
2482
    while (rem >= vec->sfv_len) {
2483
      rem -= vec->sfv_len;
2484
      vec++;
2485
      sfvcnt--;
2486
    }
2487
    PR_ASSERT(sfvcnt > 0);
2488
2489
    vec->sfv_off += rem;
2490
    vec->sfv_len -= rem;
2491
    PR_ASSERT(vec->sfv_len > 0);
2492
2493
    op.arg1.osfd = sd->secret->md.osfd;
2494
    op.arg2.buffer = vec;
2495
    op.arg3.amount = sfvcnt;
2496
    op.arg4.flags = 0;
2497
    op.nbytes_to_send = nbytes_to_send - count;
2498
    op.result.code = count;
2499
    op.timeout = timeout;
2500
    op.function = pt_solaris_sendfile_cont;
2501
    op.event = POLLOUT | POLLPRI;
2502
    count = pt_Continue(&op);
2503
    syserrno = op.syserrno;
2504
  }
2505
2506
done:
2507
  if (count == -1) {
2508
    pt_MapError(_MD_solaris_map_sendfile_error, syserrno);
2509
    return -1;
2510
  }
2511
  if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
2512
    PR_Close(sd);
2513
  }
2514
  PR_ASSERT(count == nbytes_to_send);
2515
  return count;
2516
}
2517
2518
#    ifndef HAVE_SENDFILEV
2519
static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT;
2520
2521
static void pt_solaris_sendfilev_init_routine(void) {
2522
  void* handle;
2523
  PRBool close_it = PR_FALSE;
2524
2525
  /*
2526
   * We do not want to unload libsendfile.so.  This handle is leaked
2527
   * intentionally.
2528
   */
2529
  handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL);
2530
  PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
2531
         ("dlopen(libsendfile.so) returns %p", handle));
2532
2533
  if (NULL == handle) {
2534
    /*
2535
     * The dlopen(0, mode) call is to allow for the possibility that
2536
     * sendfilev() may become part of a standard system library in a
2537
     * future Solaris release.
2538
     */
2539
    handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL);
2540
    PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("dlopen(0) returns %p", handle));
2541
    close_it = PR_TRUE;
2542
  }
2543
  pt_solaris_sendfilev_fptr = (ssize_t(*)())dlsym(handle, "sendfilev");
2544
  PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
2545
         ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr));
2546
2547
  if (close_it) {
2548
    dlclose(handle);
2549
  }
2550
}
2551
2552
/*
2553
 * pt_SolarisDispatchSendFile
2554
 */
2555
static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc* sd, PRSendFileData* sfd,
2556
                                          PRTransmitFileFlags flags,
2557
                                          PRIntervalTime timeout) {
2558
  int rv;
2559
2560
  rv = pthread_once(&pt_solaris_sendfilev_once_block,
2561
                    pt_solaris_sendfilev_init_routine);
2562
  PR_ASSERT(0 == rv);
2563
  if (pt_solaris_sendfilev_fptr) {
2564
    return pt_SolarisSendFile(sd, sfd, flags, timeout);
2565
  } else {
2566
    return PR_EmulateSendFile(sd, sfd, flags, timeout);
2567
  }
2568
}
2569
#    endif /* !HAVE_SENDFILEV */
2570
2571
#  endif /* SOLARIS */
2572
2573
#  ifdef LINUX
2574
/*
2575
 * pt_LinuxSendFile
2576
 *
2577
 *    Send file sfd->fd across socket sd. If specified, header and trailer
2578
 *    buffers are sent before and after the file, respectively.
2579
 *
2580
 *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
2581
 *
2582
 *    return number of bytes sent or -1 on error
2583
 *
2584
 *      This implementation takes advantage of the sendfile() system
2585
 *      call available in Linux kernel 2.2 or higher.
2586
 */
2587
2588
static PRInt32 pt_LinuxSendFile(PRFileDesc* sd, PRSendFileData* sfd,
2589
                                PRTransmitFileFlags flags,
2590
0
                                PRIntervalTime timeout) {
2591
0
  struct stat statbuf;
2592
0
  size_t file_nbytes_to_send;
2593
0
  PRInt32 count = 0;
2594
0
  ssize_t rv;
2595
0
  int syserrno;
2596
0
  off_t offset;
2597
0
  PRBool tcp_cork_enabled = PR_FALSE;
2598
0
  int tcp_cork;
2599
2600
0
  if (sfd->file_nbytes == 0) {
2601
    /* Get file size */
2602
0
    if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
2603
0
      _PR_MD_MAP_FSTAT_ERROR(errno);
2604
0
      return -1;
2605
0
    }
2606
0
    file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
2607
0
  } else {
2608
0
    file_nbytes_to_send = sfd->file_nbytes;
2609
0
  }
2610
2611
0
  if ((sfd->hlen != 0 || sfd->tlen != 0) && sd->secret->md.tcp_nodelay == 0) {
2612
0
    tcp_cork = 1;
2613
0
    if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK, &tcp_cork,
2614
0
                   sizeof tcp_cork) == 0) {
2615
0
      tcp_cork_enabled = PR_TRUE;
2616
0
    } else {
2617
0
      syserrno = errno;
2618
0
      if (syserrno != EINVAL) {
2619
0
        _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno);
2620
0
        return -1;
2621
0
      }
2622
      /*
2623
       * The most likely reason for the EINVAL error is that
2624
       * TCP_NODELAY is set (with a function other than
2625
       * PR_SetSocketOption).  This is not fatal, so we keep
2626
       * on going.
2627
       */
2628
0
      PR_LOG(_pr_io_lm, PR_LOG_WARNING,
2629
0
             ("pt_LinuxSendFile: "
2630
0
              "setsockopt(TCP_CORK) failed with EINVAL\n"));
2631
0
    }
2632
0
  }
2633
2634
0
  if (sfd->hlen != 0) {
2635
0
    count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout);
2636
0
    if (count == -1) {
2637
0
      goto failed;
2638
0
    }
2639
0
  }
2640
2641
0
  if (file_nbytes_to_send != 0) {
2642
0
    offset = sfd->file_offset;
2643
0
    do {
2644
0
      rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd, &offset,
2645
0
                    file_nbytes_to_send);
2646
0
    } while (rv == -1 && (syserrno = errno) == EINTR);
2647
0
    if (rv == -1) {
2648
0
      if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) {
2649
0
        _MD_linux_map_sendfile_error(syserrno);
2650
0
        count = -1;
2651
0
        goto failed;
2652
0
      }
2653
0
      rv = 0;
2654
0
    }
2655
0
    PR_ASSERT(rv == offset - sfd->file_offset);
2656
0
    count += rv;
2657
2658
0
    if (rv < file_nbytes_to_send) {
2659
0
      pt_Continuation op;
2660
2661
0
      op.arg1.osfd = sd->secret->md.osfd;
2662
0
      op.in_fd = sfd->fd->secret->md.osfd;
2663
0
      op.offset = offset;
2664
0
      op.count = file_nbytes_to_send - rv;
2665
0
      op.result.code = count;
2666
0
      op.timeout = timeout;
2667
0
      op.function = pt_linux_sendfile_cont;
2668
0
      op.event = POLLOUT | POLLPRI;
2669
0
      count = pt_Continue(&op);
2670
0
      syserrno = op.syserrno;
2671
0
      if (count == -1) {
2672
0
        pt_MapError(_MD_linux_map_sendfile_error, syserrno);
2673
0
        goto failed;
2674
0
      }
2675
0
    }
2676
0
  }
2677
2678
0
  if (sfd->tlen != 0) {
2679
0
    rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
2680
0
    if (rv == -1) {
2681
0
      count = -1;
2682
0
      goto failed;
2683
0
    }
2684
0
    count += rv;
2685
0
  }
2686
2687
0
failed:
2688
0
  if (tcp_cork_enabled) {
2689
0
    tcp_cork = 0;
2690
0
    if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK, &tcp_cork,
2691
0
                   sizeof tcp_cork) == -1 &&
2692
0
        count != -1) {
2693
0
      _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
2694
0
      count = -1;
2695
0
    }
2696
0
  }
2697
0
  if (count != -1) {
2698
0
    if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
2699
0
      PR_Close(sd);
2700
0
    }
2701
0
    PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send);
2702
0
  }
2703
0
  return count;
2704
0
}
2705
#  endif /* LINUX */
2706
2707
#  ifdef AIX
2708
extern int _pr_aix_send_file_use_disabled;
2709
#  endif
2710
2711
static PRInt32 pt_SendFile(PRFileDesc* sd, PRSendFileData* sfd,
2712
0
                           PRTransmitFileFlags flags, PRIntervalTime timeout) {
2713
0
  if (pt_TestAbort()) {
2714
0
    return -1;
2715
0
  }
2716
  /* The socket must be in blocking mode. */
2717
0
  if (sd->secret->nonblocking) {
2718
0
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
2719
0
    return -1;
2720
0
  }
2721
#  ifdef HPUX11
2722
  return (pt_HPUXSendFile(sd, sfd, flags, timeout));
2723
#  elif defined(AIX)
2724
#    ifdef HAVE_SEND_FILE
2725
  /*
2726
   * A bug in AIX 4.3.2 results in corruption of data transferred by
2727
   * send_file(); AIX patch PTF U463956 contains the fix.  A user can
2728
   * disable the use of send_file function in NSPR, when this patch is
2729
   * not installed on the system, by setting the envionment variable
2730
   * NSPR_AIX_SEND_FILE_USE_DISABLED to 1.
2731
   */
2732
  if (_pr_aix_send_file_use_disabled) {
2733
    return (PR_EmulateSendFile(sd, sfd, flags, timeout));
2734
  } else {
2735
    return (pt_AIXSendFile(sd, sfd, flags, timeout));
2736
  }
2737
#    else
2738
  return (PR_EmulateSendFile(sd, sfd, flags, timeout));
2739
  /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/
2740
#    endif /* HAVE_SEND_FILE */
2741
#  elif defined(SOLARIS)
2742
#    ifdef HAVE_SENDFILEV
2743
  return (pt_SolarisSendFile(sd, sfd, flags, timeout));
2744
#    else
2745
  return (pt_SolarisDispatchSendFile(sd, sfd, flags, timeout));
2746
#    endif /* HAVE_SENDFILEV */
2747
#  elif defined(LINUX)
2748
0
  return (pt_LinuxSendFile(sd, sfd, flags, timeout));
2749
#  else
2750
  return (PR_EmulateSendFile(sd, sfd, flags, timeout));
2751
#  endif
2752
0
}
2753
2754
static PRInt32 pt_TransmitFile(PRFileDesc* sd, PRFileDesc* fd,
2755
                               const void* headers, PRInt32 hlen,
2756
                               PRTransmitFileFlags flags,
2757
0
                               PRIntervalTime timeout) {
2758
0
  PRSendFileData sfd;
2759
2760
0
  sfd.fd = fd;
2761
0
  sfd.file_offset = 0;
2762
0
  sfd.file_nbytes = 0;
2763
0
  sfd.header = headers;
2764
0
  sfd.hlen = hlen;
2765
0
  sfd.trailer = NULL;
2766
0
  sfd.tlen = 0;
2767
2768
0
  return (pt_SendFile(sd, &sfd, flags, timeout));
2769
0
} /* pt_TransmitFile */
2770
2771
static PRInt32 pt_AcceptRead(PRFileDesc* sd, PRFileDesc** nd, PRNetAddr** raddr,
2772
                             void* buf, PRInt32 amount,
2773
0
                             PRIntervalTime timeout) {
2774
0
  PRInt32 rv = -1;
2775
2776
0
  if (pt_TestAbort()) {
2777
0
    return rv;
2778
0
  }
2779
  /* The socket must be in blocking mode. */
2780
0
  if (sd->secret->nonblocking) {
2781
0
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
2782
0
    return rv;
2783
0
  }
2784
2785
0
  rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
2786
0
  return rv;
2787
0
} /* pt_AcceptRead */
2788
2789
0
static PRStatus pt_GetSockName(PRFileDesc* fd, PRNetAddr* addr) {
2790
0
  PRIntn rv = -1;
2791
0
  pt_SockLen addr_len = sizeof(PRNetAddr);
2792
2793
0
  if (pt_TestAbort()) {
2794
0
    return PR_FAILURE;
2795
0
  }
2796
2797
0
  rv = getsockname(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
2798
0
  if (rv == -1) {
2799
0
    pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno);
2800
0
    return PR_FAILURE;
2801
0
  }
2802
#  ifdef _PR_HAVE_SOCKADDR_LEN
2803
  /* ignore the sa_len field of struct sockaddr */
2804
  if (addr) {
2805
    addr->raw.family = ((struct sockaddr*)addr)->sa_family;
2806
  }
2807
#  endif /* _PR_HAVE_SOCKADDR_LEN */
2808
0
#  ifdef _PR_INET6
2809
0
  if (AF_INET6 == addr->raw.family) {
2810
0
    addr->raw.family = PR_AF_INET6;
2811
0
  }
2812
0
#  endif
2813
0
  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
2814
0
  PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
2815
0
  return PR_SUCCESS;
2816
0
} /* pt_GetSockName */
2817
2818
0
static PRStatus pt_GetPeerName(PRFileDesc* fd, PRNetAddr* addr) {
2819
0
  PRIntn rv = -1;
2820
0
  pt_SockLen addr_len = sizeof(PRNetAddr);
2821
2822
0
  if (pt_TestAbort()) {
2823
0
    return PR_FAILURE;
2824
0
  }
2825
2826
0
  rv = getpeername(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
2827
2828
0
  if (rv == -1) {
2829
0
    pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno);
2830
0
    return PR_FAILURE;
2831
0
  }
2832
#  ifdef _PR_HAVE_SOCKADDR_LEN
2833
  /* ignore the sa_len field of struct sockaddr */
2834
  if (addr) {
2835
    addr->raw.family = ((struct sockaddr*)addr)->sa_family;
2836
  }
2837
#  endif /* _PR_HAVE_SOCKADDR_LEN */
2838
0
#  ifdef _PR_INET6
2839
0
  if (AF_INET6 == addr->raw.family) {
2840
0
    addr->raw.family = PR_AF_INET6;
2841
0
  }
2842
0
#  endif
2843
0
  PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
2844
0
  PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
2845
0
  return PR_SUCCESS;
2846
0
} /* pt_GetPeerName */
2847
2848
0
static PRStatus pt_GetSocketOption(PRFileDesc* fd, PRSocketOptionData* data) {
2849
0
  PRIntn rv;
2850
0
  pt_SockLen length;
2851
0
  PRInt32 level, name;
2852
2853
  /*
2854
   * PR_SockOpt_Nonblocking is a special case that does not
2855
   * translate to a getsockopt() call
2856
   */
2857
0
  if (PR_SockOpt_Nonblocking == data->option) {
2858
0
    data->value.non_blocking = fd->secret->nonblocking;
2859
0
    return PR_SUCCESS;
2860
0
  }
2861
2862
0
  rv = _PR_MapOptionName(data->option, &level, &name);
2863
0
  if (PR_SUCCESS == rv) {
2864
0
    switch (data->option) {
2865
0
      case PR_SockOpt_Linger: {
2866
0
        struct linger linger;
2867
0
        length = sizeof(linger);
2868
0
        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&linger,
2869
0
                        &length);
2870
0
        PR_ASSERT((-1 == rv) || (sizeof(linger) == length));
2871
0
        data->value.linger.polarity = (linger.l_onoff) ? PR_TRUE : PR_FALSE;
2872
0
        data->value.linger.linger = PR_SecondsToInterval(linger.l_linger);
2873
0
        break;
2874
0
      }
2875
0
      case PR_SockOpt_Reuseaddr:
2876
0
      case PR_SockOpt_Keepalive:
2877
0
      case PR_SockOpt_NoDelay:
2878
0
      case PR_SockOpt_Broadcast:
2879
0
      case PR_SockOpt_Reuseport: {
2880
0
        PRIntn value;
2881
0
        length = sizeof(PRIntn);
2882
0
        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&value,
2883
0
                        &length);
2884
0
        PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
2885
0
        data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
2886
0
        break;
2887
0
      }
2888
0
      case PR_SockOpt_McastLoopback: {
2889
0
        PRUint8 xbool;
2890
0
        length = sizeof(xbool);
2891
0
        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&xbool,
2892
0
                        &length);
2893
0
        PR_ASSERT((-1 == rv) || (sizeof(xbool) == length));
2894
0
        data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE;
2895
0
        break;
2896
0
      }
2897
0
      case PR_SockOpt_RecvBufferSize:
2898
0
      case PR_SockOpt_SendBufferSize:
2899
0
      case PR_SockOpt_MaxSegment: {
2900
0
        PRIntn value;
2901
0
        length = sizeof(PRIntn);
2902
0
        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&value,
2903
0
                        &length);
2904
0
        PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
2905
0
        data->value.recv_buffer_size = value;
2906
0
        break;
2907
0
      }
2908
0
      case PR_SockOpt_IpTimeToLive:
2909
0
      case PR_SockOpt_IpTypeOfService: {
2910
0
        length = sizeof(PRUintn);
2911
0
        rv = getsockopt(fd->secret->md.osfd, level, name,
2912
0
                        (char*)&data->value.ip_ttl, &length);
2913
0
        PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
2914
0
        break;
2915
0
      }
2916
0
      case PR_SockOpt_McastTimeToLive: {
2917
0
        PRUint8 ttl;
2918
0
        length = sizeof(ttl);
2919
0
        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&ttl, &length);
2920
0
        PR_ASSERT((-1 == rv) || (sizeof(ttl) == length));
2921
0
        data->value.mcast_ttl = ttl;
2922
0
        break;
2923
0
      }
2924
0
      case PR_SockOpt_AddMember:
2925
0
      case PR_SockOpt_DropMember: {
2926
0
        struct ip_mreq mreq;
2927
0
        length = sizeof(mreq);
2928
0
        rv =
2929
0
            getsockopt(fd->secret->md.osfd, level, name, (char*)&mreq, &length);
2930
0
        PR_ASSERT((-1 == rv) || (sizeof(mreq) == length));
2931
0
        data->value.add_member.mcaddr.inet.ip = mreq.imr_multiaddr.s_addr;
2932
0
        data->value.add_member.ifaddr.inet.ip = mreq.imr_interface.s_addr;
2933
0
        break;
2934
0
      }
2935
0
      case PR_SockOpt_McastInterface: {
2936
0
        length = sizeof(data->value.mcast_if.inet.ip);
2937
0
        rv = getsockopt(fd->secret->md.osfd, level, name,
2938
0
                        (char*)&data->value.mcast_if.inet.ip, &length);
2939
0
        PR_ASSERT((-1 == rv) ||
2940
0
                  (sizeof(data->value.mcast_if.inet.ip) == length));
2941
0
        break;
2942
0
      }
2943
0
      case PR_SockOpt_DontFrag: {
2944
#  if !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)
2945
        PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
2946
        rv = PR_FAILURE;
2947
#  else
2948
0
        PRIntn value;
2949
0
        length = sizeof(value);
2950
0
        rv = getsockopt(fd->secret->md.osfd, level, name, (char*)&value,
2951
0
                        &length);
2952
#    if defined(DARWIN)
2953
        data->value.dont_fragment = value;
2954
#    else
2955
0
        data->value.dont_fragment = (value == IP_PMTUDISC_DO) ? 1 : 0;
2956
0
#    endif
2957
0
#  endif /* !(!defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)) */
2958
0
        break;
2959
0
      }
2960
0
      default:
2961
0
        PR_NOT_REACHED("Unknown socket option");
2962
0
        break;
2963
0
    }
2964
0
    if (-1 == rv) {
2965
0
      _PR_MD_MAP_GETSOCKOPT_ERROR(errno);
2966
0
    }
2967
0
  }
2968
0
  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
2969
0
} /* pt_GetSocketOption */
2970
2971
static PRStatus pt_SetSocketOption(PRFileDesc* fd,
2972
0
                                   const PRSocketOptionData* data) {
2973
0
  PRIntn rv;
2974
0
  PRInt32 level, name;
2975
2976
  /*
2977
   * PR_SockOpt_Nonblocking is a special case that does not
2978
   * translate to a setsockopt call.
2979
   */
2980
0
  if (PR_SockOpt_Nonblocking == data->option) {
2981
0
    fd->secret->nonblocking = data->value.non_blocking;
2982
0
    return PR_SUCCESS;
2983
0
  }
2984
2985
0
  rv = _PR_MapOptionName(data->option, &level, &name);
2986
0
  if (PR_SUCCESS == rv) {
2987
0
    switch (data->option) {
2988
0
      case PR_SockOpt_Linger: {
2989
0
        struct linger linger;
2990
0
        linger.l_onoff = data->value.linger.polarity;
2991
0
        linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
2992
0
        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&linger,
2993
0
                        sizeof(linger));
2994
0
        break;
2995
0
      }
2996
0
      case PR_SockOpt_Reuseaddr:
2997
0
      case PR_SockOpt_Keepalive:
2998
0
      case PR_SockOpt_NoDelay:
2999
0
      case PR_SockOpt_Broadcast:
3000
0
      case PR_SockOpt_Reuseport: {
3001
0
        PRIntn value = (data->value.reuse_addr) ? 1 : 0;
3002
0
        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&value,
3003
0
                        sizeof(PRIntn));
3004
0
#  ifdef LINUX
3005
        /* for pt_LinuxSendFile */
3006
0
        if (name == TCP_NODELAY && rv == 0) {
3007
0
          fd->secret->md.tcp_nodelay = value;
3008
0
        }
3009
0
#  endif
3010
0
        break;
3011
0
      }
3012
0
      case PR_SockOpt_McastLoopback: {
3013
0
        PRUint8 xbool = data->value.mcast_loopback ? 1 : 0;
3014
0
        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&xbool,
3015
0
                        sizeof(xbool));
3016
0
        break;
3017
0
      }
3018
0
      case PR_SockOpt_RecvBufferSize:
3019
0
      case PR_SockOpt_SendBufferSize:
3020
0
      case PR_SockOpt_MaxSegment: {
3021
0
        PRIntn value = data->value.recv_buffer_size;
3022
0
        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&value,
3023
0
                        sizeof(PRIntn));
3024
0
        break;
3025
0
      }
3026
0
      case PR_SockOpt_IpTimeToLive:
3027
0
      case PR_SockOpt_IpTypeOfService: {
3028
0
        rv = setsockopt(fd->secret->md.osfd, level, name,
3029
0
                        (char*)&data->value.ip_ttl, sizeof(PRUintn));
3030
0
        break;
3031
0
      }
3032
0
      case PR_SockOpt_McastTimeToLive: {
3033
0
        PRUint8 ttl = data->value.mcast_ttl;
3034
0
        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&ttl,
3035
0
                        sizeof(ttl));
3036
0
        break;
3037
0
      }
3038
0
      case PR_SockOpt_AddMember:
3039
0
      case PR_SockOpt_DropMember: {
3040
0
        struct ip_mreq mreq;
3041
0
        mreq.imr_multiaddr.s_addr = data->value.add_member.mcaddr.inet.ip;
3042
0
        mreq.imr_interface.s_addr = data->value.add_member.ifaddr.inet.ip;
3043
0
        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&mreq,
3044
0
                        sizeof(mreq));
3045
0
        break;
3046
0
      }
3047
0
      case PR_SockOpt_McastInterface: {
3048
0
        rv = setsockopt(fd->secret->md.osfd, level, name,
3049
0
                        (char*)&data->value.mcast_if.inet.ip,
3050
0
                        sizeof(data->value.mcast_if.inet.ip));
3051
0
        break;
3052
0
      }
3053
0
      case PR_SockOpt_DontFrag: {
3054
#  if !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)
3055
        PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
3056
        rv = PR_FAILURE;
3057
#  else
3058
0
        PRIntn value;
3059
0
#    if defined(LINUX) || defined(ANDROID)
3060
0
        value = (data->value.dont_fragment) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
3061
#    elif defined(DARWIN)
3062
        value = data->value.dont_fragment;
3063
#    endif
3064
0
        rv = setsockopt(fd->secret->md.osfd, level, name, (char*)&value,
3065
0
                        sizeof(value));
3066
0
#  endif /* !defined(DARWIN) && !defined(LINUX) && !defined(ANDROID)) */
3067
0
        break;
3068
0
      }
3069
0
      default:
3070
0
        PR_NOT_REACHED("Unknown socket option");
3071
0
        break;
3072
0
    }
3073
0
    if (-1 == rv) {
3074
0
      _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
3075
0
    }
3076
0
  }
3077
0
  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
3078
0
} /* pt_SetSocketOption */
3079
3080
/*****************************************************************************/
3081
/****************************** I/O method objects ***************************/
3082
/*****************************************************************************/
3083
3084
static PRIOMethods _pr_file_methods = {PR_DESC_FILE,
3085
                                       pt_Close,
3086
                                       pt_Read,
3087
                                       pt_Write,
3088
                                       pt_Available_f,
3089
                                       pt_Available64_f,
3090
                                       pt_Fsync,
3091
                                       pt_Seek,
3092
                                       pt_Seek64,
3093
                                       pt_FileInfo,
3094
                                       pt_FileInfo64,
3095
                                       (PRWritevFN)_PR_InvalidInt,
3096
                                       (PRConnectFN)_PR_InvalidStatus,
3097
                                       (PRAcceptFN)_PR_InvalidDesc,
3098
                                       (PRBindFN)_PR_InvalidStatus,
3099
                                       (PRListenFN)_PR_InvalidStatus,
3100
                                       (PRShutdownFN)_PR_InvalidStatus,
3101
                                       (PRRecvFN)_PR_InvalidInt,
3102
                                       (PRSendFN)_PR_InvalidInt,
3103
                                       (PRRecvfromFN)_PR_InvalidInt,
3104
                                       (PRSendtoFN)_PR_InvalidInt,
3105
                                       pt_Poll,
3106
                                       (PRAcceptreadFN)_PR_InvalidInt,
3107
                                       (PRTransmitfileFN)_PR_InvalidInt,
3108
                                       (PRGetsocknameFN)_PR_InvalidStatus,
3109
                                       (PRGetpeernameFN)_PR_InvalidStatus,
3110
                                       (PRReservedFN)_PR_InvalidInt,
3111
                                       (PRReservedFN)_PR_InvalidInt,
3112
                                       (PRGetsocketoptionFN)_PR_InvalidStatus,
3113
                                       (PRSetsocketoptionFN)_PR_InvalidStatus,
3114
                                       (PRSendfileFN)_PR_InvalidInt,
3115
                                       (PRConnectcontinueFN)_PR_InvalidStatus,
3116
                                       (PRReservedFN)_PR_InvalidInt,
3117
                                       (PRReservedFN)_PR_InvalidInt,
3118
                                       (PRReservedFN)_PR_InvalidInt,
3119
                                       (PRReservedFN)_PR_InvalidInt};
3120
3121
static PRIOMethods _pr_pipe_methods = {PR_DESC_PIPE,
3122
                                       pt_Close,
3123
                                       pt_Read,
3124
                                       pt_Write,
3125
                                       pt_Available_s,
3126
                                       pt_Available64_s,
3127
                                       pt_Synch,
3128
                                       (PRSeekFN)_PR_InvalidInt,
3129
                                       (PRSeek64FN)_PR_InvalidInt64,
3130
                                       (PRFileInfoFN)_PR_InvalidStatus,
3131
                                       (PRFileInfo64FN)_PR_InvalidStatus,
3132
                                       (PRWritevFN)_PR_InvalidInt,
3133
                                       (PRConnectFN)_PR_InvalidStatus,
3134
                                       (PRAcceptFN)_PR_InvalidDesc,
3135
                                       (PRBindFN)_PR_InvalidStatus,
3136
                                       (PRListenFN)_PR_InvalidStatus,
3137
                                       (PRShutdownFN)_PR_InvalidStatus,
3138
                                       (PRRecvFN)_PR_InvalidInt,
3139
                                       (PRSendFN)_PR_InvalidInt,
3140
                                       (PRRecvfromFN)_PR_InvalidInt,
3141
                                       (PRSendtoFN)_PR_InvalidInt,
3142
                                       pt_Poll,
3143
                                       (PRAcceptreadFN)_PR_InvalidInt,
3144
                                       (PRTransmitfileFN)_PR_InvalidInt,
3145
                                       (PRGetsocknameFN)_PR_InvalidStatus,
3146
                                       (PRGetpeernameFN)_PR_InvalidStatus,
3147
                                       (PRReservedFN)_PR_InvalidInt,
3148
                                       (PRReservedFN)_PR_InvalidInt,
3149
                                       (PRGetsocketoptionFN)_PR_InvalidStatus,
3150
                                       (PRSetsocketoptionFN)_PR_InvalidStatus,
3151
                                       (PRSendfileFN)_PR_InvalidInt,
3152
                                       (PRConnectcontinueFN)_PR_InvalidStatus,
3153
                                       (PRReservedFN)_PR_InvalidInt,
3154
                                       (PRReservedFN)_PR_InvalidInt,
3155
                                       (PRReservedFN)_PR_InvalidInt,
3156
                                       (PRReservedFN)_PR_InvalidInt};
3157
3158
static PRIOMethods _pr_tcp_methods = {
3159
    PR_DESC_SOCKET_TCP,
3160
    pt_Close,
3161
    pt_SocketRead,
3162
    pt_SocketWrite,
3163
    pt_Available_s,
3164
    pt_Available64_s,
3165
    pt_Synch,
3166
    (PRSeekFN)_PR_InvalidInt,
3167
    (PRSeek64FN)_PR_InvalidInt64,
3168
    (PRFileInfoFN)_PR_InvalidStatus,
3169
    (PRFileInfo64FN)_PR_InvalidStatus,
3170
    pt_Writev,
3171
    pt_Connect,
3172
    pt_Accept,
3173
    pt_Bind,
3174
    pt_Listen,
3175
    pt_Shutdown,
3176
    pt_Recv,
3177
    pt_Send,
3178
    (PRRecvfromFN)_PR_InvalidInt,
3179
#  if defined(LINUX) || defined(DARWIN)
3180
    pt_TCP_SendTo, /* This is for TCP Fast Open. Linux uses SendTo function for
3181
                      this. OSX uses connectx, but we imitate Linux. */
3182
#  else
3183
    (PRSendtoFN)_PR_InvalidInt,
3184
#  endif
3185
    pt_Poll,
3186
    pt_AcceptRead,
3187
    pt_TransmitFile,
3188
    pt_GetSockName,
3189
    pt_GetPeerName,
3190
    (PRReservedFN)_PR_InvalidInt,
3191
    (PRReservedFN)_PR_InvalidInt,
3192
    pt_GetSocketOption,
3193
    pt_SetSocketOption,
3194
    pt_SendFile,
3195
    pt_ConnectContinue,
3196
    (PRReservedFN)_PR_InvalidInt,
3197
    (PRReservedFN)_PR_InvalidInt,
3198
    (PRReservedFN)_PR_InvalidInt,
3199
    (PRReservedFN)_PR_InvalidInt};
3200
3201
static PRIOMethods _pr_udp_methods = {PR_DESC_SOCKET_UDP,
3202
                                      pt_Close,
3203
                                      pt_SocketRead,
3204
                                      pt_SocketWrite,
3205
                                      pt_Available_s,
3206
                                      pt_Available64_s,
3207
                                      pt_Synch,
3208
                                      (PRSeekFN)_PR_InvalidInt,
3209
                                      (PRSeek64FN)_PR_InvalidInt64,
3210
                                      (PRFileInfoFN)_PR_InvalidStatus,
3211
                                      (PRFileInfo64FN)_PR_InvalidStatus,
3212
                                      pt_Writev,
3213
                                      pt_Connect,
3214
                                      (PRAcceptFN)_PR_InvalidDesc,
3215
                                      pt_Bind,
3216
                                      pt_Listen,
3217
                                      pt_Shutdown,
3218
                                      pt_Recv,
3219
                                      pt_Send,
3220
                                      pt_RecvFrom,
3221
                                      pt_SendTo,
3222
                                      pt_Poll,
3223
                                      (PRAcceptreadFN)_PR_InvalidInt,
3224
                                      (PRTransmitfileFN)_PR_InvalidInt,
3225
                                      pt_GetSockName,
3226
                                      pt_GetPeerName,
3227
                                      (PRReservedFN)_PR_InvalidInt,
3228
                                      (PRReservedFN)_PR_InvalidInt,
3229
                                      pt_GetSocketOption,
3230
                                      pt_SetSocketOption,
3231
                                      (PRSendfileFN)_PR_InvalidInt,
3232
                                      (PRConnectcontinueFN)_PR_InvalidStatus,
3233
                                      (PRReservedFN)_PR_InvalidInt,
3234
                                      (PRReservedFN)_PR_InvalidInt,
3235
                                      (PRReservedFN)_PR_InvalidInt,
3236
                                      (PRReservedFN)_PR_InvalidInt};
3237
3238
static PRIOMethods _pr_socketpollfd_methods = {
3239
    (PRDescType)0,
3240
    (PRCloseFN)_PR_InvalidStatus,
3241
    (PRReadFN)_PR_InvalidInt,
3242
    (PRWriteFN)_PR_InvalidInt,
3243
    (PRAvailableFN)_PR_InvalidInt,
3244
    (PRAvailable64FN)_PR_InvalidInt64,
3245
    (PRFsyncFN)_PR_InvalidStatus,
3246
    (PRSeekFN)_PR_InvalidInt,
3247
    (PRSeek64FN)_PR_InvalidInt64,
3248
    (PRFileInfoFN)_PR_InvalidStatus,
3249
    (PRFileInfo64FN)_PR_InvalidStatus,
3250
    (PRWritevFN)_PR_InvalidInt,
3251
    (PRConnectFN)_PR_InvalidStatus,
3252
    (PRAcceptFN)_PR_InvalidDesc,
3253
    (PRBindFN)_PR_InvalidStatus,
3254
    (PRListenFN)_PR_InvalidStatus,
3255
    (PRShutdownFN)_PR_InvalidStatus,
3256
    (PRRecvFN)_PR_InvalidInt,
3257
    (PRSendFN)_PR_InvalidInt,
3258
    (PRRecvfromFN)_PR_InvalidInt,
3259
    (PRSendtoFN)_PR_InvalidInt,
3260
    pt_Poll,
3261
    (PRAcceptreadFN)_PR_InvalidInt,
3262
    (PRTransmitfileFN)_PR_InvalidInt,
3263
    (PRGetsocknameFN)_PR_InvalidStatus,
3264
    (PRGetpeernameFN)_PR_InvalidStatus,
3265
    (PRReservedFN)_PR_InvalidInt,
3266
    (PRReservedFN)_PR_InvalidInt,
3267
    (PRGetsocketoptionFN)_PR_InvalidStatus,
3268
    (PRSetsocketoptionFN)_PR_InvalidStatus,
3269
    (PRSendfileFN)_PR_InvalidInt,
3270
    (PRConnectcontinueFN)_PR_InvalidStatus,
3271
    (PRReservedFN)_PR_InvalidInt,
3272
    (PRReservedFN)_PR_InvalidInt,
3273
    (PRReservedFN)_PR_InvalidInt,
3274
    (PRReservedFN)_PR_InvalidInt};
3275
3276
#  if defined(HPUX) || defined(SOLARIS) || defined(LINUX) ||     \
3277
      defined(__GNU__) || defined(__GLIBC__) || defined(AIX) ||  \
3278
      defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || \
3279
      defined(NTO) || defined(DARWIN) || defined(RISCOS)
3280
0
#    define _PR_FCNTL_FLAGS O_NONBLOCK
3281
#  else
3282
#    error "Can't determine architecture"
3283
#  endif
3284
3285
/*
3286
 * Put a Unix file descriptor in non-blocking mode.
3287
 */
3288
0
static void pt_MakeFdNonblock(PRIntn osfd) {
3289
0
  PRIntn flags;
3290
0
  flags = fcntl(osfd, F_GETFL, 0);
3291
0
  flags |= _PR_FCNTL_FLAGS;
3292
0
  (void)fcntl(osfd, F_SETFL, flags);
3293
0
}
3294
3295
/*
3296
 * Put a Unix socket fd in non-blocking mode that can
3297
 * ideally be inherited by an accepted socket.
3298
 *
3299
 * Why doesn't pt_MakeFdNonblock do?  This is to deal with
3300
 * the special case of HP-UX.  HP-UX has three kinds of
3301
 * non-blocking modes for sockets: the fcntl() O_NONBLOCK
3302
 * and O_NDELAY flags and ioctl() FIOSNBIO request.  Only
3303
 * the ioctl() FIOSNBIO form of non-blocking mode is
3304
 * inherited by an accepted socket.
3305
 *
3306
 * Other platforms just use the generic pt_MakeFdNonblock
3307
 * to put a socket in non-blocking mode.
3308
 */
3309
#  ifdef HPUX
3310
static void pt_MakeSocketNonblock(PRIntn osfd) {
3311
  PRIntn one = 1;
3312
  (void)ioctl(osfd, FIOSNBIO, &one);
3313
}
3314
#  else
3315
0
#    define pt_MakeSocketNonblock pt_MakeFdNonblock
3316
#  endif
3317
3318
static PRFileDesc* pt_SetMethods(PRIntn osfd, PRDescType type,
3319
3
                                 PRBool isAcceptedSocket, PRBool imported) {
3320
3
  PRFileDesc* fd = _PR_Getfd();
3321
3322
3
  if (fd == NULL) {
3323
0
    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
3324
3
  } else {
3325
3
    fd->secret->md.osfd = osfd;
3326
3
    fd->secret->state = _PR_FILEDESC_OPEN;
3327
3
    if (imported) {
3328
3
      fd->secret->inheritable = _PR_TRI_UNKNOWN;
3329
3
    } else {
3330
      /* By default, a Unix fd is not closed on exec. */
3331
0
#  ifdef DEBUG
3332
0
      PRIntn flags;
3333
0
      flags = fcntl(osfd, F_GETFD, 0);
3334
0
      PR_ASSERT(0 == flags);
3335
0
#  endif
3336
0
      fd->secret->inheritable = _PR_TRI_TRUE;
3337
0
    }
3338
3
    switch (type) {
3339
3
      case PR_DESC_FILE:
3340
3
        fd->methods = PR_GetFileMethods();
3341
3
        break;
3342
0
      case PR_DESC_SOCKET_TCP:
3343
0
        fd->methods = PR_GetTCPMethods();
3344
#  ifdef _PR_ACCEPT_INHERIT_NONBLOCK
3345
        if (!isAcceptedSocket) {
3346
          pt_MakeSocketNonblock(osfd);
3347
        }
3348
#  else
3349
0
        pt_MakeSocketNonblock(osfd);
3350
0
#  endif
3351
0
        break;
3352
0
      case PR_DESC_SOCKET_UDP:
3353
0
        fd->methods = PR_GetUDPMethods();
3354
0
        pt_MakeFdNonblock(osfd);
3355
0
        break;
3356
0
      case PR_DESC_PIPE:
3357
0
        fd->methods = PR_GetPipeMethods();
3358
0
        pt_MakeFdNonblock(osfd);
3359
0
        break;
3360
0
      default:
3361
0
        break;
3362
3
    }
3363
3
  }
3364
3
  return fd;
3365
3
} /* pt_SetMethods */
3366
3367
3
PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void) {
3368
3
  return &_pr_file_methods;
3369
3
} /* PR_GetFileMethods */
3370
3371
0
PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void) {
3372
0
  return &_pr_pipe_methods;
3373
0
} /* PR_GetPipeMethods */
3374
3375
0
PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void) {
3376
0
  return &_pr_tcp_methods;
3377
0
} /* PR_GetTCPMethods */
3378
3379
0
PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void) {
3380
0
  return &_pr_udp_methods;
3381
0
} /* PR_GetUDPMethods */
3382
3383
0
static const PRIOMethods* PR_GetSocketPollFdMethods(void) {
3384
0
  return &_pr_socketpollfd_methods;
3385
0
} /* PR_GetSocketPollFdMethods */
3386
3387
PR_IMPLEMENT(PRFileDesc*)
3388
0
PR_AllocFileDesc(PRInt32 osfd, const PRIOMethods* methods) {
3389
0
  PRFileDesc* fd = _PR_Getfd();
3390
3391
0
  if (NULL == fd) {
3392
0
    goto failed;
3393
0
  }
3394
3395
0
  fd->methods = methods;
3396
0
  fd->secret->md.osfd = osfd;
3397
  /* Make fd non-blocking */
3398
0
  if (osfd > 2) {
3399
    /* Don't mess around with stdin, stdout or stderr */
3400
0
    if (&_pr_tcp_methods == methods) {
3401
0
      pt_MakeSocketNonblock(osfd);
3402
0
    } else {
3403
0
      pt_MakeFdNonblock(osfd);
3404
0
    }
3405
0
  }
3406
0
  fd->secret->state = _PR_FILEDESC_OPEN;
3407
0
  fd->secret->inheritable = _PR_TRI_UNKNOWN;
3408
0
  return fd;
3409
3410
0
failed:
3411
0
  PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
3412
0
  return fd;
3413
0
} /* PR_AllocFileDesc */
3414
3415
#  if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
3416
PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc* fd);
3417
#    if defined(_PR_INET6_PROBE)
3418
extern PRBool _pr_ipv6_is_present(void);
3419
0
PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket() {
3420
0
  int osfd;
3421
3422
#      if defined(DARWIN)
3423
  /*
3424
   * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3).  IPv6 on
3425
   * lesser versions is not ready for general use (see bug 222031).
3426
   */
3427
  {
3428
    struct utsname u;
3429
    if (uname(&u) != 0 || atoi(u.release) < 7) {
3430
      return PR_FALSE;
3431
    }
3432
  }
3433
#      endif
3434
3435
  /*
3436
   * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001)
3437
   * suggests that we call open("/dev/ip6", O_RDWR) to determine
3438
   * whether IPv6 APIs and the IPv6 stack are on the system.
3439
   * Our portable test below seems to work fine, so I am using it.
3440
   */
3441
0
  osfd = socket(AF_INET6, SOCK_STREAM, 0);
3442
0
  if (osfd != -1) {
3443
0
    close(osfd);
3444
0
    return PR_TRUE;
3445
0
  }
3446
0
  return PR_FALSE;
3447
0
}
3448
#    endif /* _PR_INET6_PROBE */
3449
#  endif
3450
3451
PR_IMPLEMENT(PRFileDesc*)
3452
0
PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) {
3453
0
  PRIntn osfd;
3454
0
  PRDescType ftype;
3455
0
  PRFileDesc* fd = NULL;
3456
0
#  if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
3457
0
  PRInt32 tmp_domain = domain;
3458
0
#  endif
3459
3460
0
  if (!_pr_initialized) {
3461
0
    _PR_ImplicitInitialization();
3462
0
  }
3463
3464
0
  if (pt_TestAbort()) {
3465
0
    return NULL;
3466
0
  }
3467
3468
0
  if (PF_INET != domain && PR_AF_INET6 != domain
3469
0
#  if defined(_PR_HAVE_SDP)
3470
0
      && PR_AF_INET_SDP != domain
3471
#    if defined(SOLARIS)
3472
      && PR_AF_INET6_SDP != domain
3473
#    endif /* SOLARIS */
3474
0
#  endif   /* _PR_HAVE_SDP */
3475
0
      && PF_UNIX != domain) {
3476
0
    PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
3477
0
    return fd;
3478
0
  }
3479
0
  if (type == SOCK_STREAM) {
3480
0
    ftype = PR_DESC_SOCKET_TCP;
3481
0
  } else if (type == SOCK_DGRAM) {
3482
0
    ftype = PR_DESC_SOCKET_UDP;
3483
0
  } else {
3484
0
    (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
3485
0
    return fd;
3486
0
  }
3487
0
#  if defined(_PR_HAVE_SDP)
3488
0
#    if defined(LINUX)
3489
0
  if (PR_AF_INET_SDP == domain) {
3490
0
    domain = AF_INET_SDP;
3491
0
  }
3492
#    elif defined(SOLARIS)
3493
  if (PR_AF_INET_SDP == domain) {
3494
    domain = AF_INET;
3495
    proto = PROTO_SDP;
3496
  } else if (PR_AF_INET6_SDP == domain) {
3497
    domain = AF_INET6;
3498
    proto = PROTO_SDP;
3499
  }
3500
#    endif /* SOLARIS */
3501
0
#  endif   /* _PR_HAVE_SDP */
3502
0
#  if defined(_PR_INET6_PROBE)
3503
0
  if (PR_AF_INET6 == domain) {
3504
0
    domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
3505
0
  }
3506
#  elif defined(_PR_INET6)
3507
  if (PR_AF_INET6 == domain) {
3508
    domain = AF_INET6;
3509
  }
3510
#  else
3511
  if (PR_AF_INET6 == domain) {
3512
    domain = AF_INET;
3513
  }
3514
#  endif
3515
3516
0
  osfd = socket(domain, type, proto);
3517
0
  if (osfd == -1) {
3518
0
    pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
3519
0
  } else {
3520
#  ifdef _PR_IPV6_V6ONLY_PROBE
3521
    if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default) {
3522
      int on = 0;
3523
      (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
3524
    }
3525
#  endif
3526
0
    fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
3527
0
    if (fd == NULL) {
3528
0
      close(osfd);
3529
0
    }
3530
0
  }
3531
#  ifdef _PR_NEED_SECRET_AF
3532
  if (fd != NULL) {
3533
    fd->secret->af = domain;
3534
  }
3535
#  endif
3536
0
#  if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
3537
0
  if (fd != NULL) {
3538
    /*
3539
     * For platforms with no support for IPv6
3540
     * create layered socket for IPv4-mapped IPv6 addresses
3541
     */
3542
0
    if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
3543
0
      if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
3544
0
        PR_Close(fd);
3545
0
        fd = NULL;
3546
0
      }
3547
0
    }
3548
0
  }
3549
0
#  endif
3550
0
  return fd;
3551
0
} /* PR_Socket */
3552
3553
/*****************************************************************************/
3554
/****************************** I/O public methods ***************************/
3555
/*****************************************************************************/
3556
3557
PR_IMPLEMENT(PRFileDesc*)
3558
0
PR_OpenFile(const char* name, PRIntn flags, PRIntn mode) {
3559
0
  PRFileDesc* fd = NULL;
3560
0
  PRIntn syserrno, osfd = -1, osflags = 0;
3561
0
  ;
3562
3563
0
  if (!_pr_initialized) {
3564
0
    _PR_ImplicitInitialization();
3565
0
  }
3566
3567
0
  if (pt_TestAbort()) {
3568
0
    return NULL;
3569
0
  }
3570
3571
0
  if (flags & PR_RDONLY) {
3572
0
    osflags |= O_RDONLY;
3573
0
  }
3574
0
  if (flags & PR_WRONLY) {
3575
0
    osflags |= O_WRONLY;
3576
0
  }
3577
0
  if (flags & PR_RDWR) {
3578
0
    osflags |= O_RDWR;
3579
0
  }
3580
0
  if (flags & PR_APPEND) {
3581
0
    osflags |= O_APPEND;
3582
0
  }
3583
0
  if (flags & PR_TRUNCATE) {
3584
0
    osflags |= O_TRUNC;
3585
0
  }
3586
0
  if (flags & PR_EXCL) {
3587
0
    osflags |= O_EXCL;
3588
0
  }
3589
0
  if (flags & PR_SYNC) {
3590
0
#  if defined(O_SYNC)
3591
0
    osflags |= O_SYNC;
3592
#  elif defined(O_FSYNC)
3593
    osflags |= O_FSYNC;
3594
#  else
3595
#    error "Neither O_SYNC nor O_FSYNC is defined on this platform"
3596
#  endif
3597
0
  }
3598
3599
  /*
3600
  ** We have to hold the lock across the creation in order to
3601
  ** enforce the sematics of PR_Rename(). (see the latter for
3602
  ** more details)
3603
  */
3604
0
  if (flags & PR_CREATE_FILE) {
3605
0
    osflags |= O_CREAT;
3606
0
    if (NULL != _pr_rename_lock) {
3607
0
      PR_Lock(_pr_rename_lock);
3608
0
    }
3609
0
  }
3610
3611
0
  osfd = _md_iovector._open64(name, osflags, mode);
3612
0
  syserrno = errno;
3613
3614
0
  if ((flags & PR_CREATE_FILE) && (NULL != _pr_rename_lock)) {
3615
0
    PR_Unlock(_pr_rename_lock);
3616
0
  }
3617
3618
0
  if (osfd == -1) {
3619
0
    pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
3620
0
  } else {
3621
0
    fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE);
3622
0
    if (fd == NULL) {
3623
0
      close(osfd); /* $$$ whoops! this is bad $$$ */
3624
0
    }
3625
0
  }
3626
0
  return fd;
3627
0
} /* PR_OpenFile */
3628
3629
0
PR_IMPLEMENT(PRFileDesc*) PR_Open(const char* name, PRIntn flags, PRIntn mode) {
3630
0
  return PR_OpenFile(name, flags, mode);
3631
0
} /* PR_Open */
3632
3633
0
PR_IMPLEMENT(PRStatus) PR_Delete(const char* name) {
3634
0
  PRIntn rv = -1;
3635
3636
0
  if (!_pr_initialized) {
3637
0
    _PR_ImplicitInitialization();
3638
0
  }
3639
3640
0
  if (pt_TestAbort()) {
3641
0
    return PR_FAILURE;
3642
0
  }
3643
3644
0
  rv = unlink(name);
3645
3646
0
  if (rv == -1) {
3647
0
    pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno);
3648
0
    return PR_FAILURE;
3649
0
  }
3650
0
  return PR_SUCCESS;
3651
0
} /* PR_Delete */
3652
3653
0
PR_IMPLEMENT(PRStatus) PR_Access(const char* name, PRAccessHow how) {
3654
0
  PRIntn rv;
3655
3656
0
  if (pt_TestAbort()) {
3657
0
    return PR_FAILURE;
3658
0
  }
3659
3660
0
  switch (how) {
3661
0
    case PR_ACCESS_READ_OK:
3662
0
      rv = access(name, R_OK);
3663
0
      break;
3664
0
    case PR_ACCESS_WRITE_OK:
3665
0
      rv = access(name, W_OK);
3666
0
      break;
3667
0
    case PR_ACCESS_EXISTS:
3668
0
    default:
3669
0
      rv = access(name, F_OK);
3670
0
  }
3671
0
  if (0 == rv) {
3672
0
    return PR_SUCCESS;
3673
0
  }
3674
0
  pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno);
3675
0
  return PR_FAILURE;
3676
3677
0
} /* PR_Access */
3678
3679
0
PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char* fn, PRFileInfo* info) {
3680
0
  PRInt32 rv = _PR_MD_GETFILEINFO(fn, info);
3681
0
  return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
3682
0
} /* PR_GetFileInfo */
3683
3684
0
PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char* fn, PRFileInfo64* info) {
3685
0
  PRInt32 rv;
3686
3687
0
  if (!_pr_initialized) {
3688
0
    _PR_ImplicitInitialization();
3689
0
  }
3690
0
  rv = _PR_MD_GETFILEINFO64(fn, info);
3691
0
  return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
3692
0
} /* PR_GetFileInfo64 */
3693
3694
0
PR_IMPLEMENT(PRStatus) PR_Rename(const char* from, const char* to) {
3695
0
  PRIntn rv = -1;
3696
3697
0
  if (pt_TestAbort()) {
3698
0
    return PR_FAILURE;
3699
0
  }
3700
3701
  /*
3702
  ** We have to acquire a lock here to stiffle anybody trying to create
3703
  ** a new file at the same time. And we have to hold that lock while we
3704
  ** test to see if the file exists and do the rename. The other place
3705
  ** where the lock is held is in PR_Open() when possibly creating a
3706
  ** new file.
3707
  */
3708
3709
0
  PR_Lock(_pr_rename_lock);
3710
0
  rv = access(to, F_OK);
3711
0
  if (0 == rv) {
3712
0
    PR_SetError(PR_FILE_EXISTS_ERROR, 0);
3713
0
    rv = -1;
3714
0
  } else {
3715
0
    rv = rename(from, to);
3716
0
    if (rv == -1) {
3717
0
      pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno);
3718
0
    }
3719
0
  }
3720
0
  PR_Unlock(_pr_rename_lock);
3721
0
  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
3722
0
} /* PR_Rename */
3723
3724
0
PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir* dir) {
3725
0
  if (pt_TestAbort()) {
3726
0
    return PR_FAILURE;
3727
0
  }
3728
3729
0
  if (NULL != dir->md.d) {
3730
0
    if (closedir(dir->md.d) == -1) {
3731
0
      _PR_MD_MAP_CLOSEDIR_ERROR(errno);
3732
0
      return PR_FAILURE;
3733
0
    }
3734
0
    dir->md.d = NULL;
3735
0
    PR_DELETE(dir);
3736
0
  }
3737
0
  return PR_SUCCESS;
3738
0
} /* PR_CloseDir */
3739
3740
0
PR_IMPLEMENT(PRStatus) PR_MakeDir(const char* name, PRIntn mode) {
3741
0
  PRInt32 rv = -1;
3742
3743
0
  if (pt_TestAbort()) {
3744
0
    return PR_FAILURE;
3745
0
  }
3746
3747
  /*
3748
  ** This lock is used to enforce rename semantics as described
3749
  ** in PR_Rename.
3750
  */
3751
0
  if (NULL != _pr_rename_lock) {
3752
0
    PR_Lock(_pr_rename_lock);
3753
0
  }
3754
0
  rv = mkdir(name, mode);
3755
0
  if (-1 == rv) {
3756
0
    pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno);
3757
0
  }
3758
0
  if (NULL != _pr_rename_lock) {
3759
0
    PR_Unlock(_pr_rename_lock);
3760
0
  }
3761
3762
0
  return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
3763
0
} /* PR_Makedir */
3764
3765
0
PR_IMPLEMENT(PRStatus) PR_MkDir(const char* name, PRIntn mode) {
3766
0
  return PR_MakeDir(name, mode);
3767
0
} /* PR_Mkdir */
3768
3769
0
PR_IMPLEMENT(PRStatus) PR_RmDir(const char* name) {
3770
0
  PRInt32 rv;
3771
3772
0
  if (pt_TestAbort()) {
3773
0
    return PR_FAILURE;
3774
0
  }
3775
3776
0
  rv = rmdir(name);
3777
0
  if (0 == rv) {
3778
0
    return PR_SUCCESS;
3779
0
  }
3780
0
  pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno);
3781
0
  return PR_FAILURE;
3782
0
} /* PR_Rmdir */
3783
3784
0
PR_IMPLEMENT(PRDir*) PR_OpenDir(const char* name) {
3785
0
  DIR* osdir;
3786
0
  PRDir* dir = NULL;
3787
3788
0
  if (pt_TestAbort()) {
3789
0
    return dir;
3790
0
  }
3791
3792
0
  osdir = opendir(name);
3793
0
  if (osdir == NULL) {
3794
0
    pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno);
3795
0
  } else {
3796
0
    dir = PR_NEWZAP(PRDir);
3797
0
    if (dir) {
3798
0
      dir->md.d = osdir;
3799
0
    } else {
3800
0
      (void)closedir(osdir);
3801
0
    }
3802
0
  }
3803
0
  return dir;
3804
0
} /* PR_OpenDir */
3805
3806
static PRInt32 _pr_poll_with_poll(PRPollDesc* pds, PRIntn npds,
3807
0
                                  PRIntervalTime timeout) {
3808
0
  PRInt32 ready = 0;
3809
  /*
3810
   * For restarting poll() if it is interrupted by a signal.
3811
   * We use these variables to figure out how much time has
3812
   * elapsed and how much of the timeout still remains.
3813
   */
3814
0
  PRIntervalTime start = 0, elapsed, remaining;
3815
3816
0
  if (pt_TestAbort()) {
3817
0
    return -1;
3818
0
  }
3819
3820
0
  if (0 == npds) {
3821
0
    PR_Sleep(timeout);
3822
0
  } else {
3823
0
#  define STACK_POLL_DESC_COUNT 64
3824
0
    struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT];
3825
0
    struct pollfd* syspoll;
3826
0
    PRIntn index, msecs;
3827
3828
0
    if (npds <= STACK_POLL_DESC_COUNT) {
3829
0
      syspoll = stack_syspoll;
3830
0
    } else {
3831
0
      PRThread* me = PR_GetCurrentThread();
3832
0
      if (npds > me->syspoll_count) {
3833
0
        PR_Free(me->syspoll_list);
3834
0
        me->syspoll_list =
3835
0
            (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd));
3836
0
        if (NULL == me->syspoll_list) {
3837
0
          me->syspoll_count = 0;
3838
0
          PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
3839
0
          return -1;
3840
0
        }
3841
0
        me->syspoll_count = npds;
3842
0
      }
3843
0
      syspoll = me->syspoll_list;
3844
0
    }
3845
3846
0
    for (index = 0; index < npds; ++index) {
3847
0
      PRInt16 in_flags_read = 0, in_flags_write = 0;
3848
0
      PRInt16 out_flags_read = 0, out_flags_write = 0;
3849
3850
0
      if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) {
3851
0
        if (pds[index].in_flags & PR_POLL_READ) {
3852
0
          in_flags_read = (pds[index].fd->methods->poll)(
3853
0
              pds[index].fd, pds[index].in_flags & ~PR_POLL_WRITE,
3854
0
              &out_flags_read);
3855
0
        }
3856
0
        if (pds[index].in_flags & PR_POLL_WRITE) {
3857
0
          in_flags_write = (pds[index].fd->methods->poll)(
3858
0
              pds[index].fd, pds[index].in_flags & ~PR_POLL_READ,
3859
0
              &out_flags_write);
3860
0
        }
3861
0
        if ((0 != (in_flags_read & out_flags_read)) ||
3862
0
            (0 != (in_flags_write & out_flags_write))) {
3863
          /* this one is ready right now */
3864
0
          if (0 == ready) {
3865
            /*
3866
             * We will return without calling the system
3867
             * poll function.  So zero the out_flags
3868
             * fields of all the poll descriptors before
3869
             * this one.
3870
             */
3871
0
            int i;
3872
0
            for (i = 0; i < index; i++) {
3873
0
              pds[i].out_flags = 0;
3874
0
            }
3875
0
          }
3876
0
          ready += 1;
3877
0
          pds[index].out_flags = out_flags_read | out_flags_write;
3878
0
        } else {
3879
          /* now locate the NSPR layer at the bottom of the stack */
3880
0
          PRFileDesc* bottom =
3881
0
              PR_GetIdentitiesLayer(pds[index].fd, PR_NSPR_IO_LAYER);
3882
          /* ignore a socket without PR_NSPR_IO_LAYER available */
3883
3884
0
          pds[index].out_flags = 0; /* pre-condition */
3885
0
          if ((NULL != bottom) &&
3886
0
              (_PR_FILEDESC_OPEN == bottom->secret->state)) {
3887
0
            if (0 == ready) {
3888
0
              syspoll[index].fd = bottom->secret->md.osfd;
3889
0
              syspoll[index].events = 0;
3890
0
              if (in_flags_read & PR_POLL_READ) {
3891
0
                pds[index].out_flags |= _PR_POLL_READ_SYS_READ;
3892
0
                syspoll[index].events |= POLLIN;
3893
0
              }
3894
0
              if (in_flags_read & PR_POLL_WRITE) {
3895
0
                pds[index].out_flags |= _PR_POLL_READ_SYS_WRITE;
3896
0
                syspoll[index].events |= POLLOUT;
3897
0
              }
3898
0
              if (in_flags_write & PR_POLL_READ) {
3899
0
                pds[index].out_flags |= _PR_POLL_WRITE_SYS_READ;
3900
0
                syspoll[index].events |= POLLIN;
3901
0
              }
3902
0
              if (in_flags_write & PR_POLL_WRITE) {
3903
0
                pds[index].out_flags |= _PR_POLL_WRITE_SYS_WRITE;
3904
0
                syspoll[index].events |= POLLOUT;
3905
0
              }
3906
0
              if (pds[index].in_flags & PR_POLL_EXCEPT) {
3907
0
                syspoll[index].events |= POLLPRI;
3908
0
              }
3909
0
            }
3910
0
          } else {
3911
0
            if (0 == ready) {
3912
0
              int i;
3913
0
              for (i = 0; i < index; i++) {
3914
0
                pds[i].out_flags = 0;
3915
0
              }
3916
0
            }
3917
0
            ready += 1; /* this will cause an abrupt return */
3918
0
            pds[index].out_flags = PR_POLL_NVAL; /* bogii */
3919
0
          }
3920
0
        }
3921
0
      } else {
3922
        /* make poll() ignore this entry */
3923
0
        syspoll[index].fd = -1;
3924
0
        syspoll[index].events = 0;
3925
0
        pds[index].out_flags = 0;
3926
0
      }
3927
0
    }
3928
0
    if (0 == ready) {
3929
0
      switch (timeout) {
3930
0
        case PR_INTERVAL_NO_WAIT:
3931
0
          msecs = 0;
3932
0
          break;
3933
0
        case PR_INTERVAL_NO_TIMEOUT:
3934
0
          msecs = -1;
3935
0
          break;
3936
0
        default:
3937
0
          msecs = PR_IntervalToMilliseconds(timeout);
3938
0
          start = PR_IntervalNow();
3939
0
      }
3940
3941
0
    retry:
3942
0
      ready = poll(syspoll, npds, msecs);
3943
0
      if (-1 == ready) {
3944
0
        PRIntn oserror = errno;
3945
3946
0
        if (EINTR == oserror) {
3947
0
          if (timeout == PR_INTERVAL_NO_TIMEOUT) {
3948
0
            goto retry;
3949
0
          } else if (timeout == PR_INTERVAL_NO_WAIT) {
3950
0
            ready = 0; /* don't retry, just time out */
3951
0
          } else {
3952
0
            elapsed = (PRIntervalTime)(PR_IntervalNow() - start);
3953
0
            if (elapsed > timeout) {
3954
0
              ready = 0; /* timed out */
3955
0
            } else {
3956
0
              remaining = timeout - elapsed;
3957
0
              msecs = PR_IntervalToMilliseconds(remaining);
3958
0
              goto retry;
3959
0
            }
3960
0
          }
3961
0
        } else {
3962
0
          _PR_MD_MAP_POLL_ERROR(oserror);
3963
0
        }
3964
0
      } else if (ready > 0) {
3965
0
        for (index = 0; index < npds; ++index) {
3966
0
          PRInt16 out_flags = 0;
3967
0
          if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) {
3968
0
            if (0 != syspoll[index].revents) {
3969
0
              if (syspoll[index].revents & POLLIN) {
3970
0
                if (pds[index].out_flags & _PR_POLL_READ_SYS_READ) {
3971
0
                  out_flags |= PR_POLL_READ;
3972
0
                }
3973
0
                if (pds[index].out_flags & _PR_POLL_WRITE_SYS_READ) {
3974
0
                  out_flags |= PR_POLL_WRITE;
3975
0
                }
3976
0
              }
3977
0
              if (syspoll[index].revents & POLLOUT) {
3978
0
                if (pds[index].out_flags & _PR_POLL_READ_SYS_WRITE) {
3979
0
                  out_flags |= PR_POLL_READ;
3980
0
                }
3981
0
                if (pds[index].out_flags & _PR_POLL_WRITE_SYS_WRITE) {
3982
0
                  out_flags |= PR_POLL_WRITE;
3983
0
                }
3984
0
              }
3985
0
              if (syspoll[index].revents & POLLPRI) {
3986
0
                out_flags |= PR_POLL_EXCEPT;
3987
0
              }
3988
0
              if (syspoll[index].revents & POLLERR) {
3989
0
                out_flags |= PR_POLL_ERR;
3990
0
              }
3991
0
              if (syspoll[index].revents & POLLNVAL) {
3992
0
                out_flags |= PR_POLL_NVAL;
3993
0
              }
3994
0
              if (syspoll[index].revents & POLLHUP) {
3995
0
                out_flags |= PR_POLL_HUP;
3996
0
              }
3997
0
            }
3998
0
          }
3999
0
          pds[index].out_flags = out_flags;
4000
0
        }
4001
0
      }
4002
0
    }
4003
0
  }
4004
0
  return ready;
4005
4006
0
} /* _pr_poll_with_poll */
4007
4008
#  if defined(_PR_POLL_WITH_SELECT)
4009
/*
4010
 * HPUX report the POLLHUP event for a socket when the
4011
 * shutdown(SHUT_WR) operation is called for the remote end, even though
4012
 * the socket is still writeable. Use select(), instead of poll(), to
4013
 * workaround this problem.
4014
 */
4015
static PRInt32 _pr_poll_with_select(PRPollDesc* pds, PRIntn npds,
4016
                                    PRIntervalTime timeout) {
4017
  PRInt32 ready = 0;
4018
  /*
4019
   * For restarting select() if it is interrupted by a signal.
4020
   * We use these variables to figure out how much time has
4021
   * elapsed and how much of the timeout still remains.
4022
   */
4023
  PRIntervalTime start = 0, elapsed, remaining;
4024
4025
  if (pt_TestAbort()) {
4026
    return -1;
4027
  }
4028
4029
  if (0 == npds) {
4030
    PR_Sleep(timeout);
4031
  } else {
4032
#    define STACK_POLL_DESC_COUNT 64
4033
    int stack_selectfd[STACK_POLL_DESC_COUNT];
4034
    int* selectfd;
4035
    fd_set rd, wr, ex, *rdp = NULL, *wrp = NULL, *exp = NULL;
4036
    struct timeval tv, *tvp;
4037
    PRIntn index, msecs, maxfd = 0;
4038
4039
    if (npds <= STACK_POLL_DESC_COUNT) {
4040
      selectfd = stack_selectfd;
4041
    } else {
4042
      PRThread* me = PR_GetCurrentThread();
4043
      if (npds > me->selectfd_count) {
4044
        PR_Free(me->selectfd_list);
4045
        me->selectfd_list = (int*)PR_MALLOC(npds * sizeof(int));
4046
        if (NULL == me->selectfd_list) {
4047
          me->selectfd_count = 0;
4048
          PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
4049
          return -1;
4050
        }
4051
        me->selectfd_count = npds;
4052
      }
4053
      selectfd = me->selectfd_list;
4054
    }
4055
    FD_ZERO(&rd);
4056
    FD_ZERO(&wr);
4057
    FD_ZERO(&ex);
4058
4059
    for (index = 0; index < npds; ++index) {
4060
      PRInt16 in_flags_read = 0, in_flags_write = 0;
4061
      PRInt16 out_flags_read = 0, out_flags_write = 0;
4062
4063
      if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) {
4064
        if (pds[index].in_flags & PR_POLL_READ) {
4065
          in_flags_read = (pds[index].fd->methods->poll)(
4066
              pds[index].fd, pds[index].in_flags & ~PR_POLL_WRITE,
4067
              &out_flags_read);
4068
        }
4069
        if (pds[index].in_flags & PR_POLL_WRITE) {
4070
          in_flags_write = (pds[index].fd->methods->poll)(
4071
              pds[index].fd, pds[index].in_flags & ~PR_POLL_READ,
4072
              &out_flags_write);
4073
        }
4074
        if ((0 != (in_flags_read & out_flags_read)) ||
4075
            (0 != (in_flags_write & out_flags_write))) {
4076
          /* this one is ready right now */
4077
          if (0 == ready) {
4078
            /*
4079
             * We will return without calling the system
4080
             * poll function.  So zero the out_flags
4081
             * fields of all the poll descriptors before
4082
             * this one.
4083
             */
4084
            int i;
4085
            for (i = 0; i < index; i++) {
4086
              pds[i].out_flags = 0;
4087
            }
4088
          }
4089
          ready += 1;
4090
          pds[index].out_flags = out_flags_read | out_flags_write;
4091
        } else {
4092
          /* now locate the NSPR layer at the bottom of the stack */
4093
          PRFileDesc* bottom =
4094
              PR_GetIdentitiesLayer(pds[index].fd, PR_NSPR_IO_LAYER);
4095
          /* ignore a socket without PR_NSPR_IO_LAYER available */
4096
4097
          pds[index].out_flags = 0; /* pre-condition */
4098
          if ((NULL != bottom) &&
4099
              (_PR_FILEDESC_OPEN == bottom->secret->state)) {
4100
            if (0 == ready) {
4101
              PRBool add_to_rd = PR_FALSE;
4102
              PRBool add_to_wr = PR_FALSE;
4103
              PRBool add_to_ex = PR_FALSE;
4104
4105
              selectfd[index] = bottom->secret->md.osfd;
4106
              if (in_flags_read & PR_POLL_READ) {
4107
                pds[index].out_flags |= _PR_POLL_READ_SYS_READ;
4108
                add_to_rd = PR_TRUE;
4109
              }
4110
              if (in_flags_read & PR_POLL_WRITE) {
4111
                pds[index].out_flags |= _PR_POLL_READ_SYS_WRITE;
4112
                add_to_wr = PR_TRUE;
4113
              }
4114
              if (in_flags_write & PR_POLL_READ) {
4115
                pds[index].out_flags |= _PR_POLL_WRITE_SYS_READ;
4116
                add_to_rd = PR_TRUE;
4117
              }
4118
              if (in_flags_write & PR_POLL_WRITE) {
4119
                pds[index].out_flags |= _PR_POLL_WRITE_SYS_WRITE;
4120
                add_to_wr = PR_TRUE;
4121
              }
4122
              if (pds[index].in_flags & PR_POLL_EXCEPT) {
4123
                add_to_ex = PR_TRUE;
4124
              }
4125
              if ((selectfd[index] > maxfd) &&
4126
                  (add_to_rd || add_to_wr || add_to_ex)) {
4127
                maxfd = selectfd[index];
4128
                /*
4129
                 * If maxfd is too large to be used with
4130
                 * select, fall back to calling poll.
4131
                 */
4132
                if (maxfd >= FD_SETSIZE) {
4133
                  break;
4134
                }
4135
              }
4136
              if (add_to_rd) {
4137
                FD_SET(bottom->secret->md.osfd, &rd);
4138
                rdp = &rd;
4139
              }
4140
              if (add_to_wr) {
4141
                FD_SET(bottom->secret->md.osfd, &wr);
4142
                wrp = &wr;
4143
              }
4144
              if (add_to_ex) {
4145
                FD_SET(bottom->secret->md.osfd, &ex);
4146
                exp = &ex;
4147
              }
4148
            }
4149
          } else {
4150
            if (0 == ready) {
4151
              int i;
4152
              for (i = 0; i < index; i++) {
4153
                pds[i].out_flags = 0;
4154
              }
4155
            }
4156
            ready += 1; /* this will cause an abrupt return */
4157
            pds[index].out_flags = PR_POLL_NVAL; /* bogii */
4158
          }
4159
        }
4160
      } else {
4161
        pds[index].out_flags = 0;
4162
      }
4163
    }
4164
    if (0 == ready) {
4165
      if (maxfd >= FD_SETSIZE) {
4166
        /*
4167
         * maxfd too large to be used with select, fall back to
4168
         * calling poll
4169
         */
4170
        return (_pr_poll_with_poll(pds, npds, timeout));
4171
      }
4172
      switch (timeout) {
4173
        case PR_INTERVAL_NO_WAIT:
4174
          tv.tv_sec = 0;
4175
          tv.tv_usec = 0;
4176
          tvp = &tv;
4177
          break;
4178
        case PR_INTERVAL_NO_TIMEOUT:
4179
          tvp = NULL;
4180
          break;
4181
        default:
4182
          msecs = PR_IntervalToMilliseconds(timeout);
4183
          tv.tv_sec = msecs / PR_MSEC_PER_SEC;
4184
          tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
4185
          tvp = &tv;
4186
          start = PR_IntervalNow();
4187
      }
4188
4189
    retry:
4190
      ready = select(maxfd + 1, rdp, wrp, exp, tvp);
4191
      if (-1 == ready) {
4192
        PRIntn oserror = errno;
4193
4194
        if ((EINTR == oserror) || (EAGAIN == oserror)) {
4195
          if (timeout == PR_INTERVAL_NO_TIMEOUT) {
4196
            goto retry;
4197
          } else if (timeout == PR_INTERVAL_NO_WAIT) {
4198
            ready = 0; /* don't retry, just time out */
4199
          } else {
4200
            elapsed = (PRIntervalTime)(PR_IntervalNow() - start);
4201
            if (elapsed > timeout) {
4202
              ready = 0; /* timed out */
4203
            } else {
4204
              remaining = timeout - elapsed;
4205
              msecs = PR_IntervalToMilliseconds(remaining);
4206
              tv.tv_sec = msecs / PR_MSEC_PER_SEC;
4207
              tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
4208
              goto retry;
4209
            }
4210
          }
4211
        } else if (EBADF == oserror) {
4212
          /* find all the bad fds */
4213
          ready = 0;
4214
          for (index = 0; index < npds; ++index) {
4215
            pds[index].out_flags = 0;
4216
            if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) {
4217
              if (fcntl(selectfd[index], F_GETFL, 0) == -1) {
4218
                pds[index].out_flags = PR_POLL_NVAL;
4219
                ready++;
4220
              }
4221
            }
4222
          }
4223
        } else {
4224
          _PR_MD_MAP_SELECT_ERROR(oserror);
4225
        }
4226
      } else if (ready > 0) {
4227
        for (index = 0; index < npds; ++index) {
4228
          PRInt16 out_flags = 0;
4229
          if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) {
4230
            if (FD_ISSET(selectfd[index], &rd)) {
4231
              if (pds[index].out_flags & _PR_POLL_READ_SYS_READ) {
4232
                out_flags |= PR_POLL_READ;
4233
              }
4234
              if (pds[index].out_flags & _PR_POLL_WRITE_SYS_READ) {
4235
                out_flags |= PR_POLL_WRITE;
4236
              }
4237
            }
4238
            if (FD_ISSET(selectfd[index], &wr)) {
4239
              if (pds[index].out_flags & _PR_POLL_READ_SYS_WRITE) {
4240
                out_flags |= PR_POLL_READ;
4241
              }
4242
              if (pds[index].out_flags & _PR_POLL_WRITE_SYS_WRITE) {
4243
                out_flags |= PR_POLL_WRITE;
4244
              }
4245
            }
4246
            if (FD_ISSET(selectfd[index], &ex)) {
4247
              out_flags |= PR_POLL_EXCEPT;
4248
            }
4249
          }
4250
          pds[index].out_flags = out_flags;
4251
        }
4252
      }
4253
    }
4254
  }
4255
  return ready;
4256
4257
} /* _pr_poll_with_select */
4258
#  endif /* _PR_POLL_WITH_SELECT */
4259
4260
PR_IMPLEMENT(PRInt32)
4261
0
PR_Poll(PRPollDesc* pds, PRIntn npds, PRIntervalTime timeout) {
4262
#  if defined(_PR_POLL_WITH_SELECT)
4263
  return (_pr_poll_with_select(pds, npds, timeout));
4264
#  else
4265
0
  return (_pr_poll_with_poll(pds, npds, timeout));
4266
0
#  endif
4267
0
}
4268
4269
0
PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir* dir, PRDirFlags flags) {
4270
0
  struct dirent* dp;
4271
4272
0
  if (pt_TestAbort()) {
4273
0
    return NULL;
4274
0
  }
4275
4276
0
  for (;;) {
4277
0
    errno = 0;
4278
0
    dp = readdir(dir->md.d);
4279
0
    if (NULL == dp) {
4280
0
      pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno);
4281
0
      return NULL;
4282
0
    }
4283
0
    if ((flags & PR_SKIP_DOT) && ('.' == dp->d_name[0]) &&
4284
0
        (0 == dp->d_name[1])) {
4285
0
      continue;
4286
0
    }
4287
0
    if ((flags & PR_SKIP_DOT_DOT) && ('.' == dp->d_name[0]) &&
4288
0
        ('.' == dp->d_name[1]) && (0 == dp->d_name[2])) {
4289
0
      continue;
4290
0
    }
4291
0
    if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0])) {
4292
0
      continue;
4293
0
    }
4294
0
    break;
4295
0
  }
4296
0
  dir->d.name = dp->d_name;
4297
0
  return &dir->d;
4298
0
} /* PR_ReadDir */
4299
4300
0
PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void) {
4301
0
  PRIntn domain = PF_INET;
4302
4303
0
  return PR_Socket(domain, SOCK_DGRAM, 0);
4304
0
} /* PR_NewUDPSocket */
4305
4306
0
PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void) {
4307
0
  PRIntn domain = PF_INET;
4308
4309
0
  return PR_Socket(domain, SOCK_STREAM, 0);
4310
0
} /* PR_NewTCPSocket */
4311
4312
0
PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af) {
4313
0
  return PR_Socket(af, SOCK_DGRAM, 0);
4314
0
} /* PR_NewUDPSocket */
4315
4316
0
PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af) {
4317
0
  return PR_Socket(af, SOCK_STREAM, 0);
4318
0
} /* PR_NewTCPSocket */
4319
4320
0
PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc* fds[2]) {
4321
0
  PRInt32 osfd[2];
4322
4323
0
  if (pt_TestAbort()) {
4324
0
    return PR_FAILURE;
4325
0
  }
4326
4327
0
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) {
4328
0
    pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno);
4329
0
    return PR_FAILURE;
4330
0
  }
4331
4332
0
  fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
4333
0
  if (fds[0] == NULL) {
4334
0
    close(osfd[0]);
4335
0
    close(osfd[1]);
4336
0
    return PR_FAILURE;
4337
0
  }
4338
0
  fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
4339
0
  if (fds[1] == NULL) {
4340
0
    PR_Close(fds[0]);
4341
0
    close(osfd[1]);
4342
0
    return PR_FAILURE;
4343
0
  }
4344
0
  return PR_SUCCESS;
4345
0
} /* PR_NewTCPSocketPair */
4346
4347
PR_IMPLEMENT(PRStatus)
4348
0
PR_CreatePipe(PRFileDesc** readPipe, PRFileDesc** writePipe) {
4349
0
  int pipefd[2];
4350
4351
0
  if (pt_TestAbort()) {
4352
0
    return PR_FAILURE;
4353
0
  }
4354
4355
0
  if (pipe(pipefd) == -1) {
4356
    /* XXX map pipe error */
4357
0
    PR_SetError(PR_UNKNOWN_ERROR, errno);
4358
0
    return PR_FAILURE;
4359
0
  }
4360
0
  *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
4361
0
  if (NULL == *readPipe) {
4362
0
    close(pipefd[0]);
4363
0
    close(pipefd[1]);
4364
0
    return PR_FAILURE;
4365
0
  }
4366
0
  *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
4367
0
  if (NULL == *writePipe) {
4368
0
    PR_Close(*readPipe);
4369
0
    close(pipefd[1]);
4370
0
    return PR_FAILURE;
4371
0
  }
4372
0
  return PR_SUCCESS;
4373
0
}
4374
4375
/*
4376
** Set the inheritance attribute of a file descriptor.
4377
*/
4378
0
PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(PRFileDesc* fd, PRBool inheritable) {
4379
  /*
4380
   * Only a non-layered, NSPR file descriptor can be inherited
4381
   * by a child process.
4382
   */
4383
0
  if (fd->identity != PR_NSPR_IO_LAYER) {
4384
0
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
4385
0
    return PR_FAILURE;
4386
0
  }
4387
0
  if (fd->secret->inheritable != inheritable) {
4388
0
    if (fcntl(fd->secret->md.osfd, F_SETFD, inheritable ? 0 : FD_CLOEXEC) ==
4389
0
        -1) {
4390
0
      _PR_MD_MAP_DEFAULT_ERROR(errno);
4391
0
      return PR_FAILURE;
4392
0
    }
4393
0
    fd->secret->inheritable = (_PRTriStateBool)inheritable;
4394
0
  }
4395
0
  return PR_SUCCESS;
4396
0
}
4397
4398
/*****************************************************************************/
4399
/***************************** I/O friends methods ***************************/
4400
/*****************************************************************************/
4401
4402
0
PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd) {
4403
0
  PRFileDesc* fd;
4404
4405
0
  if (!_pr_initialized) {
4406
0
    _PR_ImplicitInitialization();
4407
0
  }
4408
0
  fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE);
4409
0
  if (NULL == fd) {
4410
0
    close(osfd);
4411
0
  }
4412
0
  return fd;
4413
0
} /* PR_ImportFile */
4414
4415
0
PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd) {
4416
0
  PRFileDesc* fd;
4417
4418
0
  if (!_pr_initialized) {
4419
0
    _PR_ImplicitInitialization();
4420
0
  }
4421
0
  fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE);
4422
0
  if (NULL == fd) {
4423
0
    close(osfd);
4424
0
  }
4425
0
  return fd;
4426
0
} /* PR_ImportPipe */
4427
4428
0
PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd) {
4429
0
  PRFileDesc* fd;
4430
4431
0
  if (!_pr_initialized) {
4432
0
    _PR_ImplicitInitialization();
4433
0
  }
4434
0
  fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE);
4435
0
  if (NULL == fd) {
4436
0
    close(osfd);
4437
0
  }
4438
#  ifdef _PR_NEED_SECRET_AF
4439
  if (NULL != fd) {
4440
    fd->secret->af = PF_INET;
4441
  }
4442
#  endif
4443
0
  return fd;
4444
0
} /* PR_ImportTCPSocket */
4445
4446
0
PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd) {
4447
0
  PRFileDesc* fd;
4448
4449
0
  if (!_pr_initialized) {
4450
0
    _PR_ImplicitInitialization();
4451
0
  }
4452
0
  fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE);
4453
0
  if (NULL == fd) {
4454
0
    close(osfd);
4455
0
  }
4456
0
  return fd;
4457
0
} /* PR_ImportUDPSocket */
4458
4459
0
PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd) {
4460
0
  PRFileDesc* fd;
4461
4462
0
  if (!_pr_initialized) {
4463
0
    _PR_ImplicitInitialization();
4464
0
  }
4465
4466
0
  fd = _PR_Getfd();
4467
4468
0
  if (fd == NULL) {
4469
0
    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
4470
0
  } else {
4471
0
    fd->secret->md.osfd = osfd;
4472
0
    fd->secret->inheritable = _PR_TRI_FALSE;
4473
0
    fd->secret->state = _PR_FILEDESC_OPEN;
4474
0
    fd->methods = PR_GetSocketPollFdMethods();
4475
0
  }
4476
4477
0
  return fd;
4478
0
} /* PR_CreateSocketPollFD */
4479
4480
0
PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc* fd) {
4481
0
  if (NULL == fd) {
4482
0
    PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
4483
0
    return PR_FAILURE;
4484
0
  }
4485
0
  fd->secret->state = _PR_FILEDESC_CLOSED;
4486
0
  _PR_Putfd(fd);
4487
0
  return PR_SUCCESS;
4488
0
} /* PR_DestroySocketPollFd */
4489
4490
0
PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc* bottom) {
4491
0
  PRInt32 osfd = -1;
4492
0
  bottom =
4493
0
      (NULL == bottom) ? NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER);
4494
0
  if (NULL == bottom) {
4495
0
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
4496
0
  } else {
4497
0
    osfd = bottom->secret->md.osfd;
4498
0
  }
4499
0
  return osfd;
4500
0
} /* PR_FileDesc2NativeHandle */
4501
4502
PR_IMPLEMENT(void)
4503
0
PR_ChangeFileDescNativeHandle(PRFileDesc* fd, PRInt32 handle) {
4504
0
  if (fd) {
4505
0
    fd->secret->md.osfd = handle;
4506
0
  }
4507
0
} /*  PR_ChangeFileDescNativeHandle*/
4508
4509
0
PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc* fd) {
4510
0
  PRStatus status = PR_SUCCESS;
4511
4512
0
  if (pt_TestAbort()) {
4513
0
    return PR_FAILURE;
4514
0
  }
4515
4516
0
  PR_Lock(_pr_flock_lock);
4517
0
  while (-1 == fd->secret->lockCount) {
4518
0
    PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
4519
0
  }
4520
0
  if (0 == fd->secret->lockCount) {
4521
0
    fd->secret->lockCount = -1;
4522
0
    PR_Unlock(_pr_flock_lock);
4523
0
    status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
4524
0
    PR_Lock(_pr_flock_lock);
4525
0
    fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0;
4526
0
    PR_NotifyAllCondVar(_pr_flock_cv);
4527
0
  } else {
4528
0
    fd->secret->lockCount += 1;
4529
0
  }
4530
0
  PR_Unlock(_pr_flock_lock);
4531
4532
0
  return status;
4533
0
} /* PR_LockFile */
4534
4535
0
PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc* fd) {
4536
0
  PRStatus status = PR_SUCCESS;
4537
4538
0
  if (pt_TestAbort()) {
4539
0
    return PR_FAILURE;
4540
0
  }
4541
4542
0
  PR_Lock(_pr_flock_lock);
4543
0
  if (0 == fd->secret->lockCount) {
4544
0
    status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
4545
0
    if (PR_SUCCESS == status) {
4546
0
      fd->secret->lockCount = 1;
4547
0
    }
4548
0
  } else {
4549
0
    fd->secret->lockCount += 1;
4550
0
  }
4551
0
  PR_Unlock(_pr_flock_lock);
4552
4553
0
  return status;
4554
0
} /* PR_TLockFile */
4555
4556
0
PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc* fd) {
4557
0
  PRStatus status = PR_SUCCESS;
4558
4559
0
  if (pt_TestAbort()) {
4560
0
    return PR_FAILURE;
4561
0
  }
4562
4563
0
  PR_Lock(_pr_flock_lock);
4564
0
  if (fd->secret->lockCount == 1) {
4565
0
    status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
4566
0
    if (PR_SUCCESS == status) {
4567
0
      fd->secret->lockCount = 0;
4568
0
    }
4569
0
  } else {
4570
0
    fd->secret->lockCount -= 1;
4571
0
  }
4572
0
  PR_Unlock(_pr_flock_lock);
4573
4574
0
  return status;
4575
0
}
4576
4577
/*
4578
 * The next two entry points should not be in the API, but they are
4579
 * defined here for historical (or hysterical) reasons.
4580
 */
4581
4582
0
PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void) {
4583
#  if defined(AIX)
4584
  return sysconf(_SC_OPEN_MAX);
4585
#  else
4586
0
  struct rlimit rlim;
4587
4588
0
  if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
4589
0
    return -1;
4590
0
  }
4591
4592
0
  return rlim.rlim_max;
4593
0
#  endif
4594
0
}
4595
4596
0
PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size) {
4597
#  if defined(AIX)
4598
  return -1;
4599
#  else
4600
0
  struct rlimit rlim;
4601
0
  PRInt32 tableMax = PR_GetSysfdTableMax();
4602
4603
0
  if (tableMax < 0) {
4604
0
    return -1;
4605
0
  }
4606
0
  rlim.rlim_max = tableMax;
4607
4608
  /* Grow as much as we can; even if too big */
4609
0
  if (rlim.rlim_max < table_size) {
4610
0
    rlim.rlim_cur = rlim.rlim_max;
4611
0
  } else {
4612
0
    rlim.rlim_cur = table_size;
4613
0
  }
4614
4615
0
  if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
4616
0
    return -1;
4617
0
  }
4618
4619
0
  return rlim.rlim_cur;
4620
0
#  endif
4621
0
}
4622
4623
/*
4624
 * PR_Stat is supported for backward compatibility; some existing Java
4625
 * code uses it.  New code should use PR_GetFileInfo.
4626
 */
4627
4628
#  ifndef NO_NSPR_10_SUPPORT
4629
0
PR_IMPLEMENT(PRInt32) PR_Stat(const char* name, struct stat* buf) {
4630
0
  static PRBool unwarned = PR_TRUE;
4631
0
  if (unwarned) {
4632
0
    unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo");
4633
0
  }
4634
4635
0
  if (pt_TestAbort()) {
4636
0
    return -1;
4637
0
  }
4638
4639
0
  if (-1 == stat(name, buf)) {
4640
0
    pt_MapError(_PR_MD_MAP_STAT_ERROR, errno);
4641
0
    return -1;
4642
0
  } else {
4643
0
    return 0;
4644
0
  }
4645
0
}
4646
#  endif /* ! NO_NSPR_10_SUPPORT */
4647
4648
0
PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set* set) {
4649
0
  static PRBool unwarned = PR_TRUE;
4650
0
  if (unwarned) {
4651
0
    unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll");
4652
0
  }
4653
0
  memset(set, 0, sizeof(PR_fd_set));
4654
0
}
4655
4656
0
PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc* fh, PR_fd_set* set) {
4657
0
  static PRBool unwarned = PR_TRUE;
4658
0
  if (unwarned) {
4659
0
    unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll");
4660
0
  }
4661
0
  PR_ASSERT(set->hsize < PR_MAX_SELECT_DESC);
4662
4663
0
  set->harray[set->hsize++] = fh;
4664
0
}
4665
4666
0
PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc* fh, PR_fd_set* set) {
4667
0
  PRUint32 index, index2;
4668
0
  static PRBool unwarned = PR_TRUE;
4669
0
  if (unwarned) {
4670
0
    unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll");
4671
0
  }
4672
4673
0
  for (index = 0; index < set->hsize; index++)
4674
0
    if (set->harray[index] == fh) {
4675
0
      for (index2 = index; index2 < (set->hsize - 1); index2++) {
4676
0
        set->harray[index2] = set->harray[index2 + 1];
4677
0
      }
4678
0
      set->hsize--;
4679
0
      break;
4680
0
    }
4681
0
}
4682
4683
0
PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc* fh, PR_fd_set* set) {
4684
0
  PRUint32 index;
4685
0
  static PRBool unwarned = PR_TRUE;
4686
0
  if (unwarned) {
4687
0
    unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll");
4688
0
  }
4689
0
  for (index = 0; index < set->hsize; index++)
4690
0
    if (set->harray[index] == fh) {
4691
0
      return 1;
4692
0
    }
4693
0
  return 0;
4694
0
}
4695
4696
0
PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set* set) {
4697
0
  static PRBool unwarned = PR_TRUE;
4698
0
  if (unwarned) {
4699
0
    unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll");
4700
0
  }
4701
0
  PR_ASSERT(set->nsize < PR_MAX_SELECT_DESC);
4702
4703
0
  set->narray[set->nsize++] = fd;
4704
0
}
4705
4706
0
PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set* set) {
4707
0
  PRUint32 index, index2;
4708
0
  static PRBool unwarned = PR_TRUE;
4709
0
  if (unwarned) {
4710
0
    unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll");
4711
0
  }
4712
4713
0
  for (index = 0; index < set->nsize; index++)
4714
0
    if (set->narray[index] == fd) {
4715
0
      for (index2 = index; index2 < (set->nsize - 1); index2++) {
4716
0
        set->narray[index2] = set->narray[index2 + 1];
4717
0
      }
4718
0
      set->nsize--;
4719
0
      break;
4720
0
    }
4721
0
}
4722
4723
0
PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set* set) {
4724
0
  PRUint32 index;
4725
0
  static PRBool unwarned = PR_TRUE;
4726
0
  if (unwarned) {
4727
0
    unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll");
4728
0
  }
4729
0
  for (index = 0; index < set->nsize; index++)
4730
0
    if (set->narray[index] == fd) {
4731
0
      return 1;
4732
0
    }
4733
0
  return 0;
4734
0
}
4735
4736
#  include <sys/types.h>
4737
#  include <sys/time.h>
4738
#  if !defined(HPUX) && !defined(LINUX) && !defined(__GNU__) && \
4739
      !defined(__GLIBC__)
4740
#    include <sys/select.h>
4741
#  endif
4742
4743
0
static PRInt32 _PR_getset(PR_fd_set* pr_set, fd_set* set) {
4744
0
  PRUint32 index;
4745
0
  PRInt32 max = 0;
4746
4747
0
  if (!pr_set) {
4748
0
    return 0;
4749
0
  }
4750
4751
0
  FD_ZERO(set);
4752
4753
  /* First set the pr file handle osfds */
4754
0
  for (index = 0; index < pr_set->hsize; index++) {
4755
0
    FD_SET(pr_set->harray[index]->secret->md.osfd, set);
4756
0
    if (pr_set->harray[index]->secret->md.osfd > max) {
4757
0
      max = pr_set->harray[index]->secret->md.osfd;
4758
0
    }
4759
0
  }
4760
  /* Second set the native osfds */
4761
0
  for (index = 0; index < pr_set->nsize; index++) {
4762
0
    FD_SET(pr_set->narray[index], set);
4763
0
    if (pr_set->narray[index] > max) {
4764
0
      max = pr_set->narray[index];
4765
0
    }
4766
0
  }
4767
0
  return max;
4768
0
}
4769
4770
0
static void _PR_setset(PR_fd_set* pr_set, fd_set* set) {
4771
0
  PRUint32 index, last_used;
4772
4773
0
  if (!pr_set) {
4774
0
    return;
4775
0
  }
4776
4777
0
  for (last_used = 0, index = 0; index < pr_set->hsize; index++) {
4778
0
    if (FD_ISSET(pr_set->harray[index]->secret->md.osfd, set)) {
4779
0
      pr_set->harray[last_used++] = pr_set->harray[index];
4780
0
    }
4781
0
  }
4782
0
  pr_set->hsize = last_used;
4783
4784
0
  for (last_used = 0, index = 0; index < pr_set->nsize; index++) {
4785
0
    if (FD_ISSET(pr_set->narray[index], set)) {
4786
0
      pr_set->narray[last_used++] = pr_set->narray[index];
4787
0
    }
4788
0
  }
4789
0
  pr_set->nsize = last_used;
4790
0
}
4791
4792
PR_IMPLEMENT(PRInt32)
4793
PR_Select(PRInt32 unused, PR_fd_set* pr_rd, PR_fd_set* pr_wr, PR_fd_set* pr_ex,
4794
0
          PRIntervalTime timeout) {
4795
0
  fd_set rd, wr, ex;
4796
0
  struct timeval tv, *tvp;
4797
0
  PRInt32 max, max_fd;
4798
0
  PRInt32 rv;
4799
  /*
4800
   * For restarting select() if it is interrupted by a Unix signal.
4801
   * We use these variables to figure out how much time has elapsed
4802
   * and how much of the timeout still remains.
4803
   */
4804
0
  PRIntervalTime start = 0, elapsed, remaining;
4805
4806
0
  static PRBool unwarned = PR_TRUE;
4807
0
  if (unwarned) {
4808
0
    unwarned = _PR_Obsolete("PR_Select", "PR_Poll");
4809
0
  }
4810
4811
0
  FD_ZERO(&rd);
4812
0
  FD_ZERO(&wr);
4813
0
  FD_ZERO(&ex);
4814
4815
0
  max_fd = _PR_getset(pr_rd, &rd);
4816
0
  max_fd = (max = _PR_getset(pr_wr, &wr)) > max_fd ? max : max_fd;
4817
0
  max_fd = (max = _PR_getset(pr_ex, &ex)) > max_fd ? max : max_fd;
4818
4819
0
  if (timeout == PR_INTERVAL_NO_TIMEOUT) {
4820
0
    tvp = NULL;
4821
0
  } else {
4822
0
    tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout);
4823
0
    tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
4824
0
        timeout - PR_SecondsToInterval(tv.tv_sec));
4825
0
    tvp = &tv;
4826
0
    start = PR_IntervalNow();
4827
0
  }
4828
4829
0
retry:
4830
0
  rv = select(max_fd + 1, (_PRSelectFdSetArg_t)&rd, (_PRSelectFdSetArg_t)&wr,
4831
0
              (_PRSelectFdSetArg_t)&ex, tvp);
4832
4833
0
  if (rv == -1 && errno == EINTR) {
4834
0
    if (timeout == PR_INTERVAL_NO_TIMEOUT) {
4835
0
      goto retry;
4836
0
    } else {
4837
0
      elapsed = (PRIntervalTime)(PR_IntervalNow() - start);
4838
0
      if (elapsed > timeout) {
4839
0
        rv = 0; /* timed out */
4840
0
      } else {
4841
0
        remaining = timeout - elapsed;
4842
0
        tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining);
4843
0
        tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
4844
0
            remaining - PR_SecondsToInterval(tv.tv_sec));
4845
0
        goto retry;
4846
0
      }
4847
0
    }
4848
0
  }
4849
4850
0
  if (rv > 0) {
4851
0
    _PR_setset(pr_rd, &rd);
4852
0
    _PR_setset(pr_wr, &wr);
4853
0
    _PR_setset(pr_ex, &ex);
4854
0
  } else if (rv == -1) {
4855
0
    pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno);
4856
0
  }
4857
0
  return rv;
4858
0
}
4859
#endif /* defined(_PR_PTHREADS) */
4860
4861
#ifdef MOZ_UNICODE
4862
/* ================ UTF16 Interfaces ================================ */
4863
PR_IMPLEMENT(PRFileDesc*)
4864
PR_OpenFileUTF16(const PRUnichar* name, PRIntn flags, PRIntn mode) {
4865
  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4866
  return NULL;
4867
}
4868
4869
PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir* dir) {
4870
  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4871
  return PR_FAILURE;
4872
}
4873
4874
PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar* name) {
4875
  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4876
  return NULL;
4877
}
4878
4879
PR_IMPLEMENT(PRDirEntryUTF16*)
4880
PR_ReadDirUTF16(PRDirUTF16* dir, PRDirFlags flags) {
4881
  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4882
  return NULL;
4883
}
4884
4885
PR_IMPLEMENT(PRStatus)
4886
PR_GetFileInfo64UTF16(const PRUnichar* fn, PRFileInfo64* info) {
4887
  PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4888
  return PR_FAILURE;
4889
}
4890
/* ================ UTF16 Interfaces ================================ */
4891
#endif /* MOZ_UNICODE */
4892
4893
/* ptio.c */