Merge commit 'cecdae448e88603c98d7d079855c992be6df739f'
This commit is contained in:
commit
17230da76a
80
CMake/GeneratePkgConfig.cmake
Normal file
80
CMake/GeneratePkgConfig.cmake
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
function(get_relative_link OUTPUT PATH)
|
||||||
|
if (PATH MATCHES "^[$]<[$]<CONFIG:DEBUG>:")
|
||||||
|
set(${OUTPUT} "" PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
string(REGEX REPLACE "^[$]<[$]<NOT:[$]<CONFIG:DEBUG>>:(.*)>$" "\\1" PATH "${PATH}")
|
||||||
|
|
||||||
|
get_filename_component(NAME "${PATH}" NAME_WE)
|
||||||
|
if (IS_ABSOLUTE ${PATH})
|
||||||
|
get_filename_component(DIRECTORY_NAME "${PATH}" DIRECTORY)
|
||||||
|
if (WIN32)
|
||||||
|
set(${OUTPUT} "-l\"${DIRECTORY_NAME}/${NAME}\"" PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
get_filename_component(FULL_NAME "${PATH}" NAME)
|
||||||
|
set(${OUTPUT} "-L\"${DIRECTORY_NAME}\" -l:${FULL_NAME}" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT WIN32 AND NAME MATCHES "^lib")
|
||||||
|
string(REGEX REPLACE "^lib" "-l" LINK "${NAME}")
|
||||||
|
elseif (NAME MATCHES "^-")
|
||||||
|
set(LINK "${NAME}")
|
||||||
|
else()
|
||||||
|
string(CONCAT LINK "-l" "${NAME}")
|
||||||
|
endif()
|
||||||
|
set(${OUTPUT} "${LINK}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(generate_pkgconfig TARGET DESCRIPTION)
|
||||||
|
# message("Generating pkg-config for ${TARGET}")
|
||||||
|
get_filename_component(PREFIX "${CMAKE_INSTALL_PREFIX}" REALPATH)
|
||||||
|
|
||||||
|
get_target_property(LIST "${TARGET}" LINK_LIBRARIES)
|
||||||
|
set(REQS "")
|
||||||
|
set(LIBS "")
|
||||||
|
foreach (LIB ${LIST})
|
||||||
|
if (TARGET "${LIB}")
|
||||||
|
set(HAS_REQS 1)
|
||||||
|
list(APPEND REQS "${LIB}")
|
||||||
|
else()
|
||||||
|
set(HAS_LIBS 1)
|
||||||
|
get_relative_link(LINK "${LIB}")
|
||||||
|
if (NOT LINK EQUAL "")
|
||||||
|
list(APPEND LIBS "${LINK}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if (HAS_REQS)
|
||||||
|
set(REQUIRES "")
|
||||||
|
foreach (REQ ${REQS})
|
||||||
|
set(REQUIRES "${REQUIRES} ${REQ}")
|
||||||
|
endforeach()
|
||||||
|
set(REQUIRES "Requires.private:${REQUIRES}\n")
|
||||||
|
endif()
|
||||||
|
if (HAS_LIBS)
|
||||||
|
set(LIBRARIES "")
|
||||||
|
list(REVERSE LIBS)
|
||||||
|
list(REMOVE_DUPLICATES LIBS)
|
||||||
|
foreach (LIB ${LIBS})
|
||||||
|
set(LIBRARIES " ${LIB}${LIBRARIES}")
|
||||||
|
endforeach()
|
||||||
|
set(LIBRARIES "Libs.private:${LIBRARIES}\n")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig")
|
||||||
|
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/${TARGET}.pc" CONTENT
|
||||||
|
"prefix=${PREFIX}
|
||||||
|
|
||||||
|
Name: ${TARGET}
|
||||||
|
Description: ${DESCRIPTION}
|
||||||
|
Version: ${PROJECT_VERSION}
|
||||||
|
|
||||||
|
CFlags: -I\"\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}\"
|
||||||
|
Libs: -L\"\${prefix}/${CMAKE_INSTALL_LIBDIR}\" -l${TARGET}
|
||||||
|
${REQUIRES}${LIBRARIES}")
|
||||||
|
|
||||||
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/${TARGET}.pc" DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||||
|
endfunction()
|
|
@ -988,6 +988,28 @@ install(TARGETS tdjson TdJson tdjson_static TdJsonStatic tdjson_private tdclient
|
||||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# generate pkg-config files
|
||||||
|
include(GeneratePkgConfig)
|
||||||
|
|
||||||
|
generate_pkgconfig(tdutils "Telegram Library - Utils")
|
||||||
|
generate_pkgconfig(tdactor "Telegram Library - Actor")
|
||||||
|
generate_pkgconfig(tdnet "Telegram Library - Net")
|
||||||
|
generate_pkgconfig(tdsqlite "Telegram Library - SQLite")
|
||||||
|
generate_pkgconfig(tddb "Telegram Library - Database")
|
||||||
|
if (MEMPROF)
|
||||||
|
# generate_pkgconfig(memprof "memprof - simple library for memory usage profiling")
|
||||||
|
endif()
|
||||||
|
generate_pkgconfig(tdcore "Telegram Library - Core")
|
||||||
|
generate_pkgconfig(tdclient "Telegram Library - C++ Interface")
|
||||||
|
if (TD_ENABLE_DOTNET)
|
||||||
|
# generate_pkgconfig(tddotnet "Telegram Library - C# Interface")
|
||||||
|
endif()
|
||||||
|
# generate_pkgconfig(tdc "Telegram Library - C interface")
|
||||||
|
generate_pkgconfig(tdapi "Telegram Library - API")
|
||||||
|
generate_pkgconfig(tdjson_private "Telegram Library - JSON interface (private)")
|
||||||
|
generate_pkgconfig(tdjson "Telegram Library - JSON interface (shared)")
|
||||||
|
generate_pkgconfig(tdjson_static "Telegram Library - JSON interface (static)")
|
||||||
|
|
||||||
install(EXPORT TdTargets
|
install(EXPORT TdTargets
|
||||||
FILE TdTargets.cmake
|
FILE TdTargets.cmake
|
||||||
NAMESPACE Td::
|
NAMESPACE Td::
|
||||||
|
|
|
@ -257,7 +257,7 @@ class TdExample {
|
||||||
[this](td_api::authorizationStateWaitPassword &) {
|
[this](td_api::authorizationStateWaitPassword &) {
|
||||||
std::cout << "Enter authentication password: " << std::flush;
|
std::cout << "Enter authentication password: " << std::flush;
|
||||||
std::string password;
|
std::string password;
|
||||||
std::cin >> password;
|
std::getline(std::cin, line);
|
||||||
send_query(td_api::make_object<td_api::checkAuthenticationPassword>(password),
|
send_query(td_api::make_object<td_api::checkAuthenticationPassword>(password),
|
||||||
create_authentication_query_handler());
|
create_authentication_query_handler());
|
||||||
},
|
},
|
||||||
|
|
|
@ -149,6 +149,7 @@ public final class Client {
|
||||||
if (isClosed) {
|
if (isClosed) {
|
||||||
updateHandlers.remove(clientId); // there will be no more updates
|
updateHandlers.remove(clientId); // there will be no more updates
|
||||||
defaultExceptionHandlers.remove(clientId); // ignore further exceptions
|
defaultExceptionHandlers.remove(clientId); // ignore further exceptions
|
||||||
|
clientCount.decrementAndGet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +165,7 @@ public final class Client {
|
||||||
private static final ConcurrentHashMap<Integer, Handler> updateHandlers = new ConcurrentHashMap<Integer, Handler>();
|
private static final ConcurrentHashMap<Integer, Handler> updateHandlers = new ConcurrentHashMap<Integer, Handler>();
|
||||||
private static final ConcurrentHashMap<Long, Handler> handlers = new ConcurrentHashMap<Long, Handler>();
|
private static final ConcurrentHashMap<Long, Handler> handlers = new ConcurrentHashMap<Long, Handler>();
|
||||||
private static final AtomicLong currentQueryId = new AtomicLong();
|
private static final AtomicLong currentQueryId = new AtomicLong();
|
||||||
|
private static final AtomicLong clientCount = new AtomicLong();
|
||||||
|
|
||||||
private static final ResponseReceiver responseReceiver = new ResponseReceiver();
|
private static final ResponseReceiver responseReceiver = new ResponseReceiver();
|
||||||
|
|
||||||
|
@ -178,6 +180,7 @@ public final class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Client(ResultHandler updateHandler, ExceptionHandler updateExceptionHandler, ExceptionHandler defaultExceptionHandler) {
|
private Client(ResultHandler updateHandler, ExceptionHandler updateExceptionHandler, ExceptionHandler defaultExceptionHandler) {
|
||||||
|
clientCount.incrementAndGet();
|
||||||
nativeClientId = createNativeClient();
|
nativeClientId = createNativeClient();
|
||||||
if (updateHandler != null) {
|
if (updateHandler != null) {
|
||||||
updateHandlers.put(nativeClientId, new Handler(updateHandler, updateExceptionHandler));
|
updateHandlers.put(nativeClientId, new Handler(updateHandler, updateExceptionHandler));
|
||||||
|
|
|
@ -2905,6 +2905,7 @@ ContactsManager::ContactsManager(Td *td, ActorShared<> parent) : td_(td), parent
|
||||||
G()->shared_config().set_option_integer("telegram_service_notifications_chat_id",
|
G()->shared_config().set_option_integer("telegram_service_notifications_chat_id",
|
||||||
DialogId(get_service_notifications_user_id()).get());
|
DialogId(get_service_notifications_user_id()).get());
|
||||||
G()->shared_config().set_option_integer("replies_bot_chat_id", DialogId(get_replies_bot_user_id()).get());
|
G()->shared_config().set_option_integer("replies_bot_chat_id", DialogId(get_replies_bot_user_id()).get());
|
||||||
|
G()->shared_config().set_option_integer("group_anonymous_bot_user_id", get_anonymous_bot_user_id().get());
|
||||||
|
|
||||||
if (G()->parameters().use_chat_info_db) {
|
if (G()->parameters().use_chat_info_db) {
|
||||||
auto next_contacts_sync_date_string = G()->td_db()->get_binlog_pmc()->get("next_contacts_sync_date");
|
auto next_contacts_sync_date_string = G()->td_db()->get_binlog_pmc()->get("next_contacts_sync_date");
|
||||||
|
|
|
@ -12521,8 +12521,8 @@ MessagesManager::MessageInfo MessagesManager::parse_telegram_api_message(
|
||||||
}
|
}
|
||||||
message_info.date = message->date_;
|
message_info.date = message->date_;
|
||||||
message_info.flags = message->flags_;
|
message_info.flags = message->flags_;
|
||||||
auto reply_to_message_id = MessageId(
|
auto reply_to_message_id =
|
||||||
ServerMessageId(message_info.reply_header == nullptr ? 0 : message_info.reply_header->reply_to_msg_id_));
|
MessageId(ServerMessageId(message->reply_to_ == nullptr ? 0 : message->reply_to_->reply_to_msg_id_));
|
||||||
message_info.content =
|
message_info.content =
|
||||||
get_action_message_content(td_, std::move(message->action_), message_info.dialog_id, reply_to_message_id);
|
get_action_message_content(td_, std::move(message->action_), message_info.dialog_id, reply_to_message_id);
|
||||||
break;
|
break;
|
||||||
|
@ -12565,9 +12565,9 @@ std::pair<DialogId, unique_ptr<MessagesManager::Message>> MessagesManager::creat
|
||||||
}
|
}
|
||||||
if (!is_broadcast_channel(dialog_id) && td_->auth_manager_->is_bot()) {
|
if (!is_broadcast_channel(dialog_id) && td_->auth_manager_->is_bot()) {
|
||||||
if (dialog_id == sender_dialog_id) {
|
if (dialog_id == sender_dialog_id) {
|
||||||
sender_user_id = td_->contacts_manager_->add_anonymous_bot_user();
|
td_->contacts_manager_->add_anonymous_bot_user();
|
||||||
} else {
|
} else {
|
||||||
sender_user_id = td_->contacts_manager_->add_service_notifications_user();
|
td_->contacts_manager_->add_service_notifications_user();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19590,7 +19590,6 @@ void MessagesManager::do_read_history_on_server(DialogId dialog_id) {
|
||||||
|
|
||||||
Dialog *d = get_dialog(dialog_id);
|
Dialog *d = get_dialog(dialog_id);
|
||||||
CHECK(d != nullptr);
|
CHECK(d != nullptr);
|
||||||
CHECK(!d->updated_read_history_message_ids.empty());
|
|
||||||
|
|
||||||
for (auto top_thread_message_id : d->updated_read_history_message_ids) {
|
for (auto top_thread_message_id : d->updated_read_history_message_ids) {
|
||||||
if (!top_thread_message_id.is_valid()) {
|
if (!top_thread_message_id.is_valid()) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ class RequestActor : public Actor {
|
||||||
CHECK(future.get_state() == FutureActor<T>::State::Waiting);
|
CHECK(future.get_state() == FutureActor<T>::State::Waiting);
|
||||||
if (--tries_left_ == 0) {
|
if (--tries_left_ == 0) {
|
||||||
future.close();
|
future.close();
|
||||||
do_send_error(Status::Error(400, "Requested data is inaccessible"));
|
do_send_error(Status::Error(500, "Requested data is inaccessible"));
|
||||||
return stop();
|
return stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ class NetQueryStats {
|
||||||
void dump_pending_network_queries();
|
void dump_pending_network_queries();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NetQueryCounter::Counter count_;
|
NetQueryCounter::Counter count_{0};
|
||||||
std::atomic<bool> use_list_{true};
|
std::atomic<bool> use_list_{true};
|
||||||
TsList<NetQueryDebug> list_;
|
TsList<NetQueryDebug> list_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -115,10 +115,10 @@ class unique_ptr {
|
||||||
}
|
}
|
||||||
explicit unique_ptr(T *ptr) noexcept : ptr_(ptr) {
|
explicit unique_ptr(T *ptr) noexcept : ptr_(ptr) {
|
||||||
}
|
}
|
||||||
template <class S, class = std::enable_if_t<std::is_base_of<T, S>::value>>
|
template <class S, class = typename std::enable_if<std::is_base_of<T, S>::value>::type>
|
||||||
unique_ptr(unique_ptr<S> &&other) noexcept : ptr_(static_cast<S *>(other.release())) {
|
unique_ptr(unique_ptr<S> &&other) noexcept : ptr_(static_cast<S *>(other.release())) {
|
||||||
}
|
}
|
||||||
template <class S, class = std::enable_if_t<std::is_base_of<T, S>::value>>
|
template <class S, class = typename std::enable_if<std::is_base_of<T, S>::value>::type>
|
||||||
unique_ptr &operator=(unique_ptr<S> &&other) noexcept {
|
unique_ptr &operator=(unique_ptr<S> &&other) noexcept {
|
||||||
reset(static_cast<T *>(other.release()));
|
reset(static_cast<T *>(other.release()));
|
||||||
return *this;
|
return *this;
|
||||||
|
|
|
@ -52,11 +52,11 @@ set(TDNET_SOURCE
|
||||||
add_library(tdnet STATIC ${TDNET_SOURCE})
|
add_library(tdnet STATIC ${TDNET_SOURCE})
|
||||||
target_include_directories(tdnet PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
target_include_directories(tdnet PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||||
target_include_directories(tdnet SYSTEM PRIVATE $<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>)
|
target_include_directories(tdnet SYSTEM PRIVATE $<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>)
|
||||||
target_link_libraries(tdnet PUBLIC tdutils tdactor PRIVATE ${CMAKE_DL_LIBS} ${ZLIB_LIBRARIES})
|
target_link_libraries(tdnet PUBLIC tdutils tdactor)
|
||||||
if (NOT EMSCRIPTEN)
|
if (NOT EMSCRIPTEN)
|
||||||
target_link_libraries(tdnet PRIVATE ${OPENSSL_SSL_LIBRARY})
|
target_link_libraries(tdnet PRIVATE ${OPENSSL_SSL_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(tdnet PRIVATE ${OPENSSL_CRYPTO_LIBRARY})
|
target_link_libraries(tdnet PRIVATE ${OPENSSL_CRYPTO_LIBRARY} ${CMAKE_DL_LIBS} ${ZLIB_LIBRARIES})
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
if (MINGW)
|
if (MINGW)
|
||||||
|
|
|
@ -483,7 +483,6 @@ void write_tl(const tl_config &config, tl_outputer &out, const TL_writer &w) {
|
||||||
std::size_t types_n = config.get_type_count();
|
std::size_t types_n = config.get_type_count();
|
||||||
std::size_t functions_n = config.get_function_count();
|
std::size_t functions_n = config.get_function_count();
|
||||||
|
|
||||||
bool found_complex = false;
|
|
||||||
for (std::size_t type = 0; type < types_n; type++) {
|
for (std::size_t type = 0; type < types_n; type++) {
|
||||||
tl_type *t = config.get_type_by_num(type);
|
tl_type *t = config.get_type_by_num(type);
|
||||||
assert(t->constructors_num == t->constructors.size());
|
assert(t->constructors_num == t->constructors.size());
|
||||||
|
@ -491,7 +490,6 @@ void write_tl(const tl_config &config, tl_outputer &out, const TL_writer &w) {
|
||||||
if (t->name == "Type") {
|
if (t->name == "Type") {
|
||||||
assert(t->id == ID_VAR_TYPE);
|
assert(t->id == ID_VAR_TYPE);
|
||||||
t->flags |= FLAG_COMPLEX;
|
t->flags |= FLAG_COMPLEX;
|
||||||
found_complex = true;
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -529,7 +527,6 @@ void write_tl(const tl_config &config, tl_outputer &out, const TL_writer &w) {
|
||||||
b.exist_var_num != -1) {
|
b.exist_var_num != -1) {
|
||||||
if (!w.is_built_in_complex_type(t->name)) {
|
if (!w.is_built_in_complex_type(t->name)) {
|
||||||
t->flags |= FLAG_COMPLEX;
|
t->flags |= FLAG_COMPLEX;
|
||||||
found_complex = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(b_arg_type == NODE_TYPE_TYPE);
|
assert(b_arg_type == NODE_TYPE_TYPE);
|
||||||
|
@ -549,14 +546,13 @@ void write_tl(const tl_config &config, tl_outputer &out, const TL_writer &w) {
|
||||||
if (main_type == NODE_TYPE_VAR_TYPE) {
|
if (main_type == NODE_TYPE_VAR_TYPE) {
|
||||||
if (!w.is_built_in_complex_type(t->name)) {
|
if (!w.is_built_in_complex_type(t->name)) {
|
||||||
t->flags |= FLAG_COMPLEX;
|
t->flags |= FLAG_COMPLEX;
|
||||||
found_complex = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (found_complex) {
|
while (true) {
|
||||||
found_complex = false;
|
bool found_complex = false;
|
||||||
for (std::size_t type = 0; type < types_n; type++) {
|
for (std::size_t type = 0; type < types_n; type++) {
|
||||||
tl_type *t = config.get_type_by_num(type);
|
tl_type *t = config.get_type_by_num(type);
|
||||||
if (t->constructors_num == 0 || w.is_built_in_complex_type(t->name)) { // built-in dummy or complex types
|
if (t->constructors_num == 0 || w.is_built_in_complex_type(t->name)) { // built-in dummy or complex types
|
||||||
|
@ -576,6 +572,9 @@ void write_tl(const tl_config &config, tl_outputer &out, const TL_writer &w) {
|
||||||
// std::fprintf(stderr, "Found complex %s\n", t->name.c_str());
|
// std::fprintf(stderr, "Found complex %s\n", t->name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!found_complex) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> request_types;
|
std::set<std::string> request_types;
|
||||||
|
|
|
@ -384,17 +384,37 @@ class SocketFdImpl {
|
||||||
const NativeFd &get_native_fd() const {
|
const NativeFd &get_native_fd() const {
|
||||||
return info.native_fd();
|
return info.native_fd();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<size_t> writev(Span<IoSlice> slices) {
|
Result<size_t> writev(Span<IoSlice> slices) {
|
||||||
int native_fd = get_native_fd().socket();
|
int native_fd = get_native_fd().socket();
|
||||||
auto write_res =
|
TRY_RESULT(slices_size, narrow_cast_safe<int>(slices.size()));
|
||||||
detail::skip_eintr([&] { return ::writev(native_fd, slices.begin(), narrow_cast<int>(slices.size())); });
|
auto write_res = detail::skip_eintr([&] {
|
||||||
|
#ifdef MSG_NOSIGNAL
|
||||||
|
msghdr msg;
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.msg_iov = const_cast<iovec *>(slices.begin());
|
||||||
|
msg.msg_iovlen = slices_size;
|
||||||
|
return sendmsg(native_fd, &msg, MSG_NOSIGNAL);
|
||||||
|
#else
|
||||||
|
return ::writev(native_fd, slices.begin(), slices_size);
|
||||||
|
#endif
|
||||||
|
});
|
||||||
return write_finish(write_res);
|
return write_finish(write_res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<size_t> write(Slice slice) {
|
Result<size_t> write(Slice slice) {
|
||||||
int native_fd = get_native_fd().socket();
|
int native_fd = get_native_fd().socket();
|
||||||
auto write_res = detail::skip_eintr([&] { return ::write(native_fd, slice.begin(), slice.size()); });
|
auto write_res = detail::skip_eintr([&] {
|
||||||
|
return
|
||||||
|
#ifdef MSG_NOSIGNAL
|
||||||
|
send(native_fd, slice.begin(), slice.size(), MSG_NOSIGNAL);
|
||||||
|
#else
|
||||||
|
::write(native_fd, slice.begin(), slice.size());
|
||||||
|
#endif
|
||||||
|
});
|
||||||
return write_finish(write_res);
|
return write_finish(write_res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<size_t> write_finish(ssize_t write_res) {
|
Result<size_t> write_finish(ssize_t write_res) {
|
||||||
auto write_errno = errno;
|
auto write_errno = errno;
|
||||||
if (write_res >= 0) {
|
if (write_res >= 0) {
|
||||||
|
@ -538,6 +558,17 @@ Status init_socket_options(NativeFd &native_fd) {
|
||||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&flags), sizeof(flags));
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&flags), sizeof(flags));
|
||||||
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, reinterpret_cast<const char *>(&flags), sizeof(flags));
|
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, reinterpret_cast<const char *>(&flags), sizeof(flags));
|
||||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flags), sizeof(flags));
|
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flags), sizeof(flags));
|
||||||
|
#if TD_PORT_POSIX
|
||||||
|
#ifndef MSG_NOSIGNAL // Darwin
|
||||||
|
|
||||||
|
#ifdef SO_NOSIGPIPE
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<const char *>(&flags), sizeof(flags));
|
||||||
|
#else
|
||||||
|
#warning "Failed to suppress SIGPIPE signals. Use signal(SIGPIPE, SIG_IGN) to suppress them."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
// TODO: SO_REUSEADDR, SO_KEEPALIVE, TCP_NODELAY, SO_SNDBUF, SO_RCVBUF, TCP_QUICKACK, SO_LINGER
|
// TODO: SO_REUSEADDR, SO_KEEPALIVE, TCP_NODELAY, SO_SNDBUF, SO_RCVBUF, TCP_QUICKACK, SO_LINGER
|
||||||
|
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
|
|
|
@ -47,7 +47,7 @@ class UdpSocketReceiveHelper {
|
||||||
public:
|
public:
|
||||||
void to_native(const UdpMessage &message, WSAMSG &message_header) {
|
void to_native(const UdpMessage &message, WSAMSG &message_header) {
|
||||||
socklen_t addr_len{narrow_cast<socklen_t>(sizeof(addr_))};
|
socklen_t addr_len{narrow_cast<socklen_t>(sizeof(addr_))};
|
||||||
message_header.name = reinterpret_cast<struct sockaddr *>(&addr_);
|
message_header.name = reinterpret_cast<sockaddr *>(&addr_);
|
||||||
message_header.namelen = addr_len;
|
message_header.namelen = addr_len;
|
||||||
buf_.buf = const_cast<char *>(message.data.as_slice().begin());
|
buf_.buf = const_cast<char *>(message.data.as_slice().begin());
|
||||||
buf_.len = narrow_cast<DWORD>(message.data.size());
|
buf_.len = narrow_cast<DWORD>(message.data.size());
|
||||||
|
@ -59,8 +59,7 @@ class UdpSocketReceiveHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
void from_native(WSAMSG &message_header, size_t message_size, UdpMessage &message) {
|
void from_native(WSAMSG &message_header, size_t message_size, UdpMessage &message) {
|
||||||
message.address.init_sockaddr(reinterpret_cast<struct sockaddr *>(message_header.name), message_header.namelen)
|
message.address.init_sockaddr(reinterpret_cast<sockaddr *>(message_header.name), message_header.namelen).ignore();
|
||||||
.ignore();
|
|
||||||
message.error = Status::OK();
|
message.error = Status::OK();
|
||||||
|
|
||||||
if ((message_header.dwFlags & (MSG_TRUNC | MSG_CTRUNC)) != 0) {
|
if ((message_header.dwFlags & (MSG_TRUNC | MSG_CTRUNC)) != 0) {
|
||||||
|
@ -82,7 +81,7 @@ class UdpSocketReceiveHelper {
|
||||||
class UdpSocketSendHelper {
|
class UdpSocketSendHelper {
|
||||||
public:
|
public:
|
||||||
void to_native(const UdpMessage &message, WSAMSG &message_header) {
|
void to_native(const UdpMessage &message, WSAMSG &message_header) {
|
||||||
message_header.name = const_cast<struct sockaddr *>(message.address.get_sockaddr());
|
message_header.name = const_cast<sockaddr *>(message.address.get_sockaddr());
|
||||||
message_header.namelen = narrow_cast<socklen_t>(message.address.get_sockaddr_len());
|
message_header.namelen = narrow_cast<socklen_t>(message.address.get_sockaddr_len());
|
||||||
buf_.buf = const_cast<char *>(message.data.as_slice().begin());
|
buf_.buf = const_cast<char *>(message.data.as_slice().begin());
|
||||||
buf_.len = narrow_cast<DWORD>(message.data.size());
|
buf_.len = narrow_cast<DWORD>(message.data.size());
|
||||||
|
@ -373,7 +372,7 @@ void UdpSocketFdImplDeleter::operator()(UdpSocketFdImpl *impl) {
|
||||||
|
|
||||||
class UdpSocketReceiveHelper {
|
class UdpSocketReceiveHelper {
|
||||||
public:
|
public:
|
||||||
void to_native(const UdpSocketFd::InboundMessage &message, struct msghdr &message_header) {
|
void to_native(const UdpSocketFd::InboundMessage &message, msghdr &message_header) {
|
||||||
socklen_t addr_len{narrow_cast<socklen_t>(sizeof(addr_))};
|
socklen_t addr_len{narrow_cast<socklen_t>(sizeof(addr_))};
|
||||||
|
|
||||||
message_header.msg_name = &addr_;
|
message_header.msg_name = &addr_;
|
||||||
|
@ -387,22 +386,22 @@ class UdpSocketReceiveHelper {
|
||||||
message_header.msg_flags = 0;
|
message_header.msg_flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void from_native(struct msghdr &message_header, size_t message_size, UdpSocketFd::InboundMessage &message) {
|
void from_native(msghdr &message_header, size_t message_size, UdpSocketFd::InboundMessage &message) {
|
||||||
#if TD_LINUX
|
#if TD_LINUX
|
||||||
struct cmsghdr *cmsg;
|
cmsghdr *cmsg;
|
||||||
struct sock_extended_err *ee = nullptr;
|
sock_extended_err *ee = nullptr;
|
||||||
for (cmsg = CMSG_FIRSTHDR(&message_header); cmsg != nullptr; cmsg = CMSG_NXTHDR(&message_header, cmsg)) {
|
for (cmsg = CMSG_FIRSTHDR(&message_header); cmsg != nullptr; cmsg = CMSG_NXTHDR(&message_header, cmsg)) {
|
||||||
if (cmsg->cmsg_type == IP_PKTINFO && cmsg->cmsg_level == IPPROTO_IP) {
|
if (cmsg->cmsg_type == IP_PKTINFO && cmsg->cmsg_level == IPPROTO_IP) {
|
||||||
//auto *pi = reinterpret_cast<struct in_pktinfo *>(CMSG_DATA(cmsg));
|
//auto *pi = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cmsg));
|
||||||
} else if (cmsg->cmsg_type == IPV6_PKTINFO && cmsg->cmsg_level == IPPROTO_IPV6) {
|
} else if (cmsg->cmsg_type == IPV6_PKTINFO && cmsg->cmsg_level == IPPROTO_IPV6) {
|
||||||
//auto *pi = reinterpret_cast<struct in6_pktinfo *>(CMSG_DATA(cmsg));
|
//auto *pi = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsg));
|
||||||
} else if ((cmsg->cmsg_type == IP_RECVERR && cmsg->cmsg_level == IPPROTO_IP) ||
|
} else if ((cmsg->cmsg_type == IP_RECVERR && cmsg->cmsg_level == IPPROTO_IP) ||
|
||||||
(cmsg->cmsg_type == IPV6_RECVERR && cmsg->cmsg_level == IPPROTO_IPV6)) {
|
(cmsg->cmsg_type == IPV6_RECVERR && cmsg->cmsg_level == IPPROTO_IPV6)) {
|
||||||
ee = reinterpret_cast<struct sock_extended_err *>(CMSG_DATA(cmsg));
|
ee = reinterpret_cast<sock_extended_err *>(CMSG_DATA(cmsg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ee != nullptr) {
|
if (ee != nullptr) {
|
||||||
auto *addr = reinterpret_cast<struct sockaddr *>(SO_EE_OFFENDER(ee));
|
auto *addr = reinterpret_cast<sockaddr *>(SO_EE_OFFENDER(ee));
|
||||||
IPAddress address;
|
IPAddress address;
|
||||||
address.init_sockaddr(addr).ignore();
|
address.init_sockaddr(addr).ignore();
|
||||||
if (message.from != nullptr) {
|
if (message.from != nullptr) {
|
||||||
|
@ -417,8 +416,7 @@ class UdpSocketReceiveHelper {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (message.from != nullptr) {
|
if (message.from != nullptr) {
|
||||||
message.from
|
message.from->init_sockaddr(reinterpret_cast<sockaddr *>(message_header.msg_name), message_header.msg_namelen)
|
||||||
->init_sockaddr(reinterpret_cast<struct sockaddr *>(message_header.msg_name), message_header.msg_namelen)
|
|
||||||
.ignore();
|
.ignore();
|
||||||
}
|
}
|
||||||
if (message.error) {
|
if (message.error) {
|
||||||
|
@ -439,14 +437,14 @@ class UdpSocketReceiveHelper {
|
||||||
private:
|
private:
|
||||||
std::array<char, 1024> control_buf_;
|
std::array<char, 1024> control_buf_;
|
||||||
sockaddr_storage addr_;
|
sockaddr_storage addr_;
|
||||||
struct iovec io_vec_;
|
iovec io_vec_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UdpSocketSendHelper {
|
class UdpSocketSendHelper {
|
||||||
public:
|
public:
|
||||||
void to_native(const UdpSocketFd::OutboundMessage &message, struct msghdr &message_header) {
|
void to_native(const UdpSocketFd::OutboundMessage &message, msghdr &message_header) {
|
||||||
CHECK(message.to != nullptr && message.to->is_valid());
|
CHECK(message.to != nullptr && message.to->is_valid());
|
||||||
message_header.msg_name = const_cast<struct sockaddr *>(message.to->get_sockaddr());
|
message_header.msg_name = const_cast<sockaddr *>(message.to->get_sockaddr());
|
||||||
message_header.msg_namelen = narrow_cast<socklen_t>(message.to->get_sockaddr_len());
|
message_header.msg_namelen = narrow_cast<socklen_t>(message.to->get_sockaddr_len());
|
||||||
io_vec_.iov_base = const_cast<char *>(message.data.begin());
|
io_vec_.iov_base = const_cast<char *>(message.data.begin());
|
||||||
io_vec_.iov_len = message.data.size();
|
io_vec_.iov_len = message.data.size();
|
||||||
|
@ -459,7 +457,7 @@ class UdpSocketSendHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct iovec io_vec_;
|
iovec io_vec_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UdpSocketFdImpl {
|
class UdpSocketFdImpl {
|
||||||
|
@ -495,7 +493,7 @@ class UdpSocketFdImpl {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct msghdr message_header;
|
msghdr message_header;
|
||||||
detail::UdpSocketReceiveHelper helper;
|
detail::UdpSocketReceiveHelper helper;
|
||||||
helper.to_native(message, message_header);
|
helper.to_native(message, message_header);
|
||||||
|
|
||||||
|
@ -549,7 +547,7 @@ class UdpSocketFdImpl {
|
||||||
|
|
||||||
Status send_message(const UdpSocketFd::OutboundMessage &message, bool &is_sent) {
|
Status send_message(const UdpSocketFd::OutboundMessage &message, bool &is_sent) {
|
||||||
is_sent = false;
|
is_sent = false;
|
||||||
struct msghdr message_header;
|
msghdr message_header;
|
||||||
detail::UdpSocketSendHelper helper;
|
detail::UdpSocketSendHelper helper;
|
||||||
helper.to_native(message, message_header);
|
helper.to_native(message, message_header);
|
||||||
|
|
||||||
|
@ -651,11 +649,11 @@ class UdpSocketFdImpl {
|
||||||
#if TD_HAS_MMSG
|
#if TD_HAS_MMSG
|
||||||
Status send_messages_fast(Span<UdpSocketFd::OutboundMessage> messages, size_t &cnt) {
|
Status send_messages_fast(Span<UdpSocketFd::OutboundMessage> messages, size_t &cnt) {
|
||||||
//struct mmsghdr {
|
//struct mmsghdr {
|
||||||
// struct msghdr msg_hdr; [> Message header <]
|
// msghdr msg_hdr; [> Message header <]
|
||||||
// unsigned int msg_len; [> Number of bytes transmitted <]
|
// unsigned int msg_len; [> Number of bytes transmitted <]
|
||||||
//};
|
//};
|
||||||
struct std::array<detail::UdpSocketSendHelper, 16> helpers;
|
std::array<detail::UdpSocketSendHelper, 16> helpers;
|
||||||
struct std::array<struct mmsghdr, 16> headers;
|
std::array<mmsghdr, 16> headers;
|
||||||
size_t to_send = min(messages.size(), headers.size());
|
size_t to_send = min(messages.size(), headers.size());
|
||||||
for (size_t i = 0; i < to_send; i++) {
|
for (size_t i = 0; i < to_send; i++) {
|
||||||
helpers[i].to_native(messages[i], headers[i].msg_hdr);
|
helpers[i].to_native(messages[i], headers[i].msg_hdr);
|
||||||
|
@ -702,11 +700,11 @@ class UdpSocketFdImpl {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
//struct mmsghdr {
|
//struct mmsghdr {
|
||||||
// struct msghdr msg_hdr; [> Message header <]
|
// msghdr msg_hdr; [> Message header <]
|
||||||
// unsigned int msg_len; [> Number of bytes transmitted <]
|
// unsigned int msg_len; [> Number of bytes transmitted <]
|
||||||
//};
|
//};
|
||||||
struct std::array<detail::UdpSocketReceiveHelper, 16> helpers;
|
std::array<detail::UdpSocketReceiveHelper, 16> helpers;
|
||||||
struct std::array<struct mmsghdr, 16> headers;
|
std::array<mmsghdr, 16> headers;
|
||||||
size_t to_receive = min(messages.size(), headers.size());
|
size_t to_receive = min(messages.size(), headers.size());
|
||||||
for (size_t i = 0; i < to_receive; i++) {
|
for (size_t i = 0; i < to_receive; i++) {
|
||||||
helpers[i].to_native(messages[i], headers[i].msg_hdr);
|
helpers[i].to_native(messages[i], headers[i].msg_hdr);
|
||||||
|
|
|
@ -67,7 +67,7 @@ void EventFdLinux::release() {
|
||||||
auto native_fd = impl_->info.native_fd().fd();
|
auto native_fd = impl_->info.native_fd().fd();
|
||||||
|
|
||||||
auto result = [&]() -> Result<size_t> {
|
auto result = [&]() -> Result<size_t> {
|
||||||
auto write_res = detail::skip_eintr([&] { return ::write(native_fd, slice.begin(), slice.size()); });
|
auto write_res = detail::skip_eintr([&] { return write(native_fd, slice.begin(), slice.size()); });
|
||||||
auto write_errno = errno;
|
auto write_errno = errno;
|
||||||
if (write_res >= 0) {
|
if (write_res >= 0) {
|
||||||
return narrow_cast<size_t>(write_res);
|
return narrow_cast<size_t>(write_res);
|
||||||
|
|
|
@ -992,7 +992,7 @@ TEST(Client, Close) {
|
||||||
td::thread receive_thread([&] {
|
td::thread receive_thread([&] {
|
||||||
auto max_continue_send = td::Random::fast_bool() ? 0 : 1000;
|
auto max_continue_send = td::Random::fast_bool() ? 0 : 1000;
|
||||||
while (true) {
|
while (true) {
|
||||||
auto response = client.receive(100.0);
|
auto response = client.receive(10.0);
|
||||||
if (response.object == nullptr) {
|
if (response.object == nullptr) {
|
||||||
if (!stop_send) {
|
if (!stop_send) {
|
||||||
stop_send = true;
|
stop_send = true;
|
||||||
|
@ -1056,7 +1056,7 @@ TEST(Client, ManagerClose) {
|
||||||
auto max_continue_send = td::Random::fast_bool() ? 0 : 1000;
|
auto max_continue_send = td::Random::fast_bool() ? 0 : 1000;
|
||||||
bool can_stop_send = false;
|
bool can_stop_send = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
auto response = client_manager.receive(100.0);
|
auto response = client_manager.receive(10.0);
|
||||||
if (response.object == nullptr) {
|
if (response.object == nullptr) {
|
||||||
if (!stop_send) {
|
if (!stop_send) {
|
||||||
can_stop_send = true;
|
can_stop_send = true;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user