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 }