github.com/gdamore/mangos@v1.4.0/transport/ipc/ipc_windows.go (about)

     1  // +build windows
     2  
     3  // Copyright 2018 The Mangos Authors
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use file except in compliance with the License.
     7  // You may obtain a copy of the license at
     8  //
     9  //    http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  // Package ipc implements the IPC transport on top of Windows Named Pipes.
    18  package ipc
    19  
    20  import (
    21  	"net"
    22  
    23  	"github.com/Microsoft/go-winio"
    24  	"nanomsg.org/go-mangos"
    25  )
    26  
    27  // The options here are pretty specific to Windows Named Pipes.
    28  
    29  const (
    30  	// OptionSecurityDescriptor represents a Windows security
    31  	// descriptor in SDDL format (string).  This can only be set on
    32  	// a Listener, and must be set before the Listen routine
    33  	// is called.
    34  	OptionSecurityDescriptor = "WIN-IPC-SECURITY-DESCRIPTOR"
    35  
    36  	// OptionInputBufferSize represents the Windows Named Pipe
    37  	// input buffer size in bytes (type int32).  Default is 4096.
    38  	// This is only for Listeners, and must be set before the
    39  	// Listener is started.
    40  	OptionInputBufferSize = "WIN-IPC-INPUT-BUFFER-SIZE"
    41  
    42  	// OptionOutputBufferSize represents the Windows Named Pipe
    43  	// output buffer size in bytes (type int32).  Default is 4096.
    44  	// This is only for Listeners, and must be set before the
    45  	// Listener is started.
    46  	OptionOutputBufferSize = "WIN-IPC-OUTPUT-BUFFER-SIZE"
    47  )
    48  
    49  type pipeAddr string
    50  
    51  func (p pipeAddr) Network() string {
    52  	return "ipc"
    53  }
    54  
    55  func (p pipeAddr) String() string {
    56  	return string(p)
    57  }
    58  
    59  type dialer struct {
    60  	path string
    61  	sock mangos.Socket
    62  }
    63  
    64  // Dial implements the PipeDialer Dial method.
    65  func (d *dialer) Dial() (mangos.Pipe, error) {
    66  
    67  	conn, err := winio.DialPipe("\\\\.\\pipe\\"+d.path, nil)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	addr := pipeAddr(d.path)
    72  	return mangos.NewConnPipeIPC(conn, d.sock,
    73  		mangos.PropLocalAddr, addr, mangos.PropRemoteAddr, addr)
    74  }
    75  
    76  // SetOption implements a stub PipeDialer SetOption method.
    77  func (d *dialer) SetOption(n string, v interface{}) error {
    78  	return mangos.ErrBadOption
    79  }
    80  
    81  // GetOption implements a stub PipeDialer GetOption method.
    82  func (d *dialer) GetOption(n string) (interface{}, error) {
    83  	return nil, mangos.ErrBadOption
    84  }
    85  
    86  // listenerOptions is used for shared GetOption/SetOption logic for listeners.
    87  // We don't have dialer specific options at this point.
    88  type listenerOptions map[string]interface{}
    89  
    90  // GetOption retrieves an option value.
    91  func (o listenerOptions) get(name string) (interface{}, error) {
    92  	if o == nil {
    93  		return nil, mangos.ErrBadOption
    94  	}
    95  	v, ok := o[name]
    96  	if !ok {
    97  		return nil, mangos.ErrBadOption
    98  	}
    99  	return v, nil
   100  }
   101  
   102  // SetOption sets an option.  We have none, so just ErrBadOption.
   103  func (o listenerOptions) set(string, interface{}) error {
   104  	return mangos.ErrBadOption
   105  }
   106  
   107  type listener struct {
   108  	path     string
   109  	sock     mangos.Socket
   110  	listener net.Listener
   111  	config   winio.PipeConfig
   112  }
   113  
   114  // Listen implements the PipeListener Listen method.
   115  func (l *listener) Listen() error {
   116  	listener, err := winio.ListenPipe("\\\\.\\pipe\\"+l.path, &l.config)
   117  	if err != nil {
   118  		return err
   119  	}
   120  	l.listener = listener
   121  	return nil
   122  }
   123  
   124  func (l *listener) Address() string {
   125  	return "ipc://" + l.path
   126  }
   127  
   128  // Accept implements the the PipeListener Accept method.
   129  func (l *listener) Accept() (mangos.Pipe, error) {
   130  
   131  	conn, err := l.listener.Accept()
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	addr := pipeAddr(l.path)
   136  	return mangos.NewConnPipeIPC(conn, l.sock,
   137  		mangos.PropLocalAddr, addr, mangos.PropRemoteAddr, addr)
   138  }
   139  
   140  // Close implements the PipeListener Close method.
   141  func (l *listener) Close() error {
   142  	if l.listener != nil {
   143  		l.listener.Close()
   144  	}
   145  	return nil
   146  }
   147  
   148  // SetOption implements a stub PipeListener SetOption method.
   149  func (l *listener) SetOption(name string, val interface{}) error {
   150  	switch name {
   151  	case OptionInputBufferSize:
   152  		switch v := val.(type) {
   153  		case int32:
   154  			l.config.InputBufferSize = v
   155  			return nil
   156  		default:
   157  			return mangos.ErrBadValue
   158  		}
   159  	case OptionOutputBufferSize:
   160  		switch v := val.(type) {
   161  		case int32:
   162  			l.config.OutputBufferSize = v
   163  			return nil
   164  		default:
   165  			return mangos.ErrBadValue
   166  		}
   167  	case OptionSecurityDescriptor:
   168  		switch v := val.(type) {
   169  		case string:
   170  			l.config.SecurityDescriptor = v
   171  			return nil
   172  		default:
   173  			return mangos.ErrBadValue
   174  		}
   175  	default:
   176  		return mangos.ErrBadOption
   177  	}
   178  }
   179  
   180  // GetOption implements a stub PipeListener GetOption method.
   181  func (l *listener) GetOption(name string) (interface{}, error) {
   182  	switch name {
   183  	case OptionInputBufferSize:
   184  		return l.config.InputBufferSize, nil
   185  	case OptionOutputBufferSize:
   186  		return l.config.OutputBufferSize, nil
   187  	case OptionSecurityDescriptor:
   188  		return l.config.SecurityDescriptor, nil
   189  	}
   190  	return nil, mangos.ErrBadOption
   191  }
   192  
   193  type ipcTran struct{}
   194  
   195  // Scheme implements the Transport Scheme method.
   196  func (t *ipcTran) Scheme() string {
   197  	return "ipc"
   198  }
   199  
   200  // NewDialer implements the Transport NewDialer method.
   201  func (t *ipcTran) NewDialer(addr string, sock mangos.Socket) (mangos.PipeDialer, error) {
   202  	var err error
   203  
   204  	if addr, err = mangos.StripScheme(t, addr); err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	d := &dialer{sock: sock}
   209  	d.path = addr
   210  	return d, nil
   211  }
   212  
   213  // NewListener implements the Transport NewListener method.
   214  func (t *ipcTran) NewListener(addr string, sock mangos.Socket) (mangos.PipeListener, error) {
   215  	var err error
   216  	l := &listener{sock: sock}
   217  	l.config.OutputBufferSize = 4096
   218  	l.config.InputBufferSize = 4096
   219  	l.config.SecurityDescriptor = ""
   220  	l.config.MessageMode = false
   221  
   222  	if addr, err = mangos.StripScheme(t, addr); err != nil {
   223  		return nil, err
   224  	}
   225  
   226  	l.path = addr
   227  
   228  	return l, nil
   229  }
   230  
   231  // NewTransport allocates a new IPC transport.
   232  func NewTransport() mangos.Transport {
   233  	return &ipcTran{}
   234  }