static inline int sapi_cli_select(int fd) { fd_set wfd, dfd; struct timeval tv; int ret; FD_ZERO(&wfd); FD_ZERO(&dfd); PHP_SAFE_FD_SET(fd, &wfd); tv.tv_sec = (long)FG(default_socket_timeout); tv.tv_usec = 0; ret = php_select(fd+1, &dfd, &wfd, &dfd, &tv); return ret != -1; }
static inline long hs_response_select(php_stream *stream, long timeout TSRMLS_DC) { php_socket_t max_fd = 0; int retval, max_set_count = 0; struct timeval tv; struct timeval *tv_p = NULL; fd_set fds; FD_ZERO(&fds); if (php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT|PHP_STREAM_CAST_INTERNAL, (void*)&max_fd, 1) == SUCCESS && max_fd != -1) { PHP_SAFE_FD_SET(max_fd, &fds); max_set_count++; } PHP_SAFE_MAX_FD(max_fd, max_set_count); if (timeout > 0) { tv.tv_sec = timeout; tv.tv_usec = 0; tv_p = &tv; } retval = php_select(max_fd+1, &fds, NULL, NULL, tv_p); if (retval == -1) { zend_error(E_WARNING, "[HandlerSocket] unable to select"); return -1; } if (!PHP_SAFE_FD_ISSET(max_fd, &fds)) { return -1; } return 0; }
int php_yar_socket_send(yar_transport_interface_t* self, yar_request_t *request, char **msg) /* {{{ */ { fd_set rfds; zend_string *payload; struct timeval tv; int ret = -1, fd, retval; char buf[SEND_BUF_SIZE]; yar_header_t header = {0}; yar_socket_data_t *data = (yar_socket_data_t *)self->data; FD_ZERO(&rfds); if (SUCCESS == php_stream_cast(data->stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&fd, 1) && fd >= 0) { PHP_SAFE_FD_SET(fd, &rfds); } else { spprintf(msg, 0, "Unable cast socket fd form stream (%s)", strerror(errno)); return 0; } if (!(payload = php_yar_request_pack(request, msg))) { return 0; } DEBUG_C(ZEND_ULONG_FMT": pack request by '%.*s', result len '%ld', content: '%.32s'", request->id, 7, ZSTR_VAL(payload), ZSTR_LEN(payload), ZSTR_VAL(payload) + 8); /* for tcp/unix RPC, we need another way to supports auth */ php_yar_protocol_render(&header, request->id, "Yar PHP Client", NULL, ZSTR_LEN(payload), data->persistent? YAR_PROTOCOL_PERSISTENT : 0); memcpy(buf, (char *)&header, sizeof(yar_header_t)); tv.tv_sec = (ulong)(YAR_G(timeout) / 1000); tv.tv_usec = (ulong)((YAR_G(timeout) % 1000)? (YAR_G(timeout) & 1000) * 1000 : 0); retval = php_select(fd+1, NULL, &rfds, NULL, &tv); if (retval == -1) { zend_string_release(payload); spprintf(msg, 0, "select error '%s'", strerror(errno)); return 0; } else if (retval == 0) { zend_string_release(payload); spprintf(msg, 0, "select timeout '%ld' seconds reached", YAR_G(timeout)); return 0; } if (PHP_SAFE_FD_ISSET(fd, &rfds)) { size_t bytes_left = 0, bytes_sent = 0; if (ZSTR_LEN(payload) > (sizeof(buf) - sizeof(yar_header_t))) { memcpy(buf + sizeof(yar_header_t), ZSTR_VAL(payload), sizeof(buf) - sizeof(yar_header_t)); if ((ret = php_stream_xport_sendto(data->stream, buf, sizeof(buf), 0, NULL, 0)) < 0) { zend_string_release(payload); spprintf(msg, 0, "unable to send data"); return 0; } } else { memcpy(buf + sizeof(yar_header_t), ZSTR_VAL(payload), ZSTR_LEN(payload)); if ((ret = php_stream_xport_sendto(data->stream, buf, sizeof(yar_header_t) + ZSTR_LEN(payload), 0, NULL, 0)) < 0) { zend_string_release(payload); spprintf(msg, 0, "unable to send data"); return 0; } } bytes_sent = ret - sizeof(yar_header_t); bytes_left = ZSTR_LEN(payload) - bytes_sent; wait_io: if (bytes_left) { retval = php_select(fd+1, NULL, &rfds, NULL, &tv); if (retval == -1) { zend_string_release(payload); spprintf(msg, 0, "select error '%s'", strerror(errno)); return 0; } else if (retval == 0) { zend_string_release(payload); spprintf(msg, 0, "select timeout %ldms reached", YAR_G(timeout)); return 0; } if (PHP_SAFE_FD_ISSET(fd, &rfds)) { if ((ret = php_stream_xport_sendto(data->stream, ZSTR_VAL(payload) + bytes_sent, bytes_left, 0, NULL, 0)) > 0) { bytes_left -= ret; bytes_sent += ret; } } goto wait_io; } } zend_string_release(payload); return ret < 0? 0 : 1; } /* }}} */
yar_response_t * php_yar_socket_exec(yar_transport_interface_t* self, yar_request_t *request) /* {{{ */ { fd_set rfds; struct timeval tv; yar_header_t *header; yar_response_t *response; int fd, retval, recvd; size_t len = 0, total_recvd = 0; char *msg, buf[RECV_BUF_SIZE], *payload = NULL; yar_socket_data_t *data = (yar_socket_data_t *)self->data; response = ecalloc(1, sizeof(yar_response_t)); FD_ZERO(&rfds); if (SUCCESS == php_stream_cast(data->stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&fd, 1) && fd >= 0) { PHP_SAFE_FD_SET(fd, &rfds); } else { len = snprintf(buf, sizeof(buf), "Unable cast socket fd form stream (%s)", strerror(errno)); php_yar_response_set_error(response, YAR_ERR_TRANSPORT, buf, len); return response; } tv.tv_sec = (ulong)(YAR_G(timeout) / 1000); tv.tv_usec = (ulong)((YAR_G(timeout) % 1000)? (YAR_G(timeout) & 1000) * 1000 : 0); wait_io: retval = php_select(fd+1, &rfds, NULL, NULL, &tv); if (retval == -1) { len = snprintf(buf, sizeof(buf), "Unable to select %d '%s'", fd, strerror(errno)); php_yar_response_set_error(response, YAR_ERR_TRANSPORT, buf, len); return response; } else if (retval == 0) { len = snprintf(buf, sizeof(buf), "select timeout %ldms reached", YAR_G(timeout)); php_yar_response_set_error(response, YAR_ERR_TRANSPORT, buf, len); return response; } if (PHP_SAFE_FD_ISSET(fd, &rfds)) { zval *retval, rret; if (!payload) { if ((recvd = php_stream_xport_recvfrom(data->stream, buf, sizeof(buf), 0, NULL, NULL, NULL)) > 0) { if (!(header = php_yar_protocol_parse(buf))) { php_yar_error(response, YAR_ERR_PROTOCOL, "malformed response header '%.32s'", payload); return response; } payload = emalloc(header->body_len); len = header->body_len; total_recvd = recvd - sizeof(yar_header_t); memcpy(payload, buf + sizeof(yar_header_t), total_recvd); if (recvd < (sizeof(yar_header_t) + len)) { goto wait_io; } } else if (recvd < 0) { /* this should never happen */ goto wait_io; } } else { if ((recvd = php_stream_xport_recvfrom(data->stream, payload + total_recvd, len - total_recvd, 0, NULL, NULL, NULL)) > 0) { total_recvd += recvd; } if (total_recvd < len) { goto wait_io; } } if (len) { if (!(retval = php_yar_packager_unpack(payload, len, &msg, &rret))) { php_yar_response_set_error(response, YAR_ERR_PACKAGER, msg, strlen(msg)); efree(msg); return response; } php_yar_response_map_retval(response, retval); DEBUG_C(ZEND_ULONG_FMT": server response content packaged by '%.*s', len '%ld', content '%.32s'", response->id, 7, payload, header->body_len, payload + 8); efree(payload); zval_ptr_dtor(retval); } else { php_yar_response_set_error(response, YAR_ERR_EMPTY_RESPONSE, ZEND_STRL("empty response")); } return response; } else { goto wait_io; } } /* }}} */