1d4afb5ceSopenharmony_ci /* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "private-lib-core.h" 26d4afb5ceSopenharmony_ci 27d4afb5ceSopenharmony_ci#define LWSNTPC_LI_NONE 0 28d4afb5ceSopenharmony_ci#define LWSNTPC_VN_3 3 29d4afb5ceSopenharmony_ci#define LWSNTPC_MODE_CLIENT 3 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_cistruct vhd_ntpc { 32d4afb5ceSopenharmony_ci struct lws_context *context; 33d4afb5ceSopenharmony_ci struct lws_vhost *vhost; 34d4afb5ceSopenharmony_ci const struct lws_protocols *protocol; 35d4afb5ceSopenharmony_ci lws_sorted_usec_list_t sul_conn; 36d4afb5ceSopenharmony_ci lws_sorted_usec_list_t sul_write; /* track write retries */ 37d4afb5ceSopenharmony_ci const char *ntp_server_ads; 38d4afb5ceSopenharmony_ci struct lws *wsi_udp; 39d4afb5ceSopenharmony_ci uint16_t retry_count_conn; 40d4afb5ceSopenharmony_ci uint16_t retry_count_write; 41d4afb5ceSopenharmony_ci 42d4afb5ceSopenharmony_ci char set_time; 43d4afb5ceSopenharmony_ci}; 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci/* 46d4afb5ceSopenharmony_ci * Without a valid ntp we won't be able to do anything requiring client tls. 47d4afb5ceSopenharmony_ci * 48d4afb5ceSopenharmony_ci * We have our own outer backoff scheme that just keeps retrying dns lookup 49d4afb5ceSopenharmony_ci * and the transaction forever. 50d4afb5ceSopenharmony_ci */ 51d4afb5ceSopenharmony_ci 52d4afb5ceSopenharmony_cistatic const uint32_t botable[] = 53d4afb5ceSopenharmony_ci { 300, 500, 650, 800, 800, 900, 1000, 1100, 1500 }; 54d4afb5ceSopenharmony_cistatic const lws_retry_bo_t bo = { 55d4afb5ceSopenharmony_ci botable, LWS_ARRAY_SIZE(botable), LWS_RETRY_CONCEAL_ALWAYS, 0, 0, 20 }; 56d4afb5ceSopenharmony_ci 57d4afb5ceSopenharmony_ci/* 58d4afb5ceSopenharmony_ci * Once we resolved the remote server (implying we should have network), 59d4afb5ceSopenharmony_ci * we use a different policy on the wsi itself that gives it a few tries before 60d4afb5ceSopenharmony_ci * failing the wsi and using to outer retry policy to get dns to a different 61d4afb5ceSopenharmony_ci * server in the pool and try fresh 62d4afb5ceSopenharmony_ci */ 63d4afb5ceSopenharmony_ci 64d4afb5ceSopenharmony_cistatic const uint32_t botable2[] = { 1000, 1250, 5000 /* in case dog slow */ }; 65d4afb5ceSopenharmony_cistatic const lws_retry_bo_t bo2 = { 66d4afb5ceSopenharmony_ci botable2, LWS_ARRAY_SIZE(botable2), LWS_ARRAY_SIZE(botable2), 67d4afb5ceSopenharmony_ci /* don't conceal after the last table entry */ 0, 0, 20 }; 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_cistatic void 70d4afb5ceSopenharmony_cilws_ntpc_retry_conn(struct lws_sorted_usec_list *sul) 71d4afb5ceSopenharmony_ci{ 72d4afb5ceSopenharmony_ci struct vhd_ntpc *v = lws_container_of(sul, struct vhd_ntpc, sul_conn); 73d4afb5ceSopenharmony_ci 74d4afb5ceSopenharmony_ci lwsl_debug("%s: wsi_udp: %s\n", __func__, lws_wsi_tag(v->wsi_udp)); 75d4afb5ceSopenharmony_ci 76d4afb5ceSopenharmony_ci if (v->wsi_udp || !lws_dll2_is_detached(&v->sul_conn.list)) 77d4afb5ceSopenharmony_ci return; 78d4afb5ceSopenharmony_ci 79d4afb5ceSopenharmony_ci /* create the UDP socket aimed at the server */ 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci lwsl_notice("%s: server %s\n", __func__, v->ntp_server_ads); 82d4afb5ceSopenharmony_ci 83d4afb5ceSopenharmony_ci v->retry_count_write = 0; 84d4afb5ceSopenharmony_ci v->wsi_udp = lws_create_adopt_udp(v->vhost, v->ntp_server_ads, 123, 0, 85d4afb5ceSopenharmony_ci v->protocol->name, NULL, NULL, NULL, 86d4afb5ceSopenharmony_ci &bo2, "ntpclient"); 87d4afb5ceSopenharmony_ci lwsl_debug("%s: created wsi_udp: %s\n", __func__, lws_wsi_tag(v->wsi_udp)); 88d4afb5ceSopenharmony_ci if (!v->wsi_udp) { 89d4afb5ceSopenharmony_ci lwsl_err("%s: unable to create udp skt\n", __func__); 90d4afb5ceSopenharmony_ci 91d4afb5ceSopenharmony_ci lws_retry_sul_schedule(v->context, 0, &v->sul_conn, &bo, 92d4afb5ceSopenharmony_ci lws_ntpc_retry_conn, &v->retry_count_conn); 93d4afb5ceSopenharmony_ci } 94d4afb5ceSopenharmony_ci} 95d4afb5ceSopenharmony_ci 96d4afb5ceSopenharmony_cistatic void 97d4afb5ceSopenharmony_cilws_ntpc_retry_write(struct lws_sorted_usec_list *sul) 98d4afb5ceSopenharmony_ci{ 99d4afb5ceSopenharmony_ci struct vhd_ntpc *v = lws_container_of(sul, struct vhd_ntpc, sul_write); 100d4afb5ceSopenharmony_ci 101d4afb5ceSopenharmony_ci lwsl_debug("%s\n", __func__); 102d4afb5ceSopenharmony_ci 103d4afb5ceSopenharmony_ci if (v && v->wsi_udp) 104d4afb5ceSopenharmony_ci lws_callback_on_writable(v->wsi_udp); 105d4afb5ceSopenharmony_ci} 106d4afb5ceSopenharmony_ci 107d4afb5ceSopenharmony_cistatic int 108d4afb5ceSopenharmony_cicallback_ntpc(struct lws *wsi, enum lws_callback_reasons reason, void *user, 109d4afb5ceSopenharmony_ci void *in, size_t len) 110d4afb5ceSopenharmony_ci{ 111d4afb5ceSopenharmony_ci struct vhd_ntpc *v = (struct vhd_ntpc *) 112d4afb5ceSopenharmony_ci lws_protocol_vh_priv_get(lws_get_vhost(wsi), 113d4afb5ceSopenharmony_ci lws_get_protocol(wsi)); 114d4afb5ceSopenharmony_ci uint8_t pkt[LWS_PRE + 48]; 115d4afb5ceSopenharmony_ci struct timeval t1; 116d4afb5ceSopenharmony_ci int64_t delta_us; 117d4afb5ceSopenharmony_ci uint64_t ns; 118d4afb5ceSopenharmony_ci 119d4afb5ceSopenharmony_ci switch (reason) { 120d4afb5ceSopenharmony_ci 121d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ 122d4afb5ceSopenharmony_ci if (v) 123d4afb5ceSopenharmony_ci break; 124d4afb5ceSopenharmony_ci 125d4afb5ceSopenharmony_ci lwsl_debug("%s: LWS_CALLBACK_PROTOCOL_INIT:\n", __func__); 126d4afb5ceSopenharmony_ci lws_protocol_vh_priv_zalloc(wsi->a.vhost, wsi->a.protocol, 127d4afb5ceSopenharmony_ci sizeof(*v)); 128d4afb5ceSopenharmony_ci v = (struct vhd_ntpc *)lws_protocol_vh_priv_get(wsi->a.vhost, 129d4afb5ceSopenharmony_ci wsi->a.protocol); 130d4afb5ceSopenharmony_ci v->context = lws_get_context(wsi); 131d4afb5ceSopenharmony_ci v->vhost = lws_get_vhost(wsi); 132d4afb5ceSopenharmony_ci v->protocol = lws_get_protocol(wsi); 133d4afb5ceSopenharmony_ci 134d4afb5ceSopenharmony_ci v->context->ntpclient_priv = v; 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci if (!lws_system_get_ops(wsi->a.context) || 137d4afb5ceSopenharmony_ci !lws_system_get_ops(wsi->a.context)->set_clock) { 138d4afb5ceSopenharmony_ci#if !defined(LWS_ESP_PLATFORM) 139d4afb5ceSopenharmony_ci lwsl_err("%s: set up system ops for set_clock\n", 140d4afb5ceSopenharmony_ci __func__); 141d4afb5ceSopenharmony_ci#endif 142d4afb5ceSopenharmony_ci 143d4afb5ceSopenharmony_ci // return -1; 144d4afb5ceSopenharmony_ci } 145d4afb5ceSopenharmony_ci 146d4afb5ceSopenharmony_ci /* register our lws_system notifier */ 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_ci v->ntp_server_ads = "pool.ntp.org"; 149d4afb5ceSopenharmony_ci lws_plat_ntpclient_config(v->context); 150d4afb5ceSopenharmony_ci lws_system_blob_get_single_ptr(lws_system_get_blob( 151d4afb5ceSopenharmony_ci v->context, LWS_SYSBLOB_TYPE_NTP_SERVER, 0), 152d4afb5ceSopenharmony_ci (const uint8_t **)&v->ntp_server_ads); 153d4afb5ceSopenharmony_ci if (!v->ntp_server_ads || v->ntp_server_ads[0] == '\0') 154d4afb5ceSopenharmony_ci v->ntp_server_ads = "pool.ntp.org"; 155d4afb5ceSopenharmony_ci 156d4afb5ceSopenharmony_ci lwsl_notice("%s: using ntp server %s\n", __func__, 157d4afb5ceSopenharmony_ci v->ntp_server_ads); 158d4afb5ceSopenharmony_ci break; 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */ 161d4afb5ceSopenharmony_ci if (!v) 162d4afb5ceSopenharmony_ci break; 163d4afb5ceSopenharmony_ci if (v->wsi_udp) 164d4afb5ceSopenharmony_ci lws_set_timeout(v->wsi_udp, 1, LWS_TO_KILL_ASYNC); 165d4afb5ceSopenharmony_ci v->wsi_udp = NULL; 166d4afb5ceSopenharmony_ci goto cancel_conn_timer; 167d4afb5ceSopenharmony_ci 168d4afb5ceSopenharmony_ci /* callbacks related to raw socket descriptor */ 169d4afb5ceSopenharmony_ci 170d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_ADOPT: 171d4afb5ceSopenharmony_ci lwsl_debug("%s: LWS_CALLBACK_RAW_ADOPT\n", __func__); 172d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 173d4afb5ceSopenharmony_ci break; 174d4afb5ceSopenharmony_ci 175d4afb5ceSopenharmony_ci case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: 176d4afb5ceSopenharmony_ci lwsl_info("%s: CONNECTION_ERROR\n", __func__); 177d4afb5ceSopenharmony_ci goto do_close; 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_CLOSE: 180d4afb5ceSopenharmony_ci lwsl_debug("%s: LWS_CALLBACK_RAW_CLOSE\n", __func__); 181d4afb5ceSopenharmony_cido_close: 182d4afb5ceSopenharmony_ci v->wsi_udp = NULL; 183d4afb5ceSopenharmony_ci 184d4afb5ceSopenharmony_ci /* cancel any pending write retry */ 185d4afb5ceSopenharmony_ci lws_sul_cancel(&v->sul_write); 186d4afb5ceSopenharmony_ci 187d4afb5ceSopenharmony_ci if (v->set_time) 188d4afb5ceSopenharmony_ci goto cancel_conn_timer; 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci lws_retry_sul_schedule(v->context, 0, &v->sul_conn, &bo, 191d4afb5ceSopenharmony_ci lws_ntpc_retry_conn, 192d4afb5ceSopenharmony_ci &v->retry_count_conn); 193d4afb5ceSopenharmony_ci break; 194d4afb5ceSopenharmony_ci 195d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_RX: 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci if (len != 48) 198d4afb5ceSopenharmony_ci return 0; /* ignore it */ 199d4afb5ceSopenharmony_ci 200d4afb5ceSopenharmony_ci /* 201d4afb5ceSopenharmony_ci * First get the seconds, corrected for the ntp epoch of 1900 202d4afb5ceSopenharmony_ci * vs the unix epoch of 1970. Then shift the seconds up by 1bn 203d4afb5ceSopenharmony_ci * and add in the ns 204d4afb5ceSopenharmony_ci */ 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci ns = (uint64_t)lws_ser_ru32be(((uint8_t *)in) + 40) - (uint64_t)2208988800; 207d4afb5ceSopenharmony_ci ns = (ns * 1000000000) + lws_ser_ru32be(((uint8_t *)in) + 44); 208d4afb5ceSopenharmony_ci 209d4afb5ceSopenharmony_ci /* 210d4afb5ceSopenharmony_ci * Compute the step 211d4afb5ceSopenharmony_ci */ 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_ci gettimeofday(&t1, NULL); 214d4afb5ceSopenharmony_ci 215d4afb5ceSopenharmony_ci delta_us = ((int64_t)ns / 1000) - 216d4afb5ceSopenharmony_ci ((t1.tv_sec * LWS_US_PER_SEC) + t1.tv_usec); 217d4afb5ceSopenharmony_ci 218d4afb5ceSopenharmony_ci lwsl_notice("%s: Unix time: %llu, step: %lldus\n", __func__, 219d4afb5ceSopenharmony_ci (unsigned long long)ns / 1000000000, 220d4afb5ceSopenharmony_ci (long long)delta_us); 221d4afb5ceSopenharmony_ci 222d4afb5ceSopenharmony_ci#if defined(LWS_PLAT_FREERTOS) 223d4afb5ceSopenharmony_ci { 224d4afb5ceSopenharmony_ci struct timeval t; 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci t.tv_sec = (unsigned long long)ns / 1000000000; 227d4afb5ceSopenharmony_ci t.tv_usec = (ns % 1000000000) / 1000; 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci lws_sul_nonmonotonic_adjust(wsi->a.context, delta_us); 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ci settimeofday(&t, NULL); 232d4afb5ceSopenharmony_ci } 233d4afb5ceSopenharmony_ci#endif 234d4afb5ceSopenharmony_ci if (lws_system_get_ops(wsi->a.context) && 235d4afb5ceSopenharmony_ci lws_system_get_ops(wsi->a.context)->set_clock) 236d4afb5ceSopenharmony_ci lws_system_get_ops(wsi->a.context)->set_clock((int64_t)ns / 1000); 237d4afb5ceSopenharmony_ci 238d4afb5ceSopenharmony_ci v->set_time = 1; 239d4afb5ceSopenharmony_ci lws_state_transition_steps(&wsi->a.context->mgr_system, 240d4afb5ceSopenharmony_ci LWS_SYSTATE_OPERATIONAL); 241d4afb5ceSopenharmony_ci 242d4afb5ceSopenharmony_ci /* close the wsi */ 243d4afb5ceSopenharmony_ci return -1; 244d4afb5ceSopenharmony_ci 245d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_WRITEABLE: 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ci /* 248d4afb5ceSopenharmony_ci * UDP is not reliable, it can be locally dropped, or dropped 249d4afb5ceSopenharmony_ci * by any intermediary or the remote peer. So even though we 250d4afb5ceSopenharmony_ci * will do the write in a moment, we schedule another request 251d4afb5ceSopenharmony_ci * for rewrite according to the wsi retry policy. 252d4afb5ceSopenharmony_ci * 253d4afb5ceSopenharmony_ci * If the result came before, we'll cancel it in the close flow. 254d4afb5ceSopenharmony_ci * 255d4afb5ceSopenharmony_ci * If we have already reached the end of our concealed retries 256d4afb5ceSopenharmony_ci * in the policy, just close without another write. 257d4afb5ceSopenharmony_ci */ 258d4afb5ceSopenharmony_ci if (lws_dll2_is_detached(&v->sul_write.list) && 259d4afb5ceSopenharmony_ci lws_retry_sul_schedule_retry_wsi(wsi, &v->sul_write, 260d4afb5ceSopenharmony_ci lws_ntpc_retry_write, 261d4afb5ceSopenharmony_ci &v->retry_count_write)) { 262d4afb5ceSopenharmony_ci /* we have reached the end of our concealed retries */ 263d4afb5ceSopenharmony_ci lwsl_warn("%s: concealed retries done, failing\n", __func__); 264d4afb5ceSopenharmony_ci goto retry_conn; 265d4afb5ceSopenharmony_ci } 266d4afb5ceSopenharmony_ci 267d4afb5ceSopenharmony_ci memset(pkt + LWS_PRE, 0, sizeof(pkt) - LWS_PRE); 268d4afb5ceSopenharmony_ci pkt[LWS_PRE] = (LWSNTPC_LI_NONE << 6) | 269d4afb5ceSopenharmony_ci (LWSNTPC_VN_3 << 3) | 270d4afb5ceSopenharmony_ci (LWSNTPC_MODE_CLIENT << 0); 271d4afb5ceSopenharmony_ci 272d4afb5ceSopenharmony_ci if (lws_write(wsi, pkt + LWS_PRE, sizeof(pkt) - LWS_PRE, 0) == 273d4afb5ceSopenharmony_ci sizeof(pkt) - LWS_PRE) 274d4afb5ceSopenharmony_ci break; 275d4afb5ceSopenharmony_ci 276d4afb5ceSopenharmony_ci lwsl_err("%s: Failed to write ntp client req\n", __func__); 277d4afb5ceSopenharmony_ci 278d4afb5ceSopenharmony_ciretry_conn: 279d4afb5ceSopenharmony_ci lws_retry_sul_schedule(wsi->a.context, 0, &v->sul_conn, &bo, 280d4afb5ceSopenharmony_ci lws_ntpc_retry_conn, 281d4afb5ceSopenharmony_ci &v->retry_count_conn); 282d4afb5ceSopenharmony_ci 283d4afb5ceSopenharmony_ci return -1; 284d4afb5ceSopenharmony_ci 285d4afb5ceSopenharmony_ci default: 286d4afb5ceSopenharmony_ci break; 287d4afb5ceSopenharmony_ci } 288d4afb5ceSopenharmony_ci 289d4afb5ceSopenharmony_ci return 0; 290d4afb5ceSopenharmony_ci 291d4afb5ceSopenharmony_ci 292d4afb5ceSopenharmony_cicancel_conn_timer: 293d4afb5ceSopenharmony_ci lws_sul_cancel(&v->sul_conn); 294d4afb5ceSopenharmony_ci 295d4afb5ceSopenharmony_ci return 0; 296d4afb5ceSopenharmony_ci} 297d4afb5ceSopenharmony_ci 298d4afb5ceSopenharmony_civoid 299d4afb5ceSopenharmony_cilws_ntpc_trigger(struct lws_context *ctx) 300d4afb5ceSopenharmony_ci{ 301d4afb5ceSopenharmony_ci struct vhd_ntpc *v = (struct vhd_ntpc *)ctx->ntpclient_priv; 302d4afb5ceSopenharmony_ci 303d4afb5ceSopenharmony_ci lwsl_notice("%s\n", __func__); 304d4afb5ceSopenharmony_ci v->retry_count_conn = 0; 305d4afb5ceSopenharmony_ci lws_ntpc_retry_conn(&v->sul_conn); 306d4afb5ceSopenharmony_ci} 307d4afb5ceSopenharmony_ci 308d4afb5ceSopenharmony_cistruct lws_protocols lws_system_protocol_ntpc = 309d4afb5ceSopenharmony_ci { "lws-ntpclient", callback_ntpc, 0, 128, 0, NULL, 0 }; 310d4afb5ceSopenharmony_ci 311