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 #include "test/core/util/reconnect_server.h" 20 21 #include <grpc/grpc.h> 22 #include <grpc/support/alloc.h> 23 #include <grpc/support/log.h> 24 #include <grpc/support/sync.h> 25 #include <grpc/support/time.h> 26 #include <string.h> 27 28 #include "src/core/lib/gpr/host_port.h" 29 #include "src/core/lib/iomgr/endpoint.h" 30 #include "src/core/lib/iomgr/sockaddr.h" 31 #include "src/core/lib/iomgr/tcp_server.h" 32 #include "test/core/util/port.h" 33 #include "test/core/util/test_tcp_server.h" 34 35 static void pretty_print_backoffs(reconnect_server* server) { 36 gpr_timespec diff; 37 int i = 1; 38 double expected_backoff = 1000.0, backoff; 39 timestamp_list* head = server->head; 40 gpr_log(GPR_INFO, "reconnect server: new connection"); 41 for (head = server->head; head && head->next; head = head->next, i++) { 42 diff = gpr_time_sub(head->next->timestamp, head->timestamp); 43 backoff = gpr_time_to_millis(diff); 44 gpr_log(GPR_INFO, 45 "retry %2d:backoff %6.2fs,expected backoff %6.2fs, jitter %4.2f%%", 46 i, backoff / 1000.0, expected_backoff / 1000.0, 47 (backoff - expected_backoff) * 100.0 / expected_backoff); 48 expected_backoff *= 1.6; 49 int max_reconnect_backoff_ms = 120 * 1000; 50 if (server->max_reconnect_backoff_ms > 0) { 51 max_reconnect_backoff_ms = server->max_reconnect_backoff_ms; 52 } 53 if (expected_backoff > max_reconnect_backoff_ms) { 54 expected_backoff = max_reconnect_backoff_ms; 55 } 56 } 57 } 58 59 static void on_connect(void* arg, grpc_endpoint* tcp, 60 grpc_pollset* accepting_pollset, 61 grpc_tcp_server_acceptor* acceptor) { 62 gpr_free(acceptor); 63 char* peer; 64 char* last_colon; 65 reconnect_server* server = static_cast<reconnect_server*>(arg); 66 gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); 67 timestamp_list* new_tail; 68 peer = grpc_endpoint_get_peer(tcp); 69 grpc_endpoint_shutdown(tcp, 70 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Connected")); 71 grpc_endpoint_destroy(tcp); 72 if (peer) { 73 last_colon = strrchr(peer, ':'); 74 if (server->peer == nullptr) { 75 server->peer = peer; 76 } else { 77 if (last_colon == nullptr) { 78 gpr_log(GPR_ERROR, "peer does not contain a ':'"); 79 } else if (strncmp(server->peer, peer, 80 static_cast<size_t>(last_colon - peer)) != 0) { 81 gpr_log(GPR_ERROR, "mismatched peer! %s vs %s", server->peer, peer); 82 } 83 gpr_free(peer); 84 } 85 } 86 new_tail = static_cast<timestamp_list*>(gpr_malloc(sizeof(timestamp_list))); 87 new_tail->timestamp = now; 88 new_tail->next = nullptr; 89 if (server->tail == nullptr) { 90 server->head = new_tail; 91 server->tail = new_tail; 92 } else { 93 server->tail->next = new_tail; 94 server->tail = new_tail; 95 } 96 pretty_print_backoffs(server); 97 } 98 99 void reconnect_server_init(reconnect_server* server) { 100 test_tcp_server_init(&server->tcp_server, on_connect, server); 101 server->head = nullptr; 102 server->tail = nullptr; 103 server->peer = nullptr; 104 server->max_reconnect_backoff_ms = 0; 105 } 106 107 void reconnect_server_start(reconnect_server* server, int port) { 108 test_tcp_server_start(&server->tcp_server, port); 109 } 110 111 void reconnect_server_poll(reconnect_server* server, int seconds) { 112 test_tcp_server_poll(&server->tcp_server, seconds); 113 } 114 115 void reconnect_server_clear_timestamps(reconnect_server* server) { 116 timestamp_list* new_head = server->head; 117 while (server->head) { 118 new_head = server->head->next; 119 gpr_free(server->head); 120 server->head = new_head; 121 } 122 server->tail = nullptr; 123 gpr_free(server->peer); 124 server->peer = nullptr; 125 } 126 127 void reconnect_server_destroy(reconnect_server* server) { 128 reconnect_server_clear_timestamps(server); 129 test_tcp_server_destroy(&server->tcp_server); 130 } 131