mirror of https://github.com/grpc/grpc.git
commit
77bcd5a58a
109 changed files with 1858 additions and 1045 deletions
@ -0,0 +1,60 @@ |
|||||||
|
Server-side API for Authenticating Clients |
||||||
|
========================================== |
||||||
|
|
||||||
|
NOTE: This document describes how server-side authentication works in C-core based gRPC implementations only. In gRPC Java and Go, server side authentication is handled differently. |
||||||
|
|
||||||
|
## AuthContext |
||||||
|
|
||||||
|
To perform server-side authentication, gRPC exposes the *authentication context* for each call. The context exposes important authentication-related information about the RPC such as the type of security/authentication type being used and the peer identity. |
||||||
|
|
||||||
|
The authentication context is structured as a multi-map of key-value pairs - the *auth properties*. In addition to that, for authenticated RPCs, the set of properties corresponding to a selected key will represent the verified identity of the caller - the *peer identity*. |
||||||
|
|
||||||
|
The contents of the *auth properties* are populated by an *auth interceptor*. The interceptor also chooses which property key will act as the peer identity (e.g. for client certificate authentication this property will be `"x509_common_name"` or `"x509_subject_alternative_name"`). |
||||||
|
|
||||||
|
WARNING: AuthContext is the only reliable source of truth when it comes to authenticating RPCs. Using any other call/context properties for authentication purposes is wrong and inherently unsafe. |
||||||
|
|
||||||
|
####Example AuthContext contents |
||||||
|
|
||||||
|
For secure channel using mutual TLS authentication with both client and server certificates (test certificates from this repository are used). |
||||||
|
|
||||||
|
Populated auth properties: |
||||||
|
``` |
||||||
|
"transport_security_type": "ssl" # connection is secured using TLS/SSL |
||||||
|
"x509_common_name": "*.test.google.com" # from client's certificate |
||||||
|
"x509_pem_cert": "-----BEGIN CERTIFICATE-----\n..." # client's PEM encoded certificate |
||||||
|
"x509_subject_alternative_name": "*.test.google.fr" |
||||||
|
"x509_subject_alternative_name": "waterzooi.test.google.be" |
||||||
|
"x509_subject_alternative_name": "*.test.youtube.com" |
||||||
|
"x509_subject_alternative_name": "192.168.1.3" |
||||||
|
``` |
||||||
|
|
||||||
|
The peer identity is set of all properties named `"x509_subject_alternative_name"`: |
||||||
|
``` |
||||||
|
peer_identity_property_name = "x509_subject_alternative_name" |
||||||
|
``` |
||||||
|
|
||||||
|
## AuthProperty |
||||||
|
|
||||||
|
Auth properties are elements of the AuthContext. They have a name (a key of type string) and a value which can be a string or binary data. |
||||||
|
|
||||||
|
## Auth Interceptors |
||||||
|
|
||||||
|
Auth interceptors are gRPC components that populate contents of the auth context based on gRPC's internal state and/or call metadata. |
||||||
|
gRPC comes with some basic "interceptors" already built-in. |
||||||
|
|
||||||
|
WARNING: While there is a public API that allows anyone to write their own custom interceptor, please think twice before using it. |
||||||
|
There are legitimate uses for custom interceptors but you should keep in mind that as auth interceptors essentially decide which RPCs are authenticated and which are not, their code is very sensitive from the security perspective and getting things wrong might have serious consequences. If unsure, we strongly recommend to rely on official & proven interceptors that come with gRPC. |
||||||
|
|
||||||
|
####Available auth interceptors |
||||||
|
- TLS/SSL certificate authentication (built into gRPC's security layer, automatically used whenever you use a secure connection) |
||||||
|
- (coming soon) JWT auth token authentication |
||||||
|
- more will be added over time |
||||||
|
|
||||||
|
## Status (by language) |
||||||
|
C-core exposes low level API to access auth context contents and to implement an auth interceptor. |
||||||
|
In C++, the auth interceptor API is exposed as `AuthMetadataProcessor`. |
||||||
|
|
||||||
|
A high level API to access AuthContext contents is available in these languages: |
||||||
|
- C++ |
||||||
|
- C# (implementation in-progress) |
||||||
|
- other languages coming soon |
@ -1,159 +0,0 @@ |
|||||||
# Copyright 2015, Google Inc. |
|
||||||
# All rights reserved. |
|
||||||
# |
|
||||||
# Redistribution and use in source and binary forms, with or without |
|
||||||
# modification, are permitted provided that the following conditions are |
|
||||||
# met: |
|
||||||
# |
|
||||||
# * Redistributions of source code must retain the above copyright |
|
||||||
# notice, this list of conditions and the following disclaimer. |
|
||||||
# * Redistributions in binary form must reproduce the above |
|
||||||
# copyright notice, this list of conditions and the following disclaimer |
|
||||||
# in the documentation and/or other materials provided with the |
|
||||||
# distribution. |
|
||||||
# * Neither the name of Google Inc. nor the names of its |
|
||||||
# contributors may be used to endorse or promote products derived from |
|
||||||
# this software without specific prior written permission. |
|
||||||
# |
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
"""Affords a connectivity-state-listenable channel.""" |
|
||||||
|
|
||||||
import threading |
|
||||||
import time |
|
||||||
|
|
||||||
from grpc._adapter import _low |
|
||||||
from grpc._adapter import _types |
|
||||||
from grpc.beta import interfaces |
|
||||||
from grpc.framework.foundation import callable_util |
|
||||||
|
|
||||||
_CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = ( |
|
||||||
'Exception calling channel subscription callback!') |
|
||||||
|
|
||||||
_LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = { |
|
||||||
state: connectivity |
|
||||||
for state, connectivity in zip(_types.ConnectivityState, |
|
||||||
interfaces.ChannelConnectivity) |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
class ConnectivityChannel(object): |
|
||||||
|
|
||||||
def __init__(self, low_channel): |
|
||||||
self._lock = threading.Lock() |
|
||||||
self._low_channel = low_channel |
|
||||||
|
|
||||||
self._polling = False |
|
||||||
self._connectivity = None |
|
||||||
self._try_to_connect = False |
|
||||||
self._callbacks_and_connectivities = [] |
|
||||||
self._delivering = False |
|
||||||
|
|
||||||
def _deliveries(self, connectivity): |
|
||||||
callbacks_needing_update = [] |
|
||||||
for callback_and_connectivity in self._callbacks_and_connectivities: |
|
||||||
callback, callback_connectivity = callback_and_connectivity |
|
||||||
if callback_connectivity is not connectivity: |
|
||||||
callbacks_needing_update.append(callback) |
|
||||||
callback_and_connectivity[1] = connectivity |
|
||||||
return callbacks_needing_update |
|
||||||
|
|
||||||
def _deliver(self, initial_connectivity, initial_callbacks): |
|
||||||
connectivity = initial_connectivity |
|
||||||
callbacks = initial_callbacks |
|
||||||
while True: |
|
||||||
for callback in callbacks: |
|
||||||
callable_util.call_logging_exceptions( |
|
||||||
callback, _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE, |
|
||||||
connectivity) |
|
||||||
with self._lock: |
|
||||||
callbacks = self._deliveries(self._connectivity) |
|
||||||
if callbacks: |
|
||||||
connectivity = self._connectivity |
|
||||||
else: |
|
||||||
self._delivering = False |
|
||||||
return |
|
||||||
|
|
||||||
def _spawn_delivery(self, connectivity, callbacks): |
|
||||||
delivering_thread = threading.Thread( |
|
||||||
target=self._deliver, args=(connectivity, callbacks,)) |
|
||||||
delivering_thread.start() |
|
||||||
self._delivering = True |
|
||||||
|
|
||||||
# TODO(issue 3064): Don't poll. |
|
||||||
def _poll_connectivity(self, low_channel, initial_try_to_connect): |
|
||||||
try_to_connect = initial_try_to_connect |
|
||||||
low_connectivity = low_channel.check_connectivity_state(try_to_connect) |
|
||||||
with self._lock: |
|
||||||
self._connectivity = _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[ |
|
||||||
low_connectivity] |
|
||||||
callbacks = tuple( |
|
||||||
callback |
|
||||||
for callback, unused_but_known_to_be_none_connectivity in |
|
||||||
self._callbacks_and_connectivities) |
|
||||||
for callback_and_connectivity in self._callbacks_and_connectivities: |
|
||||||
callback_and_connectivity[1] = self._connectivity |
|
||||||
if callbacks: |
|
||||||
self._spawn_delivery(self._connectivity, callbacks) |
|
||||||
completion_queue = _low.CompletionQueue() |
|
||||||
while True: |
|
||||||
low_channel.watch_connectivity_state(low_connectivity, |
|
||||||
time.time() + 0.2, |
|
||||||
completion_queue, None) |
|
||||||
event = completion_queue.next() |
|
||||||
with self._lock: |
|
||||||
if not self._callbacks_and_connectivities and not self._try_to_connect: |
|
||||||
self._polling = False |
|
||||||
self._connectivity = None |
|
||||||
completion_queue.shutdown() |
|
||||||
break |
|
||||||
try_to_connect = self._try_to_connect |
|
||||||
self._try_to_connect = False |
|
||||||
if event.success or try_to_connect: |
|
||||||
low_connectivity = low_channel.check_connectivity_state( |
|
||||||
try_to_connect) |
|
||||||
with self._lock: |
|
||||||
self._connectivity = _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[ |
|
||||||
low_connectivity] |
|
||||||
if not self._delivering: |
|
||||||
callbacks = self._deliveries(self._connectivity) |
|
||||||
if callbacks: |
|
||||||
self._spawn_delivery(self._connectivity, callbacks) |
|
||||||
|
|
||||||
def subscribe(self, callback, try_to_connect): |
|
||||||
with self._lock: |
|
||||||
if not self._callbacks_and_connectivities and not self._polling: |
|
||||||
polling_thread = threading.Thread( |
|
||||||
target=self._poll_connectivity, |
|
||||||
args=(self._low_channel, bool(try_to_connect))) |
|
||||||
polling_thread.start() |
|
||||||
self._polling = True |
|
||||||
self._callbacks_and_connectivities.append([callback, None]) |
|
||||||
elif not self._delivering and self._connectivity is not None: |
|
||||||
self._spawn_delivery(self._connectivity, (callback,)) |
|
||||||
self._try_to_connect |= bool(try_to_connect) |
|
||||||
self._callbacks_and_connectivities.append( |
|
||||||
[callback, self._connectivity]) |
|
||||||
else: |
|
||||||
self._try_to_connect |= bool(try_to_connect) |
|
||||||
self._callbacks_and_connectivities.append([callback, None]) |
|
||||||
|
|
||||||
def unsubscribe(self, callback): |
|
||||||
with self._lock: |
|
||||||
for index, (subscribed_callback, unused_connectivity |
|
||||||
) in enumerate(self._callbacks_and_connectivities): |
|
||||||
if callback == subscribed_callback: |
|
||||||
self._callbacks_and_connectivities.pop(index) |
|
||||||
break |
|
||||||
|
|
||||||
def low_channel(self): |
|
||||||
return self._low_channel |
|
@ -0,0 +1,116 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2017, Google Inc. |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following disclaimer |
||||||
|
* in the documentation and/or other materials provided with the |
||||||
|
* distribution. |
||||||
|
* * Neither the name of Google Inc. nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived from |
||||||
|
* this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "src/core/ext/client_channel/parse_address.h" |
||||||
|
#include "src/core/lib/iomgr/sockaddr.h" |
||||||
|
|
||||||
|
#include <string.h> |
||||||
|
#ifdef GRPC_HAVE_UNIX_SOCKET |
||||||
|
#include <sys/un.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
#include "src/core/lib/iomgr/exec_ctx.h" |
||||||
|
#include "src/core/lib/iomgr/socket_utils.h" |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
#ifdef GRPC_HAVE_UNIX_SOCKET |
||||||
|
|
||||||
|
static void test_parse_unix(const char *uri_text, const char *pathname) { |
||||||
|
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
||||||
|
grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0); |
||||||
|
grpc_resolved_address addr; |
||||||
|
|
||||||
|
GPR_ASSERT(1 == parse_unix(uri, &addr)); |
||||||
|
struct sockaddr_un *addr_un = (struct sockaddr_un *)addr.addr; |
||||||
|
GPR_ASSERT(AF_UNIX == addr_un->sun_family); |
||||||
|
GPR_ASSERT(0 == strcmp(addr_un->sun_path, pathname)); |
||||||
|
|
||||||
|
grpc_uri_destroy(uri); |
||||||
|
grpc_exec_ctx_finish(&exec_ctx); |
||||||
|
} |
||||||
|
|
||||||
|
#else /* GRPC_HAVE_UNIX_SOCKET */ |
||||||
|
|
||||||
|
static void test_parse_unix(const char *uri_text, const char *pathname) {} |
||||||
|
|
||||||
|
#endif /* GRPC_HAVE_UNIX_SOCKET */ |
||||||
|
|
||||||
|
static void test_parse_ipv4(const char *uri_text, const char *host, |
||||||
|
unsigned short port) { |
||||||
|
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
||||||
|
grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0); |
||||||
|
grpc_resolved_address addr; |
||||||
|
char ntop_buf[INET_ADDRSTRLEN]; |
||||||
|
|
||||||
|
GPR_ASSERT(1 == parse_ipv4(uri, &addr)); |
||||||
|
struct sockaddr_in *addr_in = (struct sockaddr_in *)addr.addr; |
||||||
|
GPR_ASSERT(AF_INET == addr_in->sin_family); |
||||||
|
GPR_ASSERT(NULL != grpc_inet_ntop(AF_INET, &addr_in->sin_addr, ntop_buf, |
||||||
|
sizeof(ntop_buf))); |
||||||
|
GPR_ASSERT(0 == strcmp(ntop_buf, host)); |
||||||
|
GPR_ASSERT(ntohs(addr_in->sin_port) == port); |
||||||
|
|
||||||
|
grpc_uri_destroy(uri); |
||||||
|
grpc_exec_ctx_finish(&exec_ctx); |
||||||
|
} |
||||||
|
|
||||||
|
static void test_parse_ipv6(const char *uri_text, const char *host, |
||||||
|
unsigned short port, uint32_t scope_id) { |
||||||
|
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; |
||||||
|
grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0); |
||||||
|
grpc_resolved_address addr; |
||||||
|
char ntop_buf[INET6_ADDRSTRLEN]; |
||||||
|
|
||||||
|
GPR_ASSERT(1 == parse_ipv6(uri, &addr)); |
||||||
|
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr.addr; |
||||||
|
GPR_ASSERT(AF_INET6 == addr_in6->sin6_family); |
||||||
|
GPR_ASSERT(NULL != grpc_inet_ntop(AF_INET6, &addr_in6->sin6_addr, ntop_buf, |
||||||
|
sizeof(ntop_buf))); |
||||||
|
GPR_ASSERT(0 == strcmp(ntop_buf, host)); |
||||||
|
GPR_ASSERT(ntohs(addr_in6->sin6_port) == port); |
||||||
|
GPR_ASSERT(addr_in6->sin6_scope_id == scope_id); |
||||||
|
|
||||||
|
grpc_uri_destroy(uri); |
||||||
|
grpc_exec_ctx_finish(&exec_ctx); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char **argv) { |
||||||
|
grpc_test_init(argc, argv); |
||||||
|
|
||||||
|
test_parse_unix("unix:/path/name", "/path/name"); |
||||||
|
test_parse_ipv4("ipv4:192.0.2.1:12345", "192.0.2.1", 12345); |
||||||
|
test_parse_ipv6("ipv6:[2001:db8::1]:12345", "2001:db8::1", 12345, 0); |
||||||
|
test_parse_ipv6("ipv6:[2001:db8::1%252]:12345", "2001:db8::1", 12345, 2); |
||||||
|
} |
Binary file not shown.
@ -0,0 +1,58 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2017, Google Inc. |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above |
||||||
|
* copyright notice, this list of conditions and the following disclaimer |
||||||
|
* in the documentation and/or other materials provided with the |
||||||
|
* distribution. |
||||||
|
* * Neither the name of Google Inc. nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived from |
||||||
|
* this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "src/core/lib/transport/transport.h" |
||||||
|
|
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {} |
||||||
|
|
||||||
|
int main(int argc, char **argv) { |
||||||
|
grpc_test_init(argc, argv); |
||||||
|
|
||||||
|
uint8_t buffer[] = "abc123"; |
||||||
|
grpc_stream_refcount r; |
||||||
|
GRPC_STREAM_REF_INIT(&r, 1, do_nothing, NULL, "test"); |
||||||
|
GPR_ASSERT(r.refs.count == 1); |
||||||
|
grpc_slice slice = |
||||||
|
grpc_slice_from_stream_owned_buffer(&r, buffer, sizeof(buffer)); |
||||||
|
GPR_ASSERT(GRPC_SLICE_START_PTR(slice) == buffer); |
||||||
|
GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == sizeof(buffer)); |
||||||
|
GPR_ASSERT(r.refs.count == 2); |
||||||
|
grpc_slice_unref(slice); |
||||||
|
GPR_ASSERT(r.refs.count == 1); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -1,256 +0,0 @@ |
|||||||
/*
|
|
||||||
* |
|
||||||
* Copyright 2015, Google Inc. |
|
||||||
* All rights reserved. |
|
||||||
* |
|
||||||
* Redistribution and use in source and binary forms, with or without |
|
||||||
* modification, are permitted provided that the following conditions are |
|
||||||
* met: |
|
||||||
* |
|
||||||
* * Redistributions of source code must retain the above copyright |
|
||||||
* notice, this list of conditions and the following disclaimer. |
|
||||||
* * Redistributions in binary form must reproduce the above |
|
||||||
* copyright notice, this list of conditions and the following disclaimer |
|
||||||
* in the documentation and/or other materials provided with the |
|
||||||
* distribution. |
|
||||||
* * Neither the name of Google Inc. nor the names of its |
|
||||||
* contributors may be used to endorse or promote products derived from |
|
||||||
* this software without specific prior written permission. |
|
||||||
* |
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
* |
|
||||||
*/ |
|
||||||
|
|
||||||
#include "src/core/lib/iomgr/port.h" |
|
||||||
#include "test/core/util/test_config.h" |
|
||||||
#if defined(GRPC_POSIX_SOCKET) && defined(GRPC_TEST_PICK_PORT) |
|
||||||
|
|
||||||
#include "test/core/util/port.h" |
|
||||||
|
|
||||||
#include <errno.h> |
|
||||||
#include <netinet/in.h> |
|
||||||
#include <stdbool.h> |
|
||||||
#include <stdio.h> |
|
||||||
#include <string.h> |
|
||||||
#include <sys/socket.h> |
|
||||||
#include <unistd.h> |
|
||||||
|
|
||||||
#include <grpc/grpc.h> |
|
||||||
#include <grpc/support/alloc.h> |
|
||||||
#include <grpc/support/log.h> |
|
||||||
#include <grpc/support/string_util.h> |
|
||||||
|
|
||||||
#include "src/core/lib/http/httpcli.h" |
|
||||||
#include "src/core/lib/iomgr/resolve_address.h" |
|
||||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
|
||||||
#include "src/core/lib/support/env.h" |
|
||||||
#include "test/core/util/port_server_client.h" |
|
||||||
|
|
||||||
#define NUM_RANDOM_PORTS_TO_PICK 100 |
|
||||||
|
|
||||||
static int *chosen_ports = NULL; |
|
||||||
static size_t num_chosen_ports = 0; |
|
||||||
|
|
||||||
static int has_port_been_chosen(int port) { |
|
||||||
size_t i; |
|
||||||
for (i = 0; i < num_chosen_ports; i++) { |
|
||||||
if (chosen_ports[i] == port) { |
|
||||||
return 1; |
|
||||||
} |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
static int free_chosen_port(int port) { |
|
||||||
size_t i; |
|
||||||
int found = 0; |
|
||||||
size_t found_at = 0; |
|
||||||
char *env = gpr_getenv("GRPC_TEST_PORT_SERVER"); |
|
||||||
/* Find the port and erase it from the list, then tell the server it can be
|
|
||||||
freed. */ |
|
||||||
for (i = 0; i < num_chosen_ports; i++) { |
|
||||||
if (chosen_ports[i] == port) { |
|
||||||
GPR_ASSERT(found == 0); |
|
||||||
found = 1; |
|
||||||
found_at = i; |
|
||||||
} |
|
||||||
} |
|
||||||
if (found) { |
|
||||||
chosen_ports[found_at] = chosen_ports[num_chosen_ports - 1]; |
|
||||||
num_chosen_ports--; |
|
||||||
if (env) { |
|
||||||
grpc_free_port_using_server(env, port); |
|
||||||
} |
|
||||||
} |
|
||||||
gpr_free(env); |
|
||||||
return found; |
|
||||||
} |
|
||||||
|
|
||||||
static void free_chosen_ports(void) { |
|
||||||
char *env = gpr_getenv("GRPC_TEST_PORT_SERVER"); |
|
||||||
if (env != NULL) { |
|
||||||
size_t i; |
|
||||||
for (i = 0; i < num_chosen_ports; i++) { |
|
||||||
grpc_free_port_using_server(env, chosen_ports[i]); |
|
||||||
} |
|
||||||
gpr_free(env); |
|
||||||
} |
|
||||||
|
|
||||||
gpr_free(chosen_ports); |
|
||||||
} |
|
||||||
|
|
||||||
static void chose_port(int port) { |
|
||||||
if (chosen_ports == NULL) { |
|
||||||
atexit(free_chosen_ports); |
|
||||||
} |
|
||||||
num_chosen_ports++; |
|
||||||
chosen_ports = gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports); |
|
||||||
chosen_ports[num_chosen_ports - 1] = port; |
|
||||||
} |
|
||||||
|
|
||||||
static bool is_port_available(int *port, bool is_tcp) { |
|
||||||
GPR_ASSERT(*port >= 0); |
|
||||||
GPR_ASSERT(*port <= 65535); |
|
||||||
|
|
||||||
/* For a port to be considered available, the kernel must support
|
|
||||||
at least one of (IPv6, IPv4), and the port must be available |
|
||||||
on each supported family. */ |
|
||||||
bool got_socket = false; |
|
||||||
for (int is_ipv6 = 1; is_ipv6 >= 0; is_ipv6--) { |
|
||||||
const int fd = |
|
||||||
socket(is_ipv6 ? AF_INET6 : AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, |
|
||||||
is_tcp ? IPPROTO_TCP : 0); |
|
||||||
if (fd >= 0) { |
|
||||||
got_socket = true; |
|
||||||
} else { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
/* Reuseaddr lets us start up a server immediately after it exits */ |
|
||||||
const int one = 1; |
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { |
|
||||||
gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno)); |
|
||||||
close(fd); |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/* Try binding to port */ |
|
||||||
grpc_resolved_address addr; |
|
||||||
if (is_ipv6) { |
|
||||||
grpc_sockaddr_make_wildcard6(*port, &addr); /* [::]:port */ |
|
||||||
} else { |
|
||||||
grpc_sockaddr_make_wildcard4(*port, &addr); /* 0.0.0.0:port */ |
|
||||||
} |
|
||||||
if (bind(fd, (struct sockaddr *)addr.addr, (socklen_t)addr.len) < 0) { |
|
||||||
gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno)); |
|
||||||
close(fd); |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
/* Get the bound port number */ |
|
||||||
if (getsockname(fd, (struct sockaddr *)addr.addr, (socklen_t *)&addr.len) < |
|
||||||
0) { |
|
||||||
gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno)); |
|
||||||
close(fd); |
|
||||||
return false; |
|
||||||
} |
|
||||||
GPR_ASSERT(addr.len <= sizeof(addr.addr)); |
|
||||||
const int actual_port = grpc_sockaddr_get_port(&addr); |
|
||||||
GPR_ASSERT(actual_port > 0); |
|
||||||
if (*port == 0) { |
|
||||||
*port = actual_port; |
|
||||||
} else { |
|
||||||
GPR_ASSERT(*port == actual_port); |
|
||||||
} |
|
||||||
|
|
||||||
close(fd); |
|
||||||
} |
|
||||||
if (!got_socket) { |
|
||||||
gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno)); |
|
||||||
return false; |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
int grpc_pick_unused_port(void) { |
|
||||||
/* We repeatedly pick a port and then see whether or not it is
|
|
||||||
available for use both as a TCP socket and a UDP socket. First, we |
|
||||||
pick a random large port number. For subsequent |
|
||||||
iterations, we bind to an anonymous port and let the OS pick the |
|
||||||
port number. The random port picking reduces the probability of |
|
||||||
races with other processes on kernels that want to reuse the same |
|
||||||
port numbers over and over. */ |
|
||||||
|
|
||||||
/* In alternating iterations we trial UDP ports before TCP ports UDP
|
|
||||||
ports -- it could be the case that this machine has been using up |
|
||||||
UDP ports and they are scarcer. */ |
|
||||||
|
|
||||||
/* Type of port to first pick in next iteration */ |
|
||||||
bool is_tcp = true; |
|
||||||
int trial = 0; |
|
||||||
|
|
||||||
char *env = gpr_getenv("GRPC_TEST_PORT_SERVER"); |
|
||||||
if (env) { |
|
||||||
int port = grpc_pick_port_using_server(env); |
|
||||||
gpr_free(env); |
|
||||||
if (port != 0) { |
|
||||||
chose_port(port); |
|
||||||
} |
|
||||||
return port; |
|
||||||
} |
|
||||||
|
|
||||||
for (;;) { |
|
||||||
int port; |
|
||||||
trial++; |
|
||||||
if (trial == 1) { |
|
||||||
port = getpid() % (65536 - 30000) + 30000; |
|
||||||
} else if (trial <= NUM_RANDOM_PORTS_TO_PICK) { |
|
||||||
port = rand() % (65536 - 30000) + 30000; |
|
||||||
} else { |
|
||||||
port = 0; |
|
||||||
} |
|
||||||
|
|
||||||
if (has_port_been_chosen(port)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
if (!is_port_available(&port, is_tcp)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
GPR_ASSERT(port > 0); |
|
||||||
/* Check that the port # is free for the other type of socket also */ |
|
||||||
if (!is_port_available(&port, !is_tcp)) { |
|
||||||
/* In the next iteration trial to bind to the other type first
|
|
||||||
because perhaps it is more rare. */ |
|
||||||
is_tcp = !is_tcp; |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
chose_port(port); |
|
||||||
return port; |
|
||||||
} |
|
||||||
|
|
||||||
/* The port iterator reached the end without finding a suitable port. */ |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
int grpc_pick_unused_port_or_die(void) { |
|
||||||
int port = grpc_pick_unused_port(); |
|
||||||
GPR_ASSERT(port > 0); |
|
||||||
return port; |
|
||||||
} |
|
||||||
|
|
||||||
void grpc_recycle_unused_port(int port) { GPR_ASSERT(free_chosen_port(port)); } |
|
||||||
|
|
||||||
#endif /* GRPC_POSIX_SOCKET && GRPC_TEST_PICK_PORT */ |
|
@ -1,247 +0,0 @@ |
|||||||
/*
|
|
||||||
* |
|
||||||
* Copyright 2015, Google Inc. |
|
||||||
* All rights reserved. |
|
||||||
* |
|
||||||
* Redistribution and use in source and binary forms, with or without |
|
||||||
* modification, are permitted provided that the following conditions are |
|
||||||
* met: |
|
||||||
* |
|
||||||
* * Redistributions of source code must retain the above copyright |
|
||||||
* notice, this list of conditions and the following disclaimer. |
|
||||||
* * Redistributions in binary form must reproduce the above |
|
||||||
* copyright notice, this list of conditions and the following disclaimer |
|
||||||
* in the documentation and/or other materials provided with the |
|
||||||
* distribution. |
|
||||||
* * Neither the name of Google Inc. nor the names of its |
|
||||||
* contributors may be used to endorse or promote products derived from |
|
||||||
* this software without specific prior written permission. |
|
||||||
* |
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
* |
|
||||||
*/ |
|
||||||
|
|
||||||
#include "src/core/lib/iomgr/port.h" |
|
||||||
#include "test/core/util/test_config.h" |
|
||||||
#if defined(GRPC_WINSOCK_SOCKET) && defined(GRPC_TEST_PICK_PORT) |
|
||||||
|
|
||||||
#include "src/core/lib/iomgr/sockaddr.h" |
|
||||||
|
|
||||||
#include "test/core/util/port.h" |
|
||||||
|
|
||||||
#include <errno.h> |
|
||||||
#include <process.h> |
|
||||||
#include <stdio.h> |
|
||||||
#include <string.h> |
|
||||||
|
|
||||||
#include <grpc/grpc.h> |
|
||||||
#include <grpc/support/alloc.h> |
|
||||||
#include <grpc/support/log.h> |
|
||||||
|
|
||||||
#include "src/core/lib/http/httpcli.h" |
|
||||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
|
||||||
#include "src/core/lib/support/env.h" |
|
||||||
#include "test/core/util/port_server_client.h" |
|
||||||
|
|
||||||
#if GPR_GETPID_IN_UNISTD_H |
|
||||||
#include <sys/unistd.h> |
|
||||||
static int _getpid() { return getpid(); } |
|
||||||
#endif |
|
||||||
|
|
||||||
#define NUM_RANDOM_PORTS_TO_PICK 100 |
|
||||||
|
|
||||||
static int *chosen_ports = NULL; |
|
||||||
static size_t num_chosen_ports = 0; |
|
||||||
|
|
||||||
static int has_port_been_chosen(int port) { |
|
||||||
size_t i; |
|
||||||
for (i = 0; i < num_chosen_ports; i++) { |
|
||||||
if (chosen_ports[i] == port) { |
|
||||||
return 1; |
|
||||||
} |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
static int free_chosen_port(int port) { |
|
||||||
size_t i; |
|
||||||
int found = 0; |
|
||||||
size_t found_at = 0; |
|
||||||
char *env = gpr_getenv("GRPC_TEST_PORT_SERVER"); |
|
||||||
if (env != NULL) { |
|
||||||
/* Find the port and erase it from the list, then tell the server it can be
|
|
||||||
freed. */ |
|
||||||
for (i = 0; i < num_chosen_ports; i++) { |
|
||||||
if (chosen_ports[i] == port) { |
|
||||||
GPR_ASSERT(found == 0); |
|
||||||
found = 1; |
|
||||||
found_at = i; |
|
||||||
} |
|
||||||
} |
|
||||||
if (found) { |
|
||||||
chosen_ports[found_at] = chosen_ports[num_chosen_ports - 1]; |
|
||||||
grpc_free_port_using_server(env, port); |
|
||||||
num_chosen_ports--; |
|
||||||
} |
|
||||||
} |
|
||||||
return found; |
|
||||||
} |
|
||||||
|
|
||||||
static void free_chosen_ports(void) { |
|
||||||
char *env = gpr_getenv("GRPC_TEST_PORT_SERVER"); |
|
||||||
if (env != NULL) { |
|
||||||
size_t i; |
|
||||||
for (i = 0; i < num_chosen_ports; i++) { |
|
||||||
grpc_free_port_using_server(env, chosen_ports[i]); |
|
||||||
} |
|
||||||
gpr_free(env); |
|
||||||
} |
|
||||||
|
|
||||||
gpr_free(chosen_ports); |
|
||||||
} |
|
||||||
|
|
||||||
static void chose_port(int port) { |
|
||||||
if (chosen_ports == NULL) { |
|
||||||
atexit(free_chosen_ports); |
|
||||||
} |
|
||||||
num_chosen_ports++; |
|
||||||
chosen_ports = gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports); |
|
||||||
chosen_ports[num_chosen_ports - 1] = port; |
|
||||||
} |
|
||||||
|
|
||||||
static int is_port_available(int *port, int is_tcp) { |
|
||||||
const int proto = is_tcp ? IPPROTO_TCP : 0; |
|
||||||
const SOCKET fd = socket(AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, proto); |
|
||||||
int one = 1; |
|
||||||
struct sockaddr_in addr; |
|
||||||
socklen_t alen = sizeof(addr); |
|
||||||
int actual_port; |
|
||||||
|
|
||||||
GPR_ASSERT(*port >= 0); |
|
||||||
GPR_ASSERT(*port <= 65535); |
|
||||||
if (INVALID_SOCKET == fd) { |
|
||||||
gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno)); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
/* Reuseaddr lets us start up a server immediately after it exits */ |
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, |
|
||||||
sizeof(one)) < 0) { |
|
||||||
gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno)); |
|
||||||
closesocket(fd); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
/* Try binding to port */ |
|
||||||
addr.sin_family = AF_INET; |
|
||||||
addr.sin_addr.s_addr = INADDR_ANY; |
|
||||||
addr.sin_port = htons((u_short)*port); |
|
||||||
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { |
|
||||||
gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno)); |
|
||||||
closesocket(fd); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
/* Get the bound port number */ |
|
||||||
if (getsockname(fd, (struct sockaddr *)&addr, &alen) < 0) { |
|
||||||
gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno)); |
|
||||||
closesocket(fd); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
GPR_ASSERT(alen <= (socklen_t)sizeof(addr)); |
|
||||||
actual_port = ntohs(addr.sin_port); |
|
||||||
GPR_ASSERT(actual_port > 0); |
|
||||||
if (*port == 0) { |
|
||||||
*port = actual_port; |
|
||||||
} else { |
|
||||||
GPR_ASSERT(*port == actual_port); |
|
||||||
} |
|
||||||
|
|
||||||
closesocket(fd); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
int grpc_pick_unused_port(void) { |
|
||||||
/* We repeatedly pick a port and then see whether or not it is
|
|
||||||
available for use both as a TCP socket and a UDP socket. First, we |
|
||||||
pick a random large port number. For subsequent |
|
||||||
iterations, we bind to an anonymous port and let the OS pick the |
|
||||||
port number. The random port picking reduces the probability of |
|
||||||
races with other processes on kernels that want to reuse the same |
|
||||||
port numbers over and over. */ |
|
||||||
|
|
||||||
/* In alternating iterations we trial UDP ports before TCP ports UDP
|
|
||||||
ports -- it could be the case that this machine has been using up |
|
||||||
UDP ports and they are scarcer. */ |
|
||||||
|
|
||||||
/* Type of port to first pick in next iteration */ |
|
||||||
int is_tcp = 1; |
|
||||||
int trial = 0; |
|
||||||
|
|
||||||
char *env = gpr_getenv("GRPC_TEST_PORT_SERVER"); |
|
||||||
if (env) { |
|
||||||
int port = grpc_pick_port_using_server(env); |
|
||||||
gpr_free(env); |
|
||||||
if (port != 0) { |
|
||||||
return port; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for (;;) { |
|
||||||
int port; |
|
||||||
trial++; |
|
||||||
if (trial == 1) { |
|
||||||
port = _getpid() % (65536 - 30000) + 30000; |
|
||||||
} else if (trial <= NUM_RANDOM_PORTS_TO_PICK) { |
|
||||||
port = rand() % (65536 - 30000) + 30000; |
|
||||||
} else { |
|
||||||
port = 0; |
|
||||||
} |
|
||||||
|
|
||||||
if (has_port_been_chosen(port)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
if (!is_port_available(&port, is_tcp)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
GPR_ASSERT(port > 0); |
|
||||||
/* Check that the port # is free for the other type of socket also */ |
|
||||||
if (!is_port_available(&port, !is_tcp)) { |
|
||||||
/* In the next iteration trial to bind to the other type first
|
|
||||||
because perhaps it is more rare. */ |
|
||||||
is_tcp = !is_tcp; |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
/* TODO(ctiller): consider caching this port in some structure, to avoid
|
|
||||||
handing it out again */ |
|
||||||
|
|
||||||
chose_port(port); |
|
||||||
return port; |
|
||||||
} |
|
||||||
|
|
||||||
/* The port iterator reached the end without finding a suitable port. */ |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
int grpc_pick_unused_port_or_die(void) { |
|
||||||
int port = grpc_pick_unused_port(); |
|
||||||
GPR_ASSERT(port > 0); |
|
||||||
return port; |
|
||||||
} |
|
||||||
|
|
||||||
void grpc_recycle_unused_port(int port) { GPR_ASSERT(free_chosen_port(port)); } |
|
||||||
|
|
||||||
#endif /* GRPC_WINSOCK_SOCKET && GRPC_TEST_PICK_PORT */ |
|
@ -0,0 +1,73 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
# Copyright 2017, Google Inc. |
||||||
|
# All rights reserved. |
||||||
|
# |
||||||
|
# Redistribution and use in source and binary forms, with or without |
||||||
|
# modification, are permitted provided that the following conditions are |
||||||
|
# met: |
||||||
|
# |
||||||
|
# * Redistributions of source code must retain the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer. |
||||||
|
# * Redistributions in binary form must reproduce the above |
||||||
|
# copyright notice, this list of conditions and the following disclaimer |
||||||
|
# in the documentation and/or other materials provided with the |
||||||
|
# distribution. |
||||||
|
# * Neither the name of Google Inc. nor the names of its |
||||||
|
# contributors may be used to endorse or promote products derived from |
||||||
|
# this software without specific prior written permission. |
||||||
|
# |
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
# |
||||||
|
# A frozen version of run_full_performance.sh that runs full performance test |
||||||
|
# suite for the latest released stable version of gRPC. |
||||||
|
set -ex |
||||||
|
|
||||||
|
# Enter the gRPC repo root |
||||||
|
cd $(dirname $0)/../.. |
||||||
|
|
||||||
|
# run 8core client vs 8core server |
||||||
|
tools/run_tests/run_performance_tests.py \ |
||||||
|
-l c++ csharp node ruby java python go node_express \ |
||||||
|
--netperf \ |
||||||
|
--category scalable \ |
||||||
|
--bq_result_table performance_released.performance_experiment \ |
||||||
|
--remote_worker_host grpc-performance-server-8core grpc-performance-client-8core grpc-performance-client2-8core \ |
||||||
|
--xml_report report_8core.xml \ |
||||||
|
|| EXIT_CODE=1 |
||||||
|
|
||||||
|
# prevent pushing leftover build files to remote hosts in the next step. |
||||||
|
git clean -fdxq --exclude='report*.xml' |
||||||
|
|
||||||
|
# scalability with 32cores (and upload to a different BQ table) |
||||||
|
tools/run_tests/run_performance_tests.py \ |
||||||
|
-l c++ java csharp go \ |
||||||
|
--netperf \ |
||||||
|
--category scalable \ |
||||||
|
--bq_result_table performance_released.performance_experiment_32core \ |
||||||
|
--remote_worker_host grpc-performance-server-32core grpc-performance-client-32core grpc-performance-client2-32core \ |
||||||
|
--xml_report report_32core.xml \ |
||||||
|
|| EXIT_CODE=1 |
||||||
|
|
||||||
|
# prevent pushing leftover build files to remote hosts in the next step. |
||||||
|
git clean -fdxq --exclude='report*.xml' |
||||||
|
|
||||||
|
# selected scenarios on Windows |
||||||
|
tools/run_tests/run_performance_tests.py \ |
||||||
|
-l csharp \ |
||||||
|
--category scalable \ |
||||||
|
--bq_result_table performance_released.performance_experiment_windows \ |
||||||
|
--remote_worker_host grpc-performance-windows1 grpc-performance-windows2 \ |
||||||
|
--xml_report report_windows.xml \ |
||||||
|
|| EXIT_CODE=1 |
||||||
|
|
||||||
|
exit $EXIT_CODE |
@ -0,0 +1,46 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
|
||||||
|
# Copyright 2017, Google Inc. |
||||||
|
# All rights reserved. |
||||||
|
# |
||||||
|
# Redistribution and use in source and binary forms, with or without |
||||||
|
# modification, are permitted provided that the following conditions are |
||||||
|
# met: |
||||||
|
# |
||||||
|
# * Redistributions of source code must retain the above copyright |
||||||
|
# notice, this list of conditions and the following disclaimer. |
||||||
|
# * Redistributions in binary form must reproduce the above |
||||||
|
# copyright notice, this list of conditions and the following disclaimer |
||||||
|
# in the documentation and/or other materials provided with the |
||||||
|
# distribution. |
||||||
|
# * Neither the name of Google Inc. nor the names of its |
||||||
|
# contributors may be used to endorse or promote products derived from |
||||||
|
# this software without specific prior written permission. |
||||||
|
# |
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
""" |
||||||
|
Wrapper around port server starting code. |
||||||
|
|
||||||
|
Used by developers who wish to run individual C/C++ tests outside of the |
||||||
|
run_tests.py infrastructure. |
||||||
|
|
||||||
|
The path to this file is called out in test/core/util/port.c, and printed as |
||||||
|
an error message to users. |
||||||
|
""" |
||||||
|
|
||||||
|
import python_utils.start_port_server as start_port_server |
||||||
|
|
||||||
|
start_port_server.start_port_server() |
||||||
|
|
||||||
|
print "Port server started successfully" |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue