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; } } /* }}} */
static zval * php_yar_client_parse_response(char *ret, size_t len, int throw_exception TSRMLS_DC) /* {{{ */ { zval *retval, *response; yar_header_t *header; char *err_msg; MAKE_STD_ZVAL(retval); ZVAL_FALSE(retval); if (!(header = php_yar_protocol_parse(&ret, &len, &err_msg TSRMLS_CC))) { php_yar_client_trigger_error(throw_exception TSRMLS_CC, YAR_ERR_PROTOCOL, "%s", err_msg); if (YAR_G(debug)) { php_yar_debug_client("0: malformed response '%s'", ret); } efree(err_msg); return retval; } if (!len || !header->body_len) { php_yar_client_trigger_error(throw_exception TSRMLS_CC, 0, "server responsed empty body"); return retval; } if (YAR_G(debug)) { php_yar_debug_client("%ld: server responsed: packager '%s', len '%ld', content '%s'", header->id, ret, len - 8, ret + 8); } if (!(response = php_yar_packager_unpack(ret, len, &err_msg TSRMLS_CC))) { php_yar_client_trigger_error(throw_exception TSRMLS_CC, YAR_ERR_PACKAGER, "%s", err_msg); efree(err_msg); return retval; } if (response && IS_ARRAY == Z_TYPE_P(response)) { zval **ppzval; uint status; HashTable *ht = Z_ARRVAL_P(response); if (zend_hash_find(ht, ZEND_STRS("s"), (void **)&ppzval) == FAILURE) { } convert_to_long(*ppzval); status = Z_LVAL_PP(ppzval); if (status == YAR_ERR_OKEY) { if (zend_hash_find(ht, ZEND_STRS("o"), (void **)&ppzval) == SUCCESS) { PHPWRITE(Z_STRVAL_PP(ppzval), Z_STRLEN_PP(ppzval)); } } else if (status == YAR_ERR_EXCEPTION) { if (zend_hash_find(ht, ZEND_STRS("e"), (void **)&ppzval) == SUCCESS) { if (throw_exception) { zval *ex, **property; MAKE_STD_ZVAL(ex); object_init_ex(ex, yar_server_exception_ce); if (zend_hash_find(Z_ARRVAL_PP(ppzval), ZEND_STRS("message"), (void **)&property) == SUCCESS) { zend_update_property(yar_server_exception_ce, ex, ZEND_STRL("message"), *property TSRMLS_CC); } if (zend_hash_find(Z_ARRVAL_PP(ppzval), ZEND_STRS("code"), (void **)&property) == SUCCESS) { zend_update_property(yar_server_exception_ce, ex, ZEND_STRL("code"), *property TSRMLS_CC); } if (zend_hash_find(Z_ARRVAL_PP(ppzval), ZEND_STRS("file"), (void **)&property) == SUCCESS) { zend_update_property(yar_server_exception_ce, ex, ZEND_STRL("file"), *property TSRMLS_CC); } if (zend_hash_find(Z_ARRVAL_PP(ppzval), ZEND_STRS("line"), (void **)&property) == SUCCESS) { zend_update_property(yar_server_exception_ce, ex, ZEND_STRL("line"), *property TSRMLS_CC); } if (zend_hash_find(Z_ARRVAL_PP(ppzval), ZEND_STRS("_type"), (void **)&property) == SUCCESS) { zend_update_property(yar_server_exception_ce, ex, ZEND_STRL("_type"), *property TSRMLS_CC); } zend_throw_exception_object(ex TSRMLS_CC); } else { zval **msg, **code; if (zend_hash_find(Z_ARRVAL_PP(ppzval), ZEND_STRS("message"), (void **)&msg) == SUCCESS && zend_hash_find(Z_ARRVAL_PP(ppzval), ZEND_STRS("code"), (void **)&code) == SUCCESS) { convert_to_string_ex(msg); convert_to_long_ex(code); php_yar_client_trigger_error(0 TSRMLS_CC, Z_LVAL_PP(code), "server threw an exception with message `%s`", Z_STRVAL_PP(msg)); } } } } else if (zend_hash_find(ht, ZEND_STRS("e"), (void **)&ppzval) == SUCCESS && IS_STRING == Z_TYPE_PP(ppzval)) { php_yar_client_trigger_error(throw_exception TSRMLS_CC, status, "%s", Z_STRVAL_PP(ppzval)); } if (zend_hash_find(ht, ZEND_STRS("r"), (void **)&ppzval) == SUCCESS) { ZVAL_ZVAL(retval, *ppzval, 1, 0); } zval_ptr_dtor(&response); } else if (response) { zval_ptr_dtor(&response); } return retval; } /* }}} */