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