1
/* -*- Mode: C++; c-basic-offset: 4 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
15
* The Initial Developer of the Original Code is Netscape
16
* Communications Corporation. Portions created by Netscape are
17
* Copyright (C) 1998-2000 Netscape Communications Corporation. All
22
* Alternatively, the contents of this file may be used under the
23
* terms of the GNU General Public License Version 2 or later (the
24
* "GPL"), in which case the provisions of the GPL are applicable
25
* instead of those above. If you wish to allow use of your
26
* version of this file only under the terms of the GPL and not to
27
* allow others to use your version of this file under the MPL,
28
* indicate your decision by deleting the provisions above and
29
* replace them with the notice and other provisions required by
30
* the GPL. If you do not delete the provisions above, a recipient
31
* may use your version of this file under either the MPL or the
41
#include <sys/types.h>
42
#include <sys/socket.h>
44
#include <sys/ioctl.h>
47
* Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or
48
* PRInt32* pointer to a _PRSockLen_t* pointer.
50
#define _PRSockLen_t int
54
** Global lock variable used to bracket calls into rusty libraries that
55
** aren't thread safe (like libc, libX, etc).
57
static PRLock *_pr_rename_lock = NULL;
58
static PRMonitor *_pr_Xfe_mon = NULL;
64
** This is a support routine to handle "deferred" i/o on sockets.
65
** It uses "select", so it is subject to all of the BeOS limitations
66
** (only READ notification, only sockets)
72
* wait for socket i/o, periodically checking for interrupt
76
static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
77
PRIntervalTime timeout)
81
PRThread *me = _PR_MD_CURRENT_THREAD();
82
PRIntervalTime epoch, now, elapsed, remaining;
83
PRBool wait_for_remaining;
88
case PR_INTERVAL_NO_WAIT:
89
PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
91
case PR_INTERVAL_NO_TIMEOUT:
93
* This is a special case of the 'default' case below.
94
* Please see the comments there.
96
tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
100
FD_SET(osfd, &rd_wr);
101
if (fd_type == READ_FD)
102
rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
104
rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
105
if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
107
_PR_MD_MAP_SELECT_ERROR(syserror);
109
if (syserror == EBADF) {
110
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF);
112
PR_SetError(PR_UNKNOWN_ERROR, syserror);
117
if (_PR_PENDING_INTERRUPT(me)) {
118
me->flags &= ~_PR_INTERRUPT;
119
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
123
} while (rv == 0 || (rv == -1 && syserror == EINTR));
126
now = epoch = PR_IntervalNow();
131
* We block in _MD_SELECT for at most
132
* _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
133
* so that there is an upper limit on the delay
134
* before the interrupt bit is checked.
136
wait_for_remaining = PR_TRUE;
137
tv.tv_sec = PR_IntervalToSeconds(remaining);
138
if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
139
wait_for_remaining = PR_FALSE;
140
tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
143
tv.tv_usec = PR_IntervalToMicroseconds(
145
PR_SecondsToInterval(tv.tv_sec));
147
FD_SET(osfd, &rd_wr);
148
if (fd_type == READ_FD)
149
rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
151
rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
153
* we don't consider EINTR a real error
155
if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
157
_PR_MD_MAP_SELECT_ERROR(syserror);
159
if (syserror == EBADF) {
160
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF);
162
PR_SetError(PR_UNKNOWN_ERROR, syserror);
167
if (_PR_PENDING_INTERRUPT(me)) {
168
me->flags &= ~_PR_INTERRUPT;
169
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
174
* We loop again if _MD_SELECT timed out or got interrupted
175
* by a signal, and the timeout deadline has not passed yet.
177
if (rv == 0 || (rv == -1 && syserror == EINTR)) {
179
* If _MD_SELECT timed out, we know how much time
180
* we spent in blocking, so we can avoid a
181
* PR_IntervalNow() call.
184
if (wait_for_remaining) {
187
now += PR_SecondsToInterval(tv.tv_sec)
188
+ PR_MicrosecondsToInterval(tv.tv_usec);
191
now = PR_IntervalNow();
193
elapsed = (PRIntervalTime) (now - epoch);
194
if (elapsed >= timeout) {
195
PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
199
remaining = timeout - elapsed;
202
} while (rv == 0 || (rv == -1 && syserror == EINTR));
209
_MD_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRInt32 flags,
210
PRIntervalTime timeout)
212
PRInt32 osfd = fd->secret->md.osfd;
214
PRThread *me = _PR_MD_CURRENT_THREAD();
217
if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_READ) {
218
_PR_MD_MAP_RECV_ERROR(EPIPE);
225
** Gah, stupid hack. If reading a zero amount, instantly return success.
226
** BONE beta 6 returns EINVAL for reads of zero bytes, which parts of
227
** mozilla use to check for socket availability.
230
if( 0 == amount ) return(0);
233
while ((rv = recv(osfd, buf, amount, flags)) == -1) {
236
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
237
if (fd->secret->nonblocking) {
240
/* If socket was supposed to be blocking,
241
wait a while for the condition to be
243
if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
245
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
253
_PR_MD_MAP_RECV_ERROR(err);
261
_MD_recvfrom (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
262
PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
264
PRInt32 osfd = fd->secret->md.osfd;
266
PRThread *me = _PR_MD_CURRENT_THREAD();
268
while ((*addrlen = PR_NETADDR_SIZE(addr)),
269
((rv = recvfrom(osfd, buf, amount, flags,
270
(struct sockaddr *) addr,
271
(_PRSockLen_t *)addrlen)) == -1)) {
274
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
275
if (fd->secret->nonblocking) {
278
if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
281
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
289
_PR_MD_MAP_RECVFROM_ERROR(err);
293
#ifdef _PR_HAVE_SOCKADDR_LEN
295
/* ignore the sa_len field of struct sockaddr */
297
addr->raw.family = ((struct sockaddr *) addr)->sa_family;
300
#endif /* _PR_HAVE_SOCKADDR_LEN */
305
_MD_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRInt32 flags,
306
PRIntervalTime timeout)
308
PRInt32 osfd = fd->secret->md.osfd;
310
PRThread *me = _PR_MD_CURRENT_THREAD();
313
if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_WRITE)
315
_PR_MD_MAP_SEND_ERROR(EPIPE);
320
while ((rv = send(osfd, buf, amount, flags)) == -1) {
323
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
324
if (fd->secret->nonblocking) {
329
if( _PR_PENDING_INTERRUPT(me)) {
331
me->flags &= ~_PR_INTERRUPT;
332
PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
336
/* in UNIX implementations, you could do a socket_io_wait here.
337
* but since BeOS doesn't yet support WRITE notification in select,
342
#else /* BONE_VERSION */
343
if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0)
347
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
357
* optimization; if bytes sent is less than "amount" call
358
* select before returning. This is because it is likely that
359
* the next writev() call will return EWOULDBLOCK.
361
if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
362
&& (timeout != PR_INTERVAL_NO_WAIT)) {
363
if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
368
#endif /* BONE_VERSION */
371
_PR_MD_MAP_SEND_ERROR(err);
381
_MD_sendto (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
382
const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
384
PRInt32 osfd = fd->secret->md.osfd;
386
PRThread *me = _PR_MD_CURRENT_THREAD();
387
#ifdef _PR_HAVE_SOCKADDR_LEN
391
((struct sockaddr *) &addrCopy)->sa_len = addrlen;
392
((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
394
while ((rv = sendto(osfd, buf, amount, flags,
395
(struct sockaddr *) &addrCopy, addrlen)) == -1) {
397
while ((rv = sendto(osfd, buf, amount, flags,
398
(struct sockaddr *) addr, addrlen)) == -1) {
402
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
403
if (fd->secret->nonblocking) {
408
if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0)
411
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
420
_PR_MD_MAP_SENDTO_ERROR(err);
432
PRFileDesc *fd, const PRIOVec *iov,
433
PRInt32 iov_size, PRIntervalTime timeout)
436
PRThread *me = _PR_MD_CURRENT_THREAD();
437
PRInt32 index, amount = 0;
438
PRInt32 osfd = fd->secret->md.osfd;
441
* Calculate the total number of bytes to be sent; needed for
442
* optimization later.
443
* We could avoid this if this number was passed in; but it is
444
* probably not a big deal because iov_size is usually small (less than
447
if (!fd->secret->nonblocking) {
448
for (index=0; index<iov_size; index++) {
449
amount += iov[index].iov_len;
453
while ((rv = writev(osfd, (const struct iovec*)iov, iov_size)) == -1) {
455
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
456
if (fd->secret->nonblocking) {
459
if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0)
462
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
470
* optimization; if bytes sent is less than "amount" call
471
* select before returning. This is because it is likely that
472
* the next writev() call will return EWOULDBLOCK.
474
if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
475
&& (timeout != PR_INTERVAL_NO_WAIT)) {
476
if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
484
_PR_MD_MAP_WRITEV_ERROR(err);
490
#endif /* BONE_VERSION */
493
_MD_accept (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen,
494
PRIntervalTime timeout)
496
PRInt32 osfd = fd->secret->md.osfd;
498
PRThread *me = _PR_MD_CURRENT_THREAD();
500
while ((rv = accept(osfd, (struct sockaddr *) addr,
501
(_PRSockLen_t *)addrlen)) == -1) {
504
if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
505
if (fd->secret->nonblocking) {
508
/* If it's SUPPOSED to be a blocking thread, wait
509
* a while to see if the triggering condition gets
512
/* Assume that we're always using a native thread */
513
if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
515
} else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
522
_PR_MD_MAP_ACCEPT_ERROR(err);
523
} else if (addr != NULL) {
525
err = getpeername(rv, (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
528
#ifdef _PR_HAVE_SOCKADDR_LEN
530
/* Mask off the first byte of struct sockaddr (the length field) */
532
addr->raw.family = ((struct sockaddr *) addr)->sa_family;
535
#endif /* _PR_HAVE_SOCKADDR_LEN */
540
_MD_connect (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen,
541
PRIntervalTime timeout)
544
PRThread *me = _PR_MD_CURRENT_THREAD();
545
PRInt32 osfd = fd->secret->md.osfd;
548
fd->secret->md.connectValueValid = PR_FALSE;
550
#ifdef _PR_HAVE_SOCKADDR_LEN
554
((struct sockaddr *) &addrCopy)->sa_len = addrlen;
555
((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
558
/* (Copied from unix.c)
559
* We initiate the connection setup by making a nonblocking connect()
560
* call. If the connect() call fails, there are two cases we handle
562
* 1. The connect() call was interrupted by a signal. In this case
563
* we simply retry connect().
564
* 2. The NSPR socket is nonblocking and connect() fails with
565
* EINPROGRESS. We first wait until the socket becomes writable.
566
* Then we try to find out whether the connection setup succeeded
571
#ifdef _PR_HAVE_SOCKADDR_LEN
572
if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) {
574
if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) {
578
fd->secret->md.connectReturnValue = rv;
579
fd->secret->md.connectReturnError = err;
580
fd->secret->md.connectValueValid = PR_TRUE;
584
if( _PR_PENDING_INTERRUPT(me)) {
586
me->flags &= ~_PR_INTERRUPT;
587
PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
597
if(!fd->secret->nonblocking && ((err == EINPROGRESS) || (err==EAGAIN) || (err==EALREADY))) {
600
** There's no timeout on this connect, but that's not
601
** a big deal, since the connect times out anyways
602
** after 30 seconds. Just sleep for 1/10th of a second
603
** and retry until we go through or die.
606
if( _PR_PENDING_INTERRUPT(me)) {
607
me->flags &= ~_PR_INTERRUPT;
608
PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
615
if( fd->secret->nonblocking && ((err == EAGAIN) || (err == EINPROGRESS))) {
616
PR_Lock(_connectLock);
617
if (connectCount < sizeof(connectList)/sizeof(connectList[0])) {
618
connectList[connectCount].osfd = osfd;
619
memcpy(&connectList[connectCount].addr, addr, addrlen);
620
connectList[connectCount].addrlen = addrlen;
621
connectList[connectCount].timeout = timeout;
623
PR_Unlock(_connectLock);
624
_PR_MD_MAP_CONNECT_ERROR(err);
626
PR_Unlock(_connectLock);
627
PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
631
#else /* BONE_VERSION */
632
if(!fd->secret->nonblocking && (err == EINTR)) {
634
rv = socket_io_wait(osfd, WRITE_FD, timeout);
640
if (_PR_PENDING_INTERRUPT(me)) {
641
me->flags &= ~_PR_INTERRUPT;
642
PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
645
err = _MD_beos_get_nonblocking_connect_error(osfd);
647
_PR_MD_MAP_CONNECT_ERROR(err);
654
_PR_MD_MAP_CONNECT_ERROR(err);
661
_MD_bind (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
664
#ifdef _PR_HAVE_SOCKADDR_LEN
668
((struct sockaddr *) &addrCopy)->sa_len = addrlen;
669
((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
670
rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen);
672
rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen);
676
_PR_MD_MAP_BIND_ERROR(err);
683
_MD_listen (PRFileDesc *fd, PRIntn backlog)
688
/* Bug workaround! Setting listen to 0 on Be accepts no connections.
689
** On most UN*Xes this sets the default.
692
if( backlog == 0 ) backlog = 5;
695
rv = listen(fd->secret->md.osfd, backlog);
698
_PR_MD_MAP_LISTEN_ERROR(err);
705
_MD_shutdown (PRFileDesc *fd, PRIntn how)
710
if (how == PR_SHUTDOWN_SEND)
711
fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_WRITE;
712
else if (how == PR_SHUTDOWN_RCV)
713
fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_READ;
714
else if (how == PR_SHUTDOWN_BOTH) {
715
fd->secret->md.sock_state = (BE_SOCK_SHUTDOWN_WRITE | BE_SOCK_SHUTDOWN_READ);
719
#else /* BONE_VERSION */
720
rv = shutdown(fd->secret->md.osfd, how);
723
_PR_MD_MAP_SHUTDOWN_ERROR(err);
730
_MD_socketpair (int af, int type, int flags, PRInt32 *osfd)
732
return PR_NOT_IMPLEMENTED_ERROR;
736
_MD_close_socket (PRInt32 osfd)
746
_MD_getsockname (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
750
rv = getsockname(fd->secret->md.osfd,
751
(struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
752
#ifdef _PR_HAVE_SOCKADDR_LEN
754
/* ignore the sa_len field of struct sockaddr */
756
addr->raw.family = ((struct sockaddr *) addr)->sa_family;
759
#endif /* _PR_HAVE_SOCKADDR_LEN */
762
_PR_MD_MAP_GETSOCKNAME_ERROR(err);
765
return rv==0?PR_SUCCESS:PR_FAILURE;
769
_MD_getpeername (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
773
rv = getpeername(fd->secret->md.osfd,
774
(struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
776
#ifdef _PR_HAVE_SOCKADDR_LEN
778
/* ignore the sa_len field of struct sockaddr */
780
addr->raw.family = ((struct sockaddr *) addr)->sa_family;
783
#endif /* _PR_HAVE_SOCKADDR_LEN */
787
_PR_MD_MAP_GETPEERNAME_ERROR(err);
789
return rv==0?PR_SUCCESS:PR_FAILURE;
793
_MD_getsockopt (PRFileDesc *fd, PRInt32 level,
794
PRInt32 optname, char* optval, PRInt32* optlen)
798
rv = getsockopt(fd->secret->md.osfd, level, optname,
799
optval, (_PRSockLen_t *)optlen);
802
_PR_MD_MAP_GETSOCKOPT_ERROR(err);
805
return rv==0?PR_SUCCESS:PR_FAILURE;
809
_MD_setsockopt (PRFileDesc *fd, PRInt32 level,
810
PRInt32 optname, const char* optval, PRInt32 optlen)
814
rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
817
_PR_MD_MAP_SETSOCKOPT_ERROR(err);
819
return rv==0?PR_SUCCESS:PR_FAILURE;
823
_MD_accept_read (PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr,
824
void *buf, PRInt32 amount, PRIntervalTime timeout)
826
return PR_NOT_IMPLEMENTED_ERROR;
831
_MD_socket (int af, int type, int flags)
835
osfd = socket( af, type, 0 );
840
_PR_MD_MAP_SOCKET_ERROR( err );
847
_MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
851
osfd = socket(domain, type, proto);
855
_PR_MD_MAP_SOCKET_ERROR(err);
863
_MD_socketavailable (PRFileDesc *fd)
868
if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) {
869
_PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO());
874
return PR_NOT_IMPLEMENTED_ERROR;
879
_MD_get_socket_error (void)
881
return PR_NOT_IMPLEMENTED_ERROR;
885
_MD_gethostname (char *name, PRUint32 namelen)
889
rv = gethostname(name, namelen);
893
_PR_MD_MAP_GETHOSTNAME_ERROR(err);
901
_MD_beos_get_nonblocking_connect_error(PRFileDesc *fd)
906
rv = recv(fd->secret->md.osfd, NULL, 0, flags);
907
PR_ASSERT(-1 == rv || 0 == rv);
908
if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) {
911
return 0; /* no error */
915
_MD_beos_get_nonblocking_connect_error(int osfd)
917
return PR_NOT_IMPLEMENTED_ERROR;
919
// _PRSockLen_t optlen = sizeof(err);
920
// if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) {
926
#endif /* BONE_VERSION */