/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include #define OTUNIXERRORS 1 /* We want OpenTransport error codes */ #include #include // All the internet typedefs #include "macsock.h" /* from macsock library */ #include "primpl.h" void _MD_InitNetAccess() { } static void macsock_map_error(int err) { switch (err) { case EBADF: PR_SetError(PR_BAD_DESCRIPTOR_ERROR, err); break; case EADDRNOTAVAIL: PR_SetError(PR_ADDRESS_NOT_AVAILABLE_ERROR, err); break; case EINPROGRESS: PR_SetError(PR_IN_PROGRESS_ERROR, err); break; case EWOULDBLOCK: PR_SetError(PR_WOULD_BLOCK_ERROR, err); break; case ENOTSOCK: PR_SetError(PR_NOT_SOCKET_ERROR, err); break; case EAFNOSUPPORT: PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); break; case ETIMEDOUT: PR_SetError(PR_IO_TIMEOUT_ERROR, err); break; case ECONNREFUSED: PR_SetError(PR_CONNECT_REFUSED_ERROR, err); break; case ENETUNREACH: PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, err); break; case EADDRINUSE: PR_SetError(PR_ADDRESS_IN_USE_ERROR, err); break; case EFAULT: PR_SetError(PR_ACCESS_FAULT_ERROR, err); break; /* * UNIX domain sockets are not supported in NSPR */ case EACCES: PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); break; case EINTR: PR_SetError(PR_PENDING_INTERRUPT_ERROR, err); break; case EINVAL: PR_SetError(PR_INVALID_ARGUMENT_ERROR, err); break; case EIO: PR_SetError(PR_IO_ERROR, err); break; case ENOENT: PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); break; case ENXIO: PR_SetError(PR_IO_ERROR, err); break; case EPROTOTYPE: PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, err); break; default: PR_SetError(PR_UNKNOWN_ERROR, err); break; } } // Errors returned: // ENETDOWN - no MacTCP driver // EPROTONOSUPPORT - bad socket type/protocol // ENOBUFS - not enough space for another socket, or failure in socket creation routine PRInt32 _MD_socket(int domain, int type, int protocol) { int err; err = macsock_socket(domain, type, protocol); if (err == -1) { macsock_map_error(errno); return -1; } return err; } // Errors: // EBADF -- bad socket id // EFAULT -- bad address format PRInt32 _MD_bind(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen) { int err; int sID = fd->secret->md.osfd; err = macsock_bind(sID, (const struct sockaddr *)addr, addrlen); if (err == -1) { macsock_map_error(errno); return -1; } return err; } // Errors: // EBADF -- bad socket id // EOPNOTSUPP -- socket is already connected, and closing // EISCONN -- already connected // EINPROGRESS -- connecting right now PRInt32 _MD_listen(PRFileDesc *fd, PRIntn backlog) { int err; int sID = fd->secret->md.osfd; err = macsock_listen(sID, backlog); if (err == -1) { macsock_map_error(errno); return -1; } return err; } // Errors: // EBADF -- bad socket id PRInt32 _MD_getsockname(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) { int err; int sID = fd->secret->md.osfd; err = macsock_getsockname(sID, (struct sockaddr *)addr, (int *)addrlen); if (err == -1) { macsock_map_error(errno); return -1; } return err; } // Errors: // EBADF - bad socket id // ENOPROTOOPT - The option is unknown PRStatus _MD_getsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen) { int err; int sID = fd->secret->md.osfd; err = macsock_getsockopt(sID, level, optname, optval, optlen); if (err == -1) { macsock_map_error(errno); return PR_FAILURE; } return PR_SUCCESS; } // Errors: // EBADF - bad socket id // ENOTCONN - socket hasnŐt been properly created PRStatus _MD_setsockopt(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen) { int err; int sID = fd->secret->md.osfd; err = macsock_setsockopt(sID, level, optname, optval, optlen); if (err == -1) { macsock_map_error(errno); return PR_FAILURE; } return PR_SUCCESS; } PRInt32 _MD_socketavailable(PRFileDesc *fd, size_t *bytes) { int err; int sID = fd->secret->md.osfd; // Careful of the return value here. 0 => failure, 1 => success err = macsock_socketavailable(sID, bytes); if (err == 0) { _PR_MD_CURRENT_THREAD()->md.osErrCode = -1; return -1; } return 0; } PRInt32 _MD_accept(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) { #pragma unused (timeout) int err; int sID = fd->secret->md.osfd; err = macsock_accept(sID, (struct sockaddr *)addr, (int *)addrlen); if (err == -1) { macsock_map_error(errno); return -1; } return err; } // Connect // check the arguments validity // issue the connect call to the stream // Errors: // EBADF -- bad socket id, bad MacTCP stream // EAFNOSUPPORT -- bad address format // EADDRINUSE -- we are listening, or duplicate socket // EINPROGRESS -- we are connecting right now // EISCONN -- already connected // ECONNREFUSED -- other side has closed, or open has failed // EALREADY -- we are connected // EINTR -- user interrupted PRInt32 _MD_connect(PRFileDesc *fd, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) { #pragma unused (timeout) int err; int sID = fd->secret->md.osfd; err = macsock_connect(sID, (struct sockaddr *)addr, addrlen); if (err == -1) { macsock_map_error(errno); return -1; } return err; } // Errors: // EBADF - bad socket ID // ENOTCONN - no such connection PRInt32 _MD_recv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { #pragma unused (timeout) int err; int sID = fd->secret->md.osfd; err = macsock_recv(sID, buf, amount, flags); if (err == -1) { macsock_map_error(errno); return -1; } return err; } PRInt32 _MD_send(PRFileDesc *fd,const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout) { #pragma unused (timeout) int err; int sID = fd->secret->md.osfd; err = macsock_send(sID, buf, amount, flags); if (err == -1) { macsock_map_error(errno); return -1; } return err; } PRInt32 _MD_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout) { #pragma unused (timeout) int err; int sID = fd->secret->md.osfd; err = macsock_recvfrom(sID, buf, amount, flags, (struct sockaddr *)addr, (int *)addrlen); if (err == -1) { macsock_map_error(errno); return -1; } return err; } PRInt32 _MD_sendto(PRFileDesc *fd,const void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout) { #pragma unused (timeout) int err; int sID = fd->secret->md.osfd; err = macsock_sendto(sID, buf, amount, flags, (struct sockaddr *)addr, addrlen); if (err == -1) { macsock_map_error(errno); return -1; } return err; } // Errors: // EBADF -- bad socket id PRInt32 _MD_closesocket(PRInt32 osfd) { int err; int sID = osfd; err = macsock_close(sID); if (err == -1) { macsock_map_error(errno); return -1; } return err; } PRInt32 _MD_writev(PRFileDesc *fd, struct PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout) { #pragma unused (fd, iov, iov_size, timeout) PR_ASSERT(0); _PR_MD_CURRENT_THREAD()->md.osErrCode = unimpErr; return -1; } PRInt32 _MD_shutdown(PRFileDesc *fd, PRIntn how) { int err; int sID = fd->secret->md.osfd; err = macsock_shutdown(sID, how); if (err == -1) { macsock_map_error(errno); return -1; } return err; } PRStatus _MD_getpeername(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen) { int err; int sID = fd->secret->md.osfd; err = macsock_getpeername(sID, (struct sockaddr *)addr, (int *)addrlen); if (err == -1) { macsock_map_error(errno); return PR_FAILURE; } return PR_SUCCESS; } void _MD_makenonblock(PRFileDesc *fd) { int err; int sID = fd->secret->md.osfd; int optval =1; err = macsock_setsockopt(sID, SOL_SOCKET, FIONBIO, (const void *)&optval, 0); if (err == -1) { macsock_map_error(errno); } } struct hostent *gethostbyname(const char * name) { return macsock_gethostbyname((char *)name); } struct hostent *gethostbyaddr(const void *addr, int addrlen, int type) { return macsock_gethostbyaddr(addr, addrlen, type); } PRStatus _MD_gethostname(char *name, int namelen) { int err; err = macsock_gethostname(name, namelen); if (err != noErr) { macsock_map_error(err); return PR_FAILURE; } return PR_SUCCESS; } #define kIPName "ip" static struct protoent sIPProto = {kIPName, NULL, INET_IP}; static struct protoent sTCPProto = {kTCPName, NULL, INET_TCP}; static struct protoent sUDPProto = {kUDPName, NULL, INET_UDP}; struct protoent *getprotobyname(const char * name) { if (strcmp(name, kIPName) == 0) return (&sIPProto); if (strcmp(name, kTCPName) == 0) return (&sTCPProto); if (strcmp(name, kUDPName) == 0) return (&sUDPProto); ErrorExit: _PR_MD_CURRENT_THREAD()->md.osErrCode = paramErr; return NULL; } struct protoent *getprotobynumber(int number) { if (number == INET_IP) return (&sIPProto); if (number == INET_TCP) return (&sTCPProto); if (number == INET_UDP) return (&sUDPProto); ErrorExit: _PR_MD_CURRENT_THREAD()->md.osErrCode = paramErr; return NULL; } PRInt32 _MD_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) { PRInt32 osfd; fd_set rd, wt, ex; PRFileDesc *bottom; PRPollDesc *pd, *epd; PRInt32 ready, maxfd = -1; PRInt16 in_flags, out_flags; struct timeval tv, *tvp = NULL; FD_ZERO(&rd); FD_ZERO(&wt); FD_ZERO(&ex); for (pd = pds, epd = pd + npds; pd < epd; pd++) { if (NULL == pd->fd) continue; in_flags = (bottom->methods->poll)(pd->fd, pd->in_flags, &pd->out_flags); if (0 != (in_flags & pd->out_flags)) ready += 1; else { bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); PR_ASSERT(NULL != bottom); osfd = bottom->secret->md.osfd; if (osfd > maxfd) maxfd = osfd; if (in_flags & PR_POLL_READ) FD_SET(osfd, &rd); if (in_flags & PR_POLL_WRITE) FD_SET(osfd, &wt); if (in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); } } if (timeout != PR_INTERVAL_NO_TIMEOUT) { PRInt32 ticksPerSecond = PR_TicksPerSecond(); tv.tv_sec = timeout / ticksPerSecond; tv.tv_usec = timeout - (ticksPerSecond * tv.tv_sec); tv.tv_usec = (PR_USEC_PER_SEC * tv.tv_usec) / ticksPerSecond; tvp = &tv; } ready = select(maxfd + 1, &rd, &wt, &ex, tvp); if (ready > 0) { ready = 0; for (pd = pds, epd = pd + npds; pd < epd; pd++) { out_flags = 0; in_flags = pd->in_flags; if ((NULL == pd->fd) || (0 == in_flags)) continue; bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); osfd = bottom->secret->md.osfd; if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; else if (FD_ISSET(osfd, &rd) || FD_ISSET(osfd, &wt)) out_flags = pd->in_flags & (PR_POLL_READ | PR_POLL_WRITE); pd->out_flags = out_flags; if (out_flags) ready++; } /* Can't do this assert because MacSock returns write fds even if we did not set it in the original write fd set. */ /*PR_ASSERT(ready > 0);*/ } else PR_ASSERT(ready == 0); return ready; } int _MD_mac_get_nonblocking_connect_error(int osfd) { int err; err = macsock_getconnectstatus (osfd); if (err == -1) { macsock_map_error(errno); return -1; } return err; }