Skip to content

Commit

Permalink
support windows named pipe
Browse files Browse the repository at this point in the history
Adds support for windows named pipes by adding an xnet package
containing functions for opening platform-agnostic local sockets

Signed-off-by: Drew Erny <drew.erny@docker.com>
  • Loading branch information
dperny committed Oct 26, 2016
1 parent 3b6410e commit a1c8923
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 7 deletions.
23 changes: 17 additions & 6 deletions manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net"
"os"
"path/filepath"
"runtime"
"sync"
"syscall"
"time"
Expand All @@ -30,6 +31,7 @@ import (
"github.com/docker/swarmkit/manager/state/raft"
"github.com/docker/swarmkit/manager/state/store"
"github.com/docker/swarmkit/protobuf/ptypes"
"github.com/docker/swarmkit/xnet"
"github.com/pkg/errors"
"golang.org/x/net/context"
"google.golang.org/grpc"
Expand Down Expand Up @@ -148,12 +150,15 @@ func New(config *Config) (*Manager, error) {
tcpAddr = net.JoinHostPort("0.0.0.0", tcpAddrPort)
}

err := os.MkdirAll(filepath.Dir(config.ProtoAddr["unix"]), 0700)
if err != nil {
return nil, errors.Wrap(err, "failed to create socket directory")
// don't create a socket directory if we're on windows. we used named pipe
if runtime.GOOS != "windows" {
err := os.MkdirAll(filepath.Dir(config.ProtoAddr["unix"]), 0700)
if err != nil {
return nil, errors.Wrap(err, "failed to create socket directory")
}
}

err = os.MkdirAll(config.StateDir, 0700)
err := os.MkdirAll(config.StateDir, 0700)
if err != nil {
return nil, errors.Wrap(err, "failed to create state directory")
}
Expand All @@ -171,7 +176,13 @@ func New(config *Config) (*Manager, error) {
listeners = make(map[string]net.Listener)

for proto, addr := range config.ProtoAddr {
l, err := net.Listen(proto, addr)
var l net.Listener
var err error
if proto == "unix" {
l, err = xnet.ListenLocal(addr)
} else {
l, err = net.Listen(proto, addr)
}

// A unix socket may fail to bind if the file already
// exists. Try replacing the file.
Expand All @@ -184,7 +195,7 @@ func New(config *Config) (*Manager, error) {
}
if proto == "unix" && unwrappedErr == syscall.EADDRINUSE {
os.Remove(addr)
l, err = net.Listen(proto, addr)
l, err = xnet.ListenLocal(addr)
if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/docker/swarmkit/log"
"github.com/docker/swarmkit/manager"
"github.com/docker/swarmkit/remotes"
"github.com/docker/swarmkit/xnet"
"github.com/pkg/errors"
"golang.org/x/net/context"
"google.golang.org/grpc"
Expand Down Expand Up @@ -559,7 +560,7 @@ func (n *Node) initManagerConnection(ctx context.Context, ready chan<- struct{})
addr := n.config.ListenControlAPI
opts = append(opts, grpc.WithDialer(
func(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("unix", addr, timeout)
return xnet.DialTimeoutLocal(addr, timeout)
}))
conn, err := grpc.Dial(addr, opts...)
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions xnet/xnet_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// +build !windows

package xnet

import (
"net"
"time"
)

// ListenLocal opens a local socket for control communication
func ListenLocal(socket string) (net.Listener, error) {
// on unix it's just a unix socket
return net.Listen("unix", socket)
}

// DialTimeoutLocal is a DialTimeout function for local sockets
func DialTimeoutLocal(socket string, timeout time.Duration) (net.Conn, error) {
// on unix, we dial a unix socket
return net.DialTimeout("unix", socket, timeout)
}
22 changes: 22 additions & 0 deletions xnet/xnet_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// +build windows

package xnet

import (
"net"
"time"

"github.com/Microsoft/go-winio"
)

// ListenLocal opens a local socket for control communication
func ListenLocal(socket string) (net.Listener, error) {
// on windows, our socket is actually a named pipe
return winio.ListenPipe(socket, nil)
}

// DialTimeoutLocal is a DialTimeout function for local sockets
func DialTimeoutLocal(socket string, timeout time.Duration) (net.Conn, error) {
// On windows, we dial a named pipe
return winio.DialPipe(socket, &timeout)
}

0 comments on commit a1c8923

Please sign in to comment.