mirror of https://github.com/grpc/grpc.git
Structures the libuv implementation to allow for a plugable BSD style socket implementation to allow for other IO Managersreviewable/pr14599/r1
parent
44fd6557ae
commit
539f5068bd
122 changed files with 8987 additions and 2250 deletions
@ -0,0 +1,63 @@ |
||||
/*
|
||||
* |
||||
* 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" |
||||
|
||||
#include <grpc/support/thd_id.h> |
||||
|
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
#include "src/core/lib/iomgr/executor.h" |
||||
#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/pollset_set_custom.h" |
||||
#include "src/core/lib/iomgr/resolve_address_custom.h" |
||||
|
||||
gpr_thd_id g_init_thread; |
||||
|
||||
static void iomgr_platform_init(void) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_executor_set_threading(false); |
||||
g_init_thread = gpr_thd_currentid(); |
||||
grpc_pollset_global_init(); |
||||
} |
||||
static void iomgr_platform_flush(void) {} |
||||
static void iomgr_platform_shutdown(void) { grpc_pollset_global_shutdown(); } |
||||
|
||||
static grpc_iomgr_platform_vtable vtable = { |
||||
iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown}; |
||||
|
||||
void grpc_custom_iomgr_init(grpc_socket_vtable* socket, |
||||
grpc_custom_resolver_vtable* resolver, |
||||
grpc_custom_timer_vtable* timer, |
||||
grpc_custom_poller_vtable* poller) { |
||||
grpc_custom_endpoint_init(socket); |
||||
grpc_custom_timer_init(timer); |
||||
grpc_custom_pollset_init(poller); |
||||
grpc_custom_pollset_set_init(); |
||||
grpc_custom_resolver_init(resolver); |
||||
grpc_set_iomgr_platform_vtable(&vtable); |
||||
} |
||||
|
||||
#ifdef GRPC_CUSTOM_SOCKET |
||||
grpc_iomgr_platform_vtable* grpc_default_iomgr_platform_vtable() { |
||||
return &vtable; |
||||
} |
||||
#endif |
@ -0,0 +1,43 @@ |
||||
/*
|
||||
* |
||||
* 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 <stddef.h> |
||||
|
||||
#include "src/core/lib/iomgr/iomgr_internal.h" |
||||
#include "src/core/lib/iomgr/timer.h" |
||||
#include "src/core/lib/iomgr/timer_manager.h" |
||||
|
||||
static grpc_iomgr_platform_vtable* iomgr_platform_vtable = nullptr; |
||||
|
||||
void grpc_set_iomgr_platform_vtable(grpc_iomgr_platform_vtable* vtable) { |
||||
iomgr_platform_vtable = vtable; |
||||
} |
||||
|
||||
void grpc_determine_iomgr_platform() { |
||||
if (iomgr_platform_vtable == nullptr) { |
||||
grpc_set_default_iomgr_platform(); |
||||
} |
||||
} |
||||
|
||||
void grpc_iomgr_platform_init() { iomgr_platform_vtable->init(); } |
||||
|
||||
void grpc_iomgr_platform_flush() { iomgr_platform_vtable->flush(); } |
||||
|
||||
void grpc_iomgr_platform_shutdown() { iomgr_platform_vtable->shutdown(); } |
@ -0,0 +1,56 @@ |
||||
/*
|
||||
* |
||||
* 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/pollset.h" |
||||
|
||||
grpc_pollset_vtable* grpc_pollset_impl; |
||||
|
||||
void grpc_set_pollset_vtable(grpc_pollset_vtable* vtable) { |
||||
grpc_pollset_impl = vtable; |
||||
} |
||||
|
||||
void grpc_pollset_global_init() { grpc_pollset_impl->global_init(); } |
||||
|
||||
void grpc_pollset_global_shutdown() { grpc_pollset_impl->global_shutdown(); } |
||||
|
||||
void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu) { |
||||
grpc_pollset_impl->init(pollset, mu); |
||||
} |
||||
|
||||
void grpc_pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) { |
||||
grpc_pollset_impl->shutdown(pollset, closure); |
||||
} |
||||
|
||||
void grpc_pollset_destroy(grpc_pollset* pollset) { |
||||
grpc_pollset_impl->destroy(pollset); |
||||
} |
||||
|
||||
grpc_error* grpc_pollset_work(grpc_pollset* pollset, |
||||
grpc_pollset_worker** worker, |
||||
grpc_millis deadline) { |
||||
return grpc_pollset_impl->work(pollset, worker, deadline); |
||||
} |
||||
|
||||
grpc_error* grpc_pollset_kick(grpc_pollset* pollset, |
||||
grpc_pollset_worker* specific_worker) { |
||||
return grpc_pollset_impl->kick(pollset, specific_worker); |
||||
} |
||||
|
||||
size_t grpc_pollset_size(void) { return grpc_pollset_impl->pollset_size(); } |
@ -0,0 +1,106 @@ |
||||
/*
|
||||
* |
||||
* 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" |
||||
|
||||
#include <stddef.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/sync.h> |
||||
|
||||
#include "src/core/lib/iomgr/closure.h" |
||||
#include "src/core/lib/iomgr/iomgr_custom.h" |
||||
#include "src/core/lib/iomgr/pollset.h" |
||||
#include "src/core/lib/iomgr/pollset_custom.h" |
||||
#include "src/core/lib/iomgr/timer.h" |
||||
|
||||
#include "src/core/lib/debug/trace.h" |
||||
|
||||
static grpc_custom_poller_vtable* poller_vtable; |
||||
|
||||
struct grpc_pollset { |
||||
gpr_mu mu; |
||||
}; |
||||
|
||||
static size_t pollset_size() { return sizeof(grpc_pollset); } |
||||
|
||||
static void pollset_global_init() { poller_vtable->init(); } |
||||
|
||||
static void pollset_global_shutdown() { poller_vtable->shutdown(); } |
||||
|
||||
static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
gpr_mu_init(&pollset->mu); |
||||
*mu = &pollset->mu; |
||||
} |
||||
|
||||
static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE); |
||||
} |
||||
|
||||
static void pollset_destroy(grpc_pollset* pollset) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
gpr_mu_destroy(&pollset->mu); |
||||
} |
||||
|
||||
static grpc_error* pollset_work(grpc_pollset* pollset, |
||||
grpc_pollset_worker** worker_hdl, |
||||
grpc_millis deadline) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
gpr_mu_unlock(&pollset->mu); |
||||
grpc_millis now = grpc_core::ExecCtx::Get()->Now(); |
||||
size_t timeout = 0; |
||||
if (deadline > now) { |
||||
timeout = deadline - now; |
||||
} |
||||
// We yield here because the poll() call might yield
|
||||
// control back to the application
|
||||
grpc_core::ExecCtx* curr = grpc_core::ExecCtx::Get(); |
||||
grpc_core::ExecCtx::Set(nullptr); |
||||
poller_vtable->poll(timeout); |
||||
grpc_core::ExecCtx::Set(curr); |
||||
grpc_core::ExecCtx::Get()->InvalidateNow(); |
||||
if (grpc_core::ExecCtx::Get()->HasWork()) { |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
} |
||||
gpr_mu_lock(&pollset->mu); |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static grpc_error* pollset_kick(grpc_pollset* pollset, |
||||
grpc_pollset_worker* specific_worker) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
poller_vtable->kick(); |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
grpc_pollset_vtable custom_pollset_vtable = { |
||||
pollset_global_init, pollset_global_shutdown, |
||||
pollset_init, pollset_shutdown, |
||||
pollset_destroy, pollset_work, |
||||
pollset_kick, pollset_size}; |
||||
|
||||
void grpc_custom_pollset_init(grpc_custom_poller_vtable* vtable) { |
||||
poller_vtable = vtable; |
||||
grpc_set_pollset_vtable(&custom_pollset_vtable); |
||||
} |
@ -0,0 +1,35 @@ |
||||
/*
|
||||
* |
||||
* 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_POLLSET_CUSTOM_H |
||||
#define GRPC_CORE_LIB_IOMGR_POLLSET_CUSTOM_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stddef.h> |
||||
|
||||
typedef struct grpc_custom_poller_vtable { |
||||
void (*init)(); |
||||
void (*poll)(size_t timeout_ms); |
||||
void (*kick)(); |
||||
void (*shutdown)(); |
||||
} grpc_custom_poller_vtable; |
||||
|
||||
void grpc_custom_pollset_init(grpc_custom_poller_vtable* vtable); |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_CUSTOM_H */ |
@ -0,0 +1,48 @@ |
||||
/*
|
||||
* |
||||
* 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" |
||||
|
||||
#include "src/core/lib/iomgr/pollset_set.h" |
||||
|
||||
grpc_pollset_set* pollset_set_create(void) { |
||||
return (grpc_pollset_set*)((intptr_t)0xdeafbeef); |
||||
} |
||||
|
||||
void pollset_set_destroy(grpc_pollset_set* pollset_set) {} |
||||
|
||||
void pollset_set_add_pollset(grpc_pollset_set* pollset_set, |
||||
grpc_pollset* pollset) {} |
||||
|
||||
void pollset_set_del_pollset(grpc_pollset_set* pollset_set, |
||||
grpc_pollset* pollset) {} |
||||
|
||||
void pollset_set_add_pollset_set(grpc_pollset_set* bag, |
||||
grpc_pollset_set* item) {} |
||||
|
||||
void pollset_set_del_pollset_set(grpc_pollset_set* bag, |
||||
grpc_pollset_set* item) {} |
||||
|
||||
static grpc_pollset_set_vtable vtable = { |
||||
pollset_set_create, pollset_set_destroy, |
||||
pollset_set_add_pollset, pollset_set_del_pollset, |
||||
pollset_set_add_pollset_set, pollset_set_del_pollset_set}; |
||||
|
||||
void grpc_custom_pollset_set_init() { grpc_set_pollset_set_vtable(&vtable); } |
@ -0,0 +1,50 @@ |
||||
/*
|
||||
* |
||||
* 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 <grpc/support/alloc.h> |
||||
#include "src/core/lib/iomgr/resolve_address.h" |
||||
|
||||
grpc_address_resolver_vtable* grpc_resolve_address_impl; |
||||
|
||||
void grpc_set_resolver_impl(grpc_address_resolver_vtable* vtable) { |
||||
grpc_resolve_address_impl = vtable; |
||||
} |
||||
|
||||
void grpc_resolve_address(const char* addr, const char* default_port, |
||||
grpc_pollset_set* interested_parties, |
||||
grpc_closure* on_done, |
||||
grpc_resolved_addresses** addresses) { |
||||
grpc_resolve_address_impl->resolve_address( |
||||
addr, default_port, interested_parties, on_done, addresses); |
||||
} |
||||
|
||||
void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addrs) { |
||||
if (addrs != nullptr) { |
||||
gpr_free(addrs->addrs); |
||||
} |
||||
gpr_free(addrs); |
||||
} |
||||
|
||||
grpc_error* grpc_blocking_resolve_address(const char* name, |
||||
const char* default_port, |
||||
grpc_resolved_addresses** addresses) { |
||||
return grpc_resolve_address_impl->blocking_resolve_address(name, default_port, |
||||
addresses); |
||||
} |
@ -0,0 +1,187 @@ |
||||
/*
|
||||
* |
||||
* 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" |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include <grpc/support/log.h> |
||||
#include "src/core/lib/gpr/host_port.h" |
||||
#include "src/core/lib/gpr/string.h" |
||||
#include "src/core/lib/gpr/useful.h" |
||||
|
||||
#include "src/core/lib/iomgr/iomgr_custom.h" |
||||
#include "src/core/lib/iomgr/resolve_address_custom.h" |
||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
typedef struct grpc_custom_resolver { |
||||
grpc_closure* on_done; |
||||
grpc_resolved_addresses** addresses; |
||||
char* host; |
||||
char* port; |
||||
} grpc_custom_resolver; |
||||
|
||||
static grpc_custom_resolver_vtable* resolve_address_vtable = nullptr; |
||||
|
||||
static int retry_named_port_failure(grpc_custom_resolver* r, |
||||
grpc_resolved_addresses** res) { |
||||
// This loop is copied from resolve_address_posix.c
|
||||
const char* svc[][2] = {{"http", "80"}, {"https", "443"}}; |
||||
for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) { |
||||
if (strcmp(r->port, svc[i][0]) == 0) { |
||||
gpr_free(r->port); |
||||
r->port = gpr_strdup(svc[i][1]); |
||||
if (res) { |
||||
grpc_error* error = |
||||
resolve_address_vtable->resolve(r->host, r->port, res); |
||||
if (error != GRPC_ERROR_NONE) { |
||||
GRPC_ERROR_UNREF(error); |
||||
return 0; |
||||
} |
||||
} else { |
||||
resolve_address_vtable->resolve_async(r, r->host, r->port); |
||||
} |
||||
return 1; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
void grpc_custom_resolve_callback(grpc_custom_resolver* r, |
||||
grpc_resolved_addresses* result, |
||||
grpc_error* error) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
grpc_core::ExecCtx exec_ctx; |
||||
if (error == GRPC_ERROR_NONE) { |
||||
*r->addresses = result; |
||||
} else if (retry_named_port_failure(r, nullptr)) { |
||||
return; |
||||
} |
||||
if (r->on_done) { |
||||
GRPC_CLOSURE_SCHED(r->on_done, error); |
||||
} |
||||
gpr_free(r->host); |
||||
gpr_free(r->port); |
||||
gpr_free(r); |
||||
} |
||||
|
||||
static grpc_error* try_split_host_port(const char* name, |
||||
const char* default_port, char** host, |
||||
char** port) { |
||||
/* parse name, splitting it into host and port parts */ |
||||
grpc_error* error; |
||||
gpr_split_host_port(name, host, port); |
||||
if (*host == nullptr) { |
||||
char* msg; |
||||
gpr_asprintf(&msg, "unparseable host:port: '%s'", name); |
||||
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); |
||||
gpr_free(msg); |
||||
return error; |
||||
} |
||||
if (*port == nullptr) { |
||||
// TODO(murgatroid99): add tests for this case
|
||||
if (default_port == nullptr) { |
||||
char* msg; |
||||
gpr_asprintf(&msg, "no port in name '%s'", name); |
||||
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); |
||||
gpr_free(msg); |
||||
return error; |
||||
} |
||||
*port = gpr_strdup(default_port); |
||||
} |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static grpc_error* blocking_resolve_address_impl( |
||||
const char* name, const char* default_port, |
||||
grpc_resolved_addresses** addresses) { |
||||
char* host; |
||||
char* port; |
||||
grpc_error* err; |
||||
|
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
|
||||
err = try_split_host_port(name, default_port, &host, &port); |
||||
if (err != GRPC_ERROR_NONE) { |
||||
gpr_free(host); |
||||
gpr_free(port); |
||||
return err; |
||||
} |
||||
|
||||
/* Call getaddrinfo */ |
||||
grpc_custom_resolver resolver; |
||||
resolver.host = host; |
||||
resolver.port = port; |
||||
|
||||
grpc_resolved_addresses* addrs; |
||||
grpc_core::ExecCtx* curr = grpc_core::ExecCtx::Get(); |
||||
grpc_core::ExecCtx::Set(nullptr); |
||||
err = resolve_address_vtable->resolve(host, port, &addrs); |
||||
if (err != GRPC_ERROR_NONE) { |
||||
if (retry_named_port_failure(&resolver, &addrs)) { |
||||
GRPC_ERROR_UNREF(err); |
||||
err = GRPC_ERROR_NONE; |
||||
} |
||||
} |
||||
grpc_core::ExecCtx::Set(curr); |
||||
if (err == GRPC_ERROR_NONE) { |
||||
*addresses = addrs; |
||||
} |
||||
gpr_free(resolver.host); |
||||
gpr_free(resolver.port); |
||||
return err; |
||||
} |
||||
|
||||
static void resolve_address_impl(const char* name, const char* default_port, |
||||
grpc_pollset_set* interested_parties, |
||||
grpc_closure* on_done, |
||||
grpc_resolved_addresses** addrs) { |
||||
grpc_custom_resolver* r = nullptr; |
||||
char* host = nullptr; |
||||
char* port = nullptr; |
||||
grpc_error* err; |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
err = try_split_host_port(name, default_port, &host, &port); |
||||
if (err != GRPC_ERROR_NONE) { |
||||
GRPC_CLOSURE_SCHED(on_done, err); |
||||
gpr_free(host); |
||||
gpr_free(port); |
||||
return; |
||||
} |
||||
r = (grpc_custom_resolver*)gpr_malloc(sizeof(grpc_custom_resolver)); |
||||
r->on_done = on_done; |
||||
r->addresses = addrs; |
||||
r->host = host; |
||||
r->port = port; |
||||
|
||||
/* Call getaddrinfo */ |
||||
resolve_address_vtable->resolve_async(r, r->host, r->port); |
||||
} |
||||
|
||||
static grpc_address_resolver_vtable custom_resolver_vtable = { |
||||
resolve_address_impl, blocking_resolve_address_impl}; |
||||
|
||||
void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl) { |
||||
resolve_address_vtable = impl; |
||||
grpc_set_resolver_impl(&custom_resolver_vtable); |
||||
} |
@ -0,0 +1,43 @@ |
||||
/*
|
||||
* |
||||
* 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_RESOLVE_ADDRESS_CUSTOM_H |
||||
#define GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_CUSTOM_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#include "src/core/lib/iomgr/resolve_address.h" |
||||
#include "src/core/lib/iomgr/sockaddr.h" |
||||
|
||||
typedef struct grpc_custom_resolver grpc_custom_resolver; |
||||
|
||||
typedef struct grpc_custom_resolver_vtable { |
||||
grpc_error* (*resolve)(char* host, char* port, grpc_resolved_addresses** res); |
||||
void (*resolve_async)(grpc_custom_resolver* resolver, char* host, char* port); |
||||
} grpc_custom_resolver_vtable; |
||||
|
||||
void grpc_custom_resolve_callback(grpc_custom_resolver* resolver, |
||||
grpc_resolved_addresses* result, |
||||
grpc_error* error); |
||||
|
||||
/* Internal APIs */ |
||||
void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl); |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_CUSTOM_H */ |
@ -1,286 +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 <uv.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/gpr/host_port.h" |
||||
#include "src/core/lib/gpr/useful.h" |
||||
#include "src/core/lib/iomgr/closure.h" |
||||
#include "src/core/lib/iomgr/error.h" |
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
#include "src/core/lib/iomgr/iomgr_uv.h" |
||||
#include "src/core/lib/iomgr/resolve_address.h" |
||||
#include "src/core/lib/iomgr/sockaddr.h" |
||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
typedef struct request { |
||||
grpc_closure* on_done; |
||||
grpc_resolved_addresses** addresses; |
||||
struct addrinfo* hints; |
||||
char* host; |
||||
char* port; |
||||
} request; |
||||
|
||||
static int retry_named_port_failure(int status, request* r, |
||||
uv_getaddrinfo_cb getaddrinfo_cb) { |
||||
if (status != 0) { |
||||
// This loop is copied from resolve_address_posix.c
|
||||
const char* svc[][2] = {{"http", "80"}, {"https", "443"}}; |
||||
for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) { |
||||
if (strcmp(r->port, svc[i][0]) == 0) { |
||||
int retry_status; |
||||
uv_getaddrinfo_t* req = |
||||
(uv_getaddrinfo_t*)gpr_malloc(sizeof(uv_getaddrinfo_t)); |
||||
req->data = r; |
||||
r->port = gpr_strdup(svc[i][1]); |
||||
retry_status = uv_getaddrinfo(uv_default_loop(), req, getaddrinfo_cb, |
||||
r->host, r->port, r->hints); |
||||
if (retry_status < 0 || getaddrinfo_cb == NULL) { |
||||
// The callback will not be called
|
||||
gpr_free(req); |
||||
} |
||||
return retry_status; |
||||
} |
||||
} |
||||
} |
||||
/* If this function calls uv_getaddrinfo, it will return that function's
|
||||
return value. That function only returns numbers <=0, so we can safely |
||||
return 1 to indicate that we never retried */ |
||||
return 1; |
||||
} |
||||
|
||||
static grpc_error* handle_addrinfo_result(int status, struct addrinfo* result, |
||||
grpc_resolved_addresses** addresses) { |
||||
struct addrinfo* resp; |
||||
size_t i; |
||||
if (status != 0) { |
||||
grpc_error* error; |
||||
*addresses = NULL; |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getaddrinfo failed"); |
||||
error = |
||||
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string(uv_strerror(status))); |
||||
return error; |
||||
} |
||||
(*addresses) = |
||||
(grpc_resolved_addresses*)gpr_malloc(sizeof(grpc_resolved_addresses)); |
||||
(*addresses)->naddrs = 0; |
||||
for (resp = result; resp != NULL; resp = resp->ai_next) { |
||||
(*addresses)->naddrs++; |
||||
} |
||||
(*addresses)->addrs = (grpc_resolved_address*)gpr_malloc( |
||||
sizeof(grpc_resolved_address) * (*addresses)->naddrs); |
||||
i = 0; |
||||
for (resp = result; resp != NULL; resp = resp->ai_next) { |
||||
memcpy(&(*addresses)->addrs[i].addr, resp->ai_addr, resp->ai_addrlen); |
||||
(*addresses)->addrs[i].len = resp->ai_addrlen; |
||||
i++; |
||||
} |
||||
|
||||
{ |
||||
for (i = 0; i < (*addresses)->naddrs; i++) { |
||||
char* buf; |
||||
grpc_sockaddr_to_string(&buf, &(*addresses)->addrs[i], 0); |
||||
gpr_free(buf); |
||||
} |
||||
} |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static void getaddrinfo_callback(uv_getaddrinfo_t* req, int status, |
||||
struct addrinfo* res) { |
||||
request* r = (request*)req->data; |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_error* error; |
||||
int retry_status; |
||||
char* port = r->port; |
||||
|
||||
gpr_free(req); |
||||
retry_status = retry_named_port_failure(status, r, getaddrinfo_callback); |
||||
if (retry_status == 0) { |
||||
/* The request is being retried. It is using its own port string, so we free
|
||||
* the original one */ |
||||
gpr_free(port); |
||||
return; |
||||
} |
||||
/* Either no retry was attempted, or the retry failed. Either way, the
|
||||
original error probably has more interesting information */ |
||||
error = handle_addrinfo_result(status, res, r->addresses); |
||||
GRPC_CLOSURE_SCHED(r->on_done, error); |
||||
|
||||
gpr_free(r->hints); |
||||
gpr_free(r->host); |
||||
gpr_free(r->port); |
||||
gpr_free(r); |
||||
uv_freeaddrinfo(res); |
||||
} |
||||
|
||||
static grpc_error* try_split_host_port(const char* name, |
||||
const char* default_port, char** host, |
||||
char** port) { |
||||
/* parse name, splitting it into host and port parts */ |
||||
grpc_error* error; |
||||
gpr_split_host_port(name, host, port); |
||||
if (*host == NULL) { |
||||
char* msg; |
||||
gpr_asprintf(&msg, "unparseable host:port: '%s'", name); |
||||
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); |
||||
gpr_free(msg); |
||||
return error; |
||||
} |
||||
if (*port == NULL) { |
||||
// TODO(murgatroid99): add tests for this case
|
||||
if (default_port == NULL) { |
||||
char* msg; |
||||
gpr_asprintf(&msg, "no port in name '%s'", name); |
||||
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); |
||||
gpr_free(msg); |
||||
return error; |
||||
} |
||||
*port = gpr_strdup(default_port); |
||||
} |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static grpc_error* blocking_resolve_address_impl( |
||||
const char* name, const char* default_port, |
||||
grpc_resolved_addresses** addresses) { |
||||
char* host; |
||||
char* port; |
||||
struct addrinfo hints; |
||||
uv_getaddrinfo_t req; |
||||
int s; |
||||
grpc_error* err; |
||||
int retry_status; |
||||
request r; |
||||
|
||||
GRPC_UV_ASSERT_SAME_THREAD(); |
||||
|
||||
req.addrinfo = NULL; |
||||
|
||||
err = try_split_host_port(name, default_port, &host, &port); |
||||
if (err != GRPC_ERROR_NONE) { |
||||
goto done; |
||||
} |
||||
|
||||
/* Call getaddrinfo */ |
||||
memset(&hints, 0, sizeof(hints)); |
||||
hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */ |
||||
hints.ai_socktype = SOCK_STREAM; /* stream socket */ |
||||
hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */ |
||||
|
||||
s = uv_getaddrinfo(uv_default_loop(), &req, NULL, host, port, &hints); |
||||
r.addresses = addresses; |
||||
r.hints = &hints; |
||||
r.host = host; |
||||
r.port = port; |
||||
retry_status = retry_named_port_failure(s, &r, NULL); |
||||
if (retry_status <= 0) { |
||||
s = retry_status; |
||||
} |
||||
err = handle_addrinfo_result(s, req.addrinfo, addresses); |
||||
|
||||
done: |
||||
gpr_free(host); |
||||
gpr_free(port); |
||||
if (req.addrinfo) { |
||||
uv_freeaddrinfo(req.addrinfo); |
||||
} |
||||
return err; |
||||
} |
||||
|
||||
grpc_error* (*grpc_blocking_resolve_address)( |
||||
const char* name, const char* default_port, |
||||
grpc_resolved_addresses** addresses) = blocking_resolve_address_impl; |
||||
|
||||
void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addrs) { |
||||
if (addrs != NULL) { |
||||
gpr_free(addrs->addrs); |
||||
} |
||||
gpr_free(addrs); |
||||
} |
||||
|
||||
static void resolve_address_impl(const char* name, const char* default_port, |
||||
grpc_pollset_set* interested_parties, |
||||
grpc_closure* on_done, |
||||
grpc_resolved_addresses** addrs) { |
||||
uv_getaddrinfo_t* req = NULL; |
||||
request* r = NULL; |
||||
struct addrinfo* hints = NULL; |
||||
char* host = NULL; |
||||
char* port = NULL; |
||||
grpc_error* err; |
||||
int s; |
||||
GRPC_UV_ASSERT_SAME_THREAD(); |
||||
err = try_split_host_port(name, default_port, &host, &port); |
||||
if (err != GRPC_ERROR_NONE) { |
||||
GRPC_CLOSURE_SCHED(on_done, err); |
||||
gpr_free(host); |
||||
gpr_free(port); |
||||
return; |
||||
} |
||||
r = (request*)gpr_malloc(sizeof(request)); |
||||
r->on_done = on_done; |
||||
r->addresses = addrs; |
||||
r->host = host; |
||||
r->port = port; |
||||
req = (uv_getaddrinfo_t*)gpr_malloc(sizeof(uv_getaddrinfo_t)); |
||||
req->data = r; |
||||
|
||||
/* Call getaddrinfo */ |
||||
hints = (addrinfo*)gpr_malloc(sizeof(struct addrinfo)); |
||||
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 */ |
||||
r->hints = hints; |
||||
|
||||
s = uv_getaddrinfo(uv_default_loop(), req, getaddrinfo_callback, host, port, |
||||
hints); |
||||
|
||||
if (s != 0) { |
||||
*addrs = NULL; |
||||
err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getaddrinfo failed"); |
||||
err = grpc_error_set_str(err, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string(uv_strerror(s))); |
||||
GRPC_CLOSURE_SCHED(on_done, err); |
||||
gpr_free(r); |
||||
gpr_free(req); |
||||
gpr_free(hints); |
||||
gpr_free(host); |
||||
gpr_free(port); |
||||
} |
||||
} |
||||
|
||||
void (*grpc_resolve_address)( |
||||
const char* name, const char* default_port, |
||||
grpc_pollset_set* interested_parties, grpc_closure* on_done, |
||||
grpc_resolved_addresses** addrs) = resolve_address_impl; |
||||
|
||||
#endif /* GRPC_UV */ |
@ -0,0 +1,54 @@ |
||||
/*
|
||||
* |
||||
* 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 */ |
@ -0,0 +1,36 @@ |
||||
/*
|
||||
* |
||||
* 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/tcp_client.h" |
||||
|
||||
grpc_tcp_client_vtable* grpc_tcp_client_impl; |
||||
|
||||
void grpc_tcp_client_connect(grpc_closure* closure, grpc_endpoint** ep, |
||||
grpc_pollset_set* interested_parties, |
||||
const grpc_channel_args* channel_args, |
||||
const grpc_resolved_address* addr, |
||||
grpc_millis deadline) { |
||||
grpc_tcp_client_impl->connect(closure, ep, interested_parties, channel_args, |
||||
addr, deadline); |
||||
} |
||||
|
||||
void grpc_set_tcp_client_impl(grpc_tcp_client_vtable* impl) { |
||||
grpc_tcp_client_impl = impl; |
||||
} |
@ -0,0 +1,151 @@ |
||||
/*
|
||||
* |
||||
* 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" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/iomgr/error.h" |
||||
#include "src/core/lib/iomgr/iomgr_custom.h" |
||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||
#include "src/core/lib/iomgr/tcp_client.h" |
||||
#include "src/core/lib/iomgr/tcp_custom.h" |
||||
#include "src/core/lib/iomgr/timer.h" |
||||
|
||||
extern grpc_core::TraceFlag grpc_tcp_trace; |
||||
extern grpc_socket_vtable* grpc_custom_socket_vtable; |
||||
|
||||
struct grpc_custom_tcp_connect { |
||||
grpc_custom_socket* socket; |
||||
grpc_timer alarm; |
||||
grpc_closure on_alarm; |
||||
grpc_closure* closure; |
||||
grpc_endpoint** endpoint; |
||||
int refs; |
||||
char* addr_name; |
||||
grpc_resource_quota* resource_quota; |
||||
}; |
||||
|
||||
static void custom_tcp_connect_cleanup(grpc_custom_tcp_connect* connect) { |
||||
grpc_custom_socket* socket = connect->socket; |
||||
grpc_resource_quota_unref_internal(connect->resource_quota); |
||||
gpr_free(connect->addr_name); |
||||
gpr_free(connect); |
||||
socket->refs--; |
||||
if (socket->refs == 0) { |
||||
grpc_custom_socket_vtable->destroy(socket); |
||||
gpr_free(socket); |
||||
} |
||||
} |
||||
|
||||
static void custom_close_callback(grpc_custom_socket* socket) {} |
||||
|
||||
static void on_alarm(void* acp, grpc_error* error) { |
||||
int done; |
||||
grpc_custom_socket* socket = (grpc_custom_socket*)acp; |
||||
grpc_custom_tcp_connect* connect = socket->connector; |
||||
if (grpc_tcp_trace.enabled()) { |
||||
const char* str = grpc_error_string(error); |
||||
gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s", |
||||
connect->addr_name, str); |
||||
} |
||||
if (error == GRPC_ERROR_NONE) { |
||||
/* error == NONE implies that the timer ran out, and wasn't cancelled. If
|
||||
it was cancelled, then the handler that cancelled it also should close |
||||
the handle, if applicable */ |
||||
grpc_custom_socket_vtable->close(socket, custom_close_callback); |
||||
} |
||||
done = (--connect->refs == 0); |
||||
if (done) { |
||||
custom_tcp_connect_cleanup(connect); |
||||
} |
||||
} |
||||
|
||||
static void custom_connect_callback(grpc_custom_socket* socket, |
||||
grpc_error* error) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_custom_tcp_connect* connect = socket->connector; |
||||
int done; |
||||
grpc_closure* closure = connect->closure; |
||||
grpc_timer_cancel(&connect->alarm); |
||||
if (error == GRPC_ERROR_NONE) { |
||||
*connect->endpoint = custom_tcp_endpoint_create( |
||||
socket, connect->resource_quota, connect->addr_name); |
||||
} |
||||
done = (--connect->refs == 0); |
||||
if (done) { |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
custom_tcp_connect_cleanup(connect); |
||||
} |
||||
GRPC_CLOSURE_SCHED(closure, error); |
||||
} |
||||
|
||||
static void tcp_connect(grpc_closure* closure, grpc_endpoint** ep, |
||||
grpc_pollset_set* interested_parties, |
||||
const grpc_channel_args* channel_args, |
||||
const grpc_resolved_address* resolved_addr, |
||||
grpc_millis deadline) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
(void)channel_args; |
||||
(void)interested_parties; |
||||
grpc_custom_tcp_connect* connect; |
||||
grpc_resource_quota* resource_quota = grpc_resource_quota_create(nullptr); |
||||
if (channel_args != nullptr) { |
||||
for (size_t i = 0; i < channel_args->num_args; i++) { |
||||
if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { |
||||
grpc_resource_quota_unref_internal(resource_quota); |
||||
resource_quota = grpc_resource_quota_ref_internal( |
||||
(grpc_resource_quota*)channel_args->args[i].value.pointer.p); |
||||
} |
||||
} |
||||
} |
||||
grpc_custom_socket* socket = |
||||
(grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket)); |
||||
socket->refs = 2; |
||||
grpc_custom_socket_vtable->init(socket, GRPC_AF_UNSPEC); |
||||
connect = |
||||
(grpc_custom_tcp_connect*)gpr_malloc(sizeof(grpc_custom_tcp_connect)); |
||||
connect->closure = closure; |
||||
connect->endpoint = ep; |
||||
connect->addr_name = grpc_sockaddr_to_uri(resolved_addr); |
||||
connect->resource_quota = resource_quota; |
||||
connect->socket = socket; |
||||
socket->connector = connect; |
||||
socket->endpoint = nullptr; |
||||
socket->listener = nullptr; |
||||
connect->refs = 2; |
||||
|
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %p %s: asynchronously connecting", |
||||
socket, connect->addr_name); |
||||
} |
||||
|
||||
grpc_custom_socket_vtable->connect( |
||||
socket, (const grpc_sockaddr*)resolved_addr->addr, resolved_addr->len, |
||||
custom_connect_callback); |
||||
GRPC_CLOSURE_INIT(&connect->on_alarm, on_alarm, socket, |
||||
grpc_schedule_on_exec_ctx); |
||||
grpc_timer_init(&connect->alarm, deadline, &connect->on_alarm); |
||||
} |
||||
|
||||
grpc_tcp_client_vtable custom_tcp_client_vtable = {tcp_connect}; |
@ -1,177 +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 <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/iomgr/error.h" |
||||
#include "src/core/lib/iomgr/iomgr_uv.h" |
||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||
#include "src/core/lib/iomgr/tcp_client.h" |
||||
#include "src/core/lib/iomgr/tcp_uv.h" |
||||
#include "src/core/lib/iomgr/timer.h" |
||||
|
||||
extern grpc_core::TraceFlag grpc_tcp_trace; |
||||
|
||||
typedef struct grpc_uv_tcp_connect { |
||||
uv_connect_t connect_req; |
||||
grpc_timer alarm; |
||||
grpc_closure on_alarm; |
||||
uv_tcp_t* tcp_handle; |
||||
grpc_closure* closure; |
||||
grpc_endpoint** endpoint; |
||||
int refs; |
||||
char* addr_name; |
||||
grpc_resource_quota* resource_quota; |
||||
} grpc_uv_tcp_connect; |
||||
|
||||
static void uv_tcp_connect_cleanup(grpc_uv_tcp_connect* connect) { |
||||
grpc_resource_quota_unref_internal(connect->resource_quota); |
||||
gpr_free(connect->addr_name); |
||||
gpr_free(connect); |
||||
} |
||||
|
||||
static void tcp_close_callback(uv_handle_t* handle) { gpr_free(handle); } |
||||
|
||||
static void uv_tc_on_alarm(void* acp, grpc_error* error) { |
||||
int done; |
||||
grpc_uv_tcp_connect* connect = (grpc_uv_tcp_connect*)acp; |
||||
if (grpc_tcp_trace.enabled()) { |
||||
const char* str = grpc_error_string(error); |
||||
gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s", |
||||
connect->addr_name, str); |
||||
} |
||||
if (error == GRPC_ERROR_NONE) { |
||||
/* error == NONE implies that the timer ran out, and wasn't cancelled. If
|
||||
it was cancelled, then the handler that cancelled it also should close |
||||
the handle, if applicable */ |
||||
uv_close((uv_handle_t*)connect->tcp_handle, tcp_close_callback); |
||||
} |
||||
done = (--connect->refs == 0); |
||||
if (done) { |
||||
uv_tcp_connect_cleanup(connect); |
||||
} |
||||
} |
||||
|
||||
static void uv_tc_on_connect(uv_connect_t* req, int status) { |
||||
grpc_uv_tcp_connect* connect = (grpc_uv_tcp_connect*)req->data; |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_error* error = GRPC_ERROR_NONE; |
||||
int done; |
||||
grpc_closure* closure = connect->closure; |
||||
grpc_timer_cancel(&connect->alarm); |
||||
if (status == 0) { |
||||
*connect->endpoint = grpc_tcp_create( |
||||
connect->tcp_handle, connect->resource_quota, connect->addr_name); |
||||
} else { |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"Failed to connect to remote host"); |
||||
error = grpc_error_set_int(error, GRPC_ERROR_INT_ERRNO, -status); |
||||
error = |
||||
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string(uv_strerror(status))); |
||||
if (status == UV_ECANCELED) { |
||||
error = |
||||
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string("Timeout occurred")); |
||||
// This should only happen if the handle is already closed
|
||||
} else { |
||||
error = grpc_error_set_str( |
||||
error, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string(uv_strerror(status))); |
||||
uv_close((uv_handle_t*)connect->tcp_handle, tcp_close_callback); |
||||
} |
||||
} |
||||
done = (--connect->refs == 0); |
||||
if (done) { |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
uv_tcp_connect_cleanup(connect); |
||||
} |
||||
GRPC_CLOSURE_SCHED(closure, error); |
||||
} |
||||
|
||||
static void tcp_client_connect_impl(grpc_closure* closure, grpc_endpoint** ep, |
||||
grpc_pollset_set* interested_parties, |
||||
const grpc_channel_args* channel_args, |
||||
const grpc_resolved_address* resolved_addr, |
||||
grpc_millis deadline) { |
||||
grpc_uv_tcp_connect* connect; |
||||
grpc_resource_quota* resource_quota = grpc_resource_quota_create(NULL); |
||||
(void)channel_args; |
||||
(void)interested_parties; |
||||
|
||||
GRPC_UV_ASSERT_SAME_THREAD(); |
||||
|
||||
if (channel_args != NULL) { |
||||
for (size_t i = 0; i < channel_args->num_args; i++) { |
||||
if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { |
||||
grpc_resource_quota_unref_internal(resource_quota); |
||||
resource_quota = grpc_resource_quota_ref_internal( |
||||
(grpc_resource_quota*)channel_args->args[i].value.pointer.p); |
||||
} |
||||
} |
||||
} |
||||
|
||||
connect = (grpc_uv_tcp_connect*)gpr_zalloc(sizeof(grpc_uv_tcp_connect)); |
||||
connect->closure = closure; |
||||
connect->endpoint = ep; |
||||
connect->tcp_handle = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t)); |
||||
connect->addr_name = grpc_sockaddr_to_uri(resolved_addr); |
||||
connect->resource_quota = resource_quota; |
||||
uv_tcp_init(uv_default_loop(), connect->tcp_handle); |
||||
connect->connect_req.data = connect; |
||||
connect->refs = 2; // One for the connect operation, one for the timer.
|
||||
|
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting", |
||||
connect->addr_name); |
||||
} |
||||
|
||||
// TODO(murgatroid99): figure out what the return value here means
|
||||
uv_tcp_connect(&connect->connect_req, connect->tcp_handle, |
||||
(const struct sockaddr*)resolved_addr->addr, uv_tc_on_connect); |
||||
GRPC_CLOSURE_INIT(&connect->on_alarm, uv_tc_on_alarm, connect, |
||||
grpc_schedule_on_exec_ctx); |
||||
grpc_timer_init(&connect->alarm, deadline, &connect->on_alarm); |
||||
} |
||||
|
||||
// overridden by api_fuzzer.c
|
||||
void (*grpc_tcp_client_connect_impl)( |
||||
grpc_closure* closure, grpc_endpoint** ep, |
||||
grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args, |
||||
const grpc_resolved_address* addr, |
||||
grpc_millis deadline) = tcp_client_connect_impl; |
||||
|
||||
void grpc_tcp_client_connect(grpc_closure* closure, grpc_endpoint** ep, |
||||
grpc_pollset_set* interested_parties, |
||||
const grpc_channel_args* channel_args, |
||||
const grpc_resolved_address* addr, |
||||
grpc_millis deadline) { |
||||
grpc_tcp_client_connect_impl(closure, ep, interested_parties, channel_args, |
||||
addr, deadline); |
||||
} |
||||
|
||||
#endif /* GRPC_UV */ |
@ -0,0 +1,365 @@ |
||||
/*
|
||||
* |
||||
* 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" |
||||
|
||||
#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/iomgr/error.h" |
||||
#include "src/core/lib/iomgr/iomgr_custom.h" |
||||
#include "src/core/lib/iomgr/network_status_tracker.h" |
||||
#include "src/core/lib/iomgr/resource_quota.h" |
||||
#include "src/core/lib/iomgr/tcp_client.h" |
||||
#include "src/core/lib/iomgr/tcp_custom.h" |
||||
#include "src/core/lib/iomgr/tcp_server.h" |
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
#include "src/core/lib/slice/slice_string_helpers.h" |
||||
|
||||
#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192 |
||||
|
||||
extern grpc_core::TraceFlag grpc_tcp_trace; |
||||
|
||||
grpc_socket_vtable* grpc_custom_socket_vtable = nullptr; |
||||
extern grpc_tcp_server_vtable custom_tcp_server_vtable; |
||||
extern grpc_tcp_client_vtable custom_tcp_client_vtable; |
||||
|
||||
void grpc_custom_endpoint_init(grpc_socket_vtable* impl) { |
||||
grpc_custom_socket_vtable = impl; |
||||
grpc_set_tcp_client_impl(&custom_tcp_client_vtable); |
||||
grpc_set_tcp_server_impl(&custom_tcp_server_vtable); |
||||
} |
||||
|
||||
typedef struct { |
||||
grpc_endpoint base; |
||||
gpr_refcount refcount; |
||||
grpc_custom_socket* socket; |
||||
|
||||
grpc_closure* read_cb; |
||||
grpc_closure* write_cb; |
||||
|
||||
grpc_slice_buffer* read_slices; |
||||
grpc_slice_buffer* write_slices; |
||||
|
||||
grpc_resource_user* resource_user; |
||||
grpc_resource_user_slice_allocator slice_allocator; |
||||
|
||||
bool shutting_down; |
||||
|
||||
char* peer_string; |
||||
} custom_tcp_endpoint; |
||||
|
||||
static void tcp_free(grpc_custom_socket* s) { |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)s->endpoint; |
||||
grpc_resource_user_unref(tcp->resource_user); |
||||
gpr_free(tcp->peer_string); |
||||
gpr_free(tcp); |
||||
s->refs--; |
||||
if (s->refs == 0) { |
||||
grpc_custom_socket_vtable->destroy(s); |
||||
gpr_free(s); |
||||
} |
||||
} |
||||
|
||||
#ifndef NDEBUG |
||||
#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__) |
||||
#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) |
||||
static void tcp_unref(custom_tcp_endpoint* tcp, const char* reason, |
||||
const char* file, int line) { |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, |
||||
"TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp->socket, reason, |
||||
val, val - 1); |
||||
} |
||||
if (gpr_unref(&tcp->refcount)) { |
||||
tcp_free(tcp->socket); |
||||
} |
||||
} |
||||
|
||||
static void tcp_ref(custom_tcp_endpoint* tcp, const char* reason, |
||||
const char* file, int line) { |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, |
||||
"TCP ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp->socket, reason, |
||||
val, val + 1); |
||||
} |
||||
gpr_ref(&tcp->refcount); |
||||
} |
||||
#else |
||||
#define TCP_UNREF(tcp, reason) tcp_unref((tcp)) |
||||
#define TCP_REF(tcp, reason) tcp_ref((tcp)) |
||||
static void tcp_unref(custom_tcp_endpoint* tcp) { |
||||
if (gpr_unref(&tcp->refcount)) { |
||||
tcp_free(tcp->socket); |
||||
} |
||||
} |
||||
|
||||
static void tcp_ref(custom_tcp_endpoint* tcp) { gpr_ref(&tcp->refcount); } |
||||
#endif |
||||
|
||||
static void call_read_cb(custom_tcp_endpoint* tcp, grpc_error* error) { |
||||
grpc_closure* cb = tcp->read_cb; |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "TCP:%p call_cb %p %p:%p", tcp->socket, cb, cb->cb, |
||||
cb->cb_arg); |
||||
size_t i; |
||||
const char* str = grpc_error_string(error); |
||||
gpr_log(GPR_DEBUG, "read: error=%s", str); |
||||
|
||||
for (i = 0; i < tcp->read_slices->count; i++) { |
||||
char* dump = grpc_dump_slice(tcp->read_slices->slices[i], |
||||
GPR_DUMP_HEX | GPR_DUMP_ASCII); |
||||
gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", tcp, tcp->peer_string, dump); |
||||
gpr_free(dump); |
||||
} |
||||
} |
||||
TCP_UNREF(tcp, "read"); |
||||
tcp->read_slices = nullptr; |
||||
tcp->read_cb = nullptr; |
||||
GRPC_CLOSURE_RUN(cb, error); |
||||
} |
||||
|
||||
static void custom_read_callback(grpc_custom_socket* socket, size_t nread, |
||||
grpc_error* error) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_slice_buffer garbage; |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)socket->endpoint; |
||||
if (error == GRPC_ERROR_NONE && nread == 0) { |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF"); |
||||
} |
||||
if (error == GRPC_ERROR_NONE) { |
||||
// Successful read
|
||||
if ((size_t)nread < tcp->read_slices->length) { |
||||
/* TODO(murgatroid99): Instead of discarding the unused part of the read
|
||||
* buffer, reuse it as the next read buffer. */ |
||||
grpc_slice_buffer_init(&garbage); |
||||
grpc_slice_buffer_trim_end( |
||||
tcp->read_slices, tcp->read_slices->length - (size_t)nread, &garbage); |
||||
grpc_slice_buffer_reset_and_unref_internal(&garbage); |
||||
} |
||||
} else { |
||||
grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices); |
||||
} |
||||
call_read_cb(tcp, error); |
||||
} |
||||
|
||||
static void tcp_read_allocation_done(void* tcpp, grpc_error* error) { |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)tcpp; |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "TCP:%p read_allocation_done: %s", tcp->socket, |
||||
grpc_error_string(error)); |
||||
} |
||||
if (error == GRPC_ERROR_NONE) { |
||||
/* Before calling read, we allocate a buffer with exactly one slice
|
||||
* to tcp->read_slices and wait for the callback indicating that the |
||||
* allocation was successful. So slices[0] should always exist here */ |
||||
char* buffer = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[0]); |
||||
size_t len = GRPC_SLICE_LENGTH(tcp->read_slices->slices[0]); |
||||
grpc_custom_socket_vtable->read(tcp->socket, buffer, len, |
||||
custom_read_callback); |
||||
} else { |
||||
grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices); |
||||
call_read_cb(tcp, GRPC_ERROR_REF(error)); |
||||
} |
||||
if (grpc_tcp_trace.enabled()) { |
||||
const char* str = grpc_error_string(error); |
||||
gpr_log(GPR_DEBUG, "Initiating read on %p: error=%s", tcp->socket, str); |
||||
} |
||||
} |
||||
|
||||
static void endpoint_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices, |
||||
grpc_closure* cb) { |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
GPR_ASSERT(tcp->read_cb == nullptr); |
||||
tcp->read_cb = cb; |
||||
tcp->read_slices = read_slices; |
||||
grpc_slice_buffer_reset_and_unref_internal(read_slices); |
||||
TCP_REF(tcp, "read"); |
||||
grpc_resource_user_alloc_slices(&tcp->slice_allocator, |
||||
GRPC_TCP_DEFAULT_READ_SLICE_SIZE, 1, |
||||
tcp->read_slices); |
||||
} |
||||
|
||||
static void custom_write_callback(grpc_custom_socket* socket, |
||||
grpc_error* error) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)socket->endpoint; |
||||
grpc_closure* cb = tcp->write_cb; |
||||
tcp->write_cb = nullptr; |
||||
if (grpc_tcp_trace.enabled()) { |
||||
const char* str = grpc_error_string(error); |
||||
gpr_log(GPR_DEBUG, "write complete on %p: error=%s", tcp->socket, str); |
||||
} |
||||
TCP_UNREF(tcp, "write"); |
||||
GRPC_CLOSURE_SCHED(cb, error); |
||||
} |
||||
|
||||
static void endpoint_write(grpc_endpoint* ep, grpc_slice_buffer* write_slices, |
||||
grpc_closure* cb) { |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
|
||||
if (grpc_tcp_trace.enabled()) { |
||||
size_t j; |
||||
|
||||
for (j = 0; j < write_slices->count; j++) { |
||||
char* data = grpc_dump_slice(write_slices->slices[j], |
||||
GPR_DUMP_HEX | GPR_DUMP_ASCII); |
||||
gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", tcp->socket, |
||||
tcp->peer_string, data); |
||||
gpr_free(data); |
||||
} |
||||
} |
||||
|
||||
if (tcp->shutting_down) { |
||||
GRPC_CLOSURE_SCHED(cb, GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"TCP socket is shutting down")); |
||||
return; |
||||
} |
||||
|
||||
GPR_ASSERT(tcp->write_cb == nullptr); |
||||
tcp->write_slices = write_slices; |
||||
GPR_ASSERT(tcp->write_slices->count <= UINT_MAX); |
||||
if (tcp->write_slices->count == 0) { |
||||
// No slices means we don't have to do anything,
|
||||
// and libuv doesn't like empty writes
|
||||
GRPC_CLOSURE_SCHED(cb, GRPC_ERROR_NONE); |
||||
return; |
||||
} |
||||
tcp->write_cb = cb; |
||||
TCP_REF(tcp, "write"); |
||||
grpc_custom_socket_vtable->write(tcp->socket, tcp->write_slices, |
||||
custom_write_callback); |
||||
} |
||||
|
||||
static void endpoint_add_to_pollset(grpc_endpoint* ep, grpc_pollset* pollset) { |
||||
// No-op. We're ignoring pollsets currently
|
||||
(void)ep; |
||||
(void)pollset; |
||||
} |
||||
|
||||
static void endpoint_add_to_pollset_set(grpc_endpoint* ep, |
||||
grpc_pollset_set* pollset) { |
||||
// No-op. We're ignoring pollsets currently
|
||||
(void)ep; |
||||
(void)pollset; |
||||
} |
||||
|
||||
static void endpoint_delete_from_pollset_set(grpc_endpoint* ep, |
||||
grpc_pollset_set* pollset) { |
||||
// No-op. We're ignoring pollsets currently
|
||||
(void)ep; |
||||
(void)pollset; |
||||
} |
||||
|
||||
static void endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) { |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; |
||||
if (!tcp->shutting_down) { |
||||
if (grpc_tcp_trace.enabled()) { |
||||
const char* str = grpc_error_string(why); |
||||
gpr_log(GPR_DEBUG, "TCP %p shutdown why=%s", tcp->socket, str); |
||||
} |
||||
tcp->shutting_down = true; |
||||
// GRPC_CLOSURE_SCHED(tcp->read_cb, GRPC_ERROR_REF(why));
|
||||
// GRPC_CLOSURE_SCHED(tcp->write_cb, GRPC_ERROR_REF(why));
|
||||
// tcp->read_cb = nullptr;
|
||||
// tcp->write_cb = nullptr;
|
||||
grpc_resource_user_shutdown(tcp->resource_user); |
||||
grpc_custom_socket_vtable->shutdown(tcp->socket); |
||||
} |
||||
GRPC_ERROR_UNREF(why); |
||||
} |
||||
|
||||
static void custom_close_callback(grpc_custom_socket* socket) { |
||||
socket->refs--; |
||||
if (socket->refs == 0) { |
||||
grpc_custom_socket_vtable->destroy(socket); |
||||
gpr_free(socket); |
||||
} else if (socket->endpoint) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)socket->endpoint; |
||||
TCP_UNREF(tcp, "destroy"); |
||||
} |
||||
} |
||||
|
||||
static void endpoint_destroy(grpc_endpoint* ep) { |
||||
grpc_network_status_unregister_endpoint(ep); |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; |
||||
grpc_custom_socket_vtable->close(tcp->socket, custom_close_callback); |
||||
} |
||||
|
||||
static char* endpoint_get_peer(grpc_endpoint* ep) { |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; |
||||
return gpr_strdup(tcp->peer_string); |
||||
} |
||||
|
||||
static grpc_resource_user* endpoint_get_resource_user(grpc_endpoint* ep) { |
||||
custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; |
||||
return tcp->resource_user; |
||||
} |
||||
|
||||
static int endpoint_get_fd(grpc_endpoint* ep) { return -1; } |
||||
|
||||
static grpc_endpoint_vtable vtable = {endpoint_read, |
||||
endpoint_write, |
||||
endpoint_add_to_pollset, |
||||
endpoint_add_to_pollset_set, |
||||
endpoint_delete_from_pollset_set, |
||||
endpoint_shutdown, |
||||
endpoint_destroy, |
||||
endpoint_get_resource_user, |
||||
endpoint_get_peer, |
||||
endpoint_get_fd}; |
||||
|
||||
grpc_endpoint* custom_tcp_endpoint_create(grpc_custom_socket* socket, |
||||
grpc_resource_quota* resource_quota, |
||||
char* peer_string) { |
||||
custom_tcp_endpoint* tcp = |
||||
(custom_tcp_endpoint*)gpr_malloc(sizeof(custom_tcp_endpoint)); |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "Creating TCP endpoint %p", socket); |
||||
} |
||||
memset(tcp, 0, sizeof(custom_tcp_endpoint)); |
||||
socket->refs++; |
||||
socket->endpoint = (grpc_endpoint*)tcp; |
||||
tcp->socket = socket; |
||||
tcp->base.vtable = &vtable; |
||||
gpr_ref_init(&tcp->refcount, 1); |
||||
tcp->peer_string = gpr_strdup(peer_string); |
||||
tcp->shutting_down = false; |
||||
tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string); |
||||
grpc_resource_user_slice_allocator_init( |
||||
&tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp); |
||||
/* Tell network status tracking code about the new endpoint */ |
||||
grpc_network_status_register_endpoint(&tcp->base); |
||||
|
||||
return &tcp->base; |
||||
} |
@ -0,0 +1,83 @@ |
||||
/*
|
||||
* |
||||
* 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_TCP_CUSTOM_H |
||||
#define GRPC_CORE_LIB_IOMGR_TCP_CUSTOM_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/endpoint.h" |
||||
#include "src/core/lib/iomgr/sockaddr.h" |
||||
|
||||
typedef struct grpc_tcp_listener grpc_tcp_listener; |
||||
typedef struct grpc_custom_tcp_connect grpc_custom_tcp_connect; |
||||
|
||||
typedef struct grpc_custom_socket { |
||||
// Implementation defined
|
||||
void* impl; |
||||
grpc_endpoint* endpoint; |
||||
grpc_tcp_listener* listener; |
||||
grpc_custom_tcp_connect* connector; |
||||
int refs; |
||||
} grpc_custom_socket; |
||||
|
||||
typedef void (*grpc_custom_connect_callback)(grpc_custom_socket* socket, |
||||
grpc_error* error); |
||||
typedef void (*grpc_custom_write_callback)(grpc_custom_socket* socket, |
||||
grpc_error* error); |
||||
typedef void (*grpc_custom_read_callback)(grpc_custom_socket* socket, |
||||
size_t nread, grpc_error* error); |
||||
typedef void (*grpc_custom_accept_callback)(grpc_custom_socket* socket, |
||||
grpc_custom_socket* client, |
||||
grpc_error* error); |
||||
typedef void (*grpc_custom_close_callback)(grpc_custom_socket* socket); |
||||
|
||||
typedef struct grpc_socket_vtable { |
||||
grpc_error* (*init)(grpc_custom_socket* socket, int domain); |
||||
void (*connect)(grpc_custom_socket* socket, const grpc_sockaddr* addr, |
||||
size_t len, grpc_custom_connect_callback cb); |
||||
void (*destroy)(grpc_custom_socket* socket); |
||||
void (*shutdown)(grpc_custom_socket* socket); |
||||
void (*close)(grpc_custom_socket* socket, grpc_custom_close_callback cb); |
||||
void (*write)(grpc_custom_socket* socket, grpc_slice_buffer* slices, |
||||
grpc_custom_write_callback cb); |
||||
void (*read)(grpc_custom_socket* socket, char* buffer, size_t length, |
||||
grpc_custom_read_callback cb); |
||||
grpc_error* (*getpeername)(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, int* len); |
||||
grpc_error* (*getsockname)(grpc_custom_socket* socket, |
||||
const grpc_sockaddr* addr, int* len); |
||||
grpc_error* (*setsockopt)(grpc_custom_socket* socket, int level, int optname, |
||||
const void* optval, uint32_t optlen); |
||||
grpc_error* (*bind)(grpc_custom_socket* socket, const grpc_sockaddr* addr, |
||||
size_t len, int flags); |
||||
grpc_error* (*listen)(grpc_custom_socket* socket); |
||||
void (*accept)(grpc_custom_socket* socket, grpc_custom_socket* client, |
||||
grpc_custom_accept_callback cb); |
||||
} grpc_socket_vtable; |
||||
|
||||
/* Internal APIs */ |
||||
void grpc_custom_endpoint_init(grpc_socket_vtable* impl); |
||||
|
||||
void grpc_custom_close_server_callback(grpc_tcp_listener* listener); |
||||
|
||||
grpc_endpoint* custom_tcp_endpoint_create(grpc_custom_socket* socket, |
||||
grpc_resource_quota* resource_quota, |
||||
char* peer_string); |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_TCP_CUSTOM_H */ |
@ -0,0 +1,73 @@ |
||||
/*
|
||||
* |
||||
* 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/tcp_server.h" |
||||
|
||||
grpc_tcp_server_vtable* grpc_tcp_server_impl; |
||||
|
||||
grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete, |
||||
const grpc_channel_args* args, |
||||
grpc_tcp_server** server) { |
||||
return grpc_tcp_server_impl->create(shutdown_complete, args, server); |
||||
} |
||||
|
||||
void grpc_tcp_server_start(grpc_tcp_server* server, grpc_pollset** pollsets, |
||||
size_t pollset_count, |
||||
grpc_tcp_server_cb on_accept_cb, void* cb_arg) { |
||||
grpc_tcp_server_impl->start(server, pollsets, pollset_count, on_accept_cb, |
||||
cb_arg); |
||||
} |
||||
|
||||
grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s, |
||||
const grpc_resolved_address* addr, |
||||
int* out_port) { |
||||
return grpc_tcp_server_impl->add_port(s, addr, out_port); |
||||
} |
||||
|
||||
unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server* s, |
||||
unsigned port_index) { |
||||
return grpc_tcp_server_impl->port_fd_count(s, port_index); |
||||
} |
||||
|
||||
int grpc_tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index, |
||||
unsigned fd_index) { |
||||
return grpc_tcp_server_impl->port_fd(s, port_index, fd_index); |
||||
} |
||||
|
||||
grpc_tcp_server* grpc_tcp_server_ref(grpc_tcp_server* s) { |
||||
return grpc_tcp_server_impl->ref(s); |
||||
} |
||||
|
||||
void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server* s, |
||||
grpc_closure* shutdown_starting) { |
||||
grpc_tcp_server_impl->shutdown_starting_add(s, shutdown_starting); |
||||
} |
||||
|
||||
void grpc_tcp_server_unref(grpc_tcp_server* s) { |
||||
grpc_tcp_server_impl->unref(s); |
||||
} |
||||
|
||||
void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) { |
||||
grpc_tcp_server_impl->shutdown_listeners(s); |
||||
} |
||||
|
||||
void grpc_set_tcp_server_impl(grpc_tcp_server_vtable* impl) { |
||||
grpc_tcp_server_impl = impl; |
||||
} |
@ -0,0 +1,479 @@ |
||||
/*
|
||||
* |
||||
* 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" |
||||
|
||||
#include <assert.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/iomgr/error.h" |
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
#include "src/core/lib/iomgr/iomgr_custom.h" |
||||
#include "src/core/lib/iomgr/sockaddr.h" |
||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||
#include "src/core/lib/iomgr/tcp_custom.h" |
||||
#include "src/core/lib/iomgr/tcp_server.h" |
||||
|
||||
extern grpc_core::TraceFlag grpc_tcp_trace; |
||||
|
||||
extern grpc_socket_vtable* grpc_custom_socket_vtable; |
||||
|
||||
/* one listening port */ |
||||
struct grpc_tcp_listener { |
||||
grpc_tcp_server* server; |
||||
unsigned port_index; |
||||
int port; |
||||
|
||||
grpc_custom_socket* socket; |
||||
|
||||
/* linked list */ |
||||
struct grpc_tcp_listener* next; |
||||
|
||||
bool closed; |
||||
}; |
||||
|
||||
struct grpc_tcp_server { |
||||
gpr_refcount refs; |
||||
|
||||
/* Called whenever accept() succeeds on a server port. */ |
||||
grpc_tcp_server_cb on_accept_cb; |
||||
void* on_accept_cb_arg; |
||||
|
||||
int open_ports; |
||||
|
||||
/* linked list of server ports */ |
||||
grpc_tcp_listener* head; |
||||
grpc_tcp_listener* tail; |
||||
|
||||
/* List of closures passed to shutdown_starting_add(). */ |
||||
grpc_closure_list shutdown_starting; |
||||
|
||||
/* shutdown callback */ |
||||
grpc_closure* shutdown_complete; |
||||
|
||||
bool shutdown; |
||||
|
||||
grpc_resource_quota* resource_quota; |
||||
}; |
||||
|
||||
static grpc_error* tcp_server_create(grpc_closure* shutdown_complete, |
||||
const grpc_channel_args* args, |
||||
grpc_tcp_server** server) { |
||||
grpc_tcp_server* s = (grpc_tcp_server*)gpr_malloc(sizeof(grpc_tcp_server)); |
||||
s->resource_quota = grpc_resource_quota_create(nullptr); |
||||
for (size_t i = 0; i < (args == nullptr ? 0 : args->num_args); i++) { |
||||
if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) { |
||||
if (args->args[i].type == GRPC_ARG_POINTER) { |
||||
grpc_resource_quota_unref_internal(s->resource_quota); |
||||
s->resource_quota = grpc_resource_quota_ref_internal( |
||||
(grpc_resource_quota*)args->args[i].value.pointer.p); |
||||
} else { |
||||
grpc_resource_quota_unref_internal(s->resource_quota); |
||||
gpr_free(s); |
||||
return GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool"); |
||||
} |
||||
} |
||||
} |
||||
gpr_ref_init(&s->refs, 1); |
||||
s->on_accept_cb = nullptr; |
||||
s->on_accept_cb_arg = nullptr; |
||||
s->open_ports = 0; |
||||
s->head = nullptr; |
||||
s->tail = nullptr; |
||||
s->shutdown_starting.head = nullptr; |
||||
s->shutdown_starting.tail = nullptr; |
||||
s->shutdown_complete = shutdown_complete; |
||||
s->shutdown = false; |
||||
*server = s; |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static grpc_tcp_server* tcp_server_ref(grpc_tcp_server* s) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
gpr_ref(&s->refs); |
||||
return s; |
||||
} |
||||
|
||||
static void tcp_server_shutdown_starting_add(grpc_tcp_server* s, |
||||
grpc_closure* shutdown_starting) { |
||||
grpc_closure_list_append(&s->shutdown_starting, shutdown_starting, |
||||
GRPC_ERROR_NONE); |
||||
} |
||||
|
||||
static void finish_shutdown(grpc_tcp_server* s) { |
||||
GPR_ASSERT(s->shutdown); |
||||
if (s->shutdown_complete != nullptr) { |
||||
GRPC_CLOSURE_SCHED(s->shutdown_complete, GRPC_ERROR_NONE); |
||||
} |
||||
|
||||
while (s->head) { |
||||
grpc_tcp_listener* sp = s->head; |
||||
s->head = sp->next; |
||||
sp->next = nullptr; |
||||
gpr_free(sp); |
||||
} |
||||
grpc_resource_quota_unref_internal(s->resource_quota); |
||||
gpr_free(s); |
||||
} |
||||
|
||||
static void custom_close_callback(grpc_custom_socket* socket) { |
||||
grpc_tcp_listener* sp = socket->listener; |
||||
if (sp) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
sp->server->open_ports--; |
||||
if (sp->server->open_ports == 0 && sp->server->shutdown) { |
||||
finish_shutdown(sp->server); |
||||
} |
||||
} |
||||
socket->refs--; |
||||
if (socket->refs == 0) { |
||||
grpc_custom_socket_vtable->destroy(socket); |
||||
gpr_free(socket); |
||||
} |
||||
} |
||||
|
||||
void grpc_custom_close_server_callback(grpc_tcp_listener* sp) { |
||||
if (sp) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
sp->server->open_ports--; |
||||
if (sp->server->open_ports == 0 && sp->server->shutdown) { |
||||
finish_shutdown(sp->server); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void close_listener(grpc_tcp_listener* sp) { |
||||
grpc_custom_socket* socket = sp->socket; |
||||
if (!sp->closed) { |
||||
sp->closed = true; |
||||
grpc_custom_socket_vtable->close(socket, custom_close_callback); |
||||
} |
||||
} |
||||
|
||||
static void tcp_server_destroy(grpc_tcp_server* s) { |
||||
int immediately_done = 0; |
||||
grpc_tcp_listener* sp; |
||||
|
||||
GPR_ASSERT(!s->shutdown); |
||||
s->shutdown = true; |
||||
|
||||
if (s->open_ports == 0) { |
||||
immediately_done = 1; |
||||
} |
||||
for (sp = s->head; sp; sp = sp->next) { |
||||
close_listener(sp); |
||||
} |
||||
|
||||
if (immediately_done) { |
||||
finish_shutdown(s); |
||||
} |
||||
} |
||||
|
||||
static void tcp_server_unref(grpc_tcp_server* s) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
if (gpr_unref(&s->refs)) { |
||||
/* Complete shutdown_starting work before destroying. */ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
GRPC_CLOSURE_LIST_SCHED(&s->shutdown_starting); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
tcp_server_destroy(s); |
||||
} |
||||
} |
||||
|
||||
static void finish_accept(grpc_tcp_listener* sp, grpc_custom_socket* socket) { |
||||
grpc_tcp_server_acceptor* acceptor = |
||||
(grpc_tcp_server_acceptor*)gpr_malloc(sizeof(*acceptor)); |
||||
grpc_endpoint* ep = nullptr; |
||||
grpc_resolved_address peer_name; |
||||
char* peer_name_string; |
||||
grpc_error* err; |
||||
|
||||
peer_name_string = nullptr; |
||||
memset(&peer_name, 0, sizeof(grpc_resolved_address)); |
||||
peer_name.len = GRPC_MAX_SOCKADDR_SIZE; |
||||
err = grpc_custom_socket_vtable->getpeername( |
||||
socket, (grpc_sockaddr*)&peer_name.addr, (int*)&peer_name.len); |
||||
if (err == GRPC_ERROR_NONE) { |
||||
peer_name_string = grpc_sockaddr_to_uri(&peer_name); |
||||
} else { |
||||
GRPC_LOG_IF_ERROR("getpeername error", err); |
||||
GRPC_ERROR_UNREF(err); |
||||
} |
||||
if (grpc_tcp_trace.enabled()) { |
||||
if (peer_name_string) { |
||||
gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection: %s", |
||||
sp->server, peer_name_string); |
||||
} else { |
||||
gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection", sp->server); |
||||
} |
||||
} |
||||
ep = custom_tcp_endpoint_create(socket, sp->server->resource_quota, |
||||
peer_name_string); |
||||
acceptor->from_server = sp->server; |
||||
acceptor->port_index = sp->port_index; |
||||
acceptor->fd_index = 0; |
||||
sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep, nullptr, acceptor); |
||||
gpr_free(peer_name_string); |
||||
} |
||||
|
||||
static void custom_accept_callback(grpc_custom_socket* socket, |
||||
grpc_custom_socket* client, |
||||
grpc_error* error); |
||||
|
||||
static void custom_accept_callback(grpc_custom_socket* socket, |
||||
grpc_custom_socket* client, |
||||
grpc_error* error) { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_tcp_listener* sp = socket->listener; |
||||
if (error != GRPC_ERROR_NONE) { |
||||
if (!sp->closed) { |
||||
gpr_log(GPR_ERROR, "Accept failed: %s", grpc_error_string(error)); |
||||
} |
||||
gpr_free(client); |
||||
GRPC_ERROR_UNREF(error); |
||||
return; |
||||
} |
||||
finish_accept(sp, client); |
||||
if (!sp->closed) { |
||||
grpc_custom_socket* new_socket = |
||||
(grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket)); |
||||
new_socket->endpoint = nullptr; |
||||
new_socket->listener = nullptr; |
||||
new_socket->connector = nullptr; |
||||
new_socket->refs = 1; |
||||
grpc_custom_socket_vtable->accept(sp->socket, new_socket, |
||||
custom_accept_callback); |
||||
} |
||||
} |
||||
|
||||
static grpc_error* add_socket_to_server(grpc_tcp_server* s, |
||||
grpc_custom_socket* socket, |
||||
const grpc_resolved_address* addr, |
||||
unsigned port_index, |
||||
grpc_tcp_listener** listener) { |
||||
grpc_tcp_listener* sp = nullptr; |
||||
int port = -1; |
||||
grpc_error* error; |
||||
grpc_resolved_address sockname_temp; |
||||
|
||||
// The last argument to uv_tcp_bind is flags
|
||||
error = grpc_custom_socket_vtable->bind(socket, (grpc_sockaddr*)addr->addr, |
||||
addr->len, 0); |
||||
if (error != GRPC_ERROR_NONE) { |
||||
return error; |
||||
} |
||||
|
||||
error = grpc_custom_socket_vtable->listen(socket); |
||||
if (error != GRPC_ERROR_NONE) { |
||||
return error; |
||||
} |
||||
|
||||
sockname_temp.len = GRPC_MAX_SOCKADDR_SIZE; |
||||
error = grpc_custom_socket_vtable->getsockname( |
||||
socket, (grpc_sockaddr*)&sockname_temp.addr, (int*)&sockname_temp.len); |
||||
if (error != GRPC_ERROR_NONE) { |
||||
return error; |
||||
} |
||||
|
||||
port = grpc_sockaddr_get_port(&sockname_temp); |
||||
|
||||
GPR_ASSERT(port >= 0); |
||||
GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); |
||||
sp = (grpc_tcp_listener*)gpr_zalloc(sizeof(grpc_tcp_listener)); |
||||
sp->next = nullptr; |
||||
if (s->head == nullptr) { |
||||
s->head = sp; |
||||
} else { |
||||
s->tail->next = sp; |
||||
} |
||||
s->tail = sp; |
||||
sp->server = s; |
||||
sp->socket = socket; |
||||
sp->port = port; |
||||
sp->port_index = port_index; |
||||
sp->closed = false; |
||||
s->open_ports++; |
||||
*listener = sp; |
||||
|
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static grpc_error* tcp_server_add_port(grpc_tcp_server* s, |
||||
const grpc_resolved_address* addr, |
||||
int* port) { |
||||
// This function is mostly copied from tcp_server_windows.c
|
||||
grpc_tcp_listener* sp = nullptr; |
||||
grpc_custom_socket* socket; |
||||
grpc_resolved_address addr6_v4mapped; |
||||
grpc_resolved_address wildcard; |
||||
grpc_resolved_address* allocated_addr = nullptr; |
||||
grpc_resolved_address sockname_temp; |
||||
unsigned port_index = 0; |
||||
grpc_error* error = GRPC_ERROR_NONE; |
||||
int family; |
||||
|
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
|
||||
if (s->tail != nullptr) { |
||||
port_index = s->tail->port_index + 1; |
||||
} |
||||
|
||||
/* Check if this is a wildcard port, and if so, try to keep the port the same
|
||||
as some previously created listener. */ |
||||
if (grpc_sockaddr_get_port(addr) == 0) { |
||||
for (sp = s->head; sp; sp = sp->next) { |
||||
socket = sp->socket; |
||||
sockname_temp.len = GRPC_MAX_SOCKADDR_SIZE; |
||||
if (nullptr == grpc_custom_socket_vtable->getsockname( |
||||
socket, (grpc_sockaddr*)&sockname_temp.addr, |
||||
(int*)&sockname_temp.len)) { |
||||
*port = grpc_sockaddr_get_port(&sockname_temp); |
||||
if (*port > 0) { |
||||
allocated_addr = |
||||
(grpc_resolved_address*)gpr_malloc(sizeof(grpc_resolved_address)); |
||||
memcpy(allocated_addr, addr, sizeof(grpc_resolved_address)); |
||||
grpc_sockaddr_set_port(allocated_addr, *port); |
||||
addr = allocated_addr; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { |
||||
addr = &addr6_v4mapped; |
||||
} |
||||
|
||||
/* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ |
||||
if (grpc_sockaddr_is_wildcard(addr, port)) { |
||||
grpc_sockaddr_make_wildcard6(*port, &wildcard); |
||||
|
||||
addr = &wildcard; |
||||
} |
||||
|
||||
if (grpc_tcp_trace.enabled()) { |
||||
char* port_string; |
||||
grpc_sockaddr_to_string(&port_string, addr, 0); |
||||
const char* str = grpc_error_string(error); |
||||
if (port_string) { |
||||
gpr_log(GPR_DEBUG, "SERVER %p add_port %s error=%s", s, port_string, str); |
||||
gpr_free(port_string); |
||||
} else { |
||||
gpr_log(GPR_DEBUG, "SERVER %p add_port error=%s", s, str); |
||||
} |
||||
} |
||||
|
||||
family = grpc_sockaddr_get_family(addr); |
||||
socket = (grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket)); |
||||
socket->refs = 1; |
||||
socket->endpoint = nullptr; |
||||
socket->listener = nullptr; |
||||
socket->connector = nullptr; |
||||
grpc_custom_socket_vtable->init(socket, family); |
||||
|
||||
if (error == GRPC_ERROR_NONE) { |
||||
#if defined(GPR_LINUX) && defined(SO_REUSEPORT) |
||||
if (family == AF_INET || family == AF_INET6) { |
||||
int enable = 1; |
||||
grpc_custom_socket_vtable->setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, |
||||
&enable, sizeof(enable)); |
||||
} |
||||
#endif /* GPR_LINUX && SO_REUSEPORT */ |
||||
error = add_socket_to_server(s, socket, addr, port_index, &sp); |
||||
} |
||||
gpr_free(allocated_addr); |
||||
|
||||
if (error != GRPC_ERROR_NONE) { |
||||
grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( |
||||
"Failed to add port to server", &error, 1); |
||||
GRPC_ERROR_UNREF(error); |
||||
error = error_out; |
||||
*port = -1; |
||||
} else { |
||||
GPR_ASSERT(sp != nullptr); |
||||
*port = sp->port; |
||||
} |
||||
socket->listener = sp; |
||||
return error; |
||||
} |
||||
|
||||
static void tcp_server_start(grpc_tcp_server* server, grpc_pollset** pollsets, |
||||
size_t pollset_count, |
||||
grpc_tcp_server_cb on_accept_cb, void* cb_arg) { |
||||
grpc_tcp_listener* sp; |
||||
(void)pollsets; |
||||
(void)pollset_count; |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "SERVER_START %p", server); |
||||
} |
||||
GPR_ASSERT(on_accept_cb); |
||||
GPR_ASSERT(!server->on_accept_cb); |
||||
server->on_accept_cb = on_accept_cb; |
||||
server->on_accept_cb_arg = cb_arg; |
||||
for (sp = server->head; sp; sp = sp->next) { |
||||
grpc_custom_socket* new_socket = |
||||
(grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket)); |
||||
new_socket->endpoint = nullptr; |
||||
new_socket->listener = nullptr; |
||||
new_socket->connector = nullptr; |
||||
new_socket->refs = 1; |
||||
grpc_custom_socket_vtable->accept(sp->socket, new_socket, |
||||
custom_accept_callback); |
||||
} |
||||
} |
||||
|
||||
static unsigned tcp_server_port_fd_count(grpc_tcp_server* s, |
||||
unsigned port_index) { |
||||
return 0; |
||||
} |
||||
|
||||
static int tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index, |
||||
unsigned fd_index) { |
||||
return -1; |
||||
} |
||||
|
||||
static void tcp_server_shutdown_listeners(grpc_tcp_server* s) { |
||||
for (grpc_tcp_listener* sp = s->head; sp; sp = sp->next) { |
||||
if (!sp->closed) { |
||||
sp->closed = true; |
||||
grpc_custom_socket_vtable->close(sp->socket, custom_close_callback); |
||||
} |
||||
} |
||||
} |
||||
|
||||
grpc_tcp_server_vtable custom_tcp_server_vtable = { |
||||
tcp_server_create, |
||||
tcp_server_start, |
||||
tcp_server_add_port, |
||||
tcp_server_port_fd_count, |
||||
tcp_server_port_fd, |
||||
tcp_server_ref, |
||||
tcp_server_shutdown_starting_add, |
||||
tcp_server_unref, |
||||
tcp_server_shutdown_listeners}; |
||||
|
||||
#ifdef GRPC_UV_TEST |
||||
grpc_tcp_server_vtable* default_tcp_server_vtable = &custom_tcp_server_vtable; |
||||
#endif |
@ -1,473 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 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 <assert.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/iomgr/error.h" |
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
#include "src/core/lib/iomgr/iomgr_uv.h" |
||||
#include "src/core/lib/iomgr/sockaddr.h" |
||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||
#include "src/core/lib/iomgr/tcp_server.h" |
||||
#include "src/core/lib/iomgr/tcp_uv.h" |
||||
|
||||
/* one listening port */ |
||||
typedef struct grpc_tcp_listener grpc_tcp_listener; |
||||
struct grpc_tcp_listener { |
||||
uv_tcp_t* handle; |
||||
grpc_tcp_server* server; |
||||
unsigned port_index; |
||||
int port; |
||||
/* linked list */ |
||||
struct grpc_tcp_listener* next; |
||||
|
||||
bool closed; |
||||
|
||||
bool has_pending_connection; |
||||
}; |
||||
|
||||
struct grpc_tcp_server { |
||||
gpr_refcount refs; |
||||
|
||||
/* Called whenever accept() succeeds on a server port. */ |
||||
grpc_tcp_server_cb on_accept_cb; |
||||
void* on_accept_cb_arg; |
||||
|
||||
int open_ports; |
||||
|
||||
/* linked list of server ports */ |
||||
grpc_tcp_listener* head; |
||||
grpc_tcp_listener* tail; |
||||
|
||||
/* List of closures passed to shutdown_starting_add(). */ |
||||
grpc_closure_list shutdown_starting; |
||||
|
||||
/* shutdown callback */ |
||||
grpc_closure* shutdown_complete; |
||||
|
||||
bool shutdown; |
||||
|
||||
grpc_resource_quota* resource_quota; |
||||
}; |
||||
|
||||
grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete, |
||||
const grpc_channel_args* args, |
||||
grpc_tcp_server** server) { |
||||
grpc_tcp_server* s = (grpc_tcp_server*)gpr_malloc(sizeof(grpc_tcp_server)); |
||||
s->resource_quota = grpc_resource_quota_create(NULL); |
||||
for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) { |
||||
if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) { |
||||
if (args->args[i].type == GRPC_ARG_POINTER) { |
||||
grpc_resource_quota_unref_internal(s->resource_quota); |
||||
s->resource_quota = grpc_resource_quota_ref_internal( |
||||
(grpc_resource_quota*)args->args[i].value.pointer.p); |
||||
} else { |
||||
grpc_resource_quota_unref_internal(s->resource_quota); |
||||
gpr_free(s); |
||||
return GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool"); |
||||
} |
||||
} |
||||
} |
||||
gpr_ref_init(&s->refs, 1); |
||||
s->on_accept_cb = NULL; |
||||
s->on_accept_cb_arg = NULL; |
||||
s->open_ports = 0; |
||||
s->head = NULL; |
||||
s->tail = NULL; |
||||
s->shutdown_starting.head = NULL; |
||||
s->shutdown_starting.tail = NULL; |
||||
s->shutdown_complete = shutdown_complete; |
||||
s->shutdown = false; |
||||
*server = s; |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
grpc_tcp_server* grpc_tcp_server_ref(grpc_tcp_server* s) { |
||||
GRPC_UV_ASSERT_SAME_THREAD(); |
||||
gpr_ref(&s->refs); |
||||
return s; |
||||
} |
||||
|
||||
void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server* s, |
||||
grpc_closure* shutdown_starting) { |
||||
grpc_closure_list_append(&s->shutdown_starting, shutdown_starting, |
||||
GRPC_ERROR_NONE); |
||||
} |
||||
|
||||
static void finish_shutdown(grpc_tcp_server* s) { |
||||
GPR_ASSERT(s->shutdown); |
||||
if (s->shutdown_complete != NULL) { |
||||
GRPC_CLOSURE_SCHED(s->shutdown_complete, GRPC_ERROR_NONE); |
||||
} |
||||
|
||||
while (s->head) { |
||||
grpc_tcp_listener* sp = s->head; |
||||
s->head = sp->next; |
||||
sp->next = NULL; |
||||
gpr_free(sp->handle); |
||||
gpr_free(sp); |
||||
} |
||||
grpc_resource_quota_unref_internal(s->resource_quota); |
||||
gpr_free(s); |
||||
} |
||||
|
||||
static void handle_close_callback(uv_handle_t* handle) { |
||||
grpc_tcp_listener* sp = (grpc_tcp_listener*)handle->data; |
||||
grpc_core::ExecCtx exec_ctx; |
||||
sp->server->open_ports--; |
||||
if (sp->server->open_ports == 0 && sp->server->shutdown) { |
||||
finish_shutdown(sp->server); |
||||
} |
||||
} |
||||
|
||||
static void close_listener(grpc_tcp_listener* sp) { |
||||
if (!sp->closed) { |
||||
sp->closed = true; |
||||
uv_close((uv_handle_t*)sp->handle, handle_close_callback); |
||||
} |
||||
} |
||||
|
||||
static void tcp_server_destroy(grpc_tcp_server* s) { |
||||
int immediately_done = 0; |
||||
grpc_tcp_listener* sp; |
||||
|
||||
GPR_ASSERT(!s->shutdown); |
||||
s->shutdown = true; |
||||
|
||||
if (s->open_ports == 0) { |
||||
immediately_done = 1; |
||||
} |
||||
for (sp = s->head; sp; sp = sp->next) { |
||||
close_listener(sp); |
||||
} |
||||
|
||||
if (immediately_done) { |
||||
finish_shutdown(s); |
||||
} |
||||
} |
||||
|
||||
void grpc_tcp_server_unref(grpc_tcp_server* s) { |
||||
GRPC_UV_ASSERT_SAME_THREAD(); |
||||
if (gpr_unref(&s->refs)) { |
||||
/* Complete shutdown_starting work before destroying. */ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
GRPC_CLOSURE_LIST_SCHED(&s->shutdown_starting); |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
tcp_server_destroy(s); |
||||
} |
||||
} |
||||
|
||||
static void finish_accept(grpc_tcp_listener* sp) { |
||||
grpc_tcp_server_acceptor* acceptor = |
||||
(grpc_tcp_server_acceptor*)gpr_malloc(sizeof(*acceptor)); |
||||
uv_tcp_t* client = NULL; |
||||
grpc_endpoint* ep = NULL; |
||||
grpc_resolved_address peer_name; |
||||
char* peer_name_string; |
||||
int err; |
||||
uv_tcp_t* server = sp->handle; |
||||
|
||||
client = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t)); |
||||
uv_tcp_init(uv_default_loop(), client); |
||||
// UV documentation says this is guaranteed to succeed
|
||||
uv_accept((uv_stream_t*)server, (uv_stream_t*)client); |
||||
peer_name_string = NULL; |
||||
memset(&peer_name, 0, sizeof(grpc_resolved_address)); |
||||
peer_name.len = sizeof(struct sockaddr_storage); |
||||
err = uv_tcp_getpeername(client, (struct sockaddr*)&peer_name.addr, |
||||
(int*)&peer_name.len); |
||||
if (err == 0) { |
||||
peer_name_string = grpc_sockaddr_to_uri(&peer_name); |
||||
} else { |
||||
gpr_log(GPR_INFO, "uv_tcp_getpeername error: %s", uv_strerror(err)); |
||||
} |
||||
if (grpc_tcp_trace.enabled()) { |
||||
if (peer_name_string) { |
||||
gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection: %s", |
||||
sp->server, peer_name_string); |
||||
} else { |
||||
gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection", sp->server); |
||||
} |
||||
} |
||||
ep = grpc_tcp_create(client, sp->server->resource_quota, peer_name_string); |
||||
acceptor->from_server = sp->server; |
||||
acceptor->port_index = sp->port_index; |
||||
acceptor->fd_index = 0; |
||||
sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep, NULL, acceptor); |
||||
gpr_free(peer_name_string); |
||||
} |
||||
|
||||
static void on_connect(uv_stream_t* server, int status) { |
||||
grpc_tcp_listener* sp = (grpc_tcp_listener*)server->data; |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
if (status < 0) { |
||||
switch (status) { |
||||
case UV_EINTR: |
||||
case UV_EAGAIN: |
||||
return; |
||||
default: |
||||
close_listener(sp); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
GPR_ASSERT(!sp->has_pending_connection); |
||||
|
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p incoming connection", sp->server); |
||||
} |
||||
|
||||
// Create acceptor.
|
||||
if (sp->server->on_accept_cb) { |
||||
finish_accept(sp); |
||||
} else { |
||||
sp->has_pending_connection = true; |
||||
} |
||||
} |
||||
|
||||
static grpc_error* add_addr_to_server(grpc_tcp_server* s, |
||||
const grpc_resolved_address* addr, |
||||
unsigned port_index, |
||||
grpc_tcp_listener** listener) { |
||||
grpc_tcp_listener* sp = NULL; |
||||
int port = -1; |
||||
int status; |
||||
grpc_error* error; |
||||
grpc_resolved_address sockname_temp; |
||||
uv_tcp_t* handle = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t)); |
||||
int family = grpc_sockaddr_get_family(addr); |
||||
|
||||
status = uv_tcp_init_ex(uv_default_loop(), handle, (unsigned int)family); |
||||
#if defined(GPR_LINUX) && defined(SO_REUSEPORT) |
||||
if (family == AF_INET || family == AF_INET6) { |
||||
int fd; |
||||
uv_fileno((uv_handle_t*)handle, &fd); |
||||
int enable = 1; |
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable)); |
||||
} |
||||
#endif /* GPR_LINUX && SO_REUSEPORT */ |
||||
|
||||
if (status != 0) { |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"Failed to initialize UV tcp handle"); |
||||
error = |
||||
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string(uv_strerror(status))); |
||||
return error; |
||||
} |
||||
|
||||
// The last argument to uv_tcp_bind is flags
|
||||
status = uv_tcp_bind(handle, (struct sockaddr*)addr->addr, 0); |
||||
if (status != 0) { |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to bind to port"); |
||||
error = |
||||
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string(uv_strerror(status))); |
||||
return error; |
||||
} |
||||
|
||||
status = uv_listen((uv_stream_t*)handle, SOMAXCONN, on_connect); |
||||
if (status != 0) { |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to listen to port"); |
||||
error = |
||||
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string(uv_strerror(status))); |
||||
return error; |
||||
} |
||||
|
||||
sockname_temp.len = (int)sizeof(struct sockaddr_storage); |
||||
status = uv_tcp_getsockname(handle, (struct sockaddr*)&sockname_temp.addr, |
||||
(int*)&sockname_temp.len); |
||||
if (status != 0) { |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getsockname failed"); |
||||
error = |
||||
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, |
||||
grpc_slice_from_static_string(uv_strerror(status))); |
||||
return error; |
||||
} |
||||
|
||||
port = grpc_sockaddr_get_port(&sockname_temp); |
||||
|
||||
GPR_ASSERT(port >= 0); |
||||
GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server"); |
||||
sp = (grpc_tcp_listener*)gpr_zalloc(sizeof(grpc_tcp_listener)); |
||||
sp->next = NULL; |
||||
if (s->head == NULL) { |
||||
s->head = sp; |
||||
} else { |
||||
s->tail->next = sp; |
||||
} |
||||
s->tail = sp; |
||||
sp->server = s; |
||||
sp->handle = handle; |
||||
sp->port = port; |
||||
sp->port_index = port_index; |
||||
sp->closed = false; |
||||
handle->data = sp; |
||||
s->open_ports++; |
||||
GPR_ASSERT(sp->handle); |
||||
*listener = sp; |
||||
|
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
static grpc_error* add_wildcard_addrs_to_server(grpc_tcp_server* s, |
||||
unsigned port_index, |
||||
int requested_port, |
||||
grpc_tcp_listener** listener) { |
||||
grpc_resolved_address wild4; |
||||
grpc_resolved_address wild6; |
||||
grpc_tcp_listener* sp = nullptr; |
||||
grpc_tcp_listener* sp2 = nullptr; |
||||
grpc_error* v6_err = GRPC_ERROR_NONE; |
||||
grpc_error* v4_err = GRPC_ERROR_NONE; |
||||
|
||||
grpc_sockaddr_make_wildcards(requested_port, &wild4, &wild6); |
||||
/* Try listening on IPv6 first. */ |
||||
if ((v6_err = add_addr_to_server(s, &wild6, port_index, &sp)) == |
||||
GRPC_ERROR_NONE) { |
||||
*listener = sp; |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
if ((v4_err = add_addr_to_server(s, &wild4, port_index, &sp2)) == |
||||
GRPC_ERROR_NONE) { |
||||
*listener = sp2; |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
grpc_error* root_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||
"Failed to add any wildcard listeners"); |
||||
root_err = grpc_error_add_child(root_err, v6_err); |
||||
root_err = grpc_error_add_child(root_err, v4_err); |
||||
return root_err; |
||||
} |
||||
|
||||
grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s, |
||||
const grpc_resolved_address* addr, |
||||
int* port) { |
||||
// This function is mostly copied from tcp_server_windows.c
|
||||
grpc_tcp_listener* sp = NULL; |
||||
grpc_resolved_address addr6_v4mapped; |
||||
grpc_resolved_address* allocated_addr = NULL; |
||||
grpc_resolved_address sockname_temp; |
||||
unsigned port_index = 0; |
||||
grpc_error* error = GRPC_ERROR_NONE; |
||||
|
||||
GRPC_UV_ASSERT_SAME_THREAD(); |
||||
|
||||
if (s->tail != NULL) { |
||||
port_index = s->tail->port_index + 1; |
||||
} |
||||
|
||||
/* Check if this is a wildcard port, and if so, try to keep the port the same
|
||||
as some previously created listener. */ |
||||
if (grpc_sockaddr_get_port(addr) == 0) { |
||||
for (sp = s->head; sp; sp = sp->next) { |
||||
sockname_temp.len = sizeof(struct sockaddr_storage); |
||||
if (0 == uv_tcp_getsockname(sp->handle, |
||||
(struct sockaddr*)&sockname_temp.addr, |
||||
(int*)&sockname_temp.len)) { |
||||
*port = grpc_sockaddr_get_port(&sockname_temp); |
||||
if (*port > 0) { |
||||
allocated_addr = |
||||
(grpc_resolved_address*)gpr_malloc(sizeof(grpc_resolved_address)); |
||||
memcpy(allocated_addr, addr, sizeof(grpc_resolved_address)); |
||||
grpc_sockaddr_set_port(allocated_addr, *port); |
||||
addr = allocated_addr; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */ |
||||
if (grpc_sockaddr_is_wildcard(addr, port)) { |
||||
error = add_wildcard_addrs_to_server(s, port_index, *port, &sp); |
||||
} else { |
||||
if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) { |
||||
addr = &addr6_v4mapped; |
||||
} |
||||
|
||||
error = add_addr_to_server(s, addr, port_index, &sp); |
||||
} |
||||
|
||||
gpr_free(allocated_addr); |
||||
|
||||
if (grpc_tcp_trace.enabled()) { |
||||
char* port_string; |
||||
grpc_sockaddr_to_string(&port_string, addr, 0); |
||||
const char* str = grpc_error_string(error); |
||||
if (port_string) { |
||||
gpr_log(GPR_DEBUG, "SERVER %p add_port %s error=%s", s, port_string, str); |
||||
gpr_free(port_string); |
||||
} else { |
||||
gpr_log(GPR_DEBUG, "SERVER %p add_port error=%s", s, str); |
||||
} |
||||
} |
||||
|
||||
if (error != GRPC_ERROR_NONE) { |
||||
grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( |
||||
"Failed to add port to server", &error, 1); |
||||
GRPC_ERROR_UNREF(error); |
||||
error = error_out; |
||||
*port = -1; |
||||
} else { |
||||
GPR_ASSERT(sp != NULL); |
||||
*port = sp->port; |
||||
} |
||||
return error; |
||||
} |
||||
|
||||
void grpc_tcp_server_start(grpc_tcp_server* server, grpc_pollset** pollsets, |
||||
size_t pollset_count, |
||||
grpc_tcp_server_cb on_accept_cb, void* cb_arg) { |
||||
grpc_tcp_listener* sp; |
||||
(void)pollsets; |
||||
(void)pollset_count; |
||||
GRPC_UV_ASSERT_SAME_THREAD(); |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "SERVER_START %p", server); |
||||
} |
||||
GPR_ASSERT(on_accept_cb); |
||||
GPR_ASSERT(!server->on_accept_cb); |
||||
server->on_accept_cb = on_accept_cb; |
||||
server->on_accept_cb_arg = cb_arg; |
||||
for (sp = server->head; sp; sp = sp->next) { |
||||
if (sp->has_pending_connection) { |
||||
finish_accept(sp); |
||||
sp->has_pending_connection = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) {} |
||||
|
||||
#endif /* GRPC_UV */ |
@ -1,53 +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_TCP_UV_H |
||||
#define GRPC_CORE_LIB_IOMGR_TCP_UV_H |
||||
/*
|
||||
Low level TCP "bottom half" implementation, for use by transports built on |
||||
top of a TCP connection. |
||||
|
||||
Note that this file does not (yet) include APIs for creating the socket in |
||||
the first place. |
||||
|
||||
All calls passing slice transfer ownership of a slice refcount unless |
||||
otherwise specified. |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/debug/trace.h" |
||||
#include "src/core/lib/iomgr/endpoint.h" |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_UV |
||||
|
||||
#include <uv.h> |
||||
|
||||
extern grpc_core::TraceFlag grpc_tcp_trace; |
||||
|
||||
#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192 |
||||
|
||||
grpc_endpoint* grpc_tcp_create(uv_tcp_t* handle, |
||||
grpc_resource_quota* resource_quota, |
||||
char* peer_string); |
||||
|
||||
#endif /* GRPC_UV */ |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_TCP_UV_H */ |
@ -0,0 +1,45 @@ |
||||
/*
|
||||
* |
||||
* 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/timer.h" |
||||
#include "src/core/lib/iomgr/timer_manager.h" |
||||
|
||||
grpc_timer_vtable* grpc_timer_impl; |
||||
|
||||
void grpc_set_timer_impl(grpc_timer_vtable* vtable) { |
||||
grpc_timer_impl = vtable; |
||||
} |
||||
|
||||
void grpc_timer_init(grpc_timer* timer, grpc_millis deadline, |
||||
grpc_closure* closure) { |
||||
grpc_timer_impl->init(timer, deadline, closure); |
||||
} |
||||
|
||||
void grpc_timer_cancel(grpc_timer* timer) { grpc_timer_impl->cancel(timer); } |
||||
|
||||
grpc_timer_check_result grpc_timer_check(grpc_millis* next) { |
||||
return grpc_timer_impl->check(next); |
||||
} |
||||
|
||||
void grpc_timer_list_init() { grpc_timer_impl->list_init(); } |
||||
|
||||
void grpc_timer_list_shutdown() { grpc_timer_impl->list_shutdown(); } |
||||
|
||||
void grpc_timer_consume_kick() { grpc_timer_impl->consume_kick(); } |
@ -0,0 +1,93 @@ |
||||
/*
|
||||
* |
||||
* 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 <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#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" |
||||
|
||||
static grpc_custom_timer_vtable* custom_timer_impl; |
||||
|
||||
void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_timer* timer = t->original; |
||||
GPR_ASSERT(timer->pending); |
||||
timer->pending = 0; |
||||
GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_NONE); |
||||
custom_timer_impl->stop(t); |
||||
gpr_free(t); |
||||
} |
||||
|
||||
static void timer_init(grpc_timer* timer, grpc_millis deadline, |
||||
grpc_closure* closure) { |
||||
uint64_t timeout; |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
grpc_millis now = grpc_core::ExecCtx::Get()->Now(); |
||||
if (deadline <= grpc_core::ExecCtx::Get()->Now()) { |
||||
GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE); |
||||
timer->pending = false; |
||||
return; |
||||
} else { |
||||
timeout = deadline - now; |
||||
} |
||||
timer->pending = true; |
||||
timer->closure = closure; |
||||
grpc_custom_timer* timer_wrapper = |
||||
(grpc_custom_timer*)gpr_malloc(sizeof(grpc_custom_timer)); |
||||
timer_wrapper->timeout_ms = timeout; |
||||
timer->custom_timer = (void*)timer_wrapper; |
||||
timer_wrapper->original = timer; |
||||
custom_timer_impl->start(timer_wrapper); |
||||
} |
||||
|
||||
static void timer_cancel(grpc_timer* timer) { |
||||
GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); |
||||
grpc_custom_timer* tw = (grpc_custom_timer*)timer->custom_timer; |
||||
if (timer->pending) { |
||||
timer->pending = 0; |
||||
GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_CANCELLED); |
||||
custom_timer_impl->stop(tw); |
||||
gpr_free(tw); |
||||
} |
||||
} |
||||
|
||||
static grpc_timer_check_result timer_check(grpc_millis* next) { |
||||
return GRPC_TIMERS_NOT_CHECKED; |
||||
} |
||||
|
||||
static void timer_list_init() {} |
||||
static void timer_list_shutdown() {} |
||||
|
||||
static void timer_consume_kick(void) {} |
||||
|
||||
static grpc_timer_vtable custom_timer_vtable = { |
||||
timer_init, timer_cancel, timer_check, |
||||
timer_list_init, timer_list_shutdown, timer_consume_kick}; |
||||
|
||||
void grpc_custom_timer_init(grpc_custom_timer_vtable* impl) { |
||||
custom_timer_impl = impl; |
||||
grpc_set_timer_impl(&custom_timer_vtable); |
||||
} |
@ -0,0 +1,43 @@ |
||||
/*
|
||||
* |
||||
* 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_TIMER_CUSTOM_H |
||||
#define GRPC_CORE_LIB_IOMGR_TIMER_CUSTOM_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/timer.h" |
||||
|
||||
typedef struct grpc_custom_timer { |
||||
// Implementation defined
|
||||
void* timer; |
||||
uint64_t timeout_ms; |
||||
|
||||
grpc_timer* original; |
||||
} grpc_custom_timer; |
||||
|
||||
typedef struct grpc_custom_timer_vtable { |
||||
void (*start)(grpc_custom_timer* t); |
||||
void (*stop)(grpc_custom_timer* t); |
||||
} grpc_custom_timer_vtable; |
||||
|
||||
void grpc_custom_timer_init(grpc_custom_timer_vtable* impl); |
||||
|
||||
void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error); |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_TIMER_CUSTOM_H */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue