static void php_sock_stream_wait_for_data(php_stream *stream, php_netstream_data_t *sock) { int retval; struct timeval *ptimeout; if (!sock || sock->socket == -1) { return; } sock->timeout_event = 0; if (sock->timeout.tv_sec == -1) ptimeout = NULL; else ptimeout = &sock->timeout; while(1) { retval = php_pollfd_for(sock->socket, PHP_POLLREADABLE, ptimeout); if (retval == 0) sock->timeout_event = 1; if (retval >= 0) break; if (php_socket_errno() != EINTR) break; } }
/* {{{ Generic socket stream operations */ static size_t php_sockop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) { php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract; int didwrite; struct timeval *ptimeout; if (sock->socket == -1) { return 0; } if (sock->timeout.tv_sec == -1) ptimeout = NULL; else ptimeout = &sock->timeout; retry: didwrite = send(sock->socket, buf, count, (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0); if (didwrite <= 0) { long err = php_socket_errno(); char *estr; if (sock->is_blocked && err == EWOULDBLOCK) { int retval; sock->timeout_event = 0; do { retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout); if (retval == 0) { sock->timeout_event = 1; break; } if (retval > 0) { /* writable now; retry */ goto retry; } err = php_socket_errno(); } while (err == EINTR); } estr = php_socket_strerror(err, NULL, 0); php_error_docref(NULL TSRMLS_CC, E_NOTICE, "send of %ld bytes failed with errno=%ld %s", (long)count, err, estr); efree(estr); } if (didwrite > 0) { php_stream_notify_progress_increment(stream->context, didwrite, 0); } if (didwrite < 0) { didwrite = 0; } return didwrite; }
/* {{{ Generic socket stream operations */ static size_t php_sockop_write(php_stream *stream, const char *buf, size_t count) { php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract; int didwrite; struct timeval *ptimeout; if (!sock || sock->socket == -1) { return 0; } if (sock->timeout.tv_sec == -1) ptimeout = NULL; else ptimeout = &sock->timeout; retry: didwrite = send(sock->socket, buf, XP_SOCK_BUF_SIZE(count), (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0); if (didwrite <= 0) { int err = php_socket_errno(); char *estr; if (sock->is_blocked && (err == EWOULDBLOCK || err == EAGAIN)) { int retval; sock->timeout_event = 0; do { retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout); if (retval == 0) { sock->timeout_event = 1; break; } if (retval > 0) { /* writable now; retry */ goto retry; } err = php_socket_errno(); } while (err == EINTR); } estr = php_socket_strerror(err, NULL, 0); php_error_docref(NULL, E_NOTICE, "send of " ZEND_LONG_FMT " bytes failed with errno=%ld %s", (zend_long)count, err, estr); efree(estr); } if (didwrite > 0) { php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), didwrite, 0); } if (didwrite < 0) { didwrite = 0; } return didwrite; }
static int php_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam) { int oldmode, flags; php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract; php_stream_xport_param *xparam; if (!sock) { return PHP_STREAM_OPTION_RETURN_NOTIMPL; } switch(option) { case PHP_STREAM_OPTION_CHECK_LIVENESS: { struct timeval tv; char buf; int alive = 1; if (value == -1) { if (sock->timeout.tv_sec == -1) { tv.tv_sec = FG(default_socket_timeout); tv.tv_usec = 0; } else { tv = sock->timeout; } } else { tv.tv_sec = value; tv.tv_usec = 0; } if (sock->socket == -1) { alive = 0; } else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) { #ifdef PHP_WIN32 int ret; #else ssize_t ret; #endif int err; ret = recv(sock->socket, &buf, sizeof(buf), MSG_PEEK); err = php_socket_errno(); if (0 == ret || /* the counterpart did properly shutdown*/ (0 > ret && err != EWOULDBLOCK && err != EAGAIN)) { /* there was an unrecoverable error */ alive = 0; } } return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR; } case PHP_STREAM_OPTION_BLOCKING: oldmode = sock->is_blocked; if (SUCCESS == php_set_sock_blocking(sock->socket, value)) { sock->is_blocked = value; return oldmode; } return PHP_STREAM_OPTION_RETURN_ERR; case PHP_STREAM_OPTION_READ_TIMEOUT: sock->timeout = *(struct timeval*)ptrparam; sock->timeout_event = 0; return PHP_STREAM_OPTION_RETURN_OK; case PHP_STREAM_OPTION_META_DATA_API: add_assoc_bool((zval *)ptrparam, "timed_out", sock->timeout_event); add_assoc_bool((zval *)ptrparam, "blocked", sock->is_blocked); add_assoc_bool((zval *)ptrparam, "eof", stream->eof); return PHP_STREAM_OPTION_RETURN_OK; case PHP_STREAM_OPTION_XPORT_API: xparam = (php_stream_xport_param *)ptrparam; switch (xparam->op) { case STREAM_XPORT_OP_LISTEN: xparam->outputs.returncode = (listen(sock->socket, xparam->inputs.backlog) == 0) ? 0: -1; return PHP_STREAM_OPTION_RETURN_OK; case STREAM_XPORT_OP_GET_NAME: xparam->outputs.returncode = php_network_get_sock_name(sock->socket, xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, xparam->want_addr ? &xparam->outputs.addr : NULL, xparam->want_addr ? &xparam->outputs.addrlen : NULL ); return PHP_STREAM_OPTION_RETURN_OK; case STREAM_XPORT_OP_GET_PEER_NAME: xparam->outputs.returncode = php_network_get_peer_name(sock->socket, xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, xparam->want_addr ? &xparam->outputs.addr : NULL, xparam->want_addr ? &xparam->outputs.addrlen : NULL ); return PHP_STREAM_OPTION_RETURN_OK; case STREAM_XPORT_OP_SEND: flags = 0; if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) { flags |= MSG_OOB; } xparam->outputs.returncode = sock_sendto(sock, xparam->inputs.buf, xparam->inputs.buflen, flags, xparam->inputs.addr, xparam->inputs.addrlen); if (xparam->outputs.returncode == -1) { char *err = php_socket_strerror(php_socket_errno(), NULL, 0); php_error_docref(NULL, E_WARNING, "%s\n", err); efree(err); } return PHP_STREAM_OPTION_RETURN_OK; case STREAM_XPORT_OP_RECV: flags = 0; if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) { flags |= MSG_OOB; } if ((xparam->inputs.flags & STREAM_PEEK) == STREAM_PEEK) { flags |= MSG_PEEK; } xparam->outputs.returncode = sock_recvfrom(sock, xparam->inputs.buf, xparam->inputs.buflen, flags, xparam->want_textaddr ? &xparam->outputs.textaddr : NULL, xparam->want_addr ? &xparam->outputs.addr : NULL, xparam->want_addr ? &xparam->outputs.addrlen : NULL ); return PHP_STREAM_OPTION_RETURN_OK; #ifdef HAVE_SHUTDOWN # ifndef SHUT_RD # define SHUT_RD 0 # endif # ifndef SHUT_WR # define SHUT_WR 1 # endif # ifndef SHUT_RDWR # define SHUT_RDWR 2 # endif case STREAM_XPORT_OP_SHUTDOWN: { static const int shutdown_how[] = {SHUT_RD, SHUT_WR, SHUT_RDWR}; xparam->outputs.returncode = shutdown(sock->socket, shutdown_how[xparam->how]); return PHP_STREAM_OPTION_RETURN_OK; } #endif default: return PHP_STREAM_OPTION_RETURN_NOTIMPL; } default: return PHP_STREAM_OPTION_RETURN_NOTIMPL; } }