Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one |
| 3 | * or more contributor license agreements. See the NOTICE file |
| 4 | * distributed with this work for additional information |
| 5 | * regarding copyright ownership. The ASF licenses this file |
| 6 | * to you under the Apache License, Version 2.0 (the |
| 7 | * "License"); you may not use this file except in compliance |
| 8 | * with the License. You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, |
| 13 | * software distributed under the License is distributed on an |
| 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | * KIND, either express or implied. See the License for the |
| 16 | * specific language governing permissions and limitations |
| 17 | * under the License. |
| 18 | */ |
| 19 | |
| 20 | package thrift |
| 21 | |
| 22 | import ( |
John Boiles | 5785279 | 2018-01-05 14:37:05 -0800 | [diff] [blame] | 23 | "context" |
Jens Geyer | 1e7971c | 2014-11-25 21:43:54 +0100 | [diff] [blame] | 24 | "crypto/tls" |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 25 | "net" |
| 26 | "time" |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 27 | ) |
| 28 | |
| 29 | type TSSLSocket struct { |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 30 | conn *socketConn |
Jens Geyer | 00a4e3e | 2015-02-27 23:06:07 +0100 | [diff] [blame] | 31 | // hostPort contains host:port (e.g. "asdf.com:12345"). The field is |
| 32 | // only valid if addr is nil. |
| 33 | hostPort string |
| 34 | // addr is nil when hostPort is not "", and is only used when the |
| 35 | // TSSLSocket is constructed from a net.Addr. |
Yuxuan 'fishy' Wang | 5dc1d26 | 2020-06-27 08:34:31 -0700 | [diff] [blame] | 36 | addr net.Addr |
Yuxuan 'fishy' Wang | 5dc1d26 | 2020-06-27 08:34:31 -0700 | [diff] [blame] | 37 | |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 38 | cfg *TConfiguration |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 39 | } |
| 40 | |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 41 | // NewTSSLSocketConf creates a net.Conn-backed TTransport, given a host and port. |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 42 | // |
| 43 | // Example: |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 44 | // |
Yuxuan 'fishy' Wang | 17373a3 | 2021-08-26 11:04:27 -0700 | [diff] [blame] | 45 | // trans := thrift.NewTSSLSocketConf("localhost:9090", &TConfiguration{ |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 46 | // ConnectTimeout: time.Second, // Use 0 for no timeout |
| 47 | // SocketTimeout: time.Second, // Use 0 for no timeout |
Yuxuan 'fishy' Wang | 17373a3 | 2021-08-26 11:04:27 -0700 | [diff] [blame] | 48 | // |
| 49 | // TLSConfig: &tls.Config{ |
| 50 | // // Fill in tls config here. |
| 51 | // } |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 52 | // }) |
Yuxuan 'fishy' Wang | 17373a3 | 2021-08-26 11:04:27 -0700 | [diff] [blame] | 53 | func NewTSSLSocketConf(hostPort string, conf *TConfiguration) *TSSLSocket { |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 54 | if cfg := conf.GetTLSConfig(); cfg != nil && cfg.MinVersion == 0 { |
James E. King, III | 0619087 | 2017-02-20 08:52:11 -0500 | [diff] [blame] | 55 | cfg.MinVersion = tls.VersionTLS10 |
| 56 | } |
Yuxuan 'fishy' Wang | 5dc1d26 | 2020-06-27 08:34:31 -0700 | [diff] [blame] | 57 | return &TSSLSocket{ |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 58 | hostPort: hostPort, |
| 59 | cfg: conf, |
Yuxuan 'fishy' Wang | 17373a3 | 2021-08-26 11:04:27 -0700 | [diff] [blame] | 60 | } |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 61 | } |
| 62 | |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 63 | // Deprecated: Use NewTSSLSocketConf instead. |
| 64 | func NewTSSLSocket(hostPort string, cfg *tls.Config) (*TSSLSocket, error) { |
| 65 | return NewTSSLSocketConf(hostPort, &TConfiguration{ |
| 66 | TLSConfig: cfg, |
| 67 | |
| 68 | noPropagation: true, |
Yuxuan 'fishy' Wang | 17373a3 | 2021-08-26 11:04:27 -0700 | [diff] [blame] | 69 | }), nil |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 70 | } |
| 71 | |
| 72 | // Deprecated: Use NewTSSLSocketConf instead. |
| 73 | func NewTSSLSocketTimeout(hostPort string, cfg *tls.Config, connectTimeout, socketTimeout time.Duration) (*TSSLSocket, error) { |
| 74 | return NewTSSLSocketConf(hostPort, &TConfiguration{ |
| 75 | ConnectTimeout: connectTimeout, |
| 76 | SocketTimeout: socketTimeout, |
| 77 | TLSConfig: cfg, |
| 78 | |
| 79 | noPropagation: true, |
Yuxuan 'fishy' Wang | 17373a3 | 2021-08-26 11:04:27 -0700 | [diff] [blame] | 80 | }), nil |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 81 | } |
| 82 | |
| 83 | // NewTSSLSocketFromAddrConf creates a TSSLSocket from a net.Addr. |
| 84 | func NewTSSLSocketFromAddrConf(addr net.Addr, conf *TConfiguration) *TSSLSocket { |
Yuxuan 'fishy' Wang | 5dc1d26 | 2020-06-27 08:34:31 -0700 | [diff] [blame] | 85 | return &TSSLSocket{ |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 86 | addr: addr, |
| 87 | cfg: conf, |
Yuxuan 'fishy' Wang | 5dc1d26 | 2020-06-27 08:34:31 -0700 | [diff] [blame] | 88 | } |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 89 | } |
| 90 | |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 91 | // Deprecated: Use NewTSSLSocketFromAddrConf instead. |
| 92 | func NewTSSLSocketFromAddrTimeout(addr net.Addr, cfg *tls.Config, connectTimeout, socketTimeout time.Duration) *TSSLSocket { |
| 93 | return NewTSSLSocketFromAddrConf(addr, &TConfiguration{ |
| 94 | ConnectTimeout: connectTimeout, |
| 95 | SocketTimeout: socketTimeout, |
| 96 | TLSConfig: cfg, |
| 97 | |
| 98 | noPropagation: true, |
| 99 | }) |
| 100 | } |
| 101 | |
| 102 | // NewTSSLSocketFromConnConf creates a TSSLSocket from an existing net.Conn. |
| 103 | func NewTSSLSocketFromConnConf(conn net.Conn, conf *TConfiguration) *TSSLSocket { |
Yuxuan 'fishy' Wang | 5dc1d26 | 2020-06-27 08:34:31 -0700 | [diff] [blame] | 104 | return &TSSLSocket{ |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 105 | conn: wrapSocketConn(conn), |
| 106 | addr: conn.RemoteAddr(), |
| 107 | cfg: conf, |
Yuxuan 'fishy' Wang | 5dc1d26 | 2020-06-27 08:34:31 -0700 | [diff] [blame] | 108 | } |
| 109 | } |
| 110 | |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 111 | // Deprecated: Use NewTSSLSocketFromConnConf instead. |
| 112 | func NewTSSLSocketFromConnTimeout(conn net.Conn, cfg *tls.Config, socketTimeout time.Duration) *TSSLSocket { |
| 113 | return NewTSSLSocketFromConnConf(conn, &TConfiguration{ |
| 114 | SocketTimeout: socketTimeout, |
| 115 | TLSConfig: cfg, |
| 116 | |
| 117 | noPropagation: true, |
| 118 | }) |
| 119 | } |
| 120 | |
| 121 | // SetTConfiguration implements TConfigurationSetter. |
| 122 | // |
| 123 | // It can be used to change connect and socket timeouts. |
| 124 | func (p *TSSLSocket) SetTConfiguration(conf *TConfiguration) { |
| 125 | p.cfg = conf |
| 126 | } |
| 127 | |
Yuxuan 'fishy' Wang | 5dc1d26 | 2020-06-27 08:34:31 -0700 | [diff] [blame] | 128 | // Sets the connect timeout |
| 129 | func (p *TSSLSocket) SetConnTimeout(timeout time.Duration) error { |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 130 | if p.cfg == nil { |
| 131 | p.cfg = &TConfiguration{} |
| 132 | } |
| 133 | p.cfg.ConnectTimeout = timeout |
Yuxuan 'fishy' Wang | 5dc1d26 | 2020-06-27 08:34:31 -0700 | [diff] [blame] | 134 | return nil |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | // Sets the socket timeout |
Yuxuan 'fishy' Wang | 5dc1d26 | 2020-06-27 08:34:31 -0700 | [diff] [blame] | 138 | func (p *TSSLSocket) SetSocketTimeout(timeout time.Duration) error { |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 139 | if p.cfg == nil { |
| 140 | p.cfg = &TConfiguration{} |
| 141 | } |
| 142 | p.cfg.SocketTimeout = timeout |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 143 | return nil |
| 144 | } |
| 145 | |
| 146 | func (p *TSSLSocket) pushDeadline(read, write bool) { |
| 147 | var t time.Time |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 148 | if timeout := p.cfg.GetSocketTimeout(); timeout > 0 { |
| 149 | t = time.Now().Add(time.Duration(timeout)) |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 150 | } |
| 151 | if read && write { |
| 152 | p.conn.SetDeadline(t) |
| 153 | } else if read { |
| 154 | p.conn.SetReadDeadline(t) |
| 155 | } else if write { |
| 156 | p.conn.SetWriteDeadline(t) |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | // Connects the socket, creating a new socket object if necessary. |
| 161 | func (p *TSSLSocket) Open() error { |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 162 | var err error |
Jens Geyer | 00a4e3e | 2015-02-27 23:06:07 +0100 | [diff] [blame] | 163 | // If we have a hostname, we need to pass the hostname to tls.Dial for |
| 164 | // certificate hostname checks. |
| 165 | if p.hostPort != "" { |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 166 | if p.conn, err = createSocketConnFromReturn(tls.DialWithDialer( |
| 167 | &net.Dialer{ |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 168 | Timeout: p.cfg.GetConnectTimeout(), |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 169 | }, |
| 170 | "tcp", |
| 171 | p.hostPort, |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 172 | p.cfg.GetTLSConfig(), |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 173 | )); err != nil { |
Yuxuan 'fishy' Wang | fe3f8a1 | 2021-04-27 19:56:58 -0700 | [diff] [blame] | 174 | return &tTransportException{ |
| 175 | typeId: NOT_OPEN, |
| 176 | err: err, |
| 177 | msg: err.Error(), |
| 178 | } |
Jens Geyer | 00a4e3e | 2015-02-27 23:06:07 +0100 | [diff] [blame] | 179 | } |
| 180 | } else { |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 181 | if p.conn.isValid() { |
Jens Geyer | 00a4e3e | 2015-02-27 23:06:07 +0100 | [diff] [blame] | 182 | return NewTTransportException(ALREADY_OPEN, "Socket already connected.") |
| 183 | } |
| 184 | if p.addr == nil { |
| 185 | return NewTTransportException(NOT_OPEN, "Cannot open nil address.") |
| 186 | } |
| 187 | if len(p.addr.Network()) == 0 { |
| 188 | return NewTTransportException(NOT_OPEN, "Cannot open bad network name.") |
| 189 | } |
| 190 | if len(p.addr.String()) == 0 { |
| 191 | return NewTTransportException(NOT_OPEN, "Cannot open bad address.") |
| 192 | } |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 193 | if p.conn, err = createSocketConnFromReturn(tls.DialWithDialer( |
| 194 | &net.Dialer{ |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 195 | Timeout: p.cfg.GetConnectTimeout(), |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 196 | }, |
| 197 | p.addr.Network(), |
| 198 | p.addr.String(), |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 199 | p.cfg.GetTLSConfig(), |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 200 | )); err != nil { |
Yuxuan 'fishy' Wang | fe3f8a1 | 2021-04-27 19:56:58 -0700 | [diff] [blame] | 201 | return &tTransportException{ |
| 202 | typeId: NOT_OPEN, |
| 203 | err: err, |
| 204 | msg: err.Error(), |
| 205 | } |
Jens Geyer | 00a4e3e | 2015-02-27 23:06:07 +0100 | [diff] [blame] | 206 | } |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 207 | } |
| 208 | return nil |
| 209 | } |
| 210 | |
Konrad Grochowski | 3b5dacb | 2014-11-24 10:55:31 +0100 | [diff] [blame] | 211 | // Retrieve the underlying net.Conn |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 212 | func (p *TSSLSocket) Conn() net.Conn { |
| 213 | return p.conn |
| 214 | } |
| 215 | |
| 216 | // Returns true if the connection is open |
| 217 | func (p *TSSLSocket) IsOpen() bool { |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 218 | return p.conn.IsOpen() |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | // Closes the socket. |
| 222 | func (p *TSSLSocket) Close() error { |
Yuxuan 'fishy' Wang | 39d7278 | 2022-01-08 01:03:57 -0800 | [diff] [blame] | 223 | return p.conn.Close() |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 224 | } |
| 225 | |
| 226 | func (p *TSSLSocket) Read(buf []byte) (int, error) { |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 227 | if !p.conn.isValid() { |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 228 | return 0, NewTTransportException(NOT_OPEN, "Connection not open") |
| 229 | } |
| 230 | p.pushDeadline(true, false) |
Yuxuan 'fishy' Wang | cfbb905 | 2020-06-09 13:07:38 -0700 | [diff] [blame] | 231 | // NOTE: Calling any of p.IsOpen, p.conn.read0, or p.conn.IsOpen between |
| 232 | // p.pushDeadline and p.conn.Read could cause the deadline set inside |
| 233 | // p.pushDeadline being reset, thus need to be avoided. |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 234 | n, err := p.conn.Read(buf) |
| 235 | return n, NewTTransportExceptionFromError(err) |
| 236 | } |
| 237 | |
| 238 | func (p *TSSLSocket) Write(buf []byte) (int, error) { |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 239 | if !p.conn.isValid() { |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 240 | return 0, NewTTransportException(NOT_OPEN, "Connection not open") |
| 241 | } |
| 242 | p.pushDeadline(false, true) |
| 243 | return p.conn.Write(buf) |
| 244 | } |
| 245 | |
John Boiles | 5785279 | 2018-01-05 14:37:05 -0800 | [diff] [blame] | 246 | func (p *TSSLSocket) Flush(ctx context.Context) error { |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 247 | return nil |
| 248 | } |
| 249 | |
| 250 | func (p *TSSLSocket) Interrupt() error { |
Yuxuan 'fishy' Wang | 05023e8 | 2020-05-26 15:31:20 -0700 | [diff] [blame] | 251 | if !p.conn.isValid() { |
Jens Geyer | 4c83595 | 2013-08-13 21:34:17 +0200 | [diff] [blame] | 252 | return nil |
| 253 | } |
| 254 | return p.conn.Close() |
| 255 | } |
Jens Geyer | ca8469e | 2015-07-26 01:25:23 +0200 | [diff] [blame] | 256 | |
| 257 | func (p *TSSLSocket) RemainingBytes() (num_bytes uint64) { |
| 258 | const maxSize = ^uint64(0) |
Kevin Wojniak | bc75467 | 2019-11-02 21:13:34 -0700 | [diff] [blame] | 259 | return maxSize // the truth is, we just don't know unless framed is used |
Jens Geyer | ca8469e | 2015-07-26 01:25:23 +0200 | [diff] [blame] | 260 | } |
Yuxuan 'fishy' Wang | c4d1c0d | 2020-12-16 17:10:48 -0800 | [diff] [blame] | 261 | |
| 262 | var _ TConfigurationSetter = (*TSSLSocket)(nil) |