source: asp3_tinet_ecnl_arm/trunk/ntshell/src/ntp_cli.c@ 359

Last change on this file since 359 was 359, checked in by coas-nagasima, 6 years ago

SDカードの挿抜を検知するよう更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 15.5 KB
Line 
1/*
2 * TOPPERS ECHONET Lite Communication Middleware
3 *
4 * Copyright (C) 2018 Cores Co., Ltd. Japan
5 *
6 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
7 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
8 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
9 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
10 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
11 * スコード中に含まれていること.
12 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
13 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
14 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
15 * の無保証規定を掲載すること.
16 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
17 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
18 * と.
19 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
20 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
21 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
22 * 報告すること.
23 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
24 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
25 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
26 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
27 * 免責すること.
28 *
29 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
30 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
31 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
32 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
33 * の責任を負わない.
34 *
35 * @(#) $Id$
36 */
37
38/*
39 * NTP クライアント
40 */
41
42#include <string.h>
43#include <string.h>
44#include <time.h>
45
46#if defined(TARGET_KERNEL_ASP)
47
48#include <kernel.h>
49#include <sil.h>
50#include <t_syslog.h>
51#include "kernel_cfg.h"
52#include "util/ntstdio.h"
53
54extern ntstdio_t ntstdio;
55
56#endif /* of #if defined(TARGET_KERNEL_ASP) */
57
58#if defined(TARGET_KERNEL_JSP)
59
60#include <t_services.h>
61#include "kernel_id.h"
62#include "tinet_id.h"
63
64#endif /* of #if defined(TARGET_KERNEL_JSP) */
65
66#include <netinet/in.h>
67#include <netinet/in_itron.h>
68
69#include <netapp/netapp.h>
70#include <netapp/netapp_var.h>
71#include "ntp_cli.h"
72
73/* NTP サーバのポート番号 */
74
75#define NTP_SRV_PORTNO UINT_C(123)
76
77/* NTP サーバのURL */
78
79#define NTP_SRV_URL "ntp.nict.jp"
80
81/* 送信間隔 */
82
83#define SLP_ITV (60*SYSTIM_HZ)
84
85/* 関数 */
86
87void ntp_cli_update_time(T_NTP_CLI_CONTEXT *nc);
88ER ntp_cli_time_synchronization(T_NTP_CLI_CONTEXT *nc, ntp_mode_t mode);
89void ntp_cli_read_time(T_NTP_CLI_CONTEXT *nc, struct timespec *tp);
90void ntp_cli_write_time(T_NTP_CLI_CONTEXT *nc, struct timespec *tp);
91void ntp_cli_read_data(T_NTP_CLI_CONTEXT *nc);
92
93/*
94 * 全域変数
95 */
96
97T_NTP_CLI_CONTEXT ntp_cli;
98
99/* UNIX:1970/1/1 - NTP:1900/1/1 */
100#define TIME_OFS (25567ll * 24 * 60 * 60)
101
102void set_systime_to_ntptime(struct timespec *tp, T_NTP_TIMESTAMP *timestamp)
103{
104 timestamp->integer = htonl((uint32_t)(tp->tv_sec + TIME_OFS));
105 timestamp->fraction = htonl((((unsigned long long)tp->tv_nsec) << 32) / 1000000000ll);
106}
107
108void set_ntptime_to_systime(struct timespec *tp, T_NTP_TIMESTAMP *timestamp)
109{
110 tp->tv_sec = ntohl(timestamp->integer) - TIME_OFS;
111 tp->tv_nsec = ((unsigned long long)(ntohl(timestamp->fraction) * 1000000000ll)) >> 32;
112}
113
114void add_timestamp(T_NTP_TIMESTAMP *dst, T_NTP_TIMESTAMP *a, T_NTP_TIMESTAMP *b)
115{
116 uint32_t ai = ntohl(a->integer);
117 uint32_t af = ntohl(a->fraction);
118 uint32_t bi = ntohl(b->integer);
119 uint32_t bf = ntohl(b->fraction);
120 uint32_t f = af + bf;
121 uint32_t o = ((f < af) || (f < bf)) ? 1u : 0;
122 uint32_t i = ai + bi + o;
123 dst->integer = htonl(i);
124 dst->fraction = htonl(f);
125}
126
127void sub_timestamp(T_NTP_TIMESTAMP *dst, T_NTP_TIMESTAMP *a, T_NTP_TIMESTAMP *b)
128{
129 uint32_t ai = ntohl(a->integer);
130 uint32_t af = ntohl(a->fraction);
131 uint32_t bi = ntohl(b->integer);
132 uint32_t bf = ntohl(b->fraction);
133 uint32_t o = (af < bf) ? 1u : 0u;
134 uint32_t f = af - bf;
135 uint32_t i = ai - bi - o;
136 dst->integer = htonl(i);
137 dst->fraction = htonl(f);
138}
139
140void div2_timestamp(T_NTP_TIMESTAMP *a)
141{
142 uint32_t ai = ntohl(a->integer);
143 uint32_t af = ntohl(a->fraction);
144
145 if ((ai & 1) != 0) {
146 ai >>= 1;
147 af >>= 1;
148 af |= 0x80000000u;
149 }
150 else {
151 ai >>= 1;
152 af >>= 1;
153 }
154
155 a->integer = htonl(ai);
156 a->fraction = htonl(af);
157}
158
159#define NTP_POLL_ASYNC 10 // 1024秒毎に時刻問い合わせ
160#define NTP_POLL_NORMAL 16 // 65536秒毎に時刻問い合わせ
161
162void ntp_cli_initialize(T_NTP_CLI_CONTEXT *nc, ID cepid)
163{
164 nc->cepid = cepid;
165 nc->state = NTP_CLI_STATE_ASYNC;
166 nc->timer = TMO_FEVR;
167 nc->snd_rmt.portno = NTP_SRV_PORTNO;
168 nc->snd_rmt.ipaddr = IPV4_ADDRANY;
169 nc->rcv_rmt.portno = 0;
170 nc->rcv_rmt.ipaddr = IPV4_ADDRANY;
171}
172
173void ntp_cli_execute()
174{
175 ntp_cli.exe_flag = 1;
176 syscall(wup_tsk(ntp_cli.tskid));
177}
178
179void ntp_cli_wakeup(T_NTP_CLI_CONTEXT *nc)
180{
181 int rcv_flag = nc->rcv_flag;
182 nc->rcv_flag = 0;
183
184 if (rcv_flag > 0) {
185 ntp_cli_read_data(nc);
186 return;
187 }
188
189 if (nc->exe_flag != 0) {
190 nc->exe_flag = 0;
191
192 nc->state = NTP_CLI_STATE_ASYNC;
193 nc->timer = 0;
194 }
195}
196
197void ntp_cli_read_data(T_NTP_CLI_CONTEXT *nc)
198{
199 struct timespec tp;
200 T_NTP_MSG *ntp = &nc->ntp_msg;
201
202 // NTP時刻応答の場合
203 if ((ntp->mode == NTP_MODE_SERVER) || (ntp->mode == NTP_MODE_BROADCAST)) {
204 switch (nc->state) {
205 case NTP_CLI_STATE_RESOLVE_ADDR:
206 case NTP_CLI_STATE_ASYNC:
207 break;
208 case NTP_CLI_STATE_REQUEST:
209 // サーバーからの応答時刻を取得
210 memcpy(&nc->receive_timestamp, &ntp->receive_timestamp, sizeof(nc->receive_timestamp));
211 memcpy(&nc->transmit_timestamp, &ntp->transmit_timestamp, sizeof(nc->transmit_timestamp));
212
213 // 現在時刻取得
214 ntp_cli_read_time(nc, &tp);
215
216 // NTP参照時刻に現在時刻を設定
217 set_systime_to_ntptime(&tp, &nc->recv_resp_timestamp);
218
219 // 時刻を更新
220 ntp_cli_update_time(nc);
221
222 nc->state = NTP_CLI_STATE_SYNC;
223 nc->poll = NTP_POLL_NORMAL;
224 nc->timer = (1 << nc->poll) * 1000 * 1000;
225 break;
226 case NTP_CLI_STATE_SYNC:
227 break;
228 }
229 }
230 // NTP時刻要求の場合
231 else if (ntp->mode == NTP_MODE_CLIENT) {
232 // 現在時刻取得
233 ntp_cli_read_time(nc, &tp);
234
235 // NTP受信・送信時刻に現在時刻を設定
236 set_systime_to_ntptime(&tp, &nc->receive_timestamp);
237 set_systime_to_ntptime(&tp, &nc->transmit_timestamp);
238
239 // NTPパケット送信
240 ntp_cli_time_synchronization(nc, NTP_MODE_SERVER);
241 }
242}
243
244void ntp_cli_update_time(T_NTP_CLI_CONTEXT *nc)
245{
246 struct timespec tp;
247 T_NTP_TIMESTAMP dt1, dt2, ofs;
248
249 sub_timestamp(&dt1, &nc->receive_timestamp, &nc->originate_timestamp);
250 sub_timestamp(&dt2, &nc->recv_resp_timestamp, &nc->transmit_timestamp);
251 sub_timestamp(&ofs, &dt1, &dt2);
252 div2_timestamp(&ofs);
253
254 // 差が大きい場合はサーバーの送信時間を設定
255 if (ntohl(ofs.integer) > 2) {
256 memcpy(&nc->reference_timestamp, &nc->transmit_timestamp, sizeof(nc->transmit_timestamp));
257 }
258 else {
259 add_timestamp(&nc->reference_timestamp, &nc->recv_resp_timestamp, &ofs);
260 }
261
262 set_ntptime_to_systime(&tp, &nc->reference_timestamp);
263
264 ntp_cli_write_time(nc, &tp);
265
266 nc->buf[0] = '\0';
267#ifndef _MSC_VER
268 if (ctime_r(&tp.tv_sec, nc->buf) != NULL)
269#else
270 if (ctime_s(nc->buf, sizeof(nc->buf), &tp.tv_sec) == 0)
271#endif
272 {
273 /* 改行コードの削除 */
274 int len = strnlen(nc->buf, sizeof(nc->buf) - 1);
275 nc->buf[len - 1] = '\0';
276 }
277 else {
278 nc->buf[0] = '\0';
279 }
280
281 ntstdio_printf(&ntstdio, "[NTP CLI,%d] recv time: %s .%09u\n",
282 nc->cepid, nc->buf, tp.tv_nsec);
283}
284
285int ntp_cli_get_timer(T_NTP_CLI_CONTEXT *nc)
286{
287 return nc->timer;
288}
289
290void ntp_cli_progress(T_NTP_CLI_CONTEXT *nc, TMO elapse)
291{
292 if (nc->timer <= 0)
293 return;
294
295 nc->timer -= elapse;
296 if (nc->timer < 0)
297 nc->timer = 0;
298}
299
300void ntp_cli_timeout(T_NTP_CLI_CONTEXT *nc)
301{
302 struct timespec tp;
303 char *line;
304
305 if (nc->timer != 0)
306 return;
307
308 switch (nc->state) {
309 case NTP_CLI_STATE_ASYNC:
310#if defined(SUPPORT_INET6) && defined(SUPPORT_INET4)
311 line = lookup_ipaddr(&nc->ipaddr6, NTP_SRV_URL, API_PROTO_IPV4);
312 if (line == NULL || !in6_is_addr_ipv4mapped(&nc->ipaddr6)) {
313 ntstdio_printf(&ntstdio, "[NTP CLI,%d] sleep %d.%03u[s], unknown host.",
314 nc->cepid, SLP_ITV / SYSTIM_HZ, SLP_ITV % SYSTIM_HZ);
315 nc->timer = SLP_ITV;
316 break;
317 }
318 nc->snd_rmt.ipaddr = ntohl(nc->ipaddr6.s6_addr32[3]);
319#else /* of #if defined(SUPPORT_INET6) && defined(SUPPORT_INET4) */
320 if ((line = lookup_ipaddr(&nc->snd_rmt.ipaddr, NTP_SRV_URL, DEFAULT_API_PROTO)) == NULL) {
321 ntstdio_printf(&ntstdio, "[NTP CLI,%d] sleep %d.%03u[s], unknown host.",
322 nc->cepid, SLP_ITV / SYSTIM_HZ, SLP_ITV % SYSTIM_HZ);
323 nc->timer = SLP_ITV;
324 break;
325 }
326#endif /* of #if defined(SUPPORT_INET6) && defined(SUPPORT_INET4) */
327 nc->state = NTP_CLI_STATE_RESOLVE_ADDR;
328 nc->timer = 1000;
329 /* through */
330 case NTP_CLI_STATE_RESOLVE_ADDR:
331 // 現在時刻取得
332 ntp_cli_read_time(nc, &tp);
333
334 // NTP開始時刻に現在時刻を設定
335 set_systime_to_ntptime(&tp, &nc->originate_timestamp);
336 memset(&nc->receive_timestamp, 0, sizeof(nc->receive_timestamp));
337 memset(&nc->transmit_timestamp, 0, sizeof(nc->transmit_timestamp));
338
339 // NTPパケット送信
340 ntp_cli_time_synchronization(nc, NTP_MODE_CLIENT);
341
342 // NTP応答待ちに遷移、500msでリトライ
343 nc->retry = 0;
344 nc->state = NTP_CLI_STATE_REQUEST;
345 nc->timer = 500 * 1000;
346 break;
347 case NTP_CLI_STATE_REQUEST:
348 nc->retry++;
349 if (nc->retry > 3) {
350 nc->state = NTP_CLI_STATE_ASYNC;
351 nc->poll = NTP_POLL_ASYNC;
352 nc->timer = (1 << nc->poll) * 1000 * 1000; // 1024秒後に時刻同期
353 break;
354 }
355 // 現在時刻取得
356 ntp_cli_read_time(nc, &tp);
357
358 // NTP開始時刻に現在時刻を設定
359 set_systime_to_ntptime(&tp, &nc->originate_timestamp);
360 memset(&nc->receive_timestamp, 0, sizeof(nc->receive_timestamp));
361 memset(&nc->transmit_timestamp, 0, sizeof(nc->transmit_timestamp));
362
363 // NTPパケット送信
364 ntp_cli_time_synchronization(nc, NTP_MODE_CLIENT);
365
366 // NTP応答待ちに遷移、500msでリトライ
367 nc->state = NTP_CLI_STATE_REQUEST;
368 nc->timer = 500 * 1000;
369 break;
370 case NTP_CLI_STATE_SYNC:
371 // 現在時刻取得
372 ntp_cli_read_time(nc, &tp);
373
374 // NTP開始時刻に現在時刻を設定
375 set_systime_to_ntptime(&tp, &nc->originate_timestamp);
376 memset(&nc->receive_timestamp, 0, sizeof(nc->receive_timestamp));
377 memset(&nc->transmit_timestamp, 0, sizeof(nc->transmit_timestamp));
378
379 // NTPパケット送信
380 ntp_cli_time_synchronization(nc, NTP_MODE_CLIENT);
381
382 // NTP応答待ちに遷移、500msでリトライ
383 nc->state = NTP_CLI_STATE_REQUEST;
384 nc->timer = 500 * 1000;
385 break;
386 }
387}
388
389ER ntp_cli_time_synchronization(T_NTP_CLI_CONTEXT *nc, ntp_mode_t mode)
390{
391 ER_UINT len = sizeof(nc->ntp_msg);
392 T_NTP_MSG *ntp = &nc->ntp_msg;
393 ER error;
394
395 memset(ntp, 0, len);
396
397 ntp->leap_indicator = 0;
398 ntp->version_number = 4;
399 ntp->mode = mode;
400 ntp->stratum = (mode == NTP_MODE_CLIENT) ? 2 : 1;
401 ntp->poll = nc->poll;
402 ntp->precision = 0xfa; // 精度は10^-6(1μs)
403 ntp->root_delay = htonl(0);
404 ntp->root_dispersion = htonl(0);
405 // 同期のための外部的な手段のないサブネット
406 ntp->reference_identifier[0] = 'L';
407 ntp->reference_identifier[1] = 'O';
408 ntp->reference_identifier[2] = 'C';
409 ntp->reference_identifier[3] = 'L';
410 // 参照タイムスタンプ
411 memcpy(&ntp->reference_timestamp, &nc->reference_timestamp, sizeof(ntp->reference_timestamp));
412 // 開始タイムスタンプ
413 memcpy(&ntp->originate_timestamp, &nc->originate_timestamp, sizeof(ntp->originate_timestamp));
414 // 受信タイムスタンプ
415 memcpy(&ntp->receive_timestamp, &nc->receive_timestamp, sizeof(ntp->receive_timestamp));
416 // 送信タイムスタンプ
417 memcpy(&ntp->transmit_timestamp, &nc->transmit_timestamp, sizeof(ntp->transmit_timestamp));
418 // 鍵識別子
419 ntp->key_identifier[0] = 0x08;
420 ntp->key_identifier[1] = 0x18;
421 ntp->key_identifier[2] = 0x00;
422 ntp->key_identifier[3] = 0x00;
423
424 if ((error = udp_snd_dat(nc->cepid, &nc->snd_rmt, ntp, len, TMO_NBLK)) != E_WBLK) {
425 ntstdio_printf(&ntstdio, "[NTP CLI,%d] udp_snd_dat error: %s",
426 nc->cepid, itron_strerror(error));
427 return error;
428 }
429 else
430 syslog(LOG_DEBUG, "[NTP CLI,%d] udp_snd_dat: to: %s.%d\n",
431 nc->cepid, ip2str(NULL, &nc->snd_rmt.ipaddr), nc->snd_rmt.portno);
432
433 return E_OK;
434}
435
436void ntp_cli_read_time(T_NTP_CLI_CONTEXT *nc, struct timespec *tp)
437{
438 SYSTIM time;
439 ER ret;
440
441 ret = get_tim(&time);
442 if (ret != E_OK) {
443 ntstdio_printf(&ntstdio, "[NTP CLI,%d] get_tim error: %s",
444 nc->cepid, itron_strerror(ret));
445 tp->tv_sec = 0;
446 tp->tv_nsec = 0;
447 return;
448 }
449
450 tp->tv_sec = time / 1000000ll;
451 tp->tv_nsec = (time % 1000000ll) * 1000ll;
452}
453
454void ntp_cli_write_time(T_NTP_CLI_CONTEXT *nc, struct timespec *tp)
455{
456 SYSTIM time;
457 ER ret;
458
459 time = (tp->tv_sec * 1000000ll) + (tp->tv_nsec / 1000ll);
460
461 ret = set_tim(time);
462 if (ret != E_OK) {
463 ntstdio_printf(&ntstdio, "[NTP CLI,%d] set_tim error: %s",
464 nc->cepid, itron_strerror(ret));
465 }
466}
467
468/*
469 * ノンブロッキングコールのコールバック関数
470 */
471
472ER
473callback_nblk_ntp_cli (ID cepid, FN fncd, void *p_parblk)
474{
475 T_NTP_CLI_CONTEXT *nc = &ntp_cli;
476 ER_UINT len;
477
478 len = *(ER_UINT*)p_parblk;
479 if (len < 0 && len != E_RLWAI) {
480 /* E_RLWAI 以外で、0 以下の場合は、エラーを意味している。*/
481 ntstdio_printf(&ntstdio, "[NTP CLI,%d] callback error: %s, fncd: %s", nc->cepid,
482 itron_strerror(len), in_strtfn(fncd));
483 }
484 else {
485 if (fncd == TEV_UDP_RCV_DAT) {
486 if ((len = udp_rcv_dat(nc->cepid, &nc->rcv_rmt, &nc->ntp_msg, len, TMO_POL)) < 0)
487 {
488 ntstdio_printf(&ntstdio, "[NTP CLI,%d] udp_rcv_dat error: %s", nc->cepid,
489 itron_strerror(len));
490 }
491 else
492 syslog(LOG_DEBUG, "[NTP CLI,%d] udp_rcv_dat len: %d", nc->cepid, len);
493
494 if (len >= sizeof(nc->ntp_msg))
495 nc->rcv_flag = len;
496 else
497 nc->rcv_flag = 0;
498 }
499 syscall(wup_tsk(nc->tskid));
500 }
501
502 return E_OK;
503}
504
505#ifdef NTP_CLI_TASK
506
507/*
508 * NTP クライアント送信タスク
509 */
510
511void
512ntp_cli_task (intptr_t exinf)
513{
514 T_NTP_CLI_CONTEXT *nc = &ntp_cli;
515 ER error, ret;
516 SYSTIM prev, time;
517 int timer;
518
519 get_tid(&nc->tskid);
520 ntstdio_printf(&ntstdio, "[NTP CLI:%d,%d] started.", nc->tskid, (ID)exinf);
521
522 /* 初期化 */
523 ntp_cli_initialize(nc, (ID)exinf);
524
525 ret = get_tim(&time);
526 if (ret != E_OK) {
527 ntstdio_printf(&ntstdio, "[NTP CLI,%d] get_tim error: %7lu,%s",
528 nc->cepid, time / SYSTIM_HZ, itron_strerror(ret));
529 return;
530 }
531
532 while (true) {
533 prev = time;
534
535 /* タイマー取得 */
536 timer = ntp_cli_get_timer(nc);
537
538 /* 待ち */
539 error = tslp_tsk(timer);
540 if ((error != E_OK) && (error != E_TMOUT)) {
541 ntstdio_printf(&ntstdio, "[NTP CLI,%d] tslp_tsk error: %s %d",
542 nc->cepid, itron_strerror(error), timer);
543 break;
544 }
545
546 ret = get_tim(&time);
547 if (ret != E_OK) {
548 ntstdio_printf(&ntstdio, "[NTP CLI,%d] get_tim error: %s",
549 nc->cepid, itron_strerror(ret));
550 break;
551 }
552
553 /* 時間経過 */
554 ntp_cli_progress(nc, time - prev);
555
556 /* 起こされた場合 */
557 if (error == E_OK) {
558 ntp_cli_wakeup(nc);
559 }
560
561 /* タイムアウト処理 */
562 ntp_cli_timeout(nc);
563 }
564}
565
566#endif
Note: See TracBrowser for help on using the repository browser.