1 /* 2 * 3 * Copyright 2015 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 // Test description at doc/connection-backoff-interop-test-description.md 20 21 #include <signal.h> 22 23 #include <condition_variable> 24 #include <memory> 25 #include <mutex> 26 #include <sstream> 27 28 #include <gflags/gflags.h> 29 #include <grpc/grpc.h> 30 #include <grpc/support/log.h> 31 #include <grpcpp/server.h> 32 #include <grpcpp/server_builder.h> 33 #include <grpcpp/server_context.h> 34 35 #include "src/proto/grpc/testing/empty.pb.h" 36 #include "src/proto/grpc/testing/messages.pb.h" 37 #include "src/proto/grpc/testing/test.grpc.pb.h" 38 #include "test/core/util/reconnect_server.h" 39 #include "test/cpp/util/test_config.h" 40 41 DEFINE_int32(control_port, 0, "Server port for controlling the server."); 42 DEFINE_int32(retry_port, 0, 43 "Server port for raw tcp connections. All incoming " 44 "connections will be closed immediately."); 45 46 using grpc::Server; 47 using grpc::ServerBuilder; 48 using grpc::ServerContext; 49 using grpc::ServerCredentials; 50 using grpc::ServerReader; 51 using grpc::ServerReaderWriter; 52 using grpc::ServerWriter; 53 using grpc::SslServerCredentialsOptions; 54 using grpc::Status; 55 using grpc::testing::Empty; 56 using grpc::testing::ReconnectInfo; 57 using grpc::testing::ReconnectParams; 58 using grpc::testing::ReconnectService; 59 60 static bool got_sigint = false; 61 62 class ReconnectServiceImpl : public ReconnectService::Service { 63 public: 64 explicit ReconnectServiceImpl(int retry_port) 65 : retry_port_(retry_port), 66 serving_(false), 67 server_started_(false), 68 shutdown_(false) { 69 reconnect_server_init(&tcp_server_); 70 } 71 72 ~ReconnectServiceImpl() { 73 if (server_started_) { 74 reconnect_server_destroy(&tcp_server_); 75 } 76 } 77 78 void Poll(int seconds) { reconnect_server_poll(&tcp_server_, seconds); } 79 80 Status Start(ServerContext* context, const ReconnectParams* request, 81 Empty* response) { 82 bool start_server = true; 83 std::unique_lock<std::mutex> lock(mu_); 84 while (serving_ && !shutdown_) { 85 cv_.wait(lock); 86 } 87 if (shutdown_) { 88 return Status(grpc::StatusCode::UNAVAILABLE, "shutting down"); 89 } 90 serving_ = true; 91 if (server_started_) { 92 start_server = false; 93 } else { 94 tcp_server_.max_reconnect_backoff_ms = 95 request->max_reconnect_backoff_ms(); 96 server_started_ = true; 97 } 98 lock.unlock(); 99 100 if (start_server) { 101 reconnect_server_start(&tcp_server_, retry_port_); 102 } else { 103 reconnect_server_clear_timestamps(&tcp_server_); 104 } 105 return Status::OK; 106 } 107 108 Status Stop(ServerContext* context, const Empty* request, 109 ReconnectInfo* response) { 110 // extract timestamps and set response 111 Verify(response); 112 reconnect_server_clear_timestamps(&tcp_server_); 113 std::lock_guard<std::mutex> lock(mu_); 114 serving_ = false; 115 cv_.notify_one(); 116 return Status::OK; 117 } 118 119 void Verify(ReconnectInfo* response) { 120 double expected_backoff = 1000.0; 121 const double kTransmissionDelay = 100.0; 122 const double kBackoffMultiplier = 1.6; 123 const double kJitterFactor = 0.2; 124 const int kMaxBackoffMs = tcp_server_.max_reconnect_backoff_ms 125 ? tcp_server_.max_reconnect_backoff_ms 126 : 120 * 1000; 127 bool passed = true; 128 for (timestamp_list* cur = tcp_server_.head; cur && cur->next; 129 cur = cur->next) { 130 double backoff = gpr_time_to_millis( 131 gpr_time_sub(cur->next->timestamp, cur->timestamp)); 132 double min_backoff = expected_backoff * (1 - kJitterFactor); 133 double max_backoff = expected_backoff * (1 + kJitterFactor); 134 if (backoff < min_backoff - kTransmissionDelay || 135 backoff > max_backoff + kTransmissionDelay) { 136 passed = false; 137 } 138 response->add_backoff_ms(static_cast<int32_t>(backoff)); 139 expected_backoff *= kBackoffMultiplier; 140 expected_backoff = 141 expected_backoff > kMaxBackoffMs ? kMaxBackoffMs : expected_backoff; 142 } 143 response->set_passed(passed); 144 } 145 146 void Shutdown() { 147 std::lock_guard<std::mutex> lock(mu_); 148 shutdown_ = true; 149 cv_.notify_all(); 150 } 151 152 private: 153 int retry_port_; 154 reconnect_server tcp_server_; 155 bool serving_; 156 bool server_started_; 157 bool shutdown_; 158 std::mutex mu_; 159 std::condition_variable cv_; 160 }; 161 162 void RunServer() { 163 std::ostringstream server_address; 164 server_address << "0.0.0.0:" << FLAGS_control_port; 165 ReconnectServiceImpl service(FLAGS_retry_port); 166 167 ServerBuilder builder; 168 builder.RegisterService(&service); 169 builder.AddListeningPort(server_address.str(), 170 grpc::InsecureServerCredentials()); 171 std::unique_ptr<Server> server(builder.BuildAndStart()); 172 gpr_log(GPR_INFO, "Server listening on %s", server_address.str().c_str()); 173 while (!got_sigint) { 174 service.Poll(5); 175 } 176 service.Shutdown(); 177 } 178 179 static void sigint_handler(int x) { got_sigint = true; } 180 181 int main(int argc, char** argv) { 182 grpc::testing::InitTest(&argc, &argv, true); 183 signal(SIGINT, sigint_handler); 184 185 GPR_ASSERT(FLAGS_control_port != 0); 186 GPR_ASSERT(FLAGS_retry_port != 0); 187 RunServer(); 188 189 return 0; 190 } 191