diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d3ddb3fc96..0ec60ecfcbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,13 +6,17 @@ set(SWOOLE_VERSION 4.7.0-dev) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -g") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +cmake_minimum_required(VERSION 2.8) + +file(READ ./config.h SWOOLE_CONFIG_FILE) set(CMAKE_MACOSX_RPATH 1) set(SWOOLE_LINK_LIBRARIES pthread dl) if (APPLE) set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") + include_directories(BEFORE /usr/local/include) + link_directories(BEFORE /usr/local/lib) else() list(APPEND SWOOLE_LINK_LIBRARIES rt crypt) endif() @@ -82,6 +86,17 @@ if (DEFINED brotli_dir) link_directories(${brotli_dir}/lib) endif() +foreach (LINE ${SWOOLE_CONFIG_FILE}) + if ("${LINE}" MATCHES "define SW_USE_CARES 1") + message(STATUS "enable c-ares") + list(APPEND SWOOLE_LINK_LIBRARIES cares) + endif() +endforeach() + +if (DEFINED enable_trace_log) + add_definitions(-DSW_LOG_TRACE_OPEN) +endif() + execute_process(COMMAND php-config --includes OUTPUT_VARIABLE PHP_INCLUDES OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND php-config --extension-dir OUTPUT_VARIABLE PHP_EXTENSION_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PHP_INCLUDES}") diff --git a/config.m4 b/config.m4 index 6904f53a075..cb7e639089f 100644 --- a/config.m4 +++ b/config.m4 @@ -50,6 +50,11 @@ PHP_ARG_ENABLE([mysqlnd], [enable mysqlnd support], [AS_HELP_STRING([--enable-mysqlnd], [Enable mysqlnd])], [no], [no]) + +PHP_ARG_ENABLE([cares], + [enable c-ares support], + [AS_HELP_STRING([--enable-cares], + [Enable cares])], [no], [no]) PHP_ARG_WITH([openssl_dir], [dir of openssl], @@ -354,7 +359,8 @@ if test "$PHP_SWOOLE" != "no"; then AC_CHECK_LIB(pthread, pthread_mutexattr_setrobust, AC_DEFINE(HAVE_PTHREAD_MUTEXATTR_SETROBUST, 1, [have pthread_mutexattr_setrobust])) AC_CHECK_LIB(pthread, pthread_mutex_consistent, AC_DEFINE(HAVE_PTHREAD_MUTEX_CONSISTENT, 1, [have pthread_mutex_consistent])) AC_CHECK_LIB(pcre, pcre_compile, AC_DEFINE(HAVE_PCRE, 1, [have pcre])) - + AC_CHECK_LIB(cares, ares_gethostbyname, AC_DEFINE(HAVE_CARES, 1, [have c-ares])) + if test "$PHP_SWOOLE_DEV" = "yes"; then AX_CHECK_COMPILE_FLAG(-Wbool-conversion, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wbool-conversion") AX_CHECK_COMPILE_FLAG(-Wignored-qualifiers, _MAINTAINER_CFLAGS="$_MAINTAINER_CFLAGS -Wignored-qualifiers") @@ -457,6 +463,11 @@ if test "$PHP_SWOOLE" != "no"; then if test "$PHP_THREAD" = "yes"; then AC_DEFINE(SW_USE_THREAD, 1, [enable thread support]) fi + + if test "$PHP_CARES" = "yes"; then + AC_DEFINE(SW_USE_CARES, 1, [do we enable c-ares support]) + PHP_ADD_LIBRARY(cares, 1, SWOOLE_SHARED_LIBADD) + fi AC_SWOOLE_CPU_AFFINITY AC_SWOOLE_HAVE_REUSEPORT diff --git a/core-tests/src/coroutine/gethostbyname.cpp b/core-tests/src/coroutine/gethostbyname.cpp index 26f2f59cf5a..02a009c4103 100644 --- a/core-tests/src/coroutine/gethostbyname.cpp +++ b/core-tests/src/coroutine/gethostbyname.cpp @@ -29,6 +29,13 @@ TEST(coroutine_gethostbyname, resolve_cache) { }); } +TEST(coroutine_gethostbyname, impl_async) { + coroutine::run([](void *arg) { + auto result = swoole::coroutine::gethostbyname_impl_with_async("www.baidu.com", AF_INET); + ASSERT_EQ(result.empty(), false); + }); +} + TEST(coroutine_gethostbyname, resolve_cache_inet4_and_inet6) { coroutine::run([](void *arg) { System::set_dns_cache_capacity(10); diff --git a/core-tests/src/coroutine/system.cpp b/core-tests/src/coroutine/system.cpp index 4499b65112e..179718f9743 100644 --- a/core-tests/src/coroutine/system.cpp +++ b/core-tests/src/coroutine/system.cpp @@ -82,7 +82,7 @@ TEST(coroutine_system, flock) { } TEST(coroutine_system, cancel_sleep) { - coroutine::run([](void *arg) { + test::coroutine::run([](void *arg) { auto co = Coroutine::get_current_safe(); Coroutine::create([co](void *){ System::sleep(0.002); diff --git a/core-tests/src/network/dns.cpp b/core-tests/src/network/dns.cpp index 5e0f72ab35d..c2961ae39e6 100644 --- a/core-tests/src/network/dns.cpp +++ b/core-tests/src/network/dns.cpp @@ -22,16 +22,55 @@ #include "swoole_socket.h" using namespace swoole; +using swoole::coroutine::Socket; +using swoole::coroutine::System; using namespace swoole::test; using namespace std; -TEST(dns, lookup) { +TEST(dns, lookup1) { test::coroutine::run([](void *arg) { - auto list = swoole::coroutine::dns_lookup("www.baidu.com", 10); + auto list = swoole::coroutine::dns_lookup("www.baidu.com", AF_INET, 10); ASSERT_GE(list.size(), 1); }); } +TEST(dns, lookup_ipv6) { + test::coroutine::run([](void *arg) { + auto list = swoole::coroutine::dns_lookup("www.google.com", AF_INET6, 2); + ASSERT_GE(list.size(), 1); + }); +} + +TEST(dns, domain_not_found) { + test::coroutine::run([](void *arg) { + auto list = swoole::coroutine::dns_lookup("www.baidu.com-not-found", AF_INET, 2); + ASSERT_EQ(list.size(), 0); + ASSERT_EQ(swoole_get_last_error(), SW_ERROR_DNSLOOKUP_RESOLVE_FAILED); + }); +} + +TEST(dns, bad_family) { + test::coroutine::run([](void *arg) { + auto list = swoole::coroutine::dns_lookup("www.google.com", 9999, 2); + ASSERT_GE(list.size(), 1); + }); +} + +TEST(dns, cancel) { + // swoole_set_trace_flags(SW_TRACE_CARES); + // swoole_set_log_level(SW_LOG_TRACE); + test::coroutine::run([](void *arg) { + auto co = Coroutine::get_current_safe(); + Coroutine::create([co](void *){ + System::sleep(0.002); + co->cancel(); + }); + auto list1 = swoole::coroutine::dns_lookup("www.baidu-not-found-for-cancel.com", AF_INET, 2); + ASSERT_EQ(list1.size(), 0); + ASSERT_EQ(swoole_get_last_error(), SW_ERROR_CO_CANCELED); + }); +} + TEST(dns, getaddrinfo) { char buf[1024] = {}; swoole::network::GetaddrinfoRequest req = {}; diff --git a/core-tests/src/os/process_pool.cpp b/core-tests/src/os/process_pool.cpp index d335b64a9af..75d5cbb29bb 100644 --- a/core-tests/src/os/process_pool.cpp +++ b/core-tests/src/os/process_pool.cpp @@ -1,6 +1,12 @@ #include "test_core.h" #include "swoole_process_pool.h" +#include + +#ifdef __MACH__ +#define sysv_signal signal +#endif + using namespace swoole; static void test_func(ProcessPool &pool) { @@ -114,4 +120,4 @@ TEST(process_pool, shutdown) { pool.destroy(); ASSERT_EQ(*shm_value, magic_number); -} \ No newline at end of file +} diff --git a/examples/http/server.php b/examples/http/server.php index a4a6325f742..b3ca4662285 100644 --- a/examples/http/server.php +++ b/examples/http/server.php @@ -17,6 +17,7 @@ function dump($var) //'open_cpu_affinity' => 1, //'task_worker_num' => 100, //'enable_port_reuse' => true, + // 'http_compression' => false, 'worker_num' => 1, //'log_file' => __DIR__.'/swoole.log', // 'reactor_num' => 24, @@ -89,6 +90,9 @@ function no_chunk(swoole_http_request $request, swoole_http_response $response) $response->status(404); $response->end(); return; + } else if ($request->server['request_uri'] == '/big_response') { + var_dump($response->end(str_repeat('A', 16 * 1024 * 1024))); + return; } else if ($request->server['request_uri'] == '/code') { $response->sendfile(__FILE__); return; diff --git a/ext-src/php_swoole.cc b/ext-src/php_swoole.cc index 8c4a3166659..be863d671e5 100644 --- a/ext-src/php_swoole.cc +++ b/ext-src/php_swoole.cc @@ -50,6 +50,10 @@ END_EXTERN_C() #include #endif +#ifdef SW_USE_CARES +#include +#endif + using swoole::network::Socket; ZEND_DECLARE_MODULE_GLOBALS(swoole) @@ -93,6 +97,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_async_dns_lookup_coro, 0, 0, 1) ZEND_ARG_INFO(0, domain_name) ZEND_ARG_INFO(0, timeout) + ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_create, 0, 0, 1) @@ -344,10 +349,7 @@ void php_swoole_set_global_option(HashTable *vht) { SWOOLE_G(display_errors) = zval_is_true(ztmp); } if (php_swoole_array_get_value(vht, "dns_server", ztmp)) { - if (SwooleG.dns_server_v4) { - sw_free(SwooleG.dns_server_v4); - } - SwooleG.dns_server_v4 = zend::String(ztmp).dup(); + swoole_set_dns_server(zend::String(ztmp).to_std_string()); } auto timeout_format = [](zval *v) -> double { @@ -879,6 +881,9 @@ PHP_MINFO_FUNCTION(swoole) { #ifdef HAVE_PCRE php_info_print_table_row(2, "pcre", "enabled"); #endif +#ifdef SW_USE_CARES + php_info_print_table_row(2, "c-ares", ares_version(nullptr)); +#endif #ifdef SW_HAVE_ZLIB #ifdef ZLIB_VERSION php_info_print_table_row(2, "zlib", ZLIB_VERSION); diff --git a/ext-src/php_swoole_coroutine_system.h b/ext-src/php_swoole_coroutine_system.h index 185ae9f9e9e..16b7d7a9e8a 100644 --- a/ext-src/php_swoole_coroutine_system.h +++ b/ext-src/php_swoole_coroutine_system.h @@ -53,6 +53,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_system_dnsLookup, 0, 0, 1) ZEND_ARG_INFO(0, domain_name) ZEND_ARG_INFO(0, timeout) + ZEND_ARG_INFO(0, type) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_swoole_coroutine_system_getaddrinfo, 0, 0, 1) diff --git a/ext-src/php_swoole_mysql_proto.h b/ext-src/php_swoole_mysql_proto.h index 604d8661fe8..858f55a4605 100644 --- a/ext-src/php_swoole_mysql_proto.h +++ b/ext-src/php_swoole_mysql_proto.h @@ -689,7 +689,7 @@ class lcb_packet : public server_packet { swMysqlPacketDump(header.length, header.number, data, "Protocol::LengthCodedBinary"); bytes_length = read_lcb(data + SW_MYSQL_PACKET_HEADER_SIZE, &length, &nul); - swTraceLog(SW_TRACE_MYSQL_CLIENT, "binary_length=%" PRIu64 ", nul=%u", header.length, nul); + swTraceLog(SW_TRACE_MYSQL_CLIENT, "binary_length=%u, nul=%u", header.length, nul); } bool is_vaild() { @@ -801,7 +801,7 @@ class row_data_text swTraceLog( SW_TRACE_MYSQL_CLIENT, "text[%" PRIu64 "]: %.*s%s", - length, SW_MIN(64, length), body, + length, (int) SW_MIN(64, length), body, nul ? "null" : ((length > 64 /*|| length > readable_length*/) ? "..." : "") ); } diff --git a/ext-src/php_swoole_private.h b/ext-src/php_swoole_private.h index e09f5607e7e..22a2e0b9c7a 100644 --- a/ext-src/php_swoole_private.h +++ b/ext-src/php_swoole_private.h @@ -84,6 +84,12 @@ extern PHPAPI int php_array_merge(zend_array *dest, zend_array *src); #endif #endif +#ifdef SW_USE_CARES +#ifndef HAVE_CARES +#error "Enable c-ares support, require c-ares library" +#endif +#endif + #ifdef SW_SOCKETS #include "ext/sockets/php_sockets.h" #define SWOOLE_SOCKETS_SUPPORT diff --git a/ext-src/swoole_async_coro.cc b/ext-src/swoole_async_coro.cc index 4bd62a68050..777fe5ff748 100644 --- a/ext-src/swoole_async_coro.cc +++ b/ext-src/swoole_async_coro.cc @@ -119,8 +119,9 @@ PHP_FUNCTION(swoole_async_dns_lookup_coro) { Coroutine::get_current_safe(); zval *domain; + long type = AF_INET; double timeout = swoole::network::Socket::default_dns_timeout; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|d", &domain, &timeout) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|dl", &domain, &timeout, &type) == FAILURE) { RETURN_FALSE; } @@ -147,7 +148,7 @@ PHP_FUNCTION(swoole_async_dns_lookup_coro) { php_swoole_check_reactor(); - vector result = swoole::coroutine::dns_lookup(Z_STRVAL_P(domain), timeout); + vector result = swoole::coroutine::dns_lookup(Z_STRVAL_P(domain), type, timeout); if (result.empty()) { swoole_set_last_error(SW_ERROR_DNSLOOKUP_RESOLVE_FAILED); RETURN_FALSE; diff --git a/ext-src/swoole_http_response.cc b/ext-src/swoole_http_response.cc index 6fd6bb9d3e7..e2c9cf2f46a 100644 --- a/ext-src/swoole_http_response.cc +++ b/ext-src/swoole_http_response.cc @@ -37,8 +37,8 @@ using http_context = swoole::http::Context; zend_class_entry *swoole_http_response_ce; static zend_object_handlers swoole_http_response_handlers; -static void http_build_header(http_context *ctx, swString *response, size_t body_length); -static ssize_t http_build_trailer(http_context *ctx, swString *response); +static void http_build_header(http_context *ctx, String *response, size_t body_length); +static ssize_t http_build_trailer(http_context *ctx, String *response); static inline void http_header_key_format(char *key, int length) { int i, state = 0; @@ -360,7 +360,7 @@ static bool parse_header_flags(http_context *ctx, const char *key, size_t keylen return true; } -static void http_build_header(http_context *ctx, swString *response, size_t body_length) { +static void http_build_header(http_context *ctx, String *response, size_t body_length) { char *buf = sw_tg_buffer()->str; size_t l_buf = sw_tg_buffer()->size; int n; @@ -503,7 +503,7 @@ static void http_build_header(http_context *ctx, swString *response, size_t body ctx->send_header_ = 1; } -static ssize_t http_build_trailer(http_context *ctx, swString *response) { +static ssize_t http_build_trailer(http_context *ctx, String *response) { char *buf = sw_tg_buffer()->str; size_t l_buf = sw_tg_buffer()->size; int n; @@ -1257,7 +1257,7 @@ static PHP_METHOD(swoole_http_response, recv) { Socket *sock = (Socket *) ctx->private_data; ssize_t retval = sock->recv_packet(timeout); - swString _tmp; + String _tmp; if (retval < 0) { swoole_set_last_error(sock->errCode); diff --git a/ext-src/swoole_mysql_coro.cc b/ext-src/swoole_mysql_coro.cc index e802e8013bd..ff1b1159480 100644 --- a/ext-src/swoole_mysql_coro.cc +++ b/ext-src/swoole_mysql_coro.cc @@ -927,11 +927,11 @@ void mysql_client::handle_row_data_text(zval *return_value, mysql::row_data *row RETVAL_STRINGL(p, row_data->text.length); _return: swTraceLog(SW_TRACE_MYSQL_CLIENT, - "%.*s=[%zu]%.*s%s", + "%.*s=[%lu]%.*s%s", field->name_length, field->name, Z_STRLEN_P(return_value), - SW_MIN(32, Z_STRLEN_P(return_value)), + (int) SW_MIN(32, Z_STRLEN_P(return_value)), Z_STRVAL_P(return_value), (Z_STRLEN_P(return_value) > 32 ? "..." : "")); } @@ -1247,36 +1247,36 @@ void mysql_statement::send_execute_request(zval *return_value, zval *params) { zval *value; ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(params), value) { switch (client->strict_type ? Z_TYPE_P(value) : (IS_NULL == Z_TYPE_P(value) ? IS_NULL : IS_STRING)) { - case IS_NULL: - *((buffer->str + null_start_offset) + (index / 8)) |= (1UL << (index % 8)); - sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_NULL); - break; - case IS_TRUE: - case IS_FALSE: - case IS_LONG: - sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_LONGLONG); - sw_mysql_int8store(stack_buffer, zval_get_long(value)); - if (buffer->append(stack_buffer, mysql::get_static_type_size(SW_MYSQL_TYPE_LONGLONG)) < 0) { - RETURN_FALSE; - } - break; - case IS_DOUBLE: - sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_DOUBLE); - sw_mysql_doublestore(stack_buffer, zval_get_double(value)); - if (buffer->append(stack_buffer, mysql::get_static_type_size(SW_MYSQL_TYPE_DOUBLE)) < 0) { - RETURN_FALSE; - } - break; - default: - zend::String str_value(value); - uint8_t lcb_size = mysql::write_lcb(stack_buffer, str_value.len()); - sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_VAR_STRING); - if (buffer->append(stack_buffer, lcb_size) < 0) { - RETURN_FALSE; - } - if (buffer->append(str_value.val(), str_value.len()) < 0) { - RETURN_FALSE; - } + case IS_NULL: + *((buffer->str + null_start_offset) + (index / 8)) |= (1UL << (index % 8)); + sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_NULL); + break; + case IS_TRUE: + case IS_FALSE: + case IS_LONG: + sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_LONGLONG); + sw_mysql_int8store(stack_buffer, zval_get_long(value)); + if (buffer->append(stack_buffer, mysql::get_static_type_size(SW_MYSQL_TYPE_LONGLONG)) < 0) { + RETURN_FALSE; + } + break; + case IS_DOUBLE: + sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_DOUBLE); + sw_mysql_doublestore(stack_buffer, zval_get_double(value)); + if (buffer->append(stack_buffer, mysql::get_static_type_size(SW_MYSQL_TYPE_DOUBLE)) < 0) { + RETURN_FALSE; + } + break; + default: + zend::String str_value(value); + uint8_t lcb_size = mysql::write_lcb(stack_buffer, str_value.len()); + sw_mysql_int2store((buffer->str + type_start_offset) + (index * 2), SW_MYSQL_TYPE_VAR_STRING); + if (buffer->append(stack_buffer, lcb_size) < 0) { + RETURN_FALSE; + } + if (buffer->append(str_value.val(), str_value.len()) < 0) { + RETURN_FALSE; + } } index++; } @@ -1483,11 +1483,10 @@ void mysql_statement::fetch(zval *return_value) { case SW_MYSQL_TYPE_LONGLONG: if (field->flags & SW_MYSQL_UNSIGNED_FLAG) { add_assoc_ulong_safe_ex(return_value, field->name, field->name_length, *(uint64_t *) p); - swTraceLog( - SW_TRACE_MYSQL_CLIENT, "%.*s=%llu", field->name_length, field->name, *(uint64_t *) p); + swTraceLog(SW_TRACE_MYSQL_CLIENT, "%.*s=%lu", field->name_length, field->name, *(uint64_t *) p); } else { add_assoc_long_ex(return_value, field->name, field->name_length, *(int64_t *) p); - swTraceLog(SW_TRACE_MYSQL_CLIENT, "%.*s=%lld", field->name_length, field->name, *(int64_t *) p); + swTraceLog(SW_TRACE_MYSQL_CLIENT, "%.*s=%ld", field->name_length, field->name, *(int64_t *) p); } break; case SW_MYSQL_TYPE_FLOAT: { @@ -1901,7 +1900,8 @@ static PHP_METHOD(swoole_mysql_coro, fetch) { mc->fetch(return_value); mc->del_timeout_controller(); if (sw_unlikely(Z_TYPE_P(return_value) == IS_FALSE)) { - swoole_mysql_coro_sync_error_properties(ZEND_THIS, mc->get_error_code(), mc->get_error_msg(), mc->is_connected()); + swoole_mysql_coro_sync_error_properties( + ZEND_THIS, mc->get_error_code(), mc->get_error_msg(), mc->is_connected()); } } @@ -1918,7 +1918,8 @@ static PHP_METHOD(swoole_mysql_coro, fetchAll) { mc->fetch_all(return_value); mc->del_timeout_controller(); if (sw_unlikely(Z_TYPE_P(return_value) == IS_FALSE)) { - swoole_mysql_coro_sync_error_properties(ZEND_THIS, mc->get_error_code(), mc->get_error_msg(), mc->is_connected()); + swoole_mysql_coro_sync_error_properties( + ZEND_THIS, mc->get_error_code(), mc->get_error_msg(), mc->is_connected()); } } @@ -1958,7 +1959,8 @@ static PHP_METHOD(swoole_mysql_coro, prepare) { mc->add_timeout_controller(timeout, Socket::TIMEOUT_RDWR); if (UNEXPECTED(!mc->send_prepare_request(statement, statement_length))) { _failed: - swoole_mysql_coro_sync_error_properties(ZEND_THIS, mc->get_error_code(), mc->get_error_msg(), mc->is_connected()); + swoole_mysql_coro_sync_error_properties( + ZEND_THIS, mc->get_error_code(), mc->get_error_msg(), mc->is_connected()); RETVAL_FALSE; } else if (UNEXPECTED(mc->get_defer())) { RETVAL_TRUE; diff --git a/ext-src/swoole_mysql_proto.cc b/ext-src/swoole_mysql_proto.cc index 8cf59cad8e3..50f3fa8d443 100644 --- a/ext-src/swoole_mysql_proto.cc +++ b/ext-src/swoole_mysql_proto.cc @@ -365,7 +365,7 @@ eof_packet::eof_packet(const char *data) : server_packet(data) { data += 2; // int<2> status_flags Status Flags server_status = sw_mysql_uint2korr2korr(data); - swTraceLog(SW_TRACE_MYSQL_CLIENT, "EOF_Packet, warnings=%u, status_code=%u", warning_count, server_status); + swTraceLog(SW_TRACE_MYSQL_CLIENT, "EOF_Packet, warnings=%u, status_code=%u", warning_count, server_status.status); } ok_packet::ok_packet(const char *data) : server_packet(data) { @@ -388,7 +388,7 @@ ok_packet::ok_packet(const char *data) : server_packet(data) { "OK_Packet, affected_rows=%" PRIu64 ", insert_id=%" PRIu64 ", status_flags=0x%08x, warnings=%u", affected_rows, last_insert_id, - server_status, + server_status.status, warning_count); } @@ -494,7 +494,7 @@ greeting_packet::greeting_packet(const char *data) : server_packet(data) { server_version.c_str(), connection_id, capability_flags, - status_flags, + status_flags.status, auth_plugin_name.c_str(), auth_plugin_data_length, auth_plugin_data); diff --git a/ext-src/swoole_server.cc b/ext-src/swoole_server.cc index 68e8dedf0b5..71b77de1029 100644 --- a/ext-src/swoole_server.cc +++ b/ext-src/swoole_server.cc @@ -1250,7 +1250,7 @@ static void php_swoole_onPipeMessage(Server *serv, EventData *req) { } swTraceLog(SW_TRACE_SERVER, - "PipeMessage: fd=%d|len=%d|src_worker_id=%d|data=%.*s\n", + "PipeMessage: fd=%ld|len=%d|src_worker_id=%d|data=%.*s\n", req->info.fd, req->info.len, req->info.reactor_id, diff --git a/include/swoole.h b/include/swoole.h index 9501908e9fe..84f225009da 100644 --- a/include/swoole.h +++ b/include/swoole.h @@ -380,6 +380,7 @@ enum swFd_type { */ SW_FD_SIGNAL, SW_FD_DNS_RESOLVER, + SW_FD_CARES, /** * SW_FD_USER or SW_FD_USER+n: for custom event */ @@ -633,7 +634,7 @@ struct Global { int signal_fd; bool signal_alarm; - uint32_t trace_flags; + long trace_flags; void (*fatal_error)(int code, const char *str, ...); @@ -647,18 +648,20 @@ struct Global { Allocator std_allocator; std::string task_tmpfile; //-----------------------[DNS]-------------------------- - char *dns_server_v4; - char *dns_server_v6; + std::string dns_server_host; + int dns_server_port; double dns_cache_refresh_time; + int dns_tries; + std::string dns_resolvconf_path; //-----------------------[AIO]-------------------------- uint32_t aio_core_worker_num; uint32_t aio_worker_num; double aio_max_wait_time; double aio_max_idle_time; - swoole::network::Socket *aio_default_socket; + network::Socket *aio_default_socket; //-----------------------[Hook]-------------------------- void *hooks[SW_MAX_HOOK_TYPE]; - std::function user_exit_condition; + std::function user_exit_condition; }; std::string dirname(const std::string &file); @@ -694,6 +697,9 @@ static inline int swoole_get_process_id() { SW_API const char *swoole_strerror(int code); SW_API void swoole_throw_error(int code); +SW_API void swoole_set_log_level(int level); +SW_API void swoole_set_trace_flags(int flags); +SW_API void swoole_set_dns_server(const std::string server); //----------------------------------------------- static sw_inline void sw_spinlock(sw_atomic_t *lock) { diff --git a/include/swoole_config.h b/include/swoole_config.h index 7ee5d23af01..239a743ae28 100644 --- a/include/swoole_config.h +++ b/include/swoole_config.h @@ -192,6 +192,7 @@ #define SW_DNS_HOST_BUFFER_SIZE 16 #define SW_DNS_SERVER_PORT 53 #define SW_DNS_DEFAULT_SERVER "8.8.8.8" +#define SW_DNS_RESOLV_CONF "/etc/resolv.conf" #define SW_Z_BEST_SPEED 1 #define SW_COMPRESSION_MIN_LENGTH_DEFAULT 20 diff --git a/include/swoole_coroutine.h b/include/swoole_coroutine.h index ccfc07ed5d8..2712a550563 100644 --- a/include/swoole_coroutine.h +++ b/include/swoole_coroutine.h @@ -72,15 +72,15 @@ class Coroutine { void yield_naked(); bool yield_ex(double timeout = -1); - inline enum State get_state() { + inline enum State get_state() const { return state; } - inline long get_init_msec() { + inline long get_init_msec() const { return init_msec; } - inline long get_cid() { + inline long get_cid() const { return cid; } @@ -100,14 +100,18 @@ class Coroutine { return ctx.is_end(); } - bool is_canceled() { + bool is_canceled() const { return resume_code_ == RC_CANCELED; } - bool is_timedout() { + bool is_timedout() const { return resume_code_ == RC_TIMEDOUT; } + bool is_suspending() const { + return state == STATE_WAITING; + } + inline void set_task(void *_task) { task = _task; } diff --git a/include/swoole_coroutine_socket.h b/include/swoole_coroutine_socket.h index 860179d6f25..e02236d2415 100644 --- a/include/swoole_coroutine_socket.h +++ b/include/swoole_coroutine_socket.h @@ -591,7 +591,11 @@ class ProtocolSwitch { } }; -std::vector dns_lookup(const char *domain, double timeout = 2.0); +std::vector dns_lookup(const char *domain, int family = AF_INET, double timeout = 2.0); +std::vector dns_lookup_impl_with_socket(const char *domain, int family, double timeout); +#ifdef SW_USE_CARES +std::vector dns_lookup_impl_with_cares(const char *domain, int family, double timeout); +#endif //------------------------------------------------------------------------------- } // namespace coroutine } // namespace swoole diff --git a/include/swoole_coroutine_system.h b/include/swoole_coroutine_system.h index 9404db8d1a8..fefaa4aeb8f 100644 --- a/include/swoole_coroutine_system.h +++ b/include/swoole_coroutine_system.h @@ -68,6 +68,7 @@ class System { /* event */ static int wait_event(int fd, int events, double timeout); }; +std::string gethostbyname_impl_with_async(const std::string &hostname, int domain, double timeout = -1); //------------------------------------------------------------------------------- } // namespace coroutine } // namespace swoole diff --git a/include/swoole_error.h b/include/swoole_error.h index d563b5264d3..251ef3f4ba2 100644 --- a/include/swoole_error.h +++ b/include/swoole_error.h @@ -38,10 +38,14 @@ enum swErrorCode { SW_ERROR_FILE_NOT_EXIST = 700, SW_ERROR_FILE_TOO_LARGE, SW_ERROR_FILE_EMPTY, - SW_ERROR_DNSLOOKUP_DUPLICATE_REQUEST, + + SW_ERROR_DNSLOOKUP_DUPLICATE_REQUEST = 710, SW_ERROR_DNSLOOKUP_RESOLVE_FAILED, SW_ERROR_DNSLOOKUP_RESOLVE_TIMEOUT, - SW_ERROR_BAD_IPV6_ADDRESS, + SW_ERROR_DNSLOOKUP_UNSUPPORTED, + SW_ERROR_DNSLOOKUP_NO_SERVER, + + SW_ERROR_BAD_IPV6_ADDRESS = 720, SW_ERROR_UNREGISTERED_SIGNAL, // EventLoop diff --git a/include/swoole_log.h b/include/swoole_log.h index 67a8607915a..a40a17b3d4c 100644 --- a/include/swoole_log.h +++ b/include/swoole_log.h @@ -243,8 +243,9 @@ enum swTrace_type { SW_TRACE_CO_HTTP_SERVER = 1u << 27, SW_TRACE_TABLE = 1u << 28, SW_TRACE_CO_CURL = 1u << 29, + SW_TRACE_CARES = 1u << 30, - SW_TRACE_ALL = 0xffffffff + SW_TRACE_ALL = 0x7fffffffffffffff }; #ifdef SW_LOG_TRACE_OPEN diff --git a/make.sh b/make.sh index 38c4e00abb3..54e64931cf6 100755 --- a/make.sh +++ b/make.sh @@ -1,6 +1,6 @@ #!/bin/sh -e __DIR__=$(cd "$(dirname "$0")";pwd) -COMPILE_PARAMS="--enable-openssl --enable-sockets --enable-mysqlnd --enable-http2 --enable-swoole-json --enable-swoole-curl" +COMPILE_PARAMS="--enable-openssl --enable-sockets --enable-mysqlnd --enable-http2 --enable-swoole-json --enable-swoole-curl --enable-cares" if [ "$(uname | grep -i darwin)"x != ""x ]; then CPU_COUNT="$(sysctl -n machdep.cpu.core_count)" diff --git a/src/core/base.cc b/src/core/base.cc index 882518d6aed..2622c5d4621 100644 --- a/src/core/base.cc +++ b/src/core/base.cc @@ -125,6 +125,10 @@ void swoole_init(void) { SwooleG.cpu_num = SW_MAX(1, sysconf(_SC_NPROCESSORS_ONLN)); SwooleG.pagesize = getpagesize(); + // DNS options + SwooleG.dns_tries = 1; + SwooleG.dns_resolvconf_path = SW_DNS_RESOLV_CONF; + // get system uname uname(&SwooleG.uname); // random seed @@ -225,9 +229,39 @@ void swoole_clean(void) { delete g_logger_instance; g_logger_instance = nullptr; } + if (SwooleTG.buffer_stack) { + delete SwooleTG.buffer_stack; + SwooleTG.buffer_stack = nullptr; + } SwooleG = {}; } +SW_API void swoole_set_log_level(int level) { + if (sw_logger()) { + sw_logger()->set_level(level); + } +} + +SW_API void swoole_set_trace_flags(int flags) { + SwooleG.trace_flags = flags; +} + +SW_API void swoole_set_dns_server(const std::string server) { + char *_port; + int dns_server_port = SW_DNS_SERVER_PORT; + char dns_server_host[32]; + strcpy(dns_server_host, server.c_str()); + if ((_port = strchr((char *)server.c_str(), ':'))) { + dns_server_port = atoi(_port + 1); + if (dns_server_port <= 0 || dns_server_port > 65535) { + dns_server_port = SW_DNS_SERVER_PORT; + } + dns_server_host[_port - server.c_str()] = '\0'; + } + SwooleG.dns_server_host = dns_server_host; + SwooleG.dns_server_port = dns_server_port; +} + bool swoole_set_task_tmpdir(const std::string &dir) { if (dir.at(0) != '/') { swWarn("wrong absolute path '%s'", dir.c_str()); diff --git a/src/core/string.cc b/src/core/string.cc index f117852d642..4c8bd7f4847 100644 --- a/src/core/string.cc +++ b/src/core/string.cc @@ -180,7 +180,7 @@ ssize_t String::split(const char *delimiter, size_t delimiter_length, const Stri while (delimiter_addr) { size_t _length = delimiter_addr - start_addr + delimiter_length; - swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[4] count=%d, length=%d", count, _length + offset); + swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[4] count=%d, length=%lu", count, _length + offset); if (handler((char *) start_addr - _offset, _length + _offset) == false) { return -1; } diff --git a/src/core/timer.cc b/src/core/timer.cc index 93290141303..dc58f44f7e2 100644 --- a/src/core/timer.cc +++ b/src/core/timer.cc @@ -142,7 +142,7 @@ TimerNode *Timer::add(long _msec, bool persistent, void *data, const TimerCallba } map.emplace(std::make_pair(tnode->id, tnode)); swTraceLog(SW_TRACE_TIMER, - "id=%ld, exec_msec=%" PRId64 ", msec=%ld, round=%" PRIu64 ", exist=%u", + "id=%ld, exec_msec=%" PRId64 ", msec=%ld, round=%" PRIu64 ", exist=%lu", tnode->id, tnode->exec_msec, _msec, @@ -158,7 +158,7 @@ bool Timer::remove(TimerNode *tnode) { if (sw_unlikely(_current_id > 0 && tnode->id == _current_id)) { tnode->removed = true; swTraceLog(SW_TRACE_TIMER, - "set-remove: id=%ld, exec_msec=%" PRId64 ", round=%" PRIu64 ", exist=%u", + "set-remove: id=%ld, exec_msec=%" PRId64 ", round=%" PRIu64 ", exist=%lu", tnode->id, tnode->exec_msec, tnode->round, @@ -175,7 +175,7 @@ bool Timer::remove(TimerNode *tnode) { tnode->destructor(tnode); } swTraceLog(SW_TRACE_TIMER, - "id=%ld, exec_msec=%" PRId64 ", round=%" PRIu64 ", exist=%u", + "id=%ld, exec_msec=%" PRId64 ", round=%" PRIu64 ", exist=%lu", tnode->id, tnode->exec_msec, tnode->round, @@ -204,7 +204,7 @@ int Timer::select() { _current_id = tnode->id; if (!tnode->removed) { swTraceLog(SW_TRACE_TIMER, - "id=%ld, exec_msec=%" PRId64 ", round=%" PRIu64 ", exist=%u", + "id=%ld, exec_msec=%" PRId64 ", round=%" PRIu64 ", exist=%lu", tnode->id, tnode->exec_msec, tnode->round, diff --git a/src/coroutine/system.cc b/src/coroutine/system.cc index fe6599be015..af03c28b1be 100644 --- a/src/coroutine/system.cc +++ b/src/coroutine/system.cc @@ -15,6 +15,7 @@ */ #include "swoole_coroutine_system.h" +#include "swoole_coroutine_socket.h" #include "swoole_lru_cache.h" #include "swoole_signal.h" @@ -135,22 +136,7 @@ ssize_t System::write_file(const char *file, char *buf, size_t length, bool lock return retval; } -std::string System::gethostbyname(const std::string &hostname, int domain, double timeout) { - if (dns_cache == nullptr && dns_cache_capacity != 0) { - dns_cache = new LRUCache(dns_cache_capacity); - } - - std::string cache_key; - if (dns_cache) { - cache_key.append(domain == AF_INET ? "4_" : "6_"); - cache_key.append(hostname); - auto cache = dns_cache->get(cache_key); - - if (cache) { - return *(std::string *) cache.get(); - } - } - +std::string gethostbyname_impl_with_async(const std::string &hostname, int domain, double timeout) { AsyncEvent ev{}; if (hostname.size() < SW_IP_MAX_LENGTH) { @@ -178,19 +164,48 @@ std::string System::gethostbyname(const std::string &hostname, int domain, doubl swoole_set_last_error(ev.error); return ""; } else { - if (dns_cache) { - std::string *addr = new std::string((char *) ev.buf); - dns_cache->set(cache_key, std::shared_ptr(addr), dns_cache_expire); - sw_free(ev.buf); - return *addr; - } - std::string addr((char *) ev.buf); sw_free(ev.buf); return addr; } } +std::string System::gethostbyname(const std::string &hostname, int domain, double timeout) { + if (dns_cache == nullptr && dns_cache_capacity != 0) { + dns_cache = new LRUCache(dns_cache_capacity); + } + + std::string cache_key; + std::string result; + + if (dns_cache) { + cache_key.append(domain == AF_INET ? "4_" : "6_"); + cache_key.append(hostname); + auto cache = dns_cache->get(cache_key); + + if (cache) { + return *(std::string *) cache.get(); + } + } + +#ifdef SW_USE_CARES + auto result_list = dns_lookup_impl_with_cares(hostname.c_str(), domain, timeout); + if (SwooleG.dns_lookup_random) { + result = result_list[rand() % result_list.size()]; + } else { + result = result_list[0]; + } +#else + result = gethostbyname_impl_with_async(hostname, domain, timeout); +#endif + + if (dns_cache) { + dns_cache->set(cache_key, std::make_shared(result), dns_cache_expire); + } + + return result; +} + std::vector System::getaddrinfo( const std::string &hostname, int family, int socktype, int protocol, const std::string &service, double timeout) { assert(!hostname.empty()); diff --git a/src/network/dns.cc b/src/network/dns.cc index afb9828c714..eb31534346f 100644 --- a/src/network/dns.cc +++ b/src/network/dns.cc @@ -18,11 +18,18 @@ #include "swoole_coroutine_socket.h" #include +#include #include -#define SW_DNS_SERVER_CONF "/etc/resolv.conf" +#ifdef SW_USE_CARES +#include +#endif + #define SW_DNS_SERVER_NUM 2 +namespace swoole { +namespace coroutine { + enum swDNS_type { SW_DNS_A_RECORD = 0x01, // Lookup IPv4 address SW_DNS_AAAA_RECORD = 0x1c, // Lookup IPv6 address @@ -36,7 +43,7 @@ enum swDNS_error { }; /* Struct for the DNS Header */ -typedef struct { +struct RecordHeader { uint16_t id; uchar rd : 1; uchar tc : 1; @@ -50,35 +57,36 @@ typedef struct { uint16_t ancount; uint16_t nscount; uint16_t arcount; -} swDNSResolver_header; +}; /* Struct for the flags for the DNS Question */ -typedef struct q_flags { +struct Q_FLAGS { uint16_t qtype; uint16_t qclass; -} Q_FLAGS; +}; /* Struct for the flags for the DNS RRs */ -typedef struct rr_flags { +struct RR_FLAGS { uint16_t type; uint16_t rdclass; uint32_t ttl; uint16_t rdlength; -} RR_FLAGS; +}; -static uint16_t swoole_dns_request_id = 1; +static uint16_t dns_request_id = 1; static int domain_encode(const char *src, int n, char *dest); static void domain_decode(char *str); static int get_dns_server(); +static std::string parse_ip_address(void *vaddr, int type); static int get_dns_server() { FILE *fp; char line[100]; char buf[16] = {}; - if ((fp = fopen(SW_DNS_SERVER_CONF, "rt")) == nullptr) { - swSysWarn("fopen(" SW_DNS_SERVER_CONF ") failed"); + if ((fp = fopen(SwooleG.dns_resolvconf_path.c_str(), "rt")) == nullptr) { + swSysWarn("fopen(%s) failed", SwooleG.dns_resolvconf_path.c_str()); return SW_ERR; } @@ -92,30 +100,53 @@ static int get_dns_server() { fclose(fp); if (strlen(buf) == 0) { - SwooleG.dns_server_v4 = sw_strdup(SW_DNS_DEFAULT_SERVER); + swoole_set_dns_server(SW_DNS_DEFAULT_SERVER); } else { - SwooleG.dns_server_v4 = sw_strdup(buf); + swoole_set_dns_server(buf); } return SW_OK; } -std::vector swoole::coroutine::dns_lookup(const char *domain, double timeout) { +static std::string parse_ip_address(void *vaddr, int type) { + auto addr = reinterpret_cast(vaddr); + std::string ip_addr; + if (type == AF_INET) { + char buff[4 * 4 + 3 + 1]; + sw_snprintf(buff, sizeof(buff), "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]); + return ip_addr.assign(buff); + } else if (type == AF_INET6) { + for (int i = 0; i < 16; i += 2) { + if (i > 0) { + ip_addr.append(":"); + } + char buf[4 + 1]; + size_t n = sw_snprintf(buf, sizeof(buf), "%02x%02x", addr[i], addr[i + 1]); + ip_addr.append(buf, n); + } + } else { + assert(0); + } + return ip_addr; +} + +std::vector dns_lookup_impl_with_socket(const char *domain, int family, double timeout) { char *_domain_name; Q_FLAGS *qflags = nullptr; char packet[SW_BUFFER_SIZE_STD]; - swDNSResolver_header *header = nullptr; + RecordHeader *header = nullptr; int steps = 0; - std::vector result; - if (SwooleG.dns_server_v4 == nullptr) { + + if (SwooleG.dns_server_host.empty()) { if (get_dns_server() < 0) { + swoole_set_last_error(SW_ERROR_DNSLOOKUP_NO_SERVER); return result; } } - header = (swDNSResolver_header *) packet; - int _request_id = swoole_dns_request_id++; + header = (RecordHeader *) packet; + int _request_id = dns_request_id++; header->id = htons(_request_id); header->qr = 0; header->opcode = 0; @@ -130,7 +161,7 @@ std::vector swoole::coroutine::dns_lookup(const char *domain, doubl header->nscount = 0x0000; header->arcount = 0x0000; - steps = sizeof(swDNSResolver_header); + steps = sizeof(RecordHeader); _domain_name = &packet[steps]; @@ -143,7 +174,7 @@ std::vector swoole::coroutine::dns_lookup(const char *domain, doubl steps += (strlen((const char *) _domain_name) + 1); qflags = (Q_FLAGS *) &packet[steps]; - qflags->qtype = htons(SW_DNS_A_RECORD); + qflags->qtype = htons(family == AF_INET6 ? SW_DNS_AAAA_RECORD : SW_DNS_A_RECORD); qflags->qclass = htons(0x0001); steps += sizeof(Q_FLAGS); @@ -151,16 +182,8 @@ std::vector swoole::coroutine::dns_lookup(const char *domain, doubl if (timeout > 0) { _sock.set_timeout(timeout); } - - char *_port; - int dns_server_port = SW_DNS_SERVER_PORT; - char dns_server_host[32]; - strcpy(dns_server_host, SwooleG.dns_server_v4); - if ((_port = strchr(SwooleG.dns_server_v4, ':'))) { - dns_server_port = atoi(_port + 1); - dns_server_host[_port - SwooleG.dns_server_v4] = '\0'; - } - if (!_sock.sendto(dns_server_host, dns_server_port, (char *) packet, steps)) { + if (!_sock.sendto(SwooleG.dns_server_host, SwooleG.dns_server_port, (char *) packet, steps)) { + swoole_set_last_error(SW_ERROR_DNSLOOKUP_RESOLVE_FAILED); return result; } @@ -181,14 +204,15 @@ std::vector swoole::coroutine::dns_lookup(const char *domain, doubl char name[10][254]; int i, j; - int ret = _sock.recv(packet, sizeof(packet) - 1); + auto ret = _sock.recv(packet, sizeof(packet) - 1); if (ret <= 0) { + swoole_set_last_error(_sock.errCode == ECANCELED ? SW_ERROR_CO_CANCELED: SW_ERROR_DNSLOOKUP_RESOLVE_FAILED); return result; } packet[ret] = 0; - header = (swDNSResolver_header *) packet; - steps = sizeof(swDNSResolver_header); + header = (RecordHeader *) packet; + steps = sizeof(RecordHeader); _domain_name = &packet[steps]; domain_decode(_domain_name); @@ -228,11 +252,9 @@ std::vector swoole::coroutine::dns_lookup(const char *domain, doubl steps = steps + sizeof(RR_FLAGS) - 2; /* Parsing the IPv4 address in the RR */ - if (ntohs(rrflags->type) == 1) { - for (j = 0; j < ntohs(rrflags->rdlength); ++j) { - rdata[i][j] = (uchar) packet[steps + j]; - } - type[i] = ntohs(rrflags->type); + type[i] = ntohs(rrflags->type); + for (j = 0; j < ntohs(rrflags->rdlength); ++j) { + rdata[i][j] = (uchar) packet[steps + j]; } /* Parsing the canonical name in the RR */ @@ -259,16 +281,17 @@ std::vector swoole::coroutine::dns_lookup(const char *domain, doubl int request_id = ntohs(header->id); // bad response if (request_id != _request_id) { + swoole_set_last_error(SW_ERROR_DNSLOOKUP_RESOLVE_FAILED); return result; } for (i = 0; i < ancount; i++) { - if (type[i] != SW_DNS_A_RECORD) { + if (type[i] != SW_DNS_A_RECORD && type[i] != SW_DNS_AAAA_RECORD) { continue; } - char address[16]; - size_t n = - sw_snprintf(address, sizeof(address), "%d.%d.%d.%d", rdata[i][0], rdata[i][1], rdata[i][2], rdata[i][3]); - result.push_back(std::string(address, n)); + result.push_back(parse_ip_address(rdata[i], type[i] == SW_DNS_A_RECORD ? AF_INET : AF_INET6)); + } + if (result.empty()) { + swoole_set_last_error(SW_ERROR_DNSLOOKUP_RESOLVE_FAILED); } return result; } @@ -319,7 +342,177 @@ static void domain_decode(char *str) { str[i - 1] = '\0'; } -namespace swoole { +#ifdef SW_USE_CARES +struct ResolvContext { + ares_channel channel; + ares_options ares_opts; + int ares_flags; + int error; + Coroutine *co; + std::unordered_map sockets; + std::vector result; +}; + +std::vector dns_lookup_impl_with_cares(const char *domain, int family, double timeout) { + if (!swoole_event_isset_handler(SW_FD_CARES)) { + ares_library_init(ARES_LIB_INIT_ALL); + swoole_event_set_handler(SW_FD_CARES | SW_EVENT_READ, [](Reactor *reactor, Event *event) -> int { + auto ctx = reinterpret_cast(event->socket->object); + swTraceLog(SW_TRACE_CARES, "[event callback] readable event, fd=%d", event->socket->fd); + ares_process_fd(ctx->channel, event->fd, ARES_SOCKET_BAD); + return SW_OK; + }); + swoole_event_set_handler(SW_FD_CARES | SW_EVENT_WRITE, [](Reactor *reactor, Event *event) -> int { + auto ctx = reinterpret_cast(event->socket->object); + swTraceLog(SW_TRACE_CARES, "[event callback] writable event, fd=%d", event->socket->fd); + ares_process_fd(ctx->channel, ARES_SOCKET_BAD, event->fd); + return SW_OK; + }); + sw_reactor()->add_destroy_callback([](void *_data) { ares_library_cleanup(); }, nullptr); + } + + ResolvContext ctx{}; + Coroutine *co = Coroutine::get_current_safe(); + ctx.co = co; + char lookups[] = "fb"; + int res; + ctx.ares_opts.lookups = lookups; + ctx.ares_opts.timeout = timeout * 1000; + ctx.ares_opts.tries = SwooleG.dns_tries; + ctx.ares_opts.sock_state_cb_data = &ctx; + ctx.ares_opts.sock_state_cb = [](void *arg, int fd, int readable, int writable) { + auto ctx = reinterpret_cast(arg); + int events = 0; + if (readable) { + events |= SW_EVENT_READ; + } + if (writable) { + events |= SW_EVENT_WRITE; + } + + swTraceLog(SW_TRACE_CARES, "[sock_state_cb], fd=%d, readable=%d, writable=%d", fd, readable, writable); + + network::Socket *_socket = nullptr; + if (ctx->sockets.find(fd) == ctx->sockets.end()) { + if (events == 0) { + swWarn("error events, fd=%d", fd); + return; + } + _socket = make_socket(fd, SW_FD_CARES); + _socket->object = ctx; + ctx->sockets[fd] = _socket; + } else { + _socket = ctx->sockets[fd]; + if (events == 0) { + swTraceLog(SW_TRACE_CARES, "[del event], fd=%d", fd); + swoole_event_del(_socket); + _socket->fd = -1; + _socket->free(); + ctx->sockets.erase(fd); + return; + } + } + + if (_socket->events) { + swoole_event_set(_socket, events); + swTraceLog(SW_TRACE_CARES, "[set event] fd=%d, events=%d", fd, events); + } else { + swoole_event_add(_socket, events); + swTraceLog(SW_TRACE_CARES, "[add event] fd=%d, events=%d", fd, events); + } + }; + ctx.ares_flags = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES | ARES_OPT_SOCK_STATE_CB | ARES_OPT_LOOKUPS; + + if ((res = ares_init_options(&ctx.channel, &ctx.ares_opts, ctx.ares_flags)) != ARES_SUCCESS) { + swWarn("ares_init_options() failed, Error: %s[%d]", ares_strerror(res), res); + goto _return; + } + + if (!SwooleG.dns_server_host.empty()) { + struct ares_addr_port_node servers; + servers.family = AF_INET; + servers.next = nullptr; + inet_pton(AF_INET, SwooleG.dns_server_host.c_str(), &servers.addr.addr4); + servers.tcp_port = 0; + servers.udp_port = SwooleG.dns_server_port; + ares_set_servers_ports(ctx.channel, &servers); + } + + ares_gethostbyname( + ctx.channel, + domain, + family, + [](void *data, int status, int timeouts, struct hostent *hostent) { + auto ctx = reinterpret_cast(data); + + swTraceLog(SW_TRACE_CARES, "[cares callback] status=%d, timeouts=%d", status, timeouts); + + if (timeouts > 0) { + ctx->error = SW_ERROR_DNSLOOKUP_RESOLVE_TIMEOUT; + goto _resume; + } + + if (status != ARES_SUCCESS) { + ctx->error = status; + goto _resume; + } + + if (hostent->h_addr_list) { + char **paddr = hostent->h_addr_list; + while (*paddr != nullptr) { + ctx->result.emplace_back(parse_ip_address(*paddr, hostent->h_addrtype)); + paddr++; + } + } + _resume: + if (ctx->co && ctx->co->is_suspending()) { + swoole_event_defer( + [](void *data) { + Coroutine *co = reinterpret_cast(data); + co->resume(); + }, + ctx->co); + ctx->co = nullptr; + } + }, + &ctx); + + if (ctx.error) { + goto _destroy; + } + + co->yield_ex(timeout); + if (co->is_canceled()) { + ares_cancel(ctx.channel); + } else if (co->is_timedout()) { + ares_process_fd(ctx.channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); + swoole_set_last_error(SW_ERROR_DNSLOOKUP_RESOLVE_TIMEOUT); + } else { + swTraceLog(SW_TRACE_CARES, "lookup success, result_count=%lu", ctx.result.size()); + } +_destroy: + if (ctx.error) { + swoole_set_last_error(ctx.error == ARES_ECANCELLED ? SW_ERROR_CO_CANCELED : SW_ERROR_DNSLOOKUP_RESOLVE_FAILED); + } + ares_destroy(ctx.channel); +_return: + return ctx.result; +} +#endif + +std::vector dns_lookup(const char *domain, int family, double timeout) { +#ifdef SW_USE_CARES + return dns_lookup_impl_with_cares(domain, family, timeout); +#else + return dns_lookup_impl_with_socket(domain, family, timeout); +#endif +} + +} // namespace coroutine + +/** + * blocking-IO, Use in synchronous mode or AIO thread pool + */ namespace network { #ifndef HAVE_GETHOSTBYNAME2_R @@ -327,9 +520,6 @@ namespace network { static std::mutex g_gethostbyname2_lock; #endif -/** - * DNS lookup - */ #ifdef HAVE_GETHOSTBYNAME2_R int gethostbyname(int flags, const char *name, char *addr) { int __af = flags & (~SW_DNS_LOOKUP_RANDOM); @@ -363,7 +553,7 @@ int gethostbyname(int flags, const char *name, char *addr) { union { char v4[INET_ADDRSTRLEN]; char v6[INET6_ADDRSTRLEN]; - } addr_list[SW_DNS_HOST_BUFFER_SIZE] {}; + } addr_list[SW_DNS_HOST_BUFFER_SIZE]{}; int i = 0; for (i = 0; i < SW_DNS_HOST_BUFFER_SIZE; i++) { @@ -426,7 +616,7 @@ int gethostbyname(int flags, const char *name, char *addr) { int getaddrinfo(GetaddrinfoRequest *req) { struct addrinfo *result = nullptr; struct addrinfo *ptr = nullptr; - struct addrinfo hints{}; + struct addrinfo hints {}; hints.ai_family = req->family; hints.ai_socktype = req->socktype; @@ -483,6 +673,5 @@ void GetaddrinfoRequest::parse_result(std::vector &retval) { } } } - } // namespace network } // namespace swoole diff --git a/src/os/async_thread.cc b/src/os/async_thread.cc index ecd4d236a30..7994ccc1544 100644 --- a/src/os/async_thread.cc +++ b/src/os/async_thread.cc @@ -252,7 +252,7 @@ void ThreadPool::create_thread(const bool is_core_worker) { } swTraceLog(SW_TRACE_AIO, - "aio_thread %s. ret=%d, error=%d", + "aio_thread %s. ret=%ld, error=%d", event->retval > 0 ? "ok" : "failed", event->retval, event->error); diff --git a/src/protocol/websocket.cc b/src/protocol/websocket.cc index d67446ed936..4e5312d6e96 100644 --- a/src/protocol/websocket.cc +++ b/src/protocol/websocket.cc @@ -92,7 +92,7 @@ ssize_t swWebSocket_get_package_length(Protocol *protocol, Socket *conn, const c return 0; } } - swTraceLog(SW_TRACE_LENGTH_PROTOCOL, "header_length=%zu, payload_length=%u", header_length, payload_length); + swTraceLog(SW_TRACE_LENGTH_PROTOCOL, "header_length=%zu, payload_length=%lu", header_length, payload_length); return header_length + payload_length; } diff --git a/src/server/base.cc b/src/server/base.cc index aeeb01e9e12..33245e01bd3 100644 --- a/src/server/base.cc +++ b/src/server/base.cc @@ -200,7 +200,7 @@ bool BaseFactory::finish(SendData *data) { return false; } } - swTrace("proxy message, fd=%d, len=%ld", worker->pipe_master, sizeof(proxy_msg.info) + proxy_msg.info.len); + swTrace("proxy message, fd=%d, len=%ld", worker->pipe_master->fd, sizeof(proxy_msg.info) + proxy_msg.info.len); } else if (data->info.type == SW_SERVER_EVENT_SEND_FILE) { memcpy(&proxy_msg.info, &data->info, sizeof(proxy_msg.info)); memcpy(proxy_msg.data, data->data, data->info.len); diff --git a/tests/swoole_coroutine/dnslookup_1.phpt b/tests/swoole_coroutine/dnslookup_1.phpt index 26af90ddb51..59e41155393 100644 --- a/tests/swoole_coroutine/dnslookup_1.phpt +++ b/tests/swoole_coroutine/dnslookup_1.phpt @@ -8,10 +8,12 @@ skip_if_offline(); --EXPECT-- diff --git a/tests/swoole_coroutine/dnslookup_2.phpt b/tests/swoole_coroutine/dnslookup_2.phpt index 9de32793040..f1727cdc712 100644 --- a/tests/swoole_coroutine/dnslookup_2.phpt +++ b/tests/swoole_coroutine/dnslookup_2.phpt @@ -5,12 +5,14 @@ swoole_coroutine: async dns lookup timeout --FILE-- '192.0.0.1:10053']); + +use Swoole\Coroutine\System; +use function Swoole\Coroutine\run; + +run(function () { $host = Swoole\Coroutine::dnsLookup('www.' . uniqid() . '.' . uniqid(), 0.5); Assert::eq($host, false); Assert::eq(swoole_last_error(), SWOOLE_ERROR_DNSLOOKUP_RESOLVE_FAILED); - Swoole\Event::exit(); }); ?> --EXPECT-- diff --git a/tests/swoole_coroutine/dnslookup_3.phpt b/tests/swoole_coroutine/dnslookup_3.phpt index 82a7ce6f5b7..1f6c343d1a9 100644 --- a/tests/swoole_coroutine/dnslookup_3.phpt +++ b/tests/swoole_coroutine/dnslookup_3.phpt @@ -10,7 +10,6 @@ go(function () { $host = swoole_async_dns_lookup_coro('www.' . uniqid() . '.' . uniqid(), 15); Assert::eq($host, false); Assert::eq(swoole_last_error(), SWOOLE_ERROR_DNSLOOKUP_RESOLVE_FAILED); - Swoole\Event::exit(); }); swoole_event_wait(); ?> diff --git a/tests/swoole_coroutine/dnslookup_4.phpt b/tests/swoole_coroutine/dnslookup_4.phpt new file mode 100644 index 00000000000..0830b6d8c6e --- /dev/null +++ b/tests/swoole_coroutine/dnslookup_4.phpt @@ -0,0 +1,19 @@ +--TEST-- +swoole_coroutine: bad dns server +--SKIPIF-- + +--FILE-- + '192.0.0.1:10053']); + $host = Swoole\Coroutine::dnsLookup('www.baidu.com', 0.5); + Assert::eq($host, false); + Assert::eq(swoole_last_error(), SWOOLE_ERROR_DNSLOOKUP_RESOLVE_FAILED); +}); +?> +--EXPECT-- diff --git a/tests/swoole_coroutine/dnslookup_ipv6.phpt b/tests/swoole_coroutine/dnslookup_ipv6.phpt new file mode 100644 index 00000000000..af94e63859f --- /dev/null +++ b/tests/swoole_coroutine/dnslookup_ipv6.phpt @@ -0,0 +1,19 @@ +--TEST-- +swoole_coroutine: dns Lookup IPv6 +--SKIPIF-- + +--FILE-- + +--EXPECT-- diff --git a/tests/swoole_http_client_coro/get_twice.phpt b/tests/swoole_http_client_coro/get_twice.phpt index 1b7a9faec65..ce7063835eb 100644 --- a/tests/swoole_http_client_coro/get_twice.phpt +++ b/tests/swoole_http_client_coro/get_twice.phpt @@ -11,11 +11,11 @@ use Swoole\Coroutine\Http\Client; const N = 2; Swoole\Coroutine\Run(function () { - $client = new Client('www.zhe800.com', 443, true); + $client = new Client('www.baidu.com', 443, true); $client->set(['timeout' => 5,]); for ($i = 0; $i < N; $i++) { $rand = mt_rand(100000, 999999999); - $path = "/email_subscribe?email=" . $rand . "@" . substr(md5(microtime(true)), 0, 8) . ".com"; + $path = "/index.php?email=" . $rand . "@" . substr(md5(microtime(true)), 0, 8) . ".com"; $result = $client->get($path); if (!$result) { var_dump("ERROR: ".$client->getStatusCode()); diff --git a/tests/swoole_http_client_coro/get_twice_keepalive.phpt b/tests/swoole_http_client_coro/get_twice_keepalive.phpt index afed15f6fa8..963f09ec22f 100644 --- a/tests/swoole_http_client_coro/get_twice_keepalive.phpt +++ b/tests/swoole_http_client_coro/get_twice_keepalive.phpt @@ -11,11 +11,11 @@ use Swoole\Coroutine\Http\Client; const N = 2; Swoole\Coroutine\Run(function () { - $client = new Client('www.zhe800.com', 443, true); + $client = new Client('www.baidu.com', 443, true); $client->set(['timeout' => 5,]); for ($i = 0; $i < N; $i++) { $rand = mt_rand(100000, 999999999); - $path = "/email_subscribe?email=" . $rand . "@" . substr(md5(microtime(true)), 0, 8) . ".com"; + $path = "/index.php?email=" . $rand . "@" . substr(md5(microtime(true)), 0, 8) . ".com"; Assert::assert($client->get($path)); Assert::assert($client->getStatusCode() == 200); } diff --git a/tests/swoole_server/unregistered_signal.phpt b/tests/swoole_server/unregistered_signal.phpt index 8199bac5511..8abab97ec24 100644 --- a/tests/swoole_server/unregistered_signal.phpt +++ b/tests/swoole_server/unregistered_signal.phpt @@ -37,4 +37,4 @@ $pm->childFirst(); $pm->run(); ?> --EXPECTF-- -[%s] WARNING %s (ERRNO 707): Unable to find callback function for signal Broken pipe: 13 +[%s] WARNING %s (ERRNO 721): Unable to find callback function for signal Broken pipe: 13