123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- // +build windows
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package util
- import (
- "context"
- "fmt"
- "net"
- "net/url"
- "strings"
- "syscall"
- "time"
- "github.com/Microsoft/go-winio"
- )
- const (
- tcpProtocol = "tcp"
- npipeProtocol = "npipe"
- )
- // CreateListener creates a listener on the specified endpoint.
- func CreateListener(endpoint string) (net.Listener, error) {
- protocol, addr, err := parseEndpoint(endpoint)
- if err != nil {
- return nil, err
- }
- switch protocol {
- case tcpProtocol:
- return net.Listen(tcpProtocol, addr)
- case npipeProtocol:
- return winio.ListenPipe(addr, nil)
- default:
- return nil, fmt.Errorf("only support tcp and npipe endpoint")
- }
- }
- // GetAddressAndDialer returns the address parsed from the given endpoint and a context dialer.
- func GetAddressAndDialer(endpoint string) (string, func(ctx context.Context, addr string) (net.Conn, error), error) {
- protocol, addr, err := parseEndpoint(endpoint)
- if err != nil {
- return "", nil, err
- }
- if protocol == tcpProtocol {
- return addr, tcpDial, nil
- }
- if protocol == npipeProtocol {
- return addr, npipeDial, nil
- }
- return "", nil, fmt.Errorf("only support tcp and npipe endpoint")
- }
- func tcpDial(ctx context.Context, addr string) (net.Conn, error) {
- return (&net.Dialer{}).DialContext(ctx, tcpProtocol, addr)
- }
- func npipeDial(ctx context.Context, addr string) (net.Conn, error) {
- return winio.DialPipeContext(ctx, addr)
- }
- func parseEndpoint(endpoint string) (string, string, error) {
- // url.Parse doesn't recognize \, so replace with / first.
- endpoint = strings.Replace(endpoint, "\\", "/", -1)
- u, err := url.Parse(endpoint)
- if err != nil {
- return "", "", err
- }
- if u.Scheme == "tcp" {
- return "tcp", u.Host, nil
- } else if u.Scheme == "npipe" {
- if strings.HasPrefix(u.Path, "//./pipe") {
- return "npipe", u.Path, nil
- }
- // fallback host if not provided.
- host := u.Host
- if host == "" {
- host = "."
- }
- return "npipe", fmt.Sprintf("//%s%s", host, u.Path), nil
- } else if u.Scheme == "" {
- return "", "", fmt.Errorf("Using %q as endpoint is deprecated, please consider using full url format", endpoint)
- } else {
- return u.Scheme, "", fmt.Errorf("protocol %q not supported", u.Scheme)
- }
- }
- // LocalEndpoint empty implementation
- func LocalEndpoint(path, file string) (string, error) {
- return "", fmt.Errorf("LocalEndpoints are unsupported in this build")
- }
- var tickCount = syscall.NewLazyDLL("kernel32.dll").NewProc("GetTickCount64")
- // GetBootTime returns the time at which the machine was started, truncated to the nearest second
- func GetBootTime() (time.Time, error) {
- currentTime := time.Now()
- output, _, err := tickCount.Call()
- if errno, ok := err.(syscall.Errno); !ok || errno != 0 {
- return time.Time{}, err
- }
- return currentTime.Add(-time.Duration(output) * time.Millisecond).Truncate(time.Second), nil
- }
- // IsUnixDomainSocket returns whether a given file is a AF_UNIX socket file
- func IsUnixDomainSocket(filePath string) (bool, error) {
- // Due to the absence of golang support for os.ModeSocket in Windows (https://github.com/golang/go/issues/33357)
- // we need to dial the file and check if we receive an error to determine if a file is Unix Domain Socket file.
- // Note that querrying for the Reparse Points (https://docs.microsoft.com/en-us/windows/win32/fileio/reparse-points)
- // for the file (using FSCTL_GET_REPARSE_POINT) and checking for reparse tag: reparseTagSocket
- // does NOT work in 1809 if the socket file is created within a bind mounted directory by a container
- // and the FSCTL is issued in the host by the kubelet.
- c, err := net.Dial("unix", filePath)
- if err == nil {
- c.Close()
- return true, nil
- }
- return false, nil
- }
- // NormalizePath converts FS paths returned by certain go frameworks (like fsnotify)
- // to native Windows paths that can be passed to Windows specific code
- func NormalizePath(path string) string {
- path = strings.ReplaceAll(path, "/", "\\")
- if strings.HasPrefix(path, "\\") {
- path = "c:" + path
- }
- return path
- }
|