* add a fake TCP and UDP server to test/core/utilpull/28351/head
parent
32770542b2
commit
2a4b7f25e6
13 changed files with 473 additions and 388 deletions
@ -0,0 +1,269 @@ |
||||
//
|
||||
// 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 "fake_udp_and_tcp_server.h" |
||||
|
||||
#include "absl/strings/match.h" |
||||
#include "absl/strings/str_cat.h" |
||||
|
||||
#include "src/core/lib/event_engine/sockaddr.h" |
||||
#include "test/core/util/port.h" |
||||
|
||||
#ifdef GPR_WINDOWS |
||||
#include "src/core/lib/iomgr/sockaddr_windows.h" |
||||
#include "src/core/lib/iomgr/socket_windows.h" |
||||
#include "src/core/lib/iomgr/tcp_windows.h" |
||||
#define BAD_SOCKET_RETURN_VAL INVALID_SOCKET |
||||
#define CLOSE_SOCKET closesocket |
||||
#else |
||||
#include <fcntl.h> |
||||
|
||||
#include "src/core/lib/iomgr/sockaddr_posix.h" |
||||
#define BAD_SOCKET_RETURN_VAL (-1) |
||||
#define CLOSE_SOCKET close |
||||
#endif |
||||
|
||||
namespace grpc_core { |
||||
namespace testing { |
||||
|
||||
FakeUdpAndTcpServer::FakeUdpAndTcpServer( |
||||
AcceptMode accept_mode, |
||||
std::function<FakeUdpAndTcpServer::ProcessReadResult(int, int, int)> |
||||
process_read_cb) |
||||
: accept_mode_(accept_mode), process_read_cb_(std::move(process_read_cb)) { |
||||
port_ = grpc_pick_unused_port_or_die(); |
||||
udp_socket_ = socket(AF_INET6, SOCK_DGRAM, 0); |
||||
if (udp_socket_ == BAD_SOCKET_RETURN_VAL) { |
||||
gpr_log(GPR_DEBUG, "Failed to create UDP ipv6 socket: %d", errno); |
||||
GPR_ASSERT(0); |
||||
} |
||||
accept_socket_ = socket(AF_INET6, SOCK_STREAM, 0); |
||||
address_ = absl::StrCat("[::]:", port_); |
||||
if (accept_socket_ == BAD_SOCKET_RETURN_VAL) { |
||||
gpr_log(GPR_ERROR, "Failed to create TCP IPv6 socket: %d", errno); |
||||
GPR_ASSERT(0); |
||||
} |
||||
#ifdef GPR_WINDOWS |
||||
char val = 1; |
||||
if (setsockopt(accept_socket_, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == |
||||
SOCKET_ERROR) { |
||||
gpr_log(GPR_DEBUG, |
||||
"Failed to set SO_REUSEADDR on TCP ipv6 socket to [::1]:%d, " |
||||
"errno: %d", |
||||
port_, errno); |
||||
GPR_ASSERT(0); |
||||
} |
||||
grpc_error_handle set_non_block_error; |
||||
set_non_block_error = grpc_tcp_set_non_block(udp_socket_); |
||||
if (set_non_block_error != GRPC_ERROR_NONE) { |
||||
gpr_log(GPR_ERROR, "Failed to configure non-blocking socket: %s", |
||||
grpc_error_std_string(set_non_block_error).c_str()); |
||||
GPR_ASSERT(0); |
||||
} |
||||
set_non_block_error = grpc_tcp_set_non_block(accept_socket_); |
||||
if (set_non_block_error != GRPC_ERROR_NONE) { |
||||
gpr_log(GPR_ERROR, "Failed to configure non-blocking socket: %s", |
||||
grpc_error_std_string(set_non_block_error).c_str()); |
||||
GPR_ASSERT(0); |
||||
} |
||||
#else |
||||
int val = 1; |
||||
if (setsockopt(accept_socket_, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != |
||||
0) { |
||||
gpr_log(GPR_DEBUG, "Failed to set SO_REUSEADDR on socket [::1]:%d", port_); |
||||
GPR_ASSERT(0); |
||||
} |
||||
if (fcntl(udp_socket_, F_SETFL, O_NONBLOCK) != 0) { |
||||
gpr_log(GPR_ERROR, "Failed to set O_NONBLOCK on socket: %d", errno); |
||||
GPR_ASSERT(0); |
||||
} |
||||
if (fcntl(accept_socket_, F_SETFL, O_NONBLOCK) != 0) { |
||||
gpr_log(GPR_ERROR, "Failed to set O_NONBLOCK on socket: %d", errno); |
||||
GPR_ASSERT(0); |
||||
} |
||||
#endif |
||||
sockaddr_in6 addr; |
||||
memset(&addr, 0, sizeof(addr)); |
||||
addr.sin6_family = AF_INET6; |
||||
addr.sin6_port = htons(port_); |
||||
(reinterpret_cast<char*>(&addr.sin6_addr))[15] = 1; |
||||
if (bind(udp_socket_, reinterpret_cast<const sockaddr*>(&addr), |
||||
sizeof(addr)) != 0) { |
||||
gpr_log(GPR_DEBUG, "Failed to bind UDP socket to [::1]:%d", port_); |
||||
GPR_ASSERT(0); |
||||
} |
||||
if (bind(accept_socket_, reinterpret_cast<const sockaddr*>(&addr), |
||||
sizeof(addr)) != 0) { |
||||
gpr_log(GPR_ERROR, "Failed to bind TCP socket to [::1]:%d : %d", port_, |
||||
errno); |
||||
GPR_ASSERT(0); |
||||
} |
||||
if (listen(accept_socket_, 100)) { |
||||
gpr_log(GPR_ERROR, "Failed to listen on socket bound to [::1]:%d : %d", |
||||
port_, errno); |
||||
GPR_ASSERT(0); |
||||
} |
||||
gpr_event_init(&stop_ev_); |
||||
run_server_loop_thd_ = absl::make_unique<std::thread>( |
||||
std::bind(&FakeUdpAndTcpServer::RunServerLoop, this)); |
||||
} |
||||
|
||||
FakeUdpAndTcpServer::~FakeUdpAndTcpServer() { |
||||
gpr_log(GPR_DEBUG, |
||||
"FakeUdpAndTcpServer stop and " |
||||
"join server thread"); |
||||
gpr_event_set(&stop_ev_, reinterpret_cast<void*>(1)); |
||||
run_server_loop_thd_->join(); |
||||
gpr_log(GPR_DEBUG, |
||||
"FakeUdpAndTcpServer join server " |
||||
"thread complete"); |
||||
CLOSE_SOCKET(accept_socket_); |
||||
CLOSE_SOCKET(udp_socket_); |
||||
} |
||||
|
||||
FakeUdpAndTcpServer::ProcessReadResult |
||||
FakeUdpAndTcpServer::CloseSocketUponReceivingBytesFromPeer( |
||||
int bytes_received_size, int read_error, int s) { |
||||
if (bytes_received_size < 0 && read_error != EAGAIN && |
||||
read_error != EWOULDBLOCK) { |
||||
gpr_log(GPR_ERROR, "Failed to receive from peer socket: %d. errno: %d", s, |
||||
errno); |
||||
GPR_ASSERT(0); |
||||
} |
||||
if (bytes_received_size >= 0) { |
||||
gpr_log(GPR_DEBUG, |
||||
"Fake TCP server received %d bytes from peer socket: %d. Close " |
||||
"the " |
||||
"connection.", |
||||
bytes_received_size, s); |
||||
return FakeUdpAndTcpServer::ProcessReadResult::kCloseSocket; |
||||
} |
||||
return FakeUdpAndTcpServer::ProcessReadResult::kContinueReading; |
||||
} |
||||
|
||||
FakeUdpAndTcpServer::ProcessReadResult |
||||
FakeUdpAndTcpServer::CloseSocketUponCloseFromPeer(int bytes_received_size, |
||||
int read_error, int s) { |
||||
if (bytes_received_size < 0 && read_error != EAGAIN && |
||||
read_error != EWOULDBLOCK) { |
||||
gpr_log(GPR_ERROR, "Failed to receive from peer socket: %d. errno: %d", s, |
||||
errno); |
||||
GPR_ASSERT(0); |
||||
} |
||||
if (bytes_received_size == 0) { |
||||
// The peer has shut down the connection.
|
||||
gpr_log(GPR_DEBUG, |
||||
"Fake TCP server received 0 bytes from peer socket: %d. Close " |
||||
"the " |
||||
"connection.", |
||||
s); |
||||
return FakeUdpAndTcpServer::ProcessReadResult::kCloseSocket; |
||||
} |
||||
return FakeUdpAndTcpServer::ProcessReadResult::kContinueReading; |
||||
} |
||||
|
||||
FakeUdpAndTcpServer::FakeUdpAndTcpServerPeer::FakeUdpAndTcpServerPeer(int fd) |
||||
: fd_(fd) {} |
||||
|
||||
FakeUdpAndTcpServer::FakeUdpAndTcpServerPeer::~FakeUdpAndTcpServerPeer() { |
||||
CLOSE_SOCKET(fd_); |
||||
} |
||||
|
||||
void FakeUdpAndTcpServer::FakeUdpAndTcpServerPeer:: |
||||
MaybeContinueSendingSettings() { |
||||
// https://tools.ietf.org/html/rfc7540#section-4.1
|
||||
const std::vector<char> kEmptyHttp2SettingsFrame = { |
||||
0x00, 0x00, 0x00, // length
|
||||
0x04, // settings type
|
||||
0x00, // flags
|
||||
0x00, 0x00, 0x00, 0x00 // stream identifier
|
||||
}; |
||||
if (total_bytes_sent_ < int(kEmptyHttp2SettingsFrame.size())) { |
||||
int bytes_to_send = kEmptyHttp2SettingsFrame.size() - total_bytes_sent_; |
||||
int bytes_sent = |
||||
send(fd_, kEmptyHttp2SettingsFrame.data() + total_bytes_sent_, |
||||
bytes_to_send, 0); |
||||
if (bytes_sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { |
||||
gpr_log(GPR_ERROR, |
||||
"Fake TCP server encountered unexpected error:%d |%s| " |
||||
"sending %d bytes on fd:%d", |
||||
errno, strerror(errno), bytes_to_send, fd_); |
||||
GPR_ASSERT(0); |
||||
} else if (bytes_sent > 0) { |
||||
total_bytes_sent_ += bytes_sent; |
||||
GPR_ASSERT(total_bytes_sent_ <= int(kEmptyHttp2SettingsFrame.size())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void FakeUdpAndTcpServer::ReadFromUdpSocket() { |
||||
char buf[100]; |
||||
recvfrom(udp_socket_, buf, sizeof(buf), 0, nullptr, nullptr); |
||||
} |
||||
|
||||
void FakeUdpAndTcpServer::RunServerLoop() { |
||||
std::set<std::unique_ptr<FakeUdpAndTcpServerPeer>> peers; |
||||
while (!gpr_event_get(&stop_ev_)) { |
||||
// handle TCP connections
|
||||
int p = accept(accept_socket_, nullptr, nullptr); |
||||
if (p != BAD_SOCKET_RETURN_VAL) { |
||||
gpr_log(GPR_DEBUG, "accepted peer socket: %d", p); |
||||
#ifdef GPR_WINDOWS |
||||
grpc_error_handle set_non_block_error; |
||||
set_non_block_error = grpc_tcp_set_non_block(p); |
||||
if (set_non_block_error != GRPC_ERROR_NONE) { |
||||
gpr_log(GPR_ERROR, "Failed to configure non-blocking socket: %s", |
||||
grpc_error_std_string(set_non_block_error).c_str()); |
||||
GPR_ASSERT(0); |
||||
} |
||||
#else |
||||
if (fcntl(p, F_SETFL, O_NONBLOCK) != 0) { |
||||
gpr_log(GPR_ERROR, "Failed to configure non-blocking socket, errno: %d", |
||||
errno); |
||||
GPR_ASSERT(0); |
||||
} |
||||
#endif |
||||
peers.insert(absl::make_unique<FakeUdpAndTcpServerPeer>(p)); |
||||
} |
||||
auto it = peers.begin(); |
||||
while (it != peers.end()) { |
||||
FakeUdpAndTcpServerPeer* peer = (*it).get(); |
||||
if (accept_mode_ == AcceptMode::kEagerlySendSettings) { |
||||
peer->MaybeContinueSendingSettings(); |
||||
} |
||||
char buf[100]; |
||||
int bytes_received_size = recv(peer->fd(), buf, 100, 0); |
||||
FakeUdpAndTcpServer::ProcessReadResult r = |
||||
process_read_cb_(bytes_received_size, errno, peer->fd()); |
||||
if (r == FakeUdpAndTcpServer::ProcessReadResult::kCloseSocket) { |
||||
it = peers.erase(it); |
||||
} else { |
||||
GPR_ASSERT(r == |
||||
FakeUdpAndTcpServer::ProcessReadResult::kContinueReading); |
||||
it++; |
||||
} |
||||
} |
||||
// read from the UDP socket
|
||||
ReadFromUdpSocket(); |
||||
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), |
||||
gpr_time_from_millis(10, GPR_TIMESPAN))); |
||||
} |
||||
} |
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc_core
|
@ -0,0 +1,137 @@ |
||||
//
|
||||
// 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 <functional> |
||||
#include <set> |
||||
#include <string> |
||||
#include <thread> |
||||
|
||||
#include "absl/memory/memory.h" |
||||
|
||||
#include <grpc/slice.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
namespace grpc_core { |
||||
namespace testing { |
||||
|
||||
// This class is used to simulate a variety of network conditions in
|
||||
// unit tests.
|
||||
//
|
||||
// Note that resulting server only listens on the IPv6 loopback
|
||||
// address, "[::1]". This is expected to be OK as all known gRPC unit test
|
||||
// environments have this address available.
|
||||
//
|
||||
// As examples, this can be used to (but is not limited to) exercise
|
||||
// the following cases:
|
||||
//
|
||||
// 1) DNS resolver's UDP requests experience packet loss:
|
||||
//
|
||||
// testing::FakeUdpAndTcpServer fake_dns_server(
|
||||
// testing::FakeUdpAndTcpServer::AcceptMode::
|
||||
// kWaitForClientToSendFirstBytes,
|
||||
// testing::FakeUdpAndTcpServer::CloseSocketUponCloseFromPeer);
|
||||
// auto server_uri = absl::StrFormat("dns:///[::]:%d/localhost:1234",
|
||||
// fake_dns_server.port());
|
||||
//
|
||||
// 2) Server gets stuck while setting up a security handshake and client's
|
||||
// security handshake times out (requires using secure channels):
|
||||
//
|
||||
// testing::FakeUdpAndTcpServer fake_server(
|
||||
// testing::FakeUdpAndTcpServer::AcceptMode::
|
||||
// kWaitForClientToSendFirstBytes,
|
||||
// testing::FakeUdpAndTcpServer::CloseSocketUponCloseFromPeer);
|
||||
// auto server_uri = absl::StrFormat("[::1]:%d", fake_server.port());
|
||||
//
|
||||
// 3) Client connections are immediately closed after sending the first bytes
|
||||
// to an insecure server:
|
||||
//
|
||||
// testing::FakeUdpAndTcpServer fake_server(
|
||||
// testing::FakeUdpAndTcpServer::AcceptMode::
|
||||
// kEagerlySendSettings,
|
||||
// testing::FakeUdpAndTcpServer::CloseSocketUponReceivingBytesFromPeer);
|
||||
// auto server_uri = absl::StrFormat("[::1]:%d", fake_server.port());
|
||||
//
|
||||
class FakeUdpAndTcpServer { |
||||
public: |
||||
enum class ProcessReadResult { |
||||
kContinueReading = 0, |
||||
kCloseSocket, |
||||
}; |
||||
|
||||
enum class AcceptMode { |
||||
kWaitForClientToSendFirstBytes, // useful for emulating ALTS based
|
||||
// grpc servers
|
||||
kEagerlySendSettings, // useful for emulating insecure grpc servers (e.g.
|
||||
// ALTS handshake servers)
|
||||
}; |
||||
|
||||
explicit FakeUdpAndTcpServer( |
||||
AcceptMode accept_mode, |
||||
std::function<ProcessReadResult(int, int, int)> process_read_cb); |
||||
|
||||
~FakeUdpAndTcpServer(); |
||||
|
||||
const char* address() { return address_.c_str(); } |
||||
|
||||
int port() { return port_; }; |
||||
|
||||
static ProcessReadResult CloseSocketUponReceivingBytesFromPeer( |
||||
int bytes_received_size, int read_error, int s); |
||||
|
||||
static ProcessReadResult CloseSocketUponCloseFromPeer(int bytes_received_size, |
||||
int read_error, int s); |
||||
|
||||
void ReadFromUdpSocket(); |
||||
|
||||
// Run a loop that periodically, every 10 ms:
|
||||
// 1) Checks if there are any new TCP connections to accept.
|
||||
// 2) Checks if any data has arrived yet on established connections,
|
||||
// and reads from them if so, processing the sockets as configured.
|
||||
void RunServerLoop(); |
||||
|
||||
private: |
||||
class FakeUdpAndTcpServerPeer { |
||||
public: |
||||
explicit FakeUdpAndTcpServerPeer(int fd); |
||||
|
||||
~FakeUdpAndTcpServerPeer(); |
||||
|
||||
void MaybeContinueSendingSettings(); |
||||
|
||||
int fd() { return fd_; } |
||||
|
||||
private: |
||||
int fd_; |
||||
int total_bytes_sent_ = 0; |
||||
}; |
||||
|
||||
int accept_socket_; |
||||
int udp_socket_; |
||||
int port_; |
||||
gpr_event stop_ev_; |
||||
std::string address_; |
||||
std::unique_ptr<std::thread> run_server_loop_thd_; |
||||
const AcceptMode accept_mode_; |
||||
std::function<ProcessReadResult(int, int, int)> process_read_cb_; |
||||
}; |
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc_core
|
@ -1,101 +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 "test/cpp/naming/dns_test_util.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/event_engine/sockaddr.h" |
||||
|
||||
#ifdef GPR_WINDOWS |
||||
#include "src/core/lib/iomgr/sockaddr_windows.h" |
||||
#include "src/core/lib/iomgr/socket_windows.h" |
||||
#define BAD_SOCKET_RETURN_VAL INVALID_SOCKET |
||||
#else |
||||
#include "src/core/lib/iomgr/sockaddr_posix.h" |
||||
#define BAD_SOCKET_RETURN_VAL (-1) |
||||
#endif |
||||
|
||||
namespace grpc { |
||||
namespace testing { |
||||
|
||||
FakeNonResponsiveDNSServer::FakeNonResponsiveDNSServer(int port) { |
||||
udp_socket_ = socket(AF_INET6, SOCK_DGRAM, 0); |
||||
tcp_socket_ = socket(AF_INET6, SOCK_STREAM, 0); |
||||
if (udp_socket_ == BAD_SOCKET_RETURN_VAL) { |
||||
gpr_log(GPR_DEBUG, "Failed to create UDP ipv6 socket"); |
||||
abort(); |
||||
} |
||||
if (tcp_socket_ == BAD_SOCKET_RETURN_VAL) { |
||||
gpr_log(GPR_DEBUG, "Failed to create TCP ipv6 socket"); |
||||
abort(); |
||||
} |
||||
sockaddr_in6 addr; |
||||
memset(&addr, 0, sizeof(addr)); |
||||
addr.sin6_family = AF_INET6; |
||||
addr.sin6_port = htons(port); |
||||
(reinterpret_cast<char*>(&addr.sin6_addr))[15] = 1; |
||||
if (bind(udp_socket_, reinterpret_cast<const sockaddr*>(&addr), |
||||
sizeof(addr)) != 0) { |
||||
gpr_log(GPR_DEBUG, "Failed to bind UDP ipv6 socket to [::1]:%d", port); |
||||
abort(); |
||||
} |
||||
#ifdef GPR_WINDOWS |
||||
char val = 1; |
||||
if (setsockopt(tcp_socket_, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == |
||||
SOCKET_ERROR) { |
||||
gpr_log(GPR_DEBUG, |
||||
"Failed to set SO_REUSEADDR on TCP ipv6 socket to [::1]:%d", port); |
||||
abort(); |
||||
} |
||||
#else |
||||
int val = 1; |
||||
if (setsockopt(tcp_socket_, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != |
||||
0) { |
||||
gpr_log(GPR_DEBUG, |
||||
"Failed to set SO_REUSEADDR on TCP ipv6 socket to [::1]:%d", port); |
||||
abort(); |
||||
} |
||||
#endif |
||||
if (bind(tcp_socket_, reinterpret_cast<const sockaddr*>(&addr), |
||||
sizeof(addr)) != 0) { |
||||
gpr_log(GPR_DEBUG, "Failed to bind TCP ipv6 socket to [::1]:%d", port); |
||||
abort(); |
||||
} |
||||
if (listen(tcp_socket_, 100)) { |
||||
gpr_log(GPR_DEBUG, "Failed to listen on TCP ipv6 socket to [::1]:%d", port); |
||||
abort(); |
||||
} |
||||
} |
||||
|
||||
FakeNonResponsiveDNSServer::~FakeNonResponsiveDNSServer() { |
||||
#ifdef GPR_WINDOWS |
||||
closesocket(udp_socket_); |
||||
closesocket(tcp_socket_); |
||||
#else |
||||
close(udp_socket_); |
||||
close(tcp_socket_); |
||||
#endif |
||||
} |
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
@ -1,38 +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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_DNS_TEST_UTIL_H |
||||
#define GRPC_DNS_TEST_UTIL_H |
||||
|
||||
namespace grpc { |
||||
namespace testing { |
||||
|
||||
class FakeNonResponsiveDNSServer { |
||||
public: |
||||
explicit FakeNonResponsiveDNSServer(int port); |
||||
virtual ~FakeNonResponsiveDNSServer(); |
||||
|
||||
private: |
||||
int udp_socket_; |
||||
int tcp_socket_; |
||||
}; |
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
||||
|
||||
#endif /* GRPC_DNS_TEST_UTIL_H */ |
Loading…
Reference in new issue