mirror of https://github.com/ossrs/srs.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
793 lines
20 KiB
C
793 lines
20 KiB
C
/*
|
|
* 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"
|
|
|
|
#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 _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;
|
|
}
|
|
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;
|
|
}
|
|
|
|
#ifdef MD_ALWAYS_UNSERIALIZED_ACCEPT
|
|
/* 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;
|
|
}
|
|
|
|
#else /* MD_ALWAYS_UNSERIALIZED_ACCEPT */
|
|
/*
|
|
* On some platforms accept() calls from different processes
|
|
* on the same listen socket must be serialized.
|
|
* The following code serializes accept()'s without process blocking.
|
|
* A pipe is used as an inter-process semaphore.
|
|
*/
|
|
int st_netfd_serialize_accept(_st_netfd_t *fd)
|
|
{
|
|
_st_netfd_t **p;
|
|
int osfd[2], err;
|
|
|
|
if (fd->aux_data) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if ((p = (_st_netfd_t **)calloc(2, sizeof(_st_netfd_t *))) == NULL) {
|
|
return -1;
|
|
}
|
|
if (pipe(osfd) < 0) {
|
|
free(p);
|
|
return -1;
|
|
}
|
|
if ((p[0] = st_netfd_open(osfd[0])) != NULL && (p[1] = st_netfd_open(osfd[1])) != NULL && write(osfd[1], " ", 1) == 1) {
|
|
fd->aux_data = p;
|
|
return 0;
|
|
}
|
|
/* Error */
|
|
err = errno;
|
|
if (p[0]) {
|
|
st_netfd_free(p[0]);
|
|
}
|
|
if (p[1]) {
|
|
st_netfd_free(p[1]);
|
|
}
|
|
close(osfd[0]);
|
|
close(osfd[1]);
|
|
free(p);
|
|
errno = err;
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void _st_netfd_free_aux_data(_st_netfd_t *fd)
|
|
{
|
|
_st_netfd_t **p = (_st_netfd_t **) fd->aux_data;
|
|
|
|
st_netfd_close(p[0]);
|
|
st_netfd_close(p[1]);
|
|
free(p);
|
|
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;
|
|
_st_netfd_t **p = (_st_netfd_t **) fd->aux_data;
|
|
ssize_t n;
|
|
char c;
|
|
|
|
for ( ; ; ) {
|
|
if (p == NULL) {
|
|
osfd = accept(fd->osfd, addr, (socklen_t *)addrlen);
|
|
} else {
|
|
/* Get the lock */
|
|
n = st_read(p[0], &c, 1, timeout);
|
|
if (n < 0) {
|
|
return NULL;
|
|
}
|
|
ST_ASSERT(n == 1);
|
|
/* Got the lock */
|
|
osfd = accept(fd->osfd, addr, (socklen_t *)addrlen);
|
|
/* Unlock */
|
|
err = errno;
|
|
n = st_write(p[1], &c, 1, timeout);
|
|
ST_ASSERT(n == 1);
|
|
errno = err;
|
|
}
|
|
if (osfd >= 0) {
|
|
break;
|
|
}
|
|
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;
|
|
}
|
|
#endif /* MD_ALWAYS_UNSERIALIZED_ACCEPT */
|
|
|
|
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;
|
|
|
|
while ((n = read(fd->osfd, buf, nbyte)) < 0) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
if (!_IO_NOT_READY_ERROR) {
|
|
return -1;
|
|
}
|
|
/* 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;
|
|
|
|
while ((n = readv(fd->osfd, iov, iov_size)) < 0) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
if (!_IO_NOT_READY_ERROR) {
|
|
return -1;
|
|
}
|
|
/* 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;
|
|
|
|
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;
|
|
}
|
|
}
|
|
/* 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;
|
|
|
|
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;
|
|
}
|
|
/* 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;
|
|
|
|
while ((n = recvfrom(fd->osfd, buf, len, 0, from, (socklen_t *)fromlen)) < 0) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
if (!_IO_NOT_READY_ERROR) {
|
|
return -1;
|
|
}
|
|
/* 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;
|
|
|
|
while ((n = sendto(fd->osfd, msg, len, 0, to, tolen)) < 0) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
if (!_IO_NOT_READY_ERROR) {
|
|
return -1;
|
|
}
|
|
/* 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;
|
|
|
|
while ((n = recvmsg(fd->osfd, msg, flags)) < 0) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
if (!_IO_NOT_READY_ERROR) {
|
|
return -1;
|
|
}
|
|
/* 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;
|
|
|
|
while ((n = sendmsg(fd->osfd, msg, flags)) < 0) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
if (!_IO_NOT_READY_ERROR) {
|
|
return -1;
|
|
}
|
|
/* 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;
|
|
}
|
|
|