blob: 5619d9626a341969452cc662181077c08ebae8a2 [file] [log] [blame]
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -07001/*
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 (
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -070023 "net"
Yuxuan 'fishy' Wang39d72782022-01-08 01:03:57 -080024 "sync/atomic"
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -070025)
26
27// socketConn is a wrapped net.Conn that tries to do connectivity check.
28type socketConn struct {
29 net.Conn
30
Yuxuan 'fishy' Wangcfbb9052020-06-09 13:07:38 -070031 buffer [1]byte
Yuxuan 'fishy' Wang39d72782022-01-08 01:03:57 -080032 closed int32
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -070033}
34
35var _ net.Conn = (*socketConn)(nil)
36
37// createSocketConnFromReturn is a language sugar to help create socketConn from
38// return values of functions like net.Dial, tls.Dial, net.Listener.Accept, etc.
39func createSocketConnFromReturn(conn net.Conn, err error) (*socketConn, error) {
40 if err != nil {
41 return nil, err
42 }
43 return &socketConn{
44 Conn: conn,
45 }, nil
46}
47
48// wrapSocketConn wraps an existing net.Conn into *socketConn.
49func wrapSocketConn(conn net.Conn) *socketConn {
50 // In case conn is already wrapped,
51 // return it as-is and avoid double wrapping.
52 if sc, ok := conn.(*socketConn); ok {
53 return sc
54 }
55
56 return &socketConn{
57 Conn: conn,
58 }
59}
60
61// isValid checks whether there's a valid connection.
62//
63// It's nil safe, and returns false if sc itself is nil, or if the underlying
64// connection is nil.
65//
66// It's the same as the previous implementation of TSocket.IsOpen and
67// TSSLSocket.IsOpen before we added connectivity check.
68func (sc *socketConn) isValid() bool {
Yuxuan 'fishy' Wang39d72782022-01-08 01:03:57 -080069 return sc != nil && sc.Conn != nil && atomic.LoadInt32(&sc.closed) == 0
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -070070}
71
72// IsOpen checks whether the connection is open.
73//
74// It's nil safe, and returns false if sc itself is nil, or if the underlying
75// connection is nil.
76//
77// Otherwise, it tries to do a connectivity check and returns the result.
Yuxuan 'fishy' Wangcfbb9052020-06-09 13:07:38 -070078//
79// It also has the side effect of resetting the previously set read deadline on
80// the socket. As a result, it shouldn't be called between setting read deadline
81// and doing actual read.
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -070082func (sc *socketConn) IsOpen() bool {
83 if !sc.isValid() {
84 return false
85 }
86 return sc.checkConn() == nil
87}
88
89// Read implements io.Reader.
90//
91// On Windows, it behaves the same as the underlying net.Conn.Read.
92//
93// On non-Windows, it treats len(p) == 0 as a connectivity check instead of
94// readability check, which means instead of blocking until there's something to
95// read (readability check), or always return (0, nil) (the default behavior of
96// go's stdlib implementation on non-Windows), it never blocks, and will return
97// an error if the connection is lost.
98func (sc *socketConn) Read(p []byte) (n int, err error) {
99 if len(p) == 0 {
100 return 0, sc.read0()
101 }
102
Yuxuan 'fishy' Wangb93fafd2020-08-02 13:36:54 -0700103 return sc.Conn.Read(p)
Yuxuan 'fishy' Wang05023e82020-05-26 15:31:20 -0700104}
Yuxuan 'fishy' Wang39d72782022-01-08 01:03:57 -0800105
106func (sc *socketConn) Close() error {
107 if !sc.isValid() {
108 // Already closed
109 return net.ErrClosed
110 }
111 atomic.StoreInt32(&sc.closed, 1)
112 return sc.Conn.Close()
113}