blob: e911bf1668188b6515f8903b4a6a204949868408 [file] [log] [blame]
Jens Geyer0e87c462013-06-18 22:25:07 +02001/*
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
20package thrift
21
22import (
John Boiles57852792018-01-05 14:37:05 -080023 "context"
Jens Geyer0e87c462013-06-18 22:25:07 +020024 "net"
25 "time"
26)
27
28type TSocket struct {
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -080029 conn *socketConn
30 addr net.Addr
31 cfg *TConfiguration
32
lvqian81334cd2020-03-26 19:08:55 +080033 connectTimeout time.Duration
34 socketTimeout time.Duration
Jens Geyer0e87c462013-06-18 22:25:07 +020035}
36
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -080037// Deprecated: Use NewTSocketConf instead.
Jens Geyer0e87c462013-06-18 22:25:07 +020038func NewTSocket(hostPort string) (*TSocket, error) {
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -080039 return NewTSocketConf(hostPort, &TConfiguration{
40 noPropagation: true,
41 })
Jens Geyer0e87c462013-06-18 22:25:07 +020042}
43
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -080044// NewTSocketConf creates a net.Conn-backed TTransport, given a host and port.
45//
46// Example:
47//
48// trans, err := thrift.NewTSocketConf("localhost:9090", &TConfiguration{
49// ConnectTimeout: time.Second, // Use 0 for no timeout
50// SocketTimeout: time.Second, // Use 0 for no timeout
51// })
52func NewTSocketConf(hostPort string, conf *TConfiguration) (*TSocket, error) {
Jens Geyer0e87c462013-06-18 22:25:07 +020053 addr, err := net.ResolveTCPAddr("tcp", hostPort)
54 if err != nil {
55 return nil, err
56 }
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -080057 return NewTSocketFromAddrConf(addr, conf), nil
Jens Geyer0e87c462013-06-18 22:25:07 +020058}
59
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -080060// Deprecated: Use NewTSocketConf instead.
61func NewTSocketTimeout(hostPort string, connTimeout time.Duration, soTimeout time.Duration) (*TSocket, error) {
62 return NewTSocketConf(hostPort, &TConfiguration{
63 ConnectTimeout: connTimeout,
64 SocketTimeout: soTimeout,
65
66 noPropagation: true,
67 })
68}
69
70// NewTSocketFromAddrConf creates a TSocket from a net.Addr
71func NewTSocketFromAddrConf(addr net.Addr, conf *TConfiguration) *TSocket {
72 return &TSocket{
73 addr: addr,
74 cfg: conf,
75 }
76}
77
78// Deprecated: Use NewTSocketFromAddrConf instead.
lvqian81334cd2020-03-26 19:08:55 +080079func NewTSocketFromAddrTimeout(addr net.Addr, connTimeout time.Duration, soTimeout time.Duration) *TSocket {
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -080080 return NewTSocketFromAddrConf(addr, &TConfiguration{
81 ConnectTimeout: connTimeout,
82 SocketTimeout: soTimeout,
83
84 noPropagation: true,
85 })
Jens Geyer0e87c462013-06-18 22:25:07 +020086}
87
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -080088// NewTSocketFromConnConf creates a TSocket from an existing net.Conn.
89func NewTSocketFromConnConf(conn net.Conn, conf *TConfiguration) *TSocket {
90 return &TSocket{
91 conn: wrapSocketConn(conn),
92 addr: conn.RemoteAddr(),
93 cfg: conf,
94 }
95}
96
97// Deprecated: Use NewTSocketFromConnConf instead.
Yuxuan 'fishy' Wang5dc1d262020-06-27 08:34:31 -070098func NewTSocketFromConnTimeout(conn net.Conn, socketTimeout time.Duration) *TSocket {
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -080099 return NewTSocketFromConnConf(conn, &TConfiguration{
100 SocketTimeout: socketTimeout,
101
102 noPropagation: true,
103 })
104}
105
106// SetTConfiguration implements TConfigurationSetter.
107//
108// It can be used to set connect and socket timeouts.
109func (p *TSocket) SetTConfiguration(conf *TConfiguration) {
110 p.cfg = conf
lvqian81334cd2020-03-26 19:08:55 +0800111}
112
113// Sets the connect timeout
114func (p *TSocket) SetConnTimeout(timeout time.Duration) error {
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -0800115 if p.cfg == nil {
116 p.cfg = &TConfiguration{
117 noPropagation: true,
118 }
119 }
120 p.cfg.ConnectTimeout = timeout
lvqian81334cd2020-03-26 19:08:55 +0800121 return nil
Jens Geyer0e87c462013-06-18 22:25:07 +0200122}
123
124// Sets the socket timeout
lvqian81334cd2020-03-26 19:08:55 +0800125func (p *TSocket) SetSocketTimeout(timeout time.Duration) error {
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -0800126 if p.cfg == nil {
127 p.cfg = &TConfiguration{
128 noPropagation: true,
129 }
130 }
131 p.cfg.SocketTimeout = timeout
Jens Geyer0e87c462013-06-18 22:25:07 +0200132 return nil
133}
134
135func (p *TSocket) pushDeadline(read, write bool) {
136 var t time.Time
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -0800137 if timeout := p.cfg.GetSocketTimeout(); timeout > 0 {
138 t = time.Now().Add(time.Duration(timeout))
Jens Geyer0e87c462013-06-18 22:25:07 +0200139 }
140 if read && write {
141 p.conn.SetDeadline(t)
142 } else if read {
143 p.conn.SetReadDeadline(t)
144 } else if write {
145 p.conn.SetWriteDeadline(t)
146 }
147}
148
149// Connects the socket, creating a new socket object if necessary.
150func (p *TSocket) Open() error {
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -0700151 if p.conn.isValid() {
Jens Geyer0e87c462013-06-18 22:25:07 +0200152 return NewTTransportException(ALREADY_OPEN, "Socket already connected.")
153 }
154 if p.addr == nil {
155 return NewTTransportException(NOT_OPEN, "Cannot open nil address.")
156 }
157 if len(p.addr.Network()) == 0 {
158 return NewTTransportException(NOT_OPEN, "Cannot open bad network name.")
159 }
160 if len(p.addr.String()) == 0 {
161 return NewTTransportException(NOT_OPEN, "Cannot open bad address.")
162 }
163 var err error
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -0700164 if p.conn, err = createSocketConnFromReturn(net.DialTimeout(
165 p.addr.Network(),
166 p.addr.String(),
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -0800167 p.cfg.GetConnectTimeout(),
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -0700168 )); err != nil {
Jens Geyer0e87c462013-06-18 22:25:07 +0200169 return NewTTransportException(NOT_OPEN, err.Error())
170 }
171 return nil
172}
173
Konrad Grochowski3b5dacb2014-11-24 10:55:31 +0100174// Retrieve the underlying net.Conn
Jens Geyer0e87c462013-06-18 22:25:07 +0200175func (p *TSocket) Conn() net.Conn {
176 return p.conn
177}
178
179// Returns true if the connection is open
180func (p *TSocket) IsOpen() bool {
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -0700181 return p.conn.IsOpen()
Jens Geyer0e87c462013-06-18 22:25:07 +0200182}
183
184// Closes the socket.
185func (p *TSocket) Close() error {
186 // Close the socket
187 if p.conn != nil {
188 err := p.conn.Close()
189 if err != nil {
190 return err
191 }
192 p.conn = nil
193 }
194 return nil
195}
196
Jens Geyer4c330942014-11-10 21:22:34 +0100197//Returns the remote address of the socket.
198func (p *TSocket) Addr() net.Addr {
199 return p.addr
200}
201
Jens Geyer0e87c462013-06-18 22:25:07 +0200202func (p *TSocket) Read(buf []byte) (int, error) {
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -0700203 if !p.conn.isValid() {
Jens Geyer0e87c462013-06-18 22:25:07 +0200204 return 0, NewTTransportException(NOT_OPEN, "Connection not open")
205 }
206 p.pushDeadline(true, false)
Yuxuan 'fishy' Wangcfbb9052020-06-09 13:07:38 -0700207 // NOTE: Calling any of p.IsOpen, p.conn.read0, or p.conn.IsOpen between
208 // p.pushDeadline and p.conn.Read could cause the deadline set inside
209 // p.pushDeadline being reset, thus need to be avoided.
Jens Geyer0e87c462013-06-18 22:25:07 +0200210 n, err := p.conn.Read(buf)
211 return n, NewTTransportExceptionFromError(err)
212}
213
214func (p *TSocket) Write(buf []byte) (int, error) {
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -0700215 if !p.conn.isValid() {
Jens Geyer0e87c462013-06-18 22:25:07 +0200216 return 0, NewTTransportException(NOT_OPEN, "Connection not open")
217 }
218 p.pushDeadline(false, true)
219 return p.conn.Write(buf)
220}
221
John Boiles57852792018-01-05 14:37:05 -0800222func (p *TSocket) Flush(ctx context.Context) error {
Jens Geyer0e87c462013-06-18 22:25:07 +0200223 return nil
224}
225
226func (p *TSocket) Interrupt() error {
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -0700227 if !p.conn.isValid() {
Jens Geyer0e87c462013-06-18 22:25:07 +0200228 return nil
229 }
230 return p.conn.Close()
231}
Jens Geyerca8469e2015-07-26 01:25:23 +0200232
233func (p *TSocket) RemainingBytes() (num_bytes uint64) {
234 const maxSize = ^uint64(0)
timestee370d7512019-05-20 19:20:42 +0800235 return maxSize // the truth is, we just don't know unless framed is used
Jens Geyerca8469e2015-07-26 01:25:23 +0200236}
Yuxuan 'fishy' Wangc4d1c0d2020-12-16 17:10:48 -0800237
238var _ TConfigurationSetter = (*TSocket)(nil)