RDK Documentation (Open Sourced RDK Components)
connectivity.cpp
1 #include "connectivity.h"
2 #include "logging.h"
3 #include <unistd.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <vector>
7 #include <string>
8 #include <fstream>
9 #include <algorithm>
10 #include <time.h>
11 #include <curl/curl.h>
12 
13 int get_connectivity_test_endpoints(std::vector<std::string>& endpoints)
14 {
15  static const int MAX_CONNECTIVITY_TEST_ENDPOINTS = 5;
16 
17  LOG_ENTRY_EXIT;
18 
19  const char* filename = "/opt/persistent/connectivity_test_endpoints";
20 
21  std::ifstream ifs(filename);
22  if (ifs.is_open())
23  {
24  for (std::string endpoint; endpoints.size() < MAX_CONNECTIVITY_TEST_ENDPOINTS && ifs >> endpoint;)
25  endpoints.push_back(endpoint);
26  ifs.close();
27  }
28 
29  if (endpoints.size() < 2) //minimum two endpoints should be there
30  {
31  LOG_WARN("%d endpoints not sufficient. adding default endpoints to %s", endpoints.size(), filename);
32 
33  if (access("/lib/systemd/system/xre-receiver.service", F_OK) == 0)
34  {
35  endpoints.push_back("xre.ccp.xcal.tv:10601");
36  endpoints.push_back("google.com");
37  endpoints.push_back("espn.com");
38  }
39  else
40  {
41  endpoints.push_back("google.com");
42  endpoints.push_back("espn.com");
43  endpoints.push_back("speedtest.net");
44  }
45  set_connectivity_test_endpoints(endpoints);
46  }
47 
48  std::string endpoints_str;
49  for (const auto& endpoint : endpoints)
50  endpoints_str.append(endpoint).append(" ");
51  LOG_INFO("endpoints = %s", endpoints_str.c_str());
52 
53  return endpoints.size();
54 }
55 
56 bool set_connectivity_test_endpoints(const std::vector<std::string>& endpoints)
57 {
58  LOG_ENTRY_EXIT;
59 
60  std::string endpoints_string;
61  for (auto endpoint : endpoints)
62  {
63  endpoints_string.append(endpoint.c_str());
64  endpoints_string.push_back(' ');
65  }
66  LOG_INFO( "%s", endpoints_string.c_str());
67  std::replace(endpoints_string.begin(), endpoints_string.end(), ' ', '\n');
68 
69  FILE *f = fopen("/opt/persistent/connectivity_test_endpoints", "w");
70  if (f == NULL)
71  {
72  LOG_ERR("fopen error %d (%s)", errno, strerror(errno));
73  return false;
74  }
75  fprintf(f, "%s", endpoints_string.c_str());
76  if (0 != fclose(f))
77  {
78  LOG_ERR("fclose error %d (%s)", errno, strerror(errno));
79  return false;
80  }
81 
82  return true;
83 }
84 
85 static long current_time ()
86 {
87  struct timespec ts;
88  clock_gettime (CLOCK_MONOTONIC, &ts);
89  return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
90 }
91 
92 bool test_connectivity(long timeout_ms)
93 {
94  LOG_ENTRY_EXIT;
95 
96  std::vector<std::string> endpoints;
97  int endpoints_count = get_connectivity_test_endpoints(endpoints);
98  long deadline = current_time() + timeout_ms, time_now = 0, time_earlier = 0;
99 
100  CURLM *curl_multi_handle = curl_multi_init();
101  if (!curl_multi_handle)
102  {
103  LOG_ERR("curl_multi_init returned NULL");
104  return -1;
105  }
106 
107  CURLMcode mc;
108  std::vector<CURL*> curl_easy_handles;
109  for (const auto& endpoint : endpoints)
110  {
111  CURL *curl_easy_handle = curl_easy_init();
112  if (!curl_easy_handle)
113  {
114  LOG_ERR("endpoint = <%s> curl_easy_init returned NULL", endpoint.c_str());
115  continue;
116  }
117  curl_easy_setopt(curl_easy_handle, CURLOPT_URL, endpoint.c_str());
118  curl_easy_setopt(curl_easy_handle, CURLOPT_PRIVATE, endpoint.c_str());
119  curl_easy_setopt(curl_easy_handle, CURLOPT_CONNECT_ONLY, 1L);
120  curl_easy_setopt(curl_easy_handle, CURLOPT_TIMEOUT_MS, deadline - current_time());
121  if (rdk_dbg_enabled(LOG_NMGR, RDK_LOG_DEBUG) == TRUE || rdk_dbg_enabled(LOG_NMGR, RDK_LOG_TRACE2) == TRUE)
122  curl_easy_setopt(curl_easy_handle, CURLOPT_VERBOSE, 1L);
123  if (CURLM_OK != (mc = curl_multi_add_handle(curl_multi_handle, curl_easy_handle)))
124  {
125  LOG_ERR("endpoint = <%s> curl_multi_add_handle returned %d (%s)", endpoint.c_str(), mc, curl_multi_strerror(mc));
126  curl_easy_cleanup(curl_easy_handle);
127  continue;
128  }
129  curl_easy_handles.push_back(curl_easy_handle);
130  }
131 
132  int connectivity = 0, handles, msgs_left;
133 #if LIBCURL_VERSION_NUM < 0x074200
134  int numfds, repeats = 0;
135 #endif
136  char *endpoint;
137  while (1)
138  {
139  if (CURLM_OK != (mc = curl_multi_perform(curl_multi_handle, &handles)))
140  {
141  LOG_ERR("curl_multi_perform returned %d (%s)", mc, curl_multi_strerror(mc));
142  break;
143  }
144  for (CURLMsg *msg; NULL != (msg = curl_multi_info_read(curl_multi_handle, &msgs_left)); )
145  {
146  if (msg->msg != CURLMSG_DONE)
147  continue;
148  if (CURLE_OK == msg->data.result)
149  connectivity++;
150  curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &endpoint);
151  LOG_INFO("endpoint = <%s> error = %d (%s)", endpoint, msg->data.result, curl_easy_strerror(msg->data.result));
152  }
153  time_earlier = time_now;
154  time_now = current_time();
155  if (handles == 0 || time_now >= deadline)
156  break;
157 #if LIBCURL_VERSION_NUM < 0x074200
158  if (CURLM_OK != (mc = curl_multi_wait(curl_multi_handle, NULL, 0, deadline - time_now, &numfds)))
159  {
160  LOG_ERR("curl_multi_wait returned %d (%s)", mc, curl_multi_strerror(mc));
161  break;
162  }
163  if (numfds == 0)
164  {
165  repeats++;
166  if (repeats > 1)
167  usleep(10*1000); /* sleep 10 ms */
168  }
169  else
170  repeats = 0;
171 #else
172  if (CURLM_OK != (mc = curl_multi_poll(curl_multi_handle, NULL, 0, deadline - time_now, NULL)))
173  {
174  LOG_ERR("curl_multi_poll returned %d (%s)", mc, curl_multi_strerror(mc));
175  break;
176  }
177 #endif
178  }
179  LOG_INFO("connectivity = %d, endpoints count = %d, handles = %d, deadline = %ld, time_now = %ld, time_earlier = %ld",
180  connectivity, endpoints_count, handles, deadline, time_now, time_earlier);
181 
182  for (const auto& curl_easy_handle : curl_easy_handles)
183  {
184  curl_easy_getinfo(curl_easy_handle, CURLINFO_PRIVATE, &endpoint);
185  LOG_DBG("endpoint = <%s> terminating attempt", endpoint);
186  curl_multi_remove_handle(curl_multi_handle, curl_easy_handle);
187  curl_easy_cleanup(curl_easy_handle);
188  }
189  curl_multi_cleanup(curl_multi_handle);
190 
191  if (connectivity >= endpoints_count - 1) // checking ~90% endpoints connectivity
192  return true;
193  return false;
194 }
replace
static int replace(std::string &str, const std::string &from, uint64_t toNumber)
Replace matching token with given number.
Definition: fragmentcollector_mpd.cpp:906
rdk_dbg_enabled
rdk_logger_Bool rdk_dbg_enabled(const char *module, rdk_LogLevel level)
Function to check if a specific log level of a module is enabled.
Definition: rdk_debug_priv.c:415
LOG_INFO
#define LOG_INFO(AAMP_JS_OBJECT, FORMAT,...)
Definition: jsutils.h:39
TRUE
#define TRUE
Defines for TRUE/FALSE/ENABLE flags.
Definition: wifi_common_hal.h:199