Coverage Report

Created: 2026-05-19 06:33

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