util_windows.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // +build windows
  2. /*
  3. Copyright 2017 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package util
  15. import (
  16. "fmt"
  17. "net"
  18. "net/url"
  19. "strings"
  20. "syscall"
  21. "time"
  22. "github.com/Microsoft/go-winio"
  23. )
  24. const (
  25. tcpProtocol = "tcp"
  26. npipeProtocol = "npipe"
  27. )
  28. // CreateListener creates a listener on the specified endpoint.
  29. func CreateListener(endpoint string) (net.Listener, error) {
  30. protocol, addr, err := parseEndpoint(endpoint)
  31. if err != nil {
  32. return nil, err
  33. }
  34. switch protocol {
  35. case tcpProtocol:
  36. return net.Listen(tcpProtocol, addr)
  37. case npipeProtocol:
  38. return winio.ListenPipe(addr, nil)
  39. default:
  40. return nil, fmt.Errorf("only support tcp and npipe endpoint")
  41. }
  42. }
  43. // GetAddressAndDialer returns the address parsed from the given endpoint and a dialer.
  44. func GetAddressAndDialer(endpoint string) (string, func(addr string, timeout time.Duration) (net.Conn, error), error) {
  45. protocol, addr, err := parseEndpoint(endpoint)
  46. if err != nil {
  47. return "", nil, err
  48. }
  49. if protocol == tcpProtocol {
  50. return addr, tcpDial, nil
  51. }
  52. if protocol == npipeProtocol {
  53. return addr, npipeDial, nil
  54. }
  55. return "", nil, fmt.Errorf("only support tcp and npipe endpoint")
  56. }
  57. func tcpDial(addr string, timeout time.Duration) (net.Conn, error) {
  58. return net.DialTimeout(tcpProtocol, addr, timeout)
  59. }
  60. func npipeDial(addr string, timeout time.Duration) (net.Conn, error) {
  61. return winio.DialPipe(addr, &timeout)
  62. }
  63. func parseEndpoint(endpoint string) (string, string, error) {
  64. // url.Parse doesn't recognize \, so replace with / first.
  65. endpoint = strings.Replace(endpoint, "\\", "/", -1)
  66. u, err := url.Parse(endpoint)
  67. if err != nil {
  68. return "", "", err
  69. }
  70. if u.Scheme == "tcp" {
  71. return "tcp", u.Host, nil
  72. } else if u.Scheme == "npipe" {
  73. if strings.HasPrefix(u.Path, "//./pipe") {
  74. return "npipe", u.Path, nil
  75. }
  76. // fallback host if not provided.
  77. host := u.Host
  78. if host == "" {
  79. host = "."
  80. }
  81. return "npipe", fmt.Sprintf("//%s%s", host, u.Path), nil
  82. } else if u.Scheme == "" {
  83. return "", "", fmt.Errorf("Using %q as endpoint is deprecated, please consider using full url format", endpoint)
  84. } else {
  85. return u.Scheme, "", fmt.Errorf("protocol %q not supported", u.Scheme)
  86. }
  87. }
  88. // LocalEndpoint empty implementation
  89. func LocalEndpoint(path, file string) (string, error) {
  90. return "", fmt.Errorf("LocalEndpoints are unsupported in this build")
  91. }
  92. var tickCount = syscall.NewLazyDLL("kernel32.dll").NewProc("GetTickCount64")
  93. // GetBootTime returns the time at which the machine was started, truncated to the nearest second
  94. func GetBootTime() (time.Time, error) {
  95. currentTime := time.Now()
  96. output, _, err := tickCount.Call()
  97. if errno, ok := err.(syscall.Errno); !ok || errno != 0 {
  98. return time.Time{}, err
  99. }
  100. return currentTime.Add(-time.Duration(output) * time.Millisecond).Truncate(time.Second), nil
  101. }