github.com/coyove/sdss@v0.0.0-20231129015646-c2ec58cca6a2/future/chrony/packet.go (about) 1 /* 2 Copyright (c) Facebook, Inc. and its affiliates. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package chrony 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "net" 24 "time" 25 26 log "github.com/sirupsen/logrus" 27 ) 28 29 // original C++ versions of those consts/structs 30 // are in https://github.com/mlichvar/chrony/blob/master/candm.h 31 32 // ReplyType identifies reply packet type 33 type ReplyType uint16 34 35 // CommandType identifies command type in both request and repy 36 type CommandType uint16 37 38 // ModeType identifies source (peer) mode 39 type ModeType uint16 40 41 // SourceStateType identifies source (peer) state 42 type SourceStateType uint16 43 44 // ResponseStatusType identifies response status 45 type ResponseStatusType uint16 46 47 // PacketType - request or reply 48 type PacketType uint8 49 50 // we implement latest (at the moment) protocol version 51 const protoVersionNumber uint8 = 6 52 const maxDataLen = 396 53 54 // packet types 55 const ( 56 pktTypeCmdRequest PacketType = 1 57 pktTypeCmdReply PacketType = 2 58 ) 59 60 func (t PacketType) String() string { 61 switch t { 62 case pktTypeCmdRequest: 63 return "request" 64 case pktTypeCmdReply: 65 return "reply" 66 default: 67 return fmt.Sprintf("unknown (%d)", t) 68 } 69 } 70 71 // request types. Only those we support, there are more 72 const ( 73 reqNSources CommandType = 14 74 reqSourceData CommandType = 15 75 reqTracking CommandType = 33 76 reqSourceStats CommandType = 34 77 reqActivity CommandType = 44 78 reqServerStats CommandType = 54 79 reqNTPData CommandType = 57 80 ) 81 82 // reply types 83 const ( 84 rpyNSources ReplyType = 2 85 rpySourceData ReplyType = 3 86 rpyTracking ReplyType = 5 87 rpySourceStats ReplyType = 6 88 rpyActivity ReplyType = 12 89 rpyServerStats ReplyType = 14 90 rpyNTPData ReplyType = 16 91 rpyServerStats2 ReplyType = 22 92 rpyServerStats3 ReplyType = 24 93 ) 94 95 // source modes 96 const ( 97 SourceModeClient ModeType = 0 98 SourceModePeer ModeType = 1 99 SourceModeRef ModeType = 2 100 ) 101 102 // source state 103 const ( 104 SourceStateSync SourceStateType = 0 105 SourceStateUnreach SourceStateType = 1 106 SourceStateFalseTicker SourceStateType = 2 107 SourceStateJittery SourceStateType = 3 108 SourceStateCandidate SourceStateType = 4 109 SourceStateOutlier SourceStateType = 5 110 ) 111 112 // source data flags 113 const ( 114 FlagNoselect uint16 = 0x1 115 FlagPrefer uint16 = 0x2 116 FlagTrust uint16 = 0x4 117 FlagRequire uint16 = 0x8 118 ) 119 120 // ntpdata flags 121 const ( 122 NTPFlagsTests uint16 = 0x3ff 123 NTPFlagInterleaved uint16 = 0x4000 124 NTPFlagAuthenticated uint16 = 0x8000 125 ) 126 127 // response status codes 128 const ( 129 sttSuccess ResponseStatusType = 0 130 sttFailed ResponseStatusType = 1 131 sttUnauth ResponseStatusType = 2 132 sttInvalid ResponseStatusType = 3 133 sttNoSuchSource ResponseStatusType = 4 134 sttInvalidTS ResponseStatusType = 5 135 sttNotEnabled ResponseStatusType = 6 136 sttBadSubnet ResponseStatusType = 7 137 sttAccessAllowed ResponseStatusType = 8 138 sttAccessDenied ResponseStatusType = 9 139 sttNoHostAccess ResponseStatusType = 10 140 sttSourceAlreadyKnown ResponseStatusType = 11 141 sttTooManySources ResponseStatusType = 12 142 sttNoRTC ResponseStatusType = 13 143 sttBadRTCFile ResponseStatusType = 14 144 sttInactive ResponseStatusType = 15 145 sttBadSample ResponseStatusType = 16 146 sttInvalidAF ResponseStatusType = 17 147 sttBadPktVersion ResponseStatusType = 18 148 sttBadPktLength ResponseStatusType = 19 149 ) 150 151 // StatusDesc provides mapping from ResponseStatusType to string 152 var StatusDesc = [20]string{ 153 "SUCCESS", 154 "FAILED", 155 "UNAUTH", 156 "INVALID", 157 "NOSUCHSOURCE", 158 "INVALIDTS", 159 "NOTENABLED", 160 "BADSUBNET", 161 "ACCESSALLOWED", 162 "ACCESSDENIED", 163 "NOHOSTACCESS", 164 "SOURCEALREADYKNOWN", 165 "TOOMANYSOURCES", 166 "NORTC", 167 "BADRTCFILE", 168 "INACTIVE", 169 "BADSAMPLE", 170 "INVALIDAF", 171 "BADPKTVERSION", 172 "BADPKTLENGTH", 173 } 174 175 func (r ResponseStatusType) String() string { 176 if int(r) >= len(StatusDesc) { 177 return fmt.Sprintf("UNKNOWN (%d)", r) 178 } 179 return StatusDesc[r] 180 } 181 182 // SourceStateDesc provides mapping from SourceStateType to string 183 var SourceStateDesc = [6]string{ 184 "sync", 185 "unreach", 186 "falseticker", 187 "jittery", 188 "candidate", 189 "outlier", 190 } 191 192 func (s SourceStateType) String() string { 193 if int(s) >= len(SourceStateDesc) { 194 return fmt.Sprintf("unknown (%d)", s) 195 } 196 return SourceStateDesc[s] 197 } 198 199 // ModeTypeDesc provides mapping from ModeType to string 200 var ModeTypeDesc = [3]string{ 201 "client", 202 "peer", 203 "reference clock", 204 } 205 206 func (m ModeType) String() string { 207 if int(m) >= len(ModeTypeDesc) { 208 return fmt.Sprintf("unknown (%d)", m) 209 } 210 return ModeTypeDesc[m] 211 } 212 213 // RequestHead is the first (common) part of the request, 214 // in a format that can be directly passed to binary.Write 215 type RequestHead struct { 216 Version uint8 217 PKTType PacketType 218 Res1 uint8 219 Res2 uint8 220 Command CommandType 221 Attempt uint16 222 Sequence uint32 223 Pad1 uint32 224 Pad2 uint32 225 } 226 227 // GetCommand returns request packet command 228 func (r *RequestHead) GetCommand() CommandType { 229 return r.Command 230 } 231 232 // SetSequence sets request packet sequence number 233 func (r *RequestHead) SetSequence(n uint32) { 234 r.Sequence = n 235 } 236 237 // RequestPacket is an interface to abstract all different outgoing packets 238 type RequestPacket interface { 239 GetCommand() CommandType 240 SetSequence(n uint32) 241 } 242 243 // ResponsePacket is an interface to abstract all different incoming packets 244 type ResponsePacket interface { 245 GetCommand() CommandType 246 GetType() PacketType 247 GetStatus() ResponseStatusType 248 } 249 250 // RequestSources - packet to request number of sources (peers) 251 type RequestSources struct { 252 RequestHead 253 // we actually need this to send proper packet 254 data [maxDataLen]uint8 255 } 256 257 // RequestSourceData - packet to request source data for source id 258 type RequestSourceData struct { 259 RequestHead 260 Index int32 261 EOR int32 262 // we pass i32 - 4 bytes 263 data [maxDataLen - 4]uint8 264 } 265 266 // RequestNTPData - packet to request NTP data for peer IP. 267 // As of now, it's only allowed by Chrony over unix socket connection. 268 type RequestNTPData struct { 269 RequestHead 270 IPAddr ipAddr 271 EOR int32 272 // we pass at max ipv6 addr - 16 bytes 273 data [maxDataLen - 16]uint8 274 } 275 276 // RequestServerStats - packet to request server stats 277 type RequestServerStats struct { 278 RequestHead 279 // we actually need this to send proper packet 280 data [maxDataLen]uint8 281 } 282 283 // RequestTracking - packet to request 'tracking' data 284 type RequestTracking struct { 285 RequestHead 286 // we actually need this to send proper packet 287 data [maxDataLen]uint8 288 } 289 290 // RequestSourceStats - packet to request 'sourcestats' data for source id 291 type RequestSourceStats struct { 292 RequestHead 293 Index int32 294 EOR int32 295 // we pass i32 - 4 bytes 296 data [maxDataLen - 4]uint8 297 } 298 299 // RequestActivity - packet to request 'activity' data 300 type RequestActivity struct { 301 RequestHead 302 // we actually need this to send proper packet 303 data [maxDataLen]uint8 304 } 305 306 // ReplyHead is the first (common) part of the reply packet, 307 // in a format that can be directly passed to binary.Read 308 type ReplyHead struct { 309 Version uint8 310 PKTType PacketType 311 Res1 uint8 312 Res2 uint8 313 Command CommandType 314 Reply ReplyType 315 Status ResponseStatusType 316 Pad1 uint16 317 Pad2 uint16 318 Pad3 uint16 319 Sequence uint32 320 Pad4 uint32 321 Pad5 uint32 322 } 323 324 // GetCommand returns reply packet command 325 func (r *ReplyHead) GetCommand() CommandType { 326 return r.Command 327 } 328 329 // GetType returns reply packet type 330 func (r *ReplyHead) GetType() PacketType { 331 return r.PKTType 332 } 333 334 // GetStatus returns reply packet status 335 func (r *ReplyHead) GetStatus() ResponseStatusType { 336 return r.Status 337 } 338 339 type replySourcesContent struct { 340 NSources uint32 341 } 342 343 // ReplySources is a usable version of a reply to 'sources' command 344 type ReplySources struct { 345 ReplyHead 346 NSources int 347 } 348 349 type replySourceDataContent struct { 350 IPAddr ipAddr 351 Poll int16 352 Stratum uint16 353 State SourceStateType 354 Mode ModeType 355 Flags uint16 356 Reachability uint16 357 SinceSample uint32 358 OrigLatestMeas chronyFloat 359 LatestMeas chronyFloat 360 LatestMeasErr chronyFloat 361 } 362 363 // SourceData contains parsed version of 'source data' reply 364 type SourceData struct { 365 IPAddr net.IP 366 Poll int16 367 Stratum uint16 368 State SourceStateType 369 Mode ModeType 370 Flags uint16 371 Reachability uint16 372 SinceSample uint32 373 OrigLatestMeas float64 374 LatestMeas float64 375 LatestMeasErr float64 376 } 377 378 func newSourceData(r *replySourceDataContent) *SourceData { 379 return &SourceData{ 380 IPAddr: r.IPAddr.ToNetIP(), 381 Poll: r.Poll, 382 Stratum: r.Stratum, 383 State: r.State, 384 Mode: r.Mode, 385 Flags: r.Flags, 386 Reachability: r.Reachability, 387 SinceSample: r.SinceSample, 388 OrigLatestMeas: r.OrigLatestMeas.ToFloat(), 389 LatestMeas: r.LatestMeas.ToFloat(), 390 LatestMeasErr: r.LatestMeasErr.ToFloat(), 391 } 392 } 393 394 // ReplySourceData is a usable version of 'source data' reply for given source id 395 type ReplySourceData struct { 396 ReplyHead 397 SourceData 398 } 399 400 type replyTrackingContent struct { 401 RefID uint32 402 IPAddr ipAddr // our current sync source 403 Stratum uint16 404 LeapStatus uint16 405 RefTime timeSpec 406 CurrentCorrection chronyFloat 407 LastOffset chronyFloat 408 RMSOffset chronyFloat 409 FreqPPM chronyFloat 410 ResidFreqPPM chronyFloat 411 SkewPPM chronyFloat 412 RootDelay chronyFloat 413 RootDispersion chronyFloat 414 LastUpdateInterval chronyFloat 415 } 416 417 // Tracking contains parsed version of 'tracking' reply 418 type Tracking struct { 419 RefID uint32 420 IPAddr net.IP 421 Stratum uint16 422 LeapStatus uint16 423 RefTime time.Time 424 CurrentCorrection float64 425 LastOffset float64 426 RMSOffset float64 427 FreqPPM float64 428 ResidFreqPPM float64 429 SkewPPM float64 430 RootDelay float64 431 RootDispersion float64 432 LastUpdateInterval float64 433 } 434 435 func newTracking(r *replyTrackingContent) *Tracking { 436 return &Tracking{ 437 RefID: r.RefID, 438 IPAddr: r.IPAddr.ToNetIP(), 439 Stratum: r.Stratum, 440 LeapStatus: r.LeapStatus, 441 RefTime: r.RefTime.ToTime(), 442 CurrentCorrection: r.CurrentCorrection.ToFloat(), 443 LastOffset: r.LastOffset.ToFloat(), 444 RMSOffset: r.RMSOffset.ToFloat(), 445 FreqPPM: r.FreqPPM.ToFloat(), 446 ResidFreqPPM: r.ResidFreqPPM.ToFloat(), 447 SkewPPM: r.SkewPPM.ToFloat(), 448 RootDelay: r.RootDelay.ToFloat(), 449 RootDispersion: r.RootDispersion.ToFloat(), 450 LastUpdateInterval: r.LastUpdateInterval.ToFloat(), 451 } 452 } 453 454 // ReplyTracking has usable 'tracking' response 455 type ReplyTracking struct { 456 ReplyHead 457 Tracking 458 } 459 460 type replySourceStatsContent struct { 461 RefID uint32 462 IPAddr ipAddr 463 NSamples uint32 464 NRuns uint32 465 SpanSeconds uint32 466 StandardDeviation chronyFloat 467 ResidFreqPPM chronyFloat 468 SkewPPM chronyFloat 469 EstimatedOffset chronyFloat 470 EstimatedOffsetErr chronyFloat 471 } 472 473 // SourceStats contains stats about the source 474 type SourceStats struct { 475 RefID uint32 476 IPAddr net.IP 477 NSamples uint32 478 NRuns uint32 479 SpanSeconds uint32 480 StandardDeviation float64 481 ResidFreqPPM float64 482 SkewPPM float64 483 EstimatedOffset float64 484 EstimatedOffsetErr float64 485 } 486 487 func newSourceStats(r *replySourceStatsContent) *SourceStats { 488 return &SourceStats{ 489 RefID: r.RefID, 490 IPAddr: r.IPAddr.ToNetIP(), 491 NSamples: r.NSamples, 492 NRuns: r.NRuns, 493 SpanSeconds: r.SpanSeconds, 494 StandardDeviation: r.StandardDeviation.ToFloat(), 495 ResidFreqPPM: r.ResidFreqPPM.ToFloat(), 496 SkewPPM: r.SkewPPM.ToFloat(), 497 EstimatedOffset: r.EstimatedOffset.ToFloat(), 498 EstimatedOffsetErr: r.EstimatedOffsetErr.ToFloat(), 499 } 500 } 501 502 // ReplySourceStats has usable 'sourcestats' response 503 type ReplySourceStats struct { 504 ReplyHead 505 SourceStats 506 } 507 508 type replyNTPDataContent struct { 509 RemoteAddr ipAddr 510 LocalAddr ipAddr 511 RemotePort uint16 512 Leap uint8 513 Version uint8 514 Mode uint8 515 Stratum uint8 516 Poll int8 517 Precision int8 518 RootDelay chronyFloat 519 RootDispersion chronyFloat 520 RefID uint32 521 RefTime timeSpec 522 Offset chronyFloat 523 PeerDelay chronyFloat 524 PeerDispersion chronyFloat 525 ResponseTime chronyFloat 526 JitterAsymmetry chronyFloat 527 Flags uint16 528 TXTssChar uint8 529 RXTssChar uint8 530 TotalTXCount uint32 531 TotalRXCount uint32 532 TotalValidCount uint32 533 Reserved [4]uint32 534 } 535 536 // NTPData contains parsed version of 'ntpdata' reply 537 type NTPData struct { 538 RemoteAddr net.IP 539 LocalAddr net.IP 540 RemotePort uint16 541 Leap uint8 542 Version uint8 543 Mode uint8 544 Stratum uint8 545 Poll int8 546 Precision int8 547 RootDelay float64 548 RootDispersion float64 549 RefID uint32 550 RefTime time.Time 551 Offset float64 552 PeerDelay float64 553 PeerDispersion float64 554 ResponseTime float64 555 JitterAsymmetry float64 556 Flags uint16 557 TXTssChar uint8 558 RXTssChar uint8 559 TotalTXCount uint32 560 TotalRXCount uint32 561 TotalValidCount uint32 562 } 563 564 func newNTPData(r *replyNTPDataContent) *NTPData { 565 return &NTPData{ 566 RemoteAddr: r.RemoteAddr.ToNetIP(), 567 LocalAddr: r.LocalAddr.ToNetIP(), 568 RemotePort: r.RemotePort, 569 Leap: r.Leap, 570 Version: r.Version, 571 Mode: r.Mode, 572 Stratum: r.Stratum, 573 Poll: r.Poll, 574 Precision: r.Precision, 575 RootDelay: r.RootDelay.ToFloat(), 576 RootDispersion: r.RootDispersion.ToFloat(), 577 RefID: r.RefID, 578 RefTime: r.RefTime.ToTime(), 579 Offset: r.Offset.ToFloat(), 580 PeerDelay: r.PeerDelay.ToFloat(), 581 PeerDispersion: r.PeerDispersion.ToFloat(), 582 ResponseTime: r.ResponseTime.ToFloat(), 583 JitterAsymmetry: r.JitterAsymmetry.ToFloat(), 584 Flags: r.Flags, 585 TXTssChar: r.TXTssChar, 586 RXTssChar: r.RXTssChar, 587 TotalTXCount: r.TotalTXCount, 588 TotalRXCount: r.TotalRXCount, 589 TotalValidCount: r.TotalValidCount, 590 } 591 } 592 593 // ReplyNTPData is a what end user will get for of 'ntp data' response 594 type ReplyNTPData struct { 595 ReplyHead 596 NTPData 597 } 598 599 // Activity contains parsed version of 'activity' reply 600 type Activity struct { 601 Online int32 602 Offline int32 603 BurstOnline int32 604 BurstOffline int32 605 Unresolved int32 606 } 607 608 // ReplyActivity is a usable version of 'activity' response 609 type ReplyActivity struct { 610 ReplyHead 611 Activity 612 } 613 614 // ServerStats contains parsed version of 'serverstats' reply 615 type ServerStats struct { 616 NTPHits uint32 617 CMDHits uint32 618 NTPDrops uint32 619 CMDDrops uint32 620 LogDrops uint32 621 } 622 623 // ReplyServerStats is a usable version of 'serverstats' response 624 type ReplyServerStats struct { 625 ReplyHead 626 ServerStats 627 } 628 629 // ServerStats2 contains parsed version of 'serverstats2' reply 630 type ServerStats2 struct { 631 NTPHits uint32 632 NKEHits uint32 633 CMDHits uint32 634 NTPDrops uint32 635 NKEDrops uint32 636 CMDDrops uint32 637 LogDrops uint32 638 NTPAuthHits uint32 639 } 640 641 // ReplyServerStats2 is a usable version of 'serverstats2' response 642 type ReplyServerStats2 struct { 643 ReplyHead 644 ServerStats2 645 } 646 647 // ServerStats3 contains parsed version of 'serverstats3' reply 648 type ServerStats3 struct { 649 NTPHits uint32 650 NKEHits uint32 651 CMDHits uint32 652 NTPDrops uint32 653 NKEDrops uint32 654 CMDDrops uint32 655 LogDrops uint32 656 NTPAuthHits uint32 657 NTPInterleavedHits uint32 658 NTPTimestamps uint32 659 NTPSpanSeconds uint32 660 } 661 662 // ReplyServerStats3 is a usable version of 'serverstats3' response 663 type ReplyServerStats3 struct { 664 ReplyHead 665 ServerStats3 666 } 667 668 // here go request constructors 669 670 // NewSourcesPacket creates new packet to request number of sources (peers) 671 func NewSourcesPacket() *RequestSources { 672 return &RequestSources{ 673 RequestHead: RequestHead{ 674 Version: protoVersionNumber, 675 PKTType: pktTypeCmdRequest, 676 Command: reqNSources, 677 }, 678 data: [maxDataLen]uint8{}, 679 } 680 } 681 682 // NewTrackingPacket creates new packet to request 'tracking' information 683 func NewTrackingPacket() *RequestTracking { 684 return &RequestTracking{ 685 RequestHead: RequestHead{ 686 Version: protoVersionNumber, 687 PKTType: pktTypeCmdRequest, 688 Command: reqTracking, 689 }, 690 data: [maxDataLen]uint8{}, 691 } 692 } 693 694 // NewSourceStatsPacket creates a new packet to request 'sourcestats' information 695 func NewSourceStatsPacket(sourceID int32) *RequestSourceStats { 696 return &RequestSourceStats{ 697 RequestHead: RequestHead{ 698 Version: protoVersionNumber, 699 PKTType: pktTypeCmdRequest, 700 Command: reqSourceStats, 701 }, 702 Index: sourceID, 703 data: [maxDataLen - 4]uint8{}, 704 } 705 } 706 707 // NewSourceDataPacket creates new packet to request 'source data' information about source with given ID 708 func NewSourceDataPacket(sourceID int32) *RequestSourceData { 709 return &RequestSourceData{ 710 RequestHead: RequestHead{ 711 Version: protoVersionNumber, 712 PKTType: pktTypeCmdRequest, 713 Command: reqSourceData, 714 }, 715 Index: sourceID, 716 data: [maxDataLen - 4]uint8{}, 717 } 718 } 719 720 // NewNTPDataPacket creates new packet to request 'ntp data' information for given peer IP 721 func NewNTPDataPacket(ip net.IP) *RequestNTPData { 722 return &RequestNTPData{ 723 RequestHead: RequestHead{ 724 Version: protoVersionNumber, 725 PKTType: pktTypeCmdRequest, 726 Command: reqNTPData, 727 }, 728 IPAddr: *newIPAddr(ip), 729 data: [maxDataLen - 16]uint8{}, 730 } 731 } 732 733 // NewServerStatsPacket creates new packet to request 'serverstats' information 734 func NewServerStatsPacket() *RequestServerStats { 735 return &RequestServerStats{ 736 RequestHead: RequestHead{ 737 Version: protoVersionNumber, 738 PKTType: pktTypeCmdRequest, 739 Command: reqServerStats, 740 }, 741 data: [maxDataLen]uint8{}, 742 } 743 } 744 745 // NewActivityPacket creates new packet to request 'activity' information 746 func NewActivityPacket() *RequestActivity { 747 return &RequestActivity{ 748 RequestHead: RequestHead{ 749 Version: protoVersionNumber, 750 PKTType: pktTypeCmdRequest, 751 Command: reqActivity, 752 }, 753 data: [maxDataLen]uint8{}, 754 } 755 } 756 757 // decodePacket decodes bytes to valid response packet 758 func decodePacket(response []byte) (ResponsePacket, error) { 759 var err error 760 r := bytes.NewReader(response) 761 head := new(ReplyHead) 762 if err = binary.Read(r, binary.BigEndian, head); err != nil { 763 return nil, err 764 } 765 log.Debugf("response head: %+v", head) 766 if head.Status != sttSuccess { 767 return nil, fmt.Errorf("got status %s (%d)", head.Status, head.Status) 768 } 769 switch head.Reply { 770 case rpyNSources: 771 data := new(replySourcesContent) 772 if err = binary.Read(r, binary.BigEndian, data); err != nil { 773 return nil, err 774 } 775 log.Debugf("response data: %+v", data) 776 return &ReplySources{ 777 ReplyHead: *head, 778 NSources: int(data.NSources), 779 }, nil 780 case rpySourceData: 781 data := new(replySourceDataContent) 782 if err = binary.Read(r, binary.BigEndian, data); err != nil { 783 return nil, err 784 } 785 log.Debugf("response data: %+v", data) 786 return &ReplySourceData{ 787 ReplyHead: *head, 788 SourceData: *newSourceData(data), 789 }, nil 790 case rpyTracking: 791 data := new(replyTrackingContent) 792 if err = binary.Read(r, binary.BigEndian, data); err != nil { 793 return nil, err 794 } 795 log.Debugf("response data: %+v", data) 796 return &ReplyTracking{ 797 ReplyHead: *head, 798 Tracking: *newTracking(data), 799 }, nil 800 case rpySourceStats: 801 data := new(replySourceStatsContent) 802 if err = binary.Read(r, binary.BigEndian, data); err != nil { 803 return nil, err 804 } 805 log.Debugf("response data: %+v", data) 806 return &ReplySourceStats{ 807 ReplyHead: *head, 808 SourceStats: *newSourceStats(data), 809 }, nil 810 case rpyActivity: 811 data := new(Activity) 812 if err = binary.Read(r, binary.BigEndian, data); err != nil { 813 return nil, err 814 } 815 log.Debugf("response data: %+v", data) 816 return &ReplyActivity{ 817 ReplyHead: *head, 818 Activity: *data, 819 }, nil 820 case rpyServerStats: 821 data := new(ServerStats) 822 if err = binary.Read(r, binary.BigEndian, data); err != nil { 823 return nil, err 824 } 825 log.Debugf("response data: %+v", data) 826 return &ReplyServerStats{ 827 ReplyHead: *head, 828 ServerStats: *data, 829 }, nil 830 case rpyNTPData: 831 data := new(replyNTPDataContent) 832 if err = binary.Read(r, binary.BigEndian, data); err != nil { 833 return nil, err 834 } 835 log.Debugf("response data: %+v", data) 836 return &ReplyNTPData{ 837 ReplyHead: *head, 838 NTPData: *newNTPData(data), 839 }, nil 840 case rpyServerStats2: 841 data := new(ServerStats2) 842 if err = binary.Read(r, binary.BigEndian, data); err != nil { 843 return nil, err 844 } 845 log.Debugf("response data: %+v", data) 846 return &ReplyServerStats2{ 847 ReplyHead: *head, 848 ServerStats2: *data, 849 }, nil 850 case rpyServerStats3: 851 data := new(ServerStats3) 852 if err = binary.Read(r, binary.BigEndian, data); err != nil { 853 return nil, err 854 } 855 log.Debugf("response data: %+v", data) 856 return &ReplyServerStats3{ 857 ReplyHead: *head, 858 ServerStats3: *data, 859 }, nil 860 default: 861 return nil, fmt.Errorf("not implemented reply type %d from %+v", head.Reply, head) 862 } 863 }