master
go 96 lines 1.76 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package ntpd
4
5 import (
6 "net"
7 "time"
8
9 "github.com/facebook/time/ntp/control"
10 )
11
12 type ntpConn interface {
13 systemInfo() (map[string]string, error)
14 peerInfo(id uint16) (map[string]string, error)
15 peerIDs() ([]uint16, error)
16 close()
17 }
18
19 func newNTPClient(c Config) (ntpConn, error) {
20 conn, err := net.DialTimeout("udp", c.Address, c.Timeout.Duration())
21 if err != nil {
22 return nil, err
23 }
24
25 client := &ntpClient{
26 conn: conn,
27 timeout: c.Timeout.Duration(),
28 client: &control.NTPClient{Connection: conn},
29 }
30
31 return client, nil
32 }
33
34 type ntpClient struct {
35 conn net.Conn
36 timeout time.Duration
37 client *control.NTPClient
38 }
39
40 func (c *ntpClient) systemInfo() (map[string]string, error) {
41 return c.peerInfo(0)
42 }
43
44 func (c *ntpClient) peerInfo(id uint16) (map[string]string, error) {
45 msg := &control.NTPControlMsgHead{
46 VnMode: control.MakeVnMode(2, control.Mode),
47 REMOp: control.OpReadVariables,
48 AssociationID: id,
49 }
50
51 if err := c.conn.SetDeadline(time.Now().Add(c.timeout)); err != nil {
52 return nil, err
53 }
54
55 resp, err := c.client.Communicate(msg)
56 if err != nil {
57 return nil, err
58 }
59
60 return resp.GetAssociationInfo()
61 }
62
63 func (c *ntpClient) peerIDs() ([]uint16, error) {
64 msg := &control.NTPControlMsgHead{
65 VnMode: control.MakeVnMode(2, control.Mode),
66 REMOp: control.OpReadStatus,
67 }
68
69 if err := c.conn.SetDeadline(time.Now().Add(c.timeout)); err != nil {
70 return nil, err
71 }
72
73 resp, err := c.client.Communicate(msg)
74 if err != nil {
75 return nil, err
76 }
77
78 peers, err := resp.GetAssociations()
79 if err != nil {
80 return nil, err
81 }
82
83 var ids []uint16
84 for id := range peers {
85 ids = append(ids, id)
86 }
87
88 return ids, nil
89 }
90
91 func (c *ntpClient) close() {
92 if c.conn != nil {
93 _ = c.conn.Close()
94 c.conn = nil
95 }
96 }