mirror of https://github.com/grpc/grpc.git
Delete libuv-iomgr implementation and GRPC_UV build option (#27188)
This has been unmaintained for years, last supported in gRPC-core v1.24.reviewable/pr27215/r1
parent
6f48ba4d94
commit
2d16865693
53 changed files with 9 additions and 10464 deletions
@ -1,179 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2019 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
#if GRPC_ARES == 1 && defined(GRPC_UV) |
||||
|
||||
#include "absl/strings/str_format.h" |
||||
|
||||
#include <ares.h> |
||||
#include <uv.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/time.h> |
||||
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" |
||||
#include "src/core/lib/gpr/string.h" |
||||
#include "src/core/lib/iomgr/work_serializer.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
void ares_uv_poll_cb(uv_poll_t* handle, int status, int events); |
||||
|
||||
void ares_uv_poll_close_cb(uv_handle_t* handle) { delete handle; } |
||||
|
||||
class GrpcPolledFdLibuv : public GrpcPolledFd { |
||||
public: |
||||
GrpcPolledFdLibuv(ares_socket_t as, |
||||
std::shared_ptr<WorkSerializer> work_serializer) |
||||
: name_(absl::StrFormat("c-ares socket: %" PRIdPTR, (intptr_t)as)), |
||||
as_(as), |
||||
work_serializer_(std::move(work_serializer)) { |
||||
handle_ = new uv_poll_t(); |
||||
uv_poll_init_socket(uv_default_loop(), handle_, as); |
||||
handle_->data = this; |
||||
} |
||||
|
||||
void RegisterForOnReadableLocked(grpc_closure* read_closure) override { |
||||
GPR_ASSERT(read_closure_ == nullptr); |
||||
GPR_ASSERT((poll_events_ & UV_READABLE) == 0); |
||||
read_closure_ = read_closure; |
||||
poll_events_ |= UV_READABLE; |
||||
uv_poll_start(handle_, poll_events_, ares_uv_poll_cb); |
||||
} |
||||
|
||||
void RegisterForOnWriteableLocked(grpc_closure* write_closure) override { |
||||
GPR_ASSERT(write_closure_ == nullptr); |
||||
GPR_ASSERT((poll_events_ & UV_WRITABLE) == 0); |
||||
write_closure_ = write_closure; |
||||
poll_events_ |= UV_WRITABLE; |
||||
uv_poll_start(handle_, poll_events_, ares_uv_poll_cb); |
||||
} |
||||
|
||||
bool IsFdStillReadableLocked() override { |
||||
/* uv_poll_t is based on poll, which is level triggered. So, if cares
|
||||
* leaves some data unread, the event will trigger again. */ |
||||
return false; |
||||
} |
||||
|
||||
void ShutdownInternalLocked(grpc_error_handle error) { |
||||
uv_poll_stop(handle_); |
||||
uv_close(reinterpret_cast<uv_handle_t*>(handle_), ares_uv_poll_close_cb); |
||||
if (read_closure_ != nullptr) { |
||||
grpc_core::ExecCtx::Run(DEBUG_LOCATION, read_closure_, |
||||
GRPC_ERROR_CANCELLED); |
||||
} |
||||
if (write_closure_ != nullptr) { |
||||
grpc_core::ExecCtx::Run(DEBUG_LOCATION, write_closure_, |
||||
GRPC_ERROR_CANCELLED); |
||||
} |
||||
} |
||||
|
||||
void ShutdownLocked(grpc_error_handle error) override { |
||||
if (grpc_core::ExecCtx::Get() == nullptr) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
ShutdownInternalLocked(error); |
||||
} else { |
||||
ShutdownInternalLocked(error); |
||||
} |
||||
} |
||||
|
||||
ares_socket_t GetWrappedAresSocketLocked() override { return as_; } |
||||
|
||||
const char* GetName() override { return name_.c_str(); } |
||||
|
||||
// TODO(apolcyn): Data members should be private.
|
||||
std::string name_; |
||||
ares_socket_t as_; |
||||
uv_poll_t* handle_; |
||||
grpc_closure* read_closure_ = nullptr; |
||||
grpc_closure* write_closure_ = nullptr; |
||||
int poll_events_ = 0; |
||||
std::shared_ptr<WorkSerializer> work_serializer_; |
||||
}; |
||||
|
||||
struct AresUvPollCbArg { |
||||
AresUvPollCbArg(uv_poll_t* handle, int status, int events) |
||||
: handle(handle), status(status), events(events) {} |
||||
|
||||
uv_poll_t* handle; |
||||
int status; |
||||
int events; |
||||
}; |
||||
|
||||
static void ares_uv_poll_cb_locked(AresUvPollCbArg* arg) { |
||||
std::unique_ptr<AresUvPollCbArg> arg_struct(arg); |
||||
uv_poll_t* handle = arg_struct->handle; |
||||
int status = arg_struct->status; |
||||
int events = arg_struct->events; |
||||
GrpcPolledFdLibuv* polled_fd = |
||||
reinterpret_cast<GrpcPolledFdLibuv*>(handle->data); |
||||
grpc_error_handle error = GRPC_ERROR_NONE; |
||||
if (status < 0) { |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("cares polling error"); |
||||
error = |
||||
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string(uv_strerror(status))); |
||||
} |
||||
if (events & UV_READABLE) { |
||||
GPR_ASSERT(polled_fd->read_closure_ != nullptr); |
||||
grpc_core::ExecCtx::Run(DEBUG_LOCATION, polled_fd->read_closure_, error); |
||||
polled_fd->read_closure_ = nullptr; |
||||
polled_fd->poll_events_ &= ~UV_READABLE; |
||||
} |
||||
if (events & UV_WRITABLE) { |
||||
GPR_ASSERT(polled_fd->write_closure_ != nullptr); |
||||
grpc_core::ExecCtx::Run(DEBUG_LOCATION, polled_fd->write_closure_, error); |
||||
polled_fd->write_closure_ = nullptr; |
||||
polled_fd->poll_events_ &= ~UV_WRITABLE; |
||||
} |
||||
uv_poll_start(handle, polled_fd->poll_events_, ares_uv_poll_cb); |
||||
} |
||||
|
||||
void ares_uv_poll_cb(uv_poll_t* handle, int status, int events) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
GrpcPolledFdLibuv* polled_fd = |
||||
reinterpret_cast<GrpcPolledFdLibuv*>(handle->data); |
||||
AresUvPollCbArg* arg = new AresUvPollCbArg(handle, status, events); |
||||
polled_fd->work_serializer_->Run([arg]() { ares_uv_poll_cb_locked(arg); }, |
||||
DEBUG_LOCATION); |
||||
} |
||||
|
||||
class GrpcPolledFdFactoryLibuv : public GrpcPolledFdFactory { |
||||
public: |
||||
GrpcPolledFd* NewGrpcPolledFdLocked( |
||||
ares_socket_t as, grpc_pollset_set* driver_pollset_set, |
||||
std::shared_ptr<WorkSerializer> work_serializer) override { |
||||
return new GrpcPolledFdLibuv(as, std::move(work_serializer)); |
||||
} |
||||
|
||||
void ConfigureAresChannelLocked(ares_channel channel) override {} |
||||
}; |
||||
|
||||
std::unique_ptr<GrpcPolledFdFactory> NewGrpcPolledFdFactory( |
||||
std::shared_ptr<WorkSerializer> work_serializer) { |
||||
return absl::make_unique<GrpcPolledFdFactoryLibuv>(); |
||||
} |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_ARES == 1 && defined(GRPC_UV) */ |
@ -1,38 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
#if GRPC_ARES == 1 && defined(GRPC_UV) |
||||
|
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" |
||||
#include "src/core/ext/filters/client_channel/server_address.h" |
||||
#include "src/core/lib/address_utils/parse_address.h" |
||||
#include "src/core/lib/gpr/string.h" |
||||
|
||||
bool grpc_ares_query_ipv6() { |
||||
/* The libuv grpc code currently does not have the code to probe for this,
|
||||
* so we assume for now that IPv6 is always available in contexts where this |
||||
* code will be used. */ |
||||
return true; |
||||
} |
||||
|
||||
#endif /* GRPC_ARES == 1 && defined(GRPC_UV) */ |
@ -1,40 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_UV |
||||
|
||||
#include <stdlib.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/iomgr/endpoint_pair.h" |
||||
|
||||
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair( |
||||
const char* /* name */, grpc_channel_args* /* args */) { |
||||
grpc_endpoint_pair endpoint_pair; |
||||
// TODO(mlumish): implement this properly under libuv
|
||||
GPR_ASSERT(false && |
||||
"grpc_iomgr_create_endpoint_pair is not suppoted with libuv"); |
||||
GPR_UNREACHABLE_CODE(return endpoint_pair); |
||||
} |
||||
|
||||
#endif /* GRPC_UV */ |
@ -1,43 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#if defined(GRPC_CUSTOM_SOCKET) && defined(GRPC_UV) |
||||
|
||||
#include "src/core/lib/iomgr/iomgr_custom.h" |
||||
#include "src/core/lib/iomgr/iomgr_internal.h" |
||||
#include "src/core/lib/iomgr/pollset_custom.h" |
||||
#include "src/core/lib/iomgr/tcp_custom.h" |
||||
#include "src/core/lib/iomgr/timer_custom.h" |
||||
|
||||
extern grpc_socket_vtable grpc_uv_socket_vtable; |
||||
extern grpc_custom_resolver_vtable uv_resolver_vtable; |
||||
extern grpc_custom_timer_vtable uv_timer_vtable; |
||||
extern grpc_custom_poller_vtable uv_pollset_vtable; |
||||
|
||||
void grpc_set_default_iomgr_platform() { |
||||
grpc_custom_iomgr_init(&grpc_uv_socket_vtable, &uv_resolver_vtable, |
||||
&uv_timer_vtable, &uv_pollset_vtable); |
||||
} |
||||
|
||||
bool grpc_iomgr_run_in_background() { return false; } |
||||
|
||||
#endif |
@ -1,95 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_UV |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include "src/core/lib/iomgr/error.h" |
||||
#include "src/core/lib/iomgr/pollset_custom.h" |
||||
|
||||
#include <uv.h> |
||||
|
||||
/* Indicates that grpc_pollset_work should run an iteration of the UV loop
|
||||
before running callbacks. This defaults to 1, and should be disabled if |
||||
grpc_pollset_work will be called within the callstack of uv_run */ |
||||
int grpc_pollset_work_run_loop = 1; |
||||
|
||||
static bool g_kicked = false; |
||||
|
||||
typedef struct uv_poller_handle { |
||||
uv_timer_t poll_timer; |
||||
uv_timer_t kick_timer; |
||||
int refs; |
||||
} uv_poller_handle; |
||||
|
||||
static uv_poller_handle* g_handle; |
||||
|
||||
static void init() { |
||||
g_handle = (uv_poller_handle*)gpr_malloc(sizeof(uv_poller_handle)); |
||||
g_handle->refs = 2; |
||||
uv_timer_init(uv_default_loop(), &g_handle->poll_timer); |
||||
uv_timer_init(uv_default_loop(), &g_handle->kick_timer); |
||||
} |
||||
|
||||
static void empty_timer_cb(uv_timer_t* handle) {} |
||||
|
||||
static void kick_timer_cb(uv_timer_t* handle) { g_kicked = false; } |
||||
|
||||
static grpc_error* run_loop(size_t timeout) { |
||||
if (grpc_pollset_work_run_loop) { |
||||
if (timeout == 0) { |
||||
uv_run(uv_default_loop(), UV_RUN_NOWAIT); |
||||
} else { |
||||
uv_timer_start(&g_handle->poll_timer, empty_timer_cb, timeout, 0); |
||||
uv_run(uv_default_loop(), UV_RUN_ONCE); |
||||
uv_timer_stop(&g_handle->poll_timer); |
||||
} |
||||
} |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static void kick() { |
||||
if (!g_kicked) { |
||||
g_kicked = true; |
||||
uv_timer_start(&g_handle->kick_timer, kick_timer_cb, 0, 0); |
||||
} |
||||
} |
||||
|
||||
static void close_timer_cb(uv_handle_t* handle) { |
||||
g_handle->refs--; |
||||
if (g_handle->refs == 0) { |
||||
gpr_free(g_handle); |
||||
} |
||||
} |
||||
|
||||
static void shutdown() { |
||||
uv_close((uv_handle_t*)&g_handle->poll_timer, close_timer_cb); |
||||
uv_close((uv_handle_t*)&g_handle->kick_timer, close_timer_cb); |
||||
if (grpc_pollset_work_run_loop) { |
||||
GPR_ASSERT(uv_run(uv_default_loop(), UV_RUN_DEFAULT) == 0); |
||||
} |
||||
} |
||||
|
||||
grpc_custom_poller_vtable uv_pollset_vtable = {init, run_loop, kick, shutdown}; |
||||
|
||||
#endif /* GRPC_UV */ |
@ -1,36 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_IOMGR_POLLSET_UV_H |
||||
#define GRPC_CORE_LIB_IOMGR_POLLSET_UV_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/error.h" |
||||
|
||||
extern int grpc_pollset_work_run_loop; |
||||
|
||||
typedef struct grpc_custom_poller_vtable { |
||||
void (*init)(void); |
||||
grpc_error* (*run_loop)(int blocking); |
||||
} grpc_custom_poller_vtable; |
||||
|
||||
void grpc_custom_pollset_global_init(grpc_custom_poller_vtable* vtable); |
||||
void grpc_custom_pollset_global_shutdown(void); |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_UV_H */ |
@ -1,54 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_CUSTOM_H |
||||
#define GRPC_CORE_LIB_IOMGR_SOCKADDR_CUSTOM_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stddef.h> |
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_UV |
||||
|
||||
#include <uv.h> |
||||
|
||||
// TODO(kpayson) It would be nice to abstract this so we don't
|
||||
// depend on anything uv specific
|
||||
typedef struct sockaddr grpc_sockaddr; |
||||
typedef struct sockaddr_in grpc_sockaddr_in; |
||||
typedef struct in_addr grpc_in_addr; |
||||
typedef struct sockaddr_in6 grpc_sockaddr_in6; |
||||
typedef struct in6_addr grpc_in6_addr; |
||||
|
||||
#define GRPC_INET_ADDRSTRLEN INET_ADDRSTRLEN |
||||
#define GRPC_INET6_ADDRSTRLEN INET6_ADDRSTRLEN |
||||
|
||||
#define GRPC_SOCK_STREAM SOCK_STREAM |
||||
#define GRPC_SOCK_DGRAM SOCK_DGRAM |
||||
|
||||
#define GRPC_AF_UNSPEC AF_UNSPEC |
||||
#define GRPC_AF_UNIX AF_UNIX |
||||
#define GRPC_AF_INET AF_INET |
||||
#define GRPC_AF_INET6 AF_INET6 |
||||
|
||||
#define GRPC_AI_PASSIVE AI_PASSIVE |
||||
|
||||
#endif // GRPC_UV
|
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_CUSTOM_H */ |
@ -1,49 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_UV |
||||
|
||||
#include "src/core/lib/iomgr/sockaddr.h" |
||||
#include "src/core/lib/iomgr/socket_utils.h" |
||||
|
||||
#include <grpc/support/log.h> |
||||
|
||||
#include <uv.h> |
||||
|
||||
uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); } |
||||
|
||||
uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); } |
||||
|
||||
uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); } |
||||
|
||||
uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); } |
||||
|
||||
int grpc_inet_pton(int af, const char* src, void* dst) { |
||||
return inet_pton(af, src, dst); |
||||
} |
||||
|
||||
const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) { |
||||
uv_inet_ntop(af, src, dst, size); |
||||
return dst; |
||||
} |
||||
|
||||
#endif /* GRPC_UV */ |
@ -1,421 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_UV |
||||
#include <limits.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/slice_buffer.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/gpr/string.h" |
||||
#include "src/core/lib/iomgr/error.h" |
||||
#include "src/core/lib/iomgr/iomgr_custom.h" |
||||
#include "src/core/lib/iomgr/resolve_address_custom.h" |
||||
#include "src/core/lib/iomgr/resource_quota.h" |
||||
#include "src/core/lib/iomgr/tcp_custom.h" |
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
#include "src/core/lib/slice/slice_string_helpers.h" |
||||
|
||||
#include <uv.h> |
||||
|
||||
#define IGNORE_CONST(addr) ((grpc_sockaddr*)(uintptr_t)(addr)) |
||||
|
||||
typedef struct uv_socket_t { |
||||
uv_connect_t connect_req; |
||||
uv_write_t write_req; |
||||
uv_shutdown_t shutdown_req; |
||||
uv_tcp_t* handle; |
||||
uv_buf_t* write_buffers; |
||||
|
||||
char* read_buf; |
||||
size_t read_len; |
||||
|
||||
int pending_connections; |
||||
grpc_custom_socket* accept_socket; |
||||
grpc_error_handle accept_error; |
||||
|
||||
grpc_custom_connect_callback connect_cb; |
||||
grpc_custom_write_callback write_cb; |
||||
grpc_custom_read_callback read_cb; |
||||
grpc_custom_accept_callback accept_cb; |
||||
grpc_custom_close_callback close_cb; |
||||
|
||||
} uv_socket_t; |
||||
|
||||
static grpc_error_handle tcp_error_create(const char* desc, int status) { |
||||
if (status == 0) { |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc); |
||||
/* All tcp errors are marked with UNAVAILABLE so that application may
|
||||
* choose to retry. */ |
||||
error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, |
||||
GRPC_STATUS_UNAVAILABLE); |
||||
return grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string(uv_strerror(status))); |
||||
} |
||||
|
||||
static void uv_socket_destroy(grpc_custom_socket* socket) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
gpr_free(uv_socket->handle); |
||||
gpr_free(uv_socket); |
||||
} |
||||
|
||||
static void alloc_uv_buf(uv_handle_t* handle, size_t suggested_size, |
||||
uv_buf_t* buf) { |
||||
uv_socket_t* uv_socket = |
||||
(uv_socket_t*)((grpc_custom_socket*)handle->data)->impl; |
||||
(void)suggested_size; |
||||
buf->base = uv_socket->read_buf; |
||||
buf->len = uv_socket->read_len; |
||||
} |
||||
|
||||
static void uv_read_callback(uv_stream_t* stream, ssize_t nread, |
||||
const uv_buf_t* buf) { |
||||
grpc_error_handle error = GRPC_ERROR_NONE; |
||||
if (nread == 0) { |
||||
// Nothing happened. Wait for the next callback
|
||||
return; |
||||
} |
||||
// TODO(murgatroid99): figure out what the return value here means
|
||||
uv_read_stop(stream); |
||||
if (nread == UV_EOF) { |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF"); |
||||
} else if (nread < 0) { |
||||
error = tcp_error_create("TCP Read failed", nread); |
||||
} |
||||
grpc_custom_socket* socket = (grpc_custom_socket*)stream->data; |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
uv_socket->read_cb(socket, (size_t)nread, error); |
||||
} |
||||
|
||||
static void uv_close_callback(uv_handle_t* handle) { |
||||
grpc_custom_socket* socket = (grpc_custom_socket*)handle->data; |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
if (uv_socket->accept_socket) { |
||||
uv_socket->accept_cb(socket, uv_socket->accept_socket, |
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING("socket closed")); |
||||
} |
||||
uv_socket->close_cb(socket); |
||||
} |
||||
|
||||
static void uv_socket_read(grpc_custom_socket* socket, char* buffer, |
||||
size_t length, grpc_custom_read_callback read_cb) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
int status; |
||||
grpc_error_handle error; |
||||
uv_socket->read_cb = read_cb; |
||||
uv_socket->read_buf = buffer; |
||||
uv_socket->read_len = length; |
||||
// TODO(murgatroid99): figure out what the return value here means
|
||||
status = |
||||
uv_read_start((uv_stream_t*)uv_socket->handle, (uv_alloc_cb)alloc_uv_buf, |
||||
(uv_read_cb)uv_read_callback); |
||||
if (status != 0) { |
||||
error = tcp_error_create("TCP Read failed at start", status); |
||||
uv_socket->read_cb(socket, 0, error); |
||||
} |
||||
} |
||||
|
||||
static void uv_write_callback(uv_write_t* req, int status) { |
||||
grpc_custom_socket* socket = (grpc_custom_socket*)req->data; |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
gpr_free(uv_socket->write_buffers); |
||||
uv_socket->write_cb(socket, tcp_error_create("TCP Write failed", status)); |
||||
} |
||||
|
||||
void uv_socket_write(grpc_custom_socket* socket, |
||||
grpc_slice_buffer* write_slices, |
||||
grpc_custom_write_callback write_cb) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
uv_socket->write_cb = write_cb; |
||||
uv_buf_t* uv_buffers; |
||||
uv_write_t* write_req; |
||||
|
||||
uv_buffers = (uv_buf_t*)gpr_malloc(sizeof(uv_buf_t) * write_slices->count); |
||||
for (size_t i = 0; i < write_slices->count; i++) { |
||||
uv_buffers[i].base = (char*)GRPC_SLICE_START_PTR(write_slices->slices[i]); |
||||
uv_buffers[i].len = GRPC_SLICE_LENGTH(write_slices->slices[i]); |
||||
} |
||||
|
||||
uv_socket->write_buffers = uv_buffers; |
||||
write_req = &uv_socket->write_req; |
||||
write_req->data = socket; |
||||
// TODO(murgatroid99): figure out what the return value here means
|
||||
uv_write(write_req, (uv_stream_t*)uv_socket->handle, uv_buffers, |
||||
write_slices->count, uv_write_callback); |
||||
} |
||||
|
||||
static void shutdown_callback(uv_shutdown_t* req, int status) {} |
||||
|
||||
static void uv_socket_shutdown(grpc_custom_socket* socket) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
uv_shutdown_t* req = &uv_socket->shutdown_req; |
||||
uv_shutdown(req, (uv_stream_t*)uv_socket->handle, shutdown_callback); |
||||
} |
||||
|
||||
static void uv_socket_close(grpc_custom_socket* socket, |
||||
grpc_custom_close_callback close_cb) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
uv_socket->close_cb = close_cb; |
||||
uv_close((uv_handle_t*)uv_socket->handle, uv_close_callback); |
||||
} |
||||
|
||||
static grpc_error_handle uv_socket_init_helper(uv_socket_t* uv_socket, |
||||
int domain) { |
||||
uv_tcp_t* tcp = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t)); |
||||
uv_socket->handle = tcp; |
||||
int status = uv_tcp_init_ex(uv_default_loop(), tcp, (unsigned int)domain); |
||||
if (status != 0) { |
||||
return tcp_error_create("Failed to initialize UV tcp handle", status); |
||||
} |
||||
#if defined(GPR_LINUX) && defined(SO_REUSEPORT) |
||||
if (domain == AF_INET || domain == AF_INET6) { |
||||
int enable = 1; |
||||
int fd; |
||||
uv_fileno((uv_handle_t*)tcp, &fd); |
||||
// TODO Handle error here.
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable)); |
||||
} |
||||
#endif |
||||
uv_socket->write_buffers = nullptr; |
||||
uv_socket->read_len = 0; |
||||
uv_tcp_nodelay(uv_socket->handle, 1); |
||||
// Node uses a garbage collector to call destructors, so we don't
|
||||
// want to hold the uv loop open with active gRPC objects.
|
||||
uv_unref((uv_handle_t*)uv_socket->handle); |
||||
uv_socket->pending_connections = 0; |
||||
uv_socket->accept_socket = nullptr; |
||||
uv_socket->accept_error = GRPC_ERROR_NONE; |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static grpc_error_handle uv_socket_init(grpc_custom_socket* socket, |
||||
int domain) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)gpr_malloc(sizeof(uv_socket_t)); |
||||
grpc_error_handle error = uv_socket_init_helper(uv_socket, domain); |
||||
if (error != GRPC_ERROR_NONE) { |
||||
return error; |
||||
} |
||||
uv_socket->handle->data = socket; |
||||
socket->impl = uv_socket; |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static grpc_error_handle uv_socket_getpeername(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, |
||||
int* addr_len) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
int err = uv_tcp_getpeername(uv_socket->handle, |
||||
(struct sockaddr*)IGNORE_CONST(addr), addr_len); |
||||
return tcp_error_create("getpeername failed", err); |
||||
} |
||||
|
||||
static grpc_error_handle uv_socket_getsockname(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, |
||||
int* addr_len) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
int err = uv_tcp_getsockname(uv_socket->handle, |
||||
(struct sockaddr*)IGNORE_CONST(addr), addr_len); |
||||
return tcp_error_create("getsockname failed", err); |
||||
} |
||||
|
||||
static void accept_new_connection(grpc_custom_socket* socket) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
if (uv_socket->pending_connections == 0 || !uv_socket->accept_socket) { |
||||
return; |
||||
} |
||||
grpc_custom_socket* new_socket = uv_socket->accept_socket; |
||||
grpc_error_handle error = uv_socket->accept_error; |
||||
uv_socket->accept_socket = nullptr; |
||||
uv_socket->accept_error = GRPC_ERROR_NONE; |
||||
uv_socket->pending_connections -= 1; |
||||
if (uv_socket->accept_error != GRPC_ERROR_NONE) { |
||||
uv_stream_t phony_handle; |
||||
uv_accept((uv_stream_t*)uv_socket->handle, &phony_handle); |
||||
uv_socket->accept_cb(socket, new_socket, error); |
||||
} else { |
||||
uv_socket_t* uv_new_socket = (uv_socket_t*)gpr_malloc(sizeof(uv_socket_t)); |
||||
uv_socket_init_helper(uv_new_socket, AF_UNSPEC); |
||||
// UV documentation says this is guaranteed to succeed
|
||||
GPR_ASSERT(uv_accept((uv_stream_t*)uv_socket->handle, |
||||
(uv_stream_t*)uv_new_socket->handle) == 0); |
||||
new_socket->impl = uv_new_socket; |
||||
uv_new_socket->handle->data = new_socket; |
||||
uv_socket->accept_cb(socket, new_socket, error); |
||||
} |
||||
} |
||||
|
||||
static void uv_on_connect(uv_stream_t* server, int status) { |
||||
grpc_custom_socket* socket = (grpc_custom_socket*)server->data; |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
if (status < 0) { |
||||
switch (status) { |
||||
case UV_EINTR: |
||||
case UV_EAGAIN: |
||||
return; |
||||
default: |
||||
uv_socket->accept_error = tcp_error_create("accept failed", status); |
||||
} |
||||
} |
||||
uv_socket->pending_connections += 1; |
||||
accept_new_connection(socket); |
||||
} |
||||
|
||||
void uv_socket_accept(grpc_custom_socket* socket, |
||||
grpc_custom_socket* new_socket, |
||||
grpc_custom_accept_callback accept_cb) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
uv_socket->accept_cb = accept_cb; |
||||
GPR_ASSERT(uv_socket->accept_socket == nullptr); |
||||
uv_socket->accept_socket = new_socket; |
||||
accept_new_connection(socket); |
||||
} |
||||
|
||||
static grpc_error_handle uv_socket_bind(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, size_t len, |
||||
int flags) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
int status = |
||||
uv_tcp_bind((uv_tcp_t*)uv_socket->handle, (struct sockaddr*)addr, 0); |
||||
return tcp_error_create("Failed to bind to port", status); |
||||
} |
||||
|
||||
static grpc_error_handle uv_socket_listen(grpc_custom_socket* socket) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
int status = |
||||
uv_listen((uv_stream_t*)uv_socket->handle, SOMAXCONN, uv_on_connect); |
||||
return tcp_error_create("Failed to listen to port", status); |
||||
} |
||||
|
||||
static void uv_tc_on_connect(uv_connect_t* req, int status) { |
||||
grpc_custom_socket* socket = (grpc_custom_socket*)req->data; |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
grpc_error_handle error; |
||||
if (status == UV_ECANCELED) { |
||||
// This should only happen if the handle is already closed
|
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timeout occurred"); |
||||
} else { |
||||
error = tcp_error_create("Failed to connect to remote host", status); |
||||
} |
||||
uv_socket->connect_cb(socket, error); |
||||
} |
||||
|
||||
static void uv_socket_connect(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, size_t len, |
||||
grpc_custom_connect_callback connect_cb) { |
||||
uv_socket_t* uv_socket = (uv_socket_t*)socket->impl; |
||||
uv_socket->connect_cb = connect_cb; |
||||
uv_socket->connect_req.data = socket; |
||||
int status = uv_tcp_connect(&uv_socket->connect_req, uv_socket->handle, |
||||
(struct sockaddr*)addr, uv_tc_on_connect); |
||||
if (status != 0) { |
||||
// The callback will not be called
|
||||
uv_socket->connect_cb(socket, tcp_error_create("connect failed", status)); |
||||
} |
||||
} |
||||
|
||||
static grpc_resolved_addresses* handle_addrinfo_result( |
||||
struct addrinfo* result) { |
||||
struct addrinfo* resp; |
||||
size_t i; |
||||
grpc_resolved_addresses* addresses = |
||||
(grpc_resolved_addresses*)gpr_malloc(sizeof(grpc_resolved_addresses)); |
||||
addresses->naddrs = 0; |
||||
for (resp = result; resp != nullptr; resp = resp->ai_next) { |
||||
addresses->naddrs++; |
||||
} |
||||
addresses->addrs = (grpc_resolved_address*)gpr_malloc( |
||||
sizeof(grpc_resolved_address) * addresses->naddrs); |
||||
for (resp = result, i = 0; resp != nullptr; resp = resp->ai_next, i++) { |
||||
memcpy(&addresses->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); |
||||
addresses->addrs[i].len = resp->ai_addrlen; |
||||
} |
||||
// addrinfo objects are allocated by libuv (e.g. in uv_getaddrinfo)
|
||||
// and not by gpr_malloc
|
||||
uv_freeaddrinfo(result); |
||||
return addresses; |
||||
} |
||||
|
||||
static void uv_resolve_callback(uv_getaddrinfo_t* req, int status, |
||||
struct addrinfo* res) { |
||||
grpc_custom_resolver* r = (grpc_custom_resolver*)req->data; |
||||
gpr_free(req); |
||||
grpc_resolved_addresses* result = nullptr; |
||||
if (status == 0) { |
||||
result = handle_addrinfo_result(res); |
||||
} |
||||
grpc_custom_resolve_callback(r, result, |
||||
tcp_error_create("getaddrinfo failed", status)); |
||||
} |
||||
|
||||
static grpc_error_handle uv_resolve(const char* host, const char* port, |
||||
grpc_resolved_addresses** result) { |
||||
int status; |
||||
uv_getaddrinfo_t req; |
||||
struct addrinfo hints; |
||||
memset(&hints, 0, sizeof(struct addrinfo)); |
||||
hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ |
||||
hints.ai_socktype = SOCK_STREAM; /* stream socket */ |
||||
hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ |
||||
status = uv_getaddrinfo(uv_default_loop(), &req, NULL, host, port, &hints); |
||||
if (status != 0) { |
||||
*result = nullptr; |
||||
} else { |
||||
*result = handle_addrinfo_result(req.addrinfo); |
||||
} |
||||
return tcp_error_create("getaddrinfo failed", status); |
||||
} |
||||
|
||||
static void uv_resolve_async(grpc_custom_resolver* r, const char* host, |
||||
const char* port) { |
||||
int status; |
||||
uv_getaddrinfo_t* req = |
||||
(uv_getaddrinfo_t*)gpr_malloc(sizeof(uv_getaddrinfo_t)); |
||||
req->data = r; |
||||
struct addrinfo hints; |
||||
memset(&hints, 0, sizeof(struct addrinfo)); |
||||
hints.ai_family = GRPC_AF_UNSPEC; /* ipv4 or ipv6 */ |
||||
hints.ai_socktype = GRPC_SOCK_STREAM; /* stream socket */ |
||||
hints.ai_flags = GRPC_AI_PASSIVE; /* for wildcard IP address */ |
||||
status = uv_getaddrinfo(uv_default_loop(), req, uv_resolve_callback, host, |
||||
port, &hints); |
||||
if (status != 0) { |
||||
gpr_free(req); |
||||
grpc_error_handle error = tcp_error_create("getaddrinfo failed", status); |
||||
grpc_custom_resolve_callback(r, NULL, error); |
||||
} |
||||
} |
||||
|
||||
grpc_custom_resolver_vtable uv_resolver_vtable = {uv_resolve, uv_resolve_async}; |
||||
|
||||
grpc_socket_vtable grpc_uv_socket_vtable = { |
||||
uv_socket_init, uv_socket_connect, uv_socket_destroy, |
||||
uv_socket_shutdown, uv_socket_close, uv_socket_write, |
||||
uv_socket_read, uv_socket_getpeername, uv_socket_getsockname, |
||||
uv_socket_bind, uv_socket_listen, uv_socket_accept}; |
||||
|
||||
#endif |
@ -1,66 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_UV |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/debug/trace.h" |
||||
#include "src/core/lib/iomgr/iomgr_custom.h" |
||||
#include "src/core/lib/iomgr/timer.h" |
||||
#include "src/core/lib/iomgr/timer_custom.h" |
||||
|
||||
#include <uv.h> |
||||
|
||||
static void timer_close_callback(uv_handle_t* handle) { gpr_free(handle); } |
||||
|
||||
static void stop_uv_timer(uv_timer_t* handle) { |
||||
uv_timer_stop(handle); |
||||
uv_unref((uv_handle_t*)handle); |
||||
uv_close((uv_handle_t*)handle, timer_close_callback); |
||||
} |
||||
|
||||
void run_expired_timer(uv_timer_t* handle) { |
||||
grpc_custom_timer* timer_wrapper = (grpc_custom_timer*)handle->data; |
||||
grpc_custom_timer_callback(timer_wrapper, GRPC_ERROR_NONE); |
||||
} |
||||
|
||||
static void timer_start(grpc_custom_timer* t) { |
||||
uv_timer_t* uv_timer; |
||||
uv_timer = (uv_timer_t*)gpr_malloc(sizeof(uv_timer_t)); |
||||
uv_timer_init(uv_default_loop(), uv_timer); |
||||
uv_timer->data = t; |
||||
t->timer = (void*)uv_timer; |
||||
uv_timer_start(uv_timer, run_expired_timer, t->timeout_ms, 0); |
||||
// Node uses a garbage collector to call destructors, so we don't
|
||||
// want to hold the uv loop open with active gRPC objects.
|
||||
uv_unref((uv_handle_t*)uv_timer); |
||||
} |
||||
|
||||
static void timer_stop(grpc_custom_timer* t) { |
||||
stop_uv_timer((uv_timer_t*)t->timer); |
||||
} |
||||
|
||||
grpc_custom_timer_vtable uv_timer_vtable = {timer_start, timer_stop}; |
||||
|
||||
#endif |
@ -1,97 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GRPC_UV |
||||
|
||||
#include <uv.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "test/core/end2end/cq_verifier_internal.h" |
||||
|
||||
typedef enum timer_state { |
||||
TIMER_STARTED, |
||||
TIMER_TRIGGERED, |
||||
TIMER_CLOSED |
||||
} timer_state; |
||||
|
||||
/* the verifier itself */ |
||||
struct cq_verifier { |
||||
/* bound completion queue */ |
||||
grpc_completion_queue* cq; |
||||
/* start of expectation list */ |
||||
expectation* first_expectation; |
||||
uv_timer_t timer; |
||||
}; |
||||
|
||||
cq_verifier* cq_verifier_create(grpc_completion_queue* cq) { |
||||
cq_verifier* v = static_cast<cq_verifier*>(gpr_malloc(sizeof(cq_verifier))); |
||||
v->cq = cq; |
||||
v->first_expectation = NULL; |
||||
uv_timer_init(uv_default_loop(), &v->timer); |
||||
v->timer.data = (void*)TIMER_STARTED; |
||||
return v; |
||||
} |
||||
|
||||
static void timer_close_cb(uv_handle_t* handle) { |
||||
handle->data = (void*)TIMER_CLOSED; |
||||
} |
||||
|
||||
void cq_verifier_destroy(cq_verifier* v) { |
||||
cq_verify(v); |
||||
uv_close((uv_handle_t*)&v->timer, timer_close_cb); |
||||
while (static_cast<timer_state>(v->timer.data) != TIMER_CLOSED) { |
||||
uv_run(uv_default_loop(), UV_RUN_NOWAIT); |
||||
} |
||||
gpr_free(v); |
||||
} |
||||
|
||||
expectation* cq_verifier_get_first_expectation(cq_verifier* v) { |
||||
return v->first_expectation; |
||||
} |
||||
|
||||
void cq_verifier_set_first_expectation(cq_verifier* v, expectation* e) { |
||||
v->first_expectation = e; |
||||
} |
||||
|
||||
static void timer_run_cb(uv_timer_t* timer) { |
||||
timer->data = (void*)TIMER_TRIGGERED; |
||||
} |
||||
|
||||
grpc_event cq_verifier_next_event(cq_verifier* v, int timeout_seconds) { |
||||
uint64_t timeout_ms = |
||||
timeout_seconds < 0 ? 0 : (uint64_t)timeout_seconds * 1000; |
||||
grpc_event ev; |
||||
v->timer.data = (void*)TIMER_STARTED; |
||||
uv_timer_start(&v->timer, timer_run_cb, timeout_ms, 0); |
||||
ev = grpc_completion_queue_next(v->cq, gpr_inf_past(GPR_CLOCK_MONOTONIC), |
||||
NULL); |
||||
// Stop the loop if the timer goes off or we get a non-timeout event
|
||||
while ((static_cast<timer_state>(v->timer.data) != TIMER_TRIGGERED) && |
||||
ev.type == GRPC_QUEUE_TIMEOUT) { |
||||
uv_run(uv_default_loop(), UV_RUN_ONCE); |
||||
ev = grpc_completion_queue_next(v->cq, gpr_inf_past(GPR_CLOCK_MONOTONIC), |
||||
NULL); |
||||
} |
||||
return ev; |
||||
} |
||||
|
||||
#endif /* GRPC_UV */ |
@ -1,215 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
// This test won't work except with libuv
|
||||
#ifdef GRPC_UV |
||||
|
||||
#include <uv.h> |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "src/core/lib/iomgr/tcp_client.h" |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
#include "src/core/lib/iomgr/iomgr.h" |
||||
#include "src/core/lib/iomgr/pollset.h" |
||||
#include "src/core/lib/iomgr/timer.h" |
||||
#include "test/core/util/resource_user_util.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
static gpr_mu* g_mu; |
||||
static grpc_pollset* g_pollset; |
||||
static int g_connections_complete = 0; |
||||
static grpc_endpoint* g_connecting = NULL; |
||||
|
||||
static grpc_millis test_deadline(void) { |
||||
return grpc_timespec_to_millis_round_up(grpc_timeout_seconds_to_deadline(10)); |
||||
} |
||||
|
||||
static void finish_connection() { |
||||
gpr_mu_lock(g_mu); |
||||
g_connections_complete++; |
||||
GPR_ASSERT( |
||||
GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, NULL))); |
||||
gpr_mu_unlock(g_mu); |
||||
} |
||||
|
||||
static void must_succeed(void* arg, grpc_error_handle error) { |
||||
GPR_ASSERT(g_connecting != NULL); |
||||
GPR_ASSERT(error == GRPC_ERROR_NONE); |
||||
grpc_endpoint_shutdown(g_connecting, GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"must_succeed called")); |
||||
grpc_endpoint_destroy(g_connecting); |
||||
g_connecting = NULL; |
||||
finish_connection(); |
||||
} |
||||
|
||||
static void must_fail(void* arg, grpc_error_handle error) { |
||||
GPR_ASSERT(g_connecting == NULL); |
||||
GPR_ASSERT(error != GRPC_ERROR_NONE); |
||||
finish_connection(); |
||||
} |
||||
|
||||
static void close_cb(uv_handle_t* handle) { gpr_free(handle); } |
||||
|
||||
static void connection_cb(uv_stream_t* server, int status) { |
||||
uv_tcp_t* client_handle = |
||||
static_cast<uv_tcp_t*>(gpr_malloc(sizeof(uv_tcp_t))); |
||||
GPR_ASSERT(0 == status); |
||||
GPR_ASSERT(0 == uv_tcp_init(uv_default_loop(), client_handle)); |
||||
GPR_ASSERT(0 == uv_accept(server, (uv_stream_t*)client_handle)); |
||||
uv_close((uv_handle_t*)client_handle, close_cb); |
||||
} |
||||
|
||||
void test_succeeds(void) { |
||||
grpc_resolved_address resolved_addr; |
||||
struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr; |
||||
uv_tcp_t* svr_handle = static_cast<uv_tcp_t*>(gpr_malloc(sizeof(uv_tcp_t))); |
||||
int connections_complete_before; |
||||
grpc_closure done; |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
gpr_log(GPR_DEBUG, "test_succeeds"); |
||||
|
||||
memset(&resolved_addr, 0, sizeof(resolved_addr)); |
||||
resolved_addr.len = sizeof(struct sockaddr_in); |
||||
addr->sin_family = AF_INET; |
||||
|
||||
/* create a phony server */ |
||||
GPR_ASSERT(0 == uv_tcp_init(uv_default_loop(), svr_handle)); |
||||
GPR_ASSERT(0 == uv_tcp_bind(svr_handle, (struct sockaddr*)addr, 0)); |
||||
GPR_ASSERT(0 == uv_listen((uv_stream_t*)svr_handle, 1, connection_cb)); |
||||
|
||||
gpr_mu_lock(g_mu); |
||||
connections_complete_before = g_connections_complete; |
||||
gpr_mu_unlock(g_mu); |
||||
|
||||
/* connect to it */ |
||||
GPR_ASSERT(uv_tcp_getsockname(svr_handle, (struct sockaddr*)addr, |
||||
(int*)&resolved_addr.len) == 0); |
||||
GRPC_CLOSURE_INIT(&done, must_succeed, NULL, grpc_schedule_on_exec_ctx); |
||||
grpc_tcp_client_connect(&done, &g_connecting, |
||||
grpc_slice_allocator_create_unlimited(), NULL, NULL, |
||||
&resolved_addr, GRPC_MILLIS_INF_FUTURE); |
||||
gpr_mu_lock(g_mu); |
||||
|
||||
while (g_connections_complete == connections_complete_before) { |
||||
grpc_pollset_worker* worker = NULL; |
||||
GPR_ASSERT(GRPC_LOG_IF_ERROR( |
||||
"pollset_work", |
||||
grpc_pollset_work(g_pollset, &worker, |
||||
grpc_timespec_to_millis_round_up( |
||||
grpc_timeout_seconds_to_deadline(5))))); |
||||
gpr_mu_unlock(g_mu); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
gpr_mu_lock(g_mu); |
||||
} |
||||
|
||||
// This will get cleaned up when the pollset runs again or gets shutdown
|
||||
uv_close((uv_handle_t*)svr_handle, close_cb); |
||||
|
||||
gpr_mu_unlock(g_mu); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
void test_fails(void) { |
||||
grpc_resolved_address resolved_addr; |
||||
struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr; |
||||
int connections_complete_before; |
||||
grpc_closure done; |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
gpr_log(GPR_DEBUG, "test_fails"); |
||||
|
||||
memset(&resolved_addr, 0, sizeof(resolved_addr)); |
||||
resolved_addr.len = sizeof(struct sockaddr_in); |
||||
addr->sin_family = AF_INET; |
||||
|
||||
gpr_mu_lock(g_mu); |
||||
connections_complete_before = g_connections_complete; |
||||
gpr_mu_unlock(g_mu); |
||||
|
||||
/* connect to a broken address */ |
||||
GRPC_CLOSURE_INIT(&done, must_fail, NULL, grpc_schedule_on_exec_ctx); |
||||
grpc_tcp_client_connect(&done, &g_connecting, |
||||
grpc_slice_allocator_create_unlimited(), NULL, NULL, |
||||
&resolved_addr, GRPC_MILLIS_INF_FUTURE); |
||||
gpr_mu_lock(g_mu); |
||||
|
||||
/* wait for the connection callback to finish */ |
||||
while (g_connections_complete == connections_complete_before) { |
||||
grpc_pollset_worker* worker = NULL; |
||||
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); |
||||
grpc_millis polling_deadline = test_deadline(); |
||||
switch (grpc_timer_check(&polling_deadline)) { |
||||
case GRPC_TIMERS_FIRED: |
||||
break; |
||||
case GRPC_TIMERS_NOT_CHECKED: |
||||
polling_deadline = grpc_timespec_to_millis_round_up(now); |
||||
ABSL_FALLTHROUGH_INTENDED; |
||||
case GRPC_TIMERS_CHECKED_AND_EMPTY: |
||||
GPR_ASSERT(GRPC_LOG_IF_ERROR( |
||||
"pollset_work", |
||||
grpc_pollset_work(g_pollset, &worker, polling_deadline))); |
||||
break; |
||||
} |
||||
gpr_mu_unlock(g_mu); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
gpr_mu_lock(g_mu); |
||||
} |
||||
|
||||
gpr_mu_unlock(g_mu); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
static void destroy_pollset(void* p, grpc_error_handle error) { |
||||
grpc_pollset_destroy(static_cast<grpc_pollset*>(p)); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
grpc_closure destroyed; |
||||
grpc::testing::TestEnvironment env(argc, argv); |
||||
grpc_init(); |
||||
{ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
g_pollset = static_cast<grpc_pollset*>(gpr_malloc(grpc_pollset_size())); |
||||
grpc_pollset_init(g_pollset, &g_mu); |
||||
|
||||
test_succeeds(); |
||||
gpr_log(GPR_ERROR, "End of first test"); |
||||
test_fails(); |
||||
GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, g_pollset, |
||||
grpc_schedule_on_exec_ctx); |
||||
grpc_pollset_shutdown(g_pollset, &destroyed); |
||||
gpr_free(g_pollset); |
||||
} |
||||
grpc_shutdown(); |
||||
return 0; |
||||
} |
||||
|
||||
#else /* GRPC_UV */ |
||||
|
||||
int main(int /*argc*/, char** /*argv*/) { return 1; } |
||||
|
||||
#endif /* GRPC_UV */ |
@ -1,339 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
// This test won't work except with libuv
|
||||
#ifdef GRPC_UV |
||||
|
||||
#include <uv.h> |
||||
|
||||
#include "src/core/lib/iomgr/tcp_server.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
#include "src/core/lib/address_utils/sockaddr_utils.h" |
||||
#include "src/core/lib/iomgr/iomgr.h" |
||||
#include "src/core/lib/iomgr/resolve_address.h" |
||||
#include "test/core/util/port.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
#define LOG_TEST(x) gpr_log(GPR_INFO, "%s", #x) |
||||
|
||||
static gpr_mu* g_mu; |
||||
static grpc_pollset* g_pollset; |
||||
static int g_nconnects = 0; |
||||
|
||||
typedef struct on_connect_result { |
||||
/* Owns a ref to server. */ |
||||
grpc_tcp_server* server; |
||||
unsigned port_index; |
||||
unsigned fd_index; |
||||
} on_connect_result; |
||||
|
||||
typedef struct server_weak_ref { |
||||
grpc_tcp_server* server; |
||||
|
||||
/* arg is this server_weak_ref. */ |
||||
grpc_closure server_shutdown; |
||||
} server_weak_ref; |
||||
|
||||
static on_connect_result g_result = {NULL, 0, 0}; |
||||
|
||||
static void on_connect_result_init(on_connect_result* result) { |
||||
result->server = NULL; |
||||
result->port_index = 0; |
||||
result->fd_index = 0; |
||||
} |
||||
|
||||
static void on_connect_result_set(on_connect_result* result, |
||||
const grpc_tcp_server_acceptor* acceptor) { |
||||
result->server = grpc_tcp_server_ref(acceptor->from_server); |
||||
result->port_index = acceptor->port_index; |
||||
result->fd_index = acceptor->fd_index; |
||||
} |
||||
|
||||
static void server_weak_ref_shutdown(void* arg, grpc_error_handle error) { |
||||
server_weak_ref* weak_ref = static_cast<server_weak_ref*>(arg); |
||||
weak_ref->server = NULL; |
||||
} |
||||
|
||||
static void server_weak_ref_init(server_weak_ref* weak_ref) { |
||||
weak_ref->server = NULL; |
||||
GRPC_CLOSURE_INIT(&weak_ref->server_shutdown, server_weak_ref_shutdown, |
||||
weak_ref, grpc_schedule_on_exec_ctx); |
||||
} |
||||
|
||||
/* Make weak_ref->server_shutdown a shutdown_starting cb on server.
|
||||
grpc_tcp_server promises that the server object will live until |
||||
weak_ref->server_shutdown has returned. A strong ref on grpc_tcp_server |
||||
should be held until server_weak_ref_set() returns to avoid a race where the |
||||
server is deleted before the shutdown_starting cb is added. */ |
||||
static void server_weak_ref_set(server_weak_ref* weak_ref, |
||||
grpc_tcp_server* server) { |
||||
grpc_tcp_server_shutdown_starting_add(server, &weak_ref->server_shutdown); |
||||
weak_ref->server = server; |
||||
} |
||||
|
||||
static void on_connect(void* arg, grpc_endpoint* tcp, grpc_pollset* pollset, |
||||
grpc_tcp_server_acceptor* acceptor) { |
||||
grpc_endpoint_shutdown(tcp, |
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Connected")); |
||||
grpc_endpoint_destroy(tcp); |
||||
|
||||
on_connect_result temp_result; |
||||
on_connect_result_set(&temp_result, acceptor); |
||||
gpr_free(acceptor); |
||||
|
||||
gpr_mu_lock(g_mu); |
||||
g_result = temp_result; |
||||
g_nconnects++; |
||||
GPR_ASSERT( |
||||
GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, NULL))); |
||||
gpr_mu_unlock(g_mu); |
||||
} |
||||
|
||||
static void test_no_op(void) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_tcp_server* s; |
||||
GPR_ASSERT(GRPC_ERROR_NONE == |
||||
grpc_tcp_server_create(NULL, NULL, |
||||
grpc_slice_allocator_factory_create( |
||||
grpc_resource_quota_create(nullptr)), |
||||
&s)); |
||||
grpc_tcp_server_unref(s); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
static void test_no_op_with_start(void) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_tcp_server* s; |
||||
GPR_ASSERT(GRPC_ERROR_NONE == |
||||
grpc_tcp_server_create(NULL, NULL, |
||||
grpc_slice_allocator_factory_create( |
||||
grpc_resource_quota_create(nullptr)) & |
||||
s)); |
||||
LOG_TEST("test_no_op_with_start"); |
||||
grpc_tcp_server_start(s, NULL, 0, on_connect, NULL); |
||||
grpc_tcp_server_unref(s); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
static void test_no_op_with_port(void) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_resolved_address resolved_addr; |
||||
struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr; |
||||
grpc_tcp_server* s; |
||||
GPR_ASSERT(GRPC_ERROR_NONE == |
||||
grpc_tcp_server_create(NULL, NULL, |
||||
grpc_slice_allocator_factory_create( |
||||
grpc_resource_quota_create(nullptr)) & |
||||
s)); |
||||
LOG_TEST("test_no_op_with_port"); |
||||
|
||||
memset(&resolved_addr, 0, sizeof(resolved_addr)); |
||||
resolved_addr.len = sizeof(struct sockaddr_in); |
||||
addr->sin_family = AF_INET; |
||||
int port; |
||||
GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr, &port) == |
||||
GRPC_ERROR_NONE && |
||||
port > 0); |
||||
|
||||
grpc_tcp_server_unref(s); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
static void test_no_op_with_port_and_start(void) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_resolved_address resolved_addr; |
||||
struct sockaddr_in* addr = (struct sockaddr_in*)resolved_addr.addr; |
||||
grpc_tcp_server* s; |
||||
GPR_ASSERT(GRPC_ERROR_NONE == |
||||
grpc_tcp_server_create(NULL, NULL, |
||||
grpc_slice_allocator_factory_create( |
||||
grpc_resource_quota_create(nullptr)) & |
||||
s)); |
||||
LOG_TEST("test_no_op_with_port_and_start"); |
||||
int port; |
||||
|
||||
memset(&resolved_addr, 0, sizeof(resolved_addr)); |
||||
resolved_addr.len = sizeof(struct sockaddr_in); |
||||
addr->sin_family = AF_INET; |
||||
GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr, &port) == |
||||
GRPC_ERROR_NONE && |
||||
port > 0); |
||||
|
||||
grpc_tcp_server_start(s, NULL, 0, on_connect, NULL); |
||||
|
||||
grpc_tcp_server_unref(s); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
|
||||
static void connect_cb(uv_connect_t* req, int status) { |
||||
GPR_ASSERT(status == 0); |
||||
gpr_free(req); |
||||
} |
||||
|
||||
static void close_cb(uv_handle_t* handle) { gpr_free(handle); } |
||||
|
||||
static void tcp_connect(const struct sockaddr* remote, socklen_t remote_len, |
||||
on_connect_result* result) { |
||||
gpr_timespec deadline = grpc_timeout_seconds_to_deadline(10); |
||||
uv_tcp_t* client_handle = |
||||
static_cast<uv_tcp_t*>(gpr_malloc(sizeof(uv_tcp_t))); |
||||
uv_connect_t* req = |
||||
static_cast<uv_connect_t*>(gpr_malloc(sizeof(uv_connect_t))); |
||||
int nconnects_before; |
||||
|
||||
gpr_mu_lock(g_mu); |
||||
nconnects_before = g_nconnects; |
||||
on_connect_result_init(&g_result); |
||||
GPR_ASSERT(uv_tcp_init(uv_default_loop(), client_handle) == 0); |
||||
gpr_log(GPR_DEBUG, "start connect"); |
||||
GPR_ASSERT(uv_tcp_connect(req, client_handle, remote, connect_cb) == 0); |
||||
gpr_log(GPR_DEBUG, "wait"); |
||||
while (g_nconnects == nconnects_before && |
||||
gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0) { |
||||
grpc_pollset_worker* worker = NULL; |
||||
GPR_ASSERT(GRPC_LOG_IF_ERROR( |
||||
"pollset_work", |
||||
grpc_pollset_work(g_pollset, &worker, |
||||
grpc_timespec_to_millis_round_up(deadline)))); |
||||
gpr_mu_unlock(g_mu); |
||||
|
||||
gpr_mu_lock(g_mu); |
||||
} |
||||
gpr_log(GPR_DEBUG, "wait done"); |
||||
GPR_ASSERT(g_nconnects == nconnects_before + 1); |
||||
uv_close((uv_handle_t*)client_handle, close_cb); |
||||
*result = g_result; |
||||
|
||||
gpr_mu_unlock(g_mu); |
||||
} |
||||
|
||||
/* Tests a tcp server with multiple ports. */ |
||||
static void test_connect(unsigned n) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_resolved_address resolved_addr; |
||||
grpc_resolved_address resolved_addr1; |
||||
struct sockaddr_storage* addr = (struct sockaddr_storage*)resolved_addr.addr; |
||||
struct sockaddr_storage* addr1 = |
||||
(struct sockaddr_storage*)resolved_addr1.addr; |
||||
int svr_port; |
||||
int svr1_port; |
||||
grpc_tcp_server* s; |
||||
GPR_ASSERT(GRPC_ERROR_NONE == |
||||
grpc_tcp_server_create(NULL, NULL, |
||||
grpc_slice_allocator_factory_create( |
||||
grpc_resource_quota_create(nullptr)) & |
||||
s)); |
||||
unsigned i; |
||||
server_weak_ref weak_ref; |
||||
server_weak_ref_init(&weak_ref); |
||||
LOG_TEST("test_connect"); |
||||
gpr_log(GPR_INFO, "clients=%d", n); |
||||
memset(&resolved_addr, 0, sizeof(resolved_addr)); |
||||
memset(&resolved_addr1, 0, sizeof(resolved_addr1)); |
||||
resolved_addr.len = sizeof(struct sockaddr_storage); |
||||
resolved_addr1.len = sizeof(struct sockaddr_storage); |
||||
addr->ss_family = addr1->ss_family = AF_INET; |
||||
GPR_ASSERT(GRPC_ERROR_NONE == |
||||
grpc_tcp_server_add_port(s, &resolved_addr, &svr_port)); |
||||
GPR_ASSERT(svr_port > 0); |
||||
GPR_ASSERT((uv_ip6_addr("::", svr_port, (struct sockaddr_in6*)addr)) == 0); |
||||
/* Cannot use wildcard (port==0), because add_port() will try to reuse the
|
||||
same port as a previous add_port(). */ |
||||
svr1_port = grpc_pick_unused_port_or_die(); |
||||
grpc_sockaddr_set_port(&resolved_addr1, svr1_port); |
||||
GPR_ASSERT(grpc_tcp_server_add_port(s, &resolved_addr1, &svr_port) == |
||||
GRPC_ERROR_NONE && |
||||
svr_port == svr1_port); |
||||
|
||||
grpc_tcp_server_start(s, &g_pollset, 1, on_connect, NULL); |
||||
|
||||
GPR_ASSERT(uv_ip6_addr("::", svr_port, (struct sockaddr_in6*)addr1) == 0); |
||||
|
||||
for (i = 0; i < n; i++) { |
||||
on_connect_result result; |
||||
on_connect_result_init(&result); |
||||
tcp_connect((struct sockaddr*)addr, (socklen_t)resolved_addr.len, &result); |
||||
GPR_ASSERT(result.port_index == 0); |
||||
GPR_ASSERT(result.server == s); |
||||
if (weak_ref.server == NULL) { |
||||
server_weak_ref_set(&weak_ref, result.server); |
||||
} |
||||
grpc_tcp_server_unref(result.server); |
||||
|
||||
on_connect_result_init(&result); |
||||
tcp_connect((struct sockaddr*)addr1, (socklen_t)resolved_addr1.len, |
||||
&result); |
||||
GPR_ASSERT(result.port_index == 1); |
||||
GPR_ASSERT(result.server == s); |
||||
grpc_tcp_server_unref(result.server); |
||||
} |
||||
|
||||
/* Weak ref to server valid until final unref. */ |
||||
GPR_ASSERT(weak_ref.server != NULL); |
||||
|
||||
grpc_tcp_server_unref(s); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
/* Weak ref lost. */ |
||||
GPR_ASSERT(weak_ref.server == NULL); |
||||
} |
||||
|
||||
static void destroy_pollset(void* p, grpc_error_handle error) { |
||||
grpc_pollset_destroy(static_cast<grpc_pollset*>(p)); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
grpc_closure destroyed; |
||||
grpc::testing::TestEnvironment env(argc, argv); |
||||
grpc_init(); |
||||
{ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
g_pollset = static_cast<grpc_pollset*>(gpr_malloc(grpc_pollset_size())); |
||||
grpc_pollset_init(g_pollset, &g_mu); |
||||
|
||||
test_no_op(); |
||||
test_no_op_with_start(); |
||||
test_no_op_with_port(); |
||||
test_no_op_with_port_and_start(); |
||||
test_connect(1); |
||||
test_connect(10); |
||||
|
||||
GRPC_CLOSURE_INIT(&destroyed, destroy_pollset, g_pollset, |
||||
grpc_schedule_on_exec_ctx); |
||||
grpc_pollset_shutdown(g_pollset, &destroyed); |
||||
|
||||
gpr_free(g_pollset); |
||||
} |
||||
grpc_shutdown(); |
||||
return 0; |
||||
} |
||||
|
||||
#else /* GRPC_UV */ |
||||
|
||||
int main(int /*argc*/, char** /*argv*/) { return 1; } |
||||
|
||||
#endif /* GRPC_UV */ |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue