github.com/gdamore/mangos@v1.4.0/transport/tcp/tcp.go (about) 1 // Copyright 2018 The Mangos Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use file except in compliance with the License. 5 // You may obtain a copy of the license at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package tcp implements the TCP transport for mangos. 16 package tcp 17 18 import ( 19 "net" 20 21 "nanomsg.org/go-mangos" 22 ) 23 24 // options is used for shared GetOption/SetOption logic. 25 type options map[string]interface{} 26 27 // GetOption retrieves an option value. 28 func (o options) get(name string) (interface{}, error) { 29 v, ok := o[name] 30 if !ok { 31 return nil, mangos.ErrBadOption 32 } 33 return v, nil 34 } 35 36 // SetOption sets an option. 37 func (o options) set(name string, val interface{}) error { 38 switch name { 39 case mangos.OptionNoDelay: 40 fallthrough 41 case mangos.OptionKeepAlive: 42 switch v := val.(type) { 43 case bool: 44 o[name] = v 45 return nil 46 default: 47 return mangos.ErrBadValue 48 } 49 } 50 return mangos.ErrBadOption 51 } 52 53 func newOptions() options { 54 o := make(map[string]interface{}) 55 o[mangos.OptionNoDelay] = true 56 o[mangos.OptionKeepAlive] = true 57 return options(o) 58 } 59 60 func (o options) configTCP(conn *net.TCPConn) error { 61 if v, ok := o[mangos.OptionNoDelay]; ok { 62 if err := conn.SetNoDelay(v.(bool)); err != nil { 63 return err 64 } 65 } 66 if v, ok := o[mangos.OptionKeepAlive]; ok { 67 if err := conn.SetKeepAlive(v.(bool)); err != nil { 68 return err 69 } 70 } 71 return nil 72 } 73 74 type dialer struct { 75 addr string 76 sock mangos.Socket 77 opts options 78 } 79 80 func (d *dialer) Dial() (_ mangos.Pipe, err error) { 81 var ( 82 addr *net.TCPAddr 83 ) 84 85 if addr, err = mangos.ResolveTCPAddr(d.addr); err != nil { 86 return nil, err 87 } 88 89 conn, err := net.DialTCP("tcp", nil, addr) 90 if err != nil { 91 return nil, err 92 } 93 if err = d.opts.configTCP(conn); err != nil { 94 conn.Close() 95 return nil, err 96 } 97 98 return mangos.NewConnPipe(conn, d.sock) 99 } 100 101 func (d *dialer) SetOption(n string, v interface{}) error { 102 return d.opts.set(n, v) 103 } 104 105 func (d *dialer) GetOption(n string) (interface{}, error) { 106 return d.opts.get(n) 107 } 108 109 type listener struct { 110 addr *net.TCPAddr 111 bound net.Addr 112 sock mangos.Socket 113 listener *net.TCPListener 114 opts options 115 } 116 117 func (l *listener) Accept() (mangos.Pipe, error) { 118 119 if l.listener == nil { 120 return nil, mangos.ErrClosed 121 } 122 conn, err := l.listener.AcceptTCP() 123 if err != nil { 124 return nil, err 125 } 126 if err = l.opts.configTCP(conn); err != nil { 127 conn.Close() 128 return nil, err 129 } 130 return mangos.NewConnPipe(conn, l.sock) 131 } 132 133 func (l *listener) Listen() (err error) { 134 l.listener, err = net.ListenTCP("tcp", l.addr) 135 if err == nil { 136 l.bound = l.listener.Addr() 137 } 138 return 139 } 140 141 func (l *listener) Address() string { 142 if b := l.bound; b != nil { 143 return "tcp://" + b.String() 144 } 145 return "tcp://" + l.addr.String() 146 } 147 148 func (l *listener) Close() error { 149 l.listener.Close() 150 return nil 151 } 152 153 func (l *listener) SetOption(n string, v interface{}) error { 154 return l.opts.set(n, v) 155 } 156 157 func (l *listener) GetOption(n string) (interface{}, error) { 158 return l.opts.get(n) 159 } 160 161 type tcpTran struct { 162 localAddr net.Addr 163 } 164 165 func (t *tcpTran) Scheme() string { 166 return "tcp" 167 } 168 169 func (t *tcpTran) NewDialer(addr string, sock mangos.Socket) (mangos.PipeDialer, error) { 170 var err error 171 if addr, err = mangos.StripScheme(t, addr); err != nil { 172 return nil, err 173 } 174 175 // check to ensure the provided addr resolves correctly. 176 if _, err = mangos.ResolveTCPAddr(addr); err != nil { 177 return nil, err 178 } 179 180 d := &dialer{addr: addr, sock: sock, opts: newOptions()} 181 182 return d, nil 183 } 184 185 func (t *tcpTran) NewListener(addr string, sock mangos.Socket) (mangos.PipeListener, error) { 186 var err error 187 l := &listener{sock: sock, opts: newOptions()} 188 189 if addr, err = mangos.StripScheme(t, addr); err != nil { 190 return nil, err 191 } 192 193 if l.addr, err = mangos.ResolveTCPAddr(addr); err != nil { 194 return nil, err 195 } 196 197 return l, nil 198 } 199 200 // NewTransport allocates a new TCP transport. 201 func NewTransport() mangos.Transport { 202 return &tcpTran{} 203 }