123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752 |
- /* SPDX-License-Identifier: MPL-1.1 OR GPL-2.0-or-later */
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is the Netscape Portable Runtime library.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1994-2000 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s): Silicon Graphics, Inc.
- *
- * Portions created by SGI are Copyright (C) 2000-2001 Silicon
- * Graphics, Inc. All Rights Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
- /*
- * This file is derived directly from Netscape Communications Corporation,
- * and consists of extensive modifications made during the year(s) 1999-2000.
- */
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <sys/uio.h>
- #include <sys/time.h>
- #include <sys/resource.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <errno.h>
- #include "common.h"
- // Global stat.
- #if defined(DEBUG) && defined(DEBUG_STATS)
- __thread unsigned long long _st_stat_recvfrom = 0;
- __thread unsigned long long _st_stat_recvfrom_eagain = 0;
- __thread unsigned long long _st_stat_sendto = 0;
- __thread unsigned long long _st_stat_sendto_eagain = 0;
- __thread unsigned long long _st_stat_read = 0;
- __thread unsigned long long _st_stat_read_eagain = 0;
- __thread unsigned long long _st_stat_readv = 0;
- __thread unsigned long long _st_stat_readv_eagain = 0;
- __thread unsigned long long _st_stat_writev = 0;
- __thread unsigned long long _st_stat_writev_eagain = 0;
- __thread unsigned long long _st_stat_recvmsg = 0;
- __thread unsigned long long _st_stat_recvmsg_eagain = 0;
- __thread unsigned long long _st_stat_sendmsg = 0;
- __thread unsigned long long _st_stat_sendmsg_eagain = 0;
- #endif
- #if EAGAIN != EWOULDBLOCK
- #define _IO_NOT_READY_ERROR ((errno == EAGAIN) || (errno == EWOULDBLOCK))
- #else
- #define _IO_NOT_READY_ERROR (errno == EAGAIN)
- #endif
- #define _LOCAL_MAXIOV 16
- /* File descriptor object free list */
- static __thread _st_netfd_t *_st_netfd_freelist = NULL;
- /* Maximum number of file descriptors that the process can open */
- static int _st_osfd_limit = -1;
- static void _st_netfd_free_aux_data(_st_netfd_t *fd);
- int _st_io_init(void)
- {
- struct sigaction sigact;
- struct rlimit rlim;
- int fdlim;
- /* Ignore SIGPIPE */
- sigact.sa_handler = SIG_IGN;
- sigemptyset(&sigact.sa_mask);
- sigact.sa_flags = 0;
- if (sigaction(SIGPIPE, &sigact, NULL) < 0)
- return -1;
- /* Set maximum number of open file descriptors */
- if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
- return -1;
- fdlim = (*_st_eventsys->fd_getlimit)();
- if (fdlim > 0 && rlim.rlim_max > (rlim_t) fdlim) {
- rlim.rlim_max = fdlim;
- }
-
- /**
- * by SRS, for osx.
- * when rlimit max is negative, for example, osx, use cur directly.
- * @see https://github.com/ossrs/srs/issues/336
- */
- if ((int)rlim.rlim_max < 0) {
- _st_osfd_limit = (int)(fdlim > 0? fdlim : rlim.rlim_cur);
- return 0;
- }
-
- rlim.rlim_cur = rlim.rlim_max;
- if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
- return -1;
- _st_osfd_limit = (int) rlim.rlim_max;
- return 0;
- }
- int st_getfdlimit(void)
- {
- return _st_osfd_limit;
- }
- void st_netfd_free(_st_netfd_t *fd)
- {
- if (!fd->inuse)
- return;
- fd->inuse = 0;
- if (fd->aux_data)
- _st_netfd_free_aux_data(fd);
- if (fd->private_data && fd->destructor)
- (*(fd->destructor))(fd->private_data);
- fd->private_data = NULL;
- fd->destructor = NULL;
- fd->next = _st_netfd_freelist;
- _st_netfd_freelist = fd;
- }
- static _st_netfd_t *_st_netfd_new(int osfd, int nonblock, int is_socket)
- {
- _st_netfd_t *fd;
- int flags = 1;
- if ((*_st_eventsys->fd_new)(osfd) < 0)
- return NULL;
- if (_st_netfd_freelist) {
- fd = _st_netfd_freelist;
- _st_netfd_freelist = _st_netfd_freelist->next;
- } else {
- fd = calloc(1, sizeof(_st_netfd_t));
- if (!fd)
- return NULL;
- }
- fd->osfd = osfd;
- fd->inuse = 1;
- fd->next = NULL;
-
- if (nonblock) {
- /* Use just one system call */
- if (is_socket && ioctl(osfd, FIONBIO, &flags) != -1)
- return fd;
- /* Do it the Posix way */
- if ((flags = fcntl(osfd, F_GETFL, 0)) < 0 ||
- fcntl(osfd, F_SETFL, flags | O_NONBLOCK) < 0) {
- st_netfd_free(fd);
- return NULL;
- }
- }
- return fd;
- }
- _st_netfd_t *st_netfd_open(int osfd)
- {
- return _st_netfd_new(osfd, 1, 0);
- }
- _st_netfd_t *st_netfd_open_socket(int osfd)
- {
- return _st_netfd_new(osfd, 1, 1);
- }
- int st_netfd_close(_st_netfd_t *fd)
- {
- if ((*_st_eventsys->fd_close)(fd->osfd) < 0)
- return -1;
-
- st_netfd_free(fd);
- return close(fd->osfd);
- }
- int st_netfd_fileno(_st_netfd_t *fd)
- {
- return (fd->osfd);
- }
- void st_netfd_setspecific(_st_netfd_t *fd, void *value, _st_destructor_t destructor)
- {
- if (value != fd->private_data) {
- /* Free up previously set non-NULL data value */
- if (fd->private_data && fd->destructor)
- (*(fd->destructor))(fd->private_data);
- }
- fd->private_data = value;
- fd->destructor = destructor;
- }
- void *st_netfd_getspecific(_st_netfd_t *fd)
- {
- return (fd->private_data);
- }
- /*
- * Wait for I/O on a single descriptor.
- */
- int st_netfd_poll(_st_netfd_t *fd, int how, st_utime_t timeout)
- {
- struct pollfd pd;
- int n;
-
- pd.fd = fd->osfd;
- pd.events = (short) how;
- pd.revents = 0;
-
- if ((n = st_poll(&pd, 1, timeout)) < 0)
- return -1;
- if (n == 0) {
- /* Timed out */
- errno = ETIME;
- return -1;
- }
- if (pd.revents & POLLNVAL) {
- errno = EBADF;
- return -1;
- }
-
- return 0;
- }
- /* No-op */
- int st_netfd_serialize_accept(_st_netfd_t *fd)
- {
- fd->aux_data = NULL;
- return 0;
- }
- /* No-op */
- static void _st_netfd_free_aux_data(_st_netfd_t *fd)
- {
- fd->aux_data = NULL;
- }
- _st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout)
- {
- int osfd, err;
- _st_netfd_t *newfd;
-
- while ((osfd = accept(fd->osfd, addr, (socklen_t *)addrlen)) < 0) {
- if (errno == EINTR)
- continue;
- if (!_IO_NOT_READY_ERROR)
- return NULL;
- /* Wait until the socket becomes readable */
- if (st_netfd_poll(fd, POLLIN, timeout) < 0)
- return NULL;
- }
-
- /* On some platforms the new socket created by accept() inherits */
- /* the nonblocking attribute of the listening socket */
- #if defined (MD_ACCEPT_NB_INHERITED)
- newfd = _st_netfd_new(osfd, 0, 1);
- #elif defined (MD_ACCEPT_NB_NOT_INHERITED)
- newfd = _st_netfd_new(osfd, 1, 1);
- #else
- #error Unknown OS
- #endif
-
- if (!newfd) {
- err = errno;
- close(osfd);
- errno = err;
- }
-
- return newfd;
- }
- int st_connect(_st_netfd_t *fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout)
- {
- int n, err = 0;
-
- while (connect(fd->osfd, addr, addrlen) < 0) {
- if (errno != EINTR) {
- /*
- * On some platforms, if connect() is interrupted (errno == EINTR)
- * after the kernel binds the socket, a subsequent connect()
- * attempt will fail with errno == EADDRINUSE. Ignore EADDRINUSE
- * iff connect() was previously interrupted. See Rich Stevens'
- * "UNIX Network Programming," Vol. 1, 2nd edition, p. 413
- * ("Interrupted connect").
- */
- if (errno != EINPROGRESS && (errno != EADDRINUSE || err == 0))
- return -1;
- /* Wait until the socket becomes writable */
- if (st_netfd_poll(fd, POLLOUT, timeout) < 0)
- return -1;
- /* Try to find out whether the connection setup succeeded or failed */
- n = sizeof(int);
- if (getsockopt(fd->osfd, SOL_SOCKET, SO_ERROR, (char *)&err, (socklen_t *)&n) < 0)
- return -1;
- if (err) {
- errno = err;
- return -1;
- }
- break;
- }
- err = 1;
- }
-
- return 0;
- }
- ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout)
- {
- ssize_t n;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_read;
- #endif
-
- while ((n = read(fd->osfd, buf, nbyte)) < 0) {
- if (errno == EINTR)
- continue;
- if (!_IO_NOT_READY_ERROR)
- return -1;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_read_eagain;
- #endif
- /* Wait until the socket becomes readable */
- if (st_netfd_poll(fd, POLLIN, timeout) < 0)
- return -1;
- }
-
- return n;
- }
- int st_read_resid(_st_netfd_t *fd, void *buf, size_t *resid, st_utime_t timeout)
- {
- struct iovec iov, *riov;
- int riov_size, rv;
-
- iov.iov_base = buf;
- iov.iov_len = *resid;
- riov = &iov;
- riov_size = 1;
- rv = st_readv_resid(fd, &riov, &riov_size, timeout);
- *resid = iov.iov_len;
- return rv;
- }
- ssize_t st_readv(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout)
- {
- ssize_t n;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_readv;
- #endif
-
- while ((n = readv(fd->osfd, iov, iov_size)) < 0) {
- if (errno == EINTR)
- continue;
- if (!_IO_NOT_READY_ERROR)
- return -1;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_readv_eagain;
- #endif
- /* Wait until the socket becomes readable */
- if (st_netfd_poll(fd, POLLIN, timeout) < 0)
- return -1;
- }
-
- return n;
- }
- int st_readv_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout)
- {
- ssize_t n;
-
- while (*iov_size > 0) {
- if (*iov_size == 1)
- n = read(fd->osfd, (*iov)->iov_base, (*iov)->iov_len);
- else
- n = readv(fd->osfd, *iov, *iov_size);
- if (n < 0) {
- if (errno == EINTR)
- continue;
- if (!_IO_NOT_READY_ERROR)
- return -1;
- } else if (n == 0)
- break;
- else {
- while ((size_t) n >= (*iov)->iov_len) {
- n -= (*iov)->iov_len;
- (*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len;
- (*iov)->iov_len = 0;
- (*iov)++;
- (*iov_size)--;
- if (n == 0)
- break;
- }
- if (*iov_size == 0)
- break;
- (*iov)->iov_base = (char *) (*iov)->iov_base + n;
- (*iov)->iov_len -= n;
- }
- /* Wait until the socket becomes readable */
- if (st_netfd_poll(fd, POLLIN, timeout) < 0)
- return -1;
- }
-
- return 0;
- }
- ssize_t st_read_fully(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout)
- {
- size_t resid = nbyte;
- return st_read_resid(fd, buf, &resid, timeout) == 0 ?
- (ssize_t) (nbyte - resid) : -1;
- }
- int st_write_resid(_st_netfd_t *fd, const void *buf, size_t *resid, st_utime_t timeout)
- {
- struct iovec iov, *riov;
- int riov_size, rv;
-
- iov.iov_base = (void *) buf; /* we promise not to modify buf */
- iov.iov_len = *resid;
- riov = &iov;
- riov_size = 1;
- rv = st_writev_resid(fd, &riov, &riov_size, timeout);
- *resid = iov.iov_len;
- return rv;
- }
- ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout)
- {
- size_t resid = nbyte;
- return st_write_resid(fd, buf, &resid, timeout) == 0 ?
- (ssize_t) (nbyte - resid) : -1;
- }
- ssize_t st_writev(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout)
- {
- ssize_t n, rv;
- size_t nleft, nbyte;
- int index, iov_cnt;
- struct iovec *tmp_iov;
- struct iovec local_iov[_LOCAL_MAXIOV];
-
- /* Calculate the total number of bytes to be sent */
- nbyte = 0;
- for (index = 0; index < iov_size; index++)
- nbyte += iov[index].iov_len;
-
- rv = (ssize_t)nbyte;
- nleft = nbyte;
- tmp_iov = (struct iovec *) iov; /* we promise not to modify iov */
- iov_cnt = iov_size;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_writev;
- #endif
-
- while (nleft > 0) {
- if (iov_cnt == 1) {
- if (st_write(fd, tmp_iov[0].iov_base, nleft, timeout) != (ssize_t) nleft)
- rv = -1;
- break;
- }
- if ((n = writev(fd->osfd, tmp_iov, iov_cnt)) < 0) {
- if (errno == EINTR)
- continue;
- if (!_IO_NOT_READY_ERROR) {
- rv = -1;
- break;
- }
- } else {
- if ((size_t) n == nleft)
- break;
- nleft -= n;
- /* Find the next unwritten vector */
- n = (ssize_t)(nbyte - nleft);
- for (index = 0; (size_t) n >= iov[index].iov_len; index++)
- n -= iov[index].iov_len;
-
- if (tmp_iov == iov) {
- /* Must copy iov's around */
- if (iov_size - index <= _LOCAL_MAXIOV) {
- tmp_iov = local_iov;
- } else {
- tmp_iov = calloc(1, (iov_size - index) * sizeof(struct iovec));
- if (tmp_iov == NULL)
- return -1;
- }
- }
-
- /* Fill in the first partial read */
- tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[n]);
- tmp_iov[0].iov_len = iov[index].iov_len - n;
- index++;
- /* Copy the remaining vectors */
- for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) {
- tmp_iov[iov_cnt].iov_base = iov[index].iov_base;
- tmp_iov[iov_cnt].iov_len = iov[index].iov_len;
- }
- }
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_writev_eagain;
- #endif
- /* Wait until the socket becomes writable */
- if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
- rv = -1;
- break;
- }
- }
-
- if (tmp_iov != iov && tmp_iov != local_iov)
- free(tmp_iov);
-
- return rv;
- }
- int st_writev_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout)
- {
- ssize_t n;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_writev;
- #endif
-
- while (*iov_size > 0) {
- if (*iov_size == 1)
- n = write(fd->osfd, (*iov)->iov_base, (*iov)->iov_len);
- else
- n = writev(fd->osfd, *iov, *iov_size);
- if (n < 0) {
- if (errno == EINTR)
- continue;
- if (!_IO_NOT_READY_ERROR)
- return -1;
- } else {
- while ((size_t) n >= (*iov)->iov_len) {
- n -= (*iov)->iov_len;
- (*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len;
- (*iov)->iov_len = 0;
- (*iov)++;
- (*iov_size)--;
- if (n == 0)
- break;
- }
- if (*iov_size == 0)
- break;
- (*iov)->iov_base = (char *) (*iov)->iov_base + n;
- (*iov)->iov_len -= n;
- }
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_writev_eagain;
- #endif
- /* Wait until the socket becomes writable */
- if (st_netfd_poll(fd, POLLOUT, timeout) < 0)
- return -1;
- }
-
- return 0;
- }
- /*
- * Simple I/O functions for UDP.
- */
- int st_recvfrom(_st_netfd_t *fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout)
- {
- int n;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_recvfrom;
- #endif
- while ((n = recvfrom(fd->osfd, buf, len, 0, from, (socklen_t *)fromlen)) < 0) {
- if (errno == EINTR)
- continue;
- if (!_IO_NOT_READY_ERROR)
- return -1;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_recvfrom_eagain;
- #endif
- /* Wait until the socket becomes readable */
- if (st_netfd_poll(fd, POLLIN, timeout) < 0)
- return -1;
- }
-
- return n;
- }
- int st_sendto(_st_netfd_t *fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout)
- {
- int n;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_sendto;
- #endif
-
- while ((n = sendto(fd->osfd, msg, len, 0, to, tolen)) < 0) {
- if (errno == EINTR)
- continue;
- if (!_IO_NOT_READY_ERROR)
- return -1;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_sendto_eagain;
- #endif
- /* Wait until the socket becomes writable */
- if (st_netfd_poll(fd, POLLOUT, timeout) < 0)
- return -1;
- }
-
- return n;
- }
- int st_recvmsg(_st_netfd_t *fd, struct msghdr *msg, int flags, st_utime_t timeout)
- {
- int n;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_recvmsg;
- #endif
-
- while ((n = recvmsg(fd->osfd, msg, flags)) < 0) {
- if (errno == EINTR)
- continue;
- if (!_IO_NOT_READY_ERROR)
- return -1;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_recvmsg_eagain;
- #endif
- /* Wait until the socket becomes readable */
- if (st_netfd_poll(fd, POLLIN, timeout) < 0)
- return -1;
- }
-
- return n;
- }
- int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags, st_utime_t timeout)
- {
- int n;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_sendmsg;
- #endif
-
- while ((n = sendmsg(fd->osfd, msg, flags)) < 0) {
- if (errno == EINTR)
- continue;
- if (!_IO_NOT_READY_ERROR)
- return -1;
- #if defined(DEBUG) && defined(DEBUG_STATS)
- ++_st_stat_sendmsg_eagain;
- #endif
- /* Wait until the socket becomes writable */
- if (st_netfd_poll(fd, POLLOUT, timeout) < 0)
- return -1;
- }
-
- return n;
- }
- /*
- * To open FIFOs or other special files.
- */
- _st_netfd_t *st_open(const char *path, int oflags, mode_t mode)
- {
- int osfd, err;
- _st_netfd_t *newfd;
-
- while ((osfd = open(path, oflags | O_NONBLOCK, mode)) < 0) {
- if (errno != EINTR)
- return NULL;
- }
-
- newfd = _st_netfd_new(osfd, 0, 0);
- if (!newfd) {
- err = errno;
- close(osfd);
- errno = err;
- }
-
- return newfd;
- }
|