github.com/gogf/gf/v2@v2.7.4/net/gtcp/gtcp_func.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gtcp
     8  
     9  import (
    10  	"crypto/rand"
    11  	"crypto/tls"
    12  	"net"
    13  	"time"
    14  
    15  	"github.com/gogf/gf/v2/errors/gerror"
    16  	"github.com/gogf/gf/v2/os/gfile"
    17  )
    18  
    19  const (
    20  	defaultConnTimeout    = 30 * time.Second       // Default connection timeout.
    21  	defaultRetryInternal  = 100 * time.Millisecond // Default retry interval.
    22  	defaultReadBufferSize = 128                    // (Byte) Buffer size for reading.
    23  )
    24  
    25  type Retry struct {
    26  	Count    int           // Retry count.
    27  	Interval time.Duration // Retry interval.
    28  }
    29  
    30  // NewNetConn creates and returns a net.Conn with given address like "127.0.0.1:80".
    31  // The optional parameter `timeout` specifies the timeout for dialing connection.
    32  func NewNetConn(address string, timeout ...time.Duration) (net.Conn, error) {
    33  	var (
    34  		network  = `tcp`
    35  		duration = defaultConnTimeout
    36  	)
    37  	if len(timeout) > 0 {
    38  		duration = timeout[0]
    39  	}
    40  	conn, err := net.DialTimeout(network, address, duration)
    41  	if err != nil {
    42  		err = gerror.Wrapf(
    43  			err,
    44  			`net.DialTimeout failed with network "%s", address "%s", timeout "%s"`,
    45  			network, address, duration,
    46  		)
    47  	}
    48  	return conn, err
    49  }
    50  
    51  // NewNetConnTLS creates and returns a TLS net.Conn with given address like "127.0.0.1:80".
    52  // The optional parameter `timeout` specifies the timeout for dialing connection.
    53  func NewNetConnTLS(address string, tlsConfig *tls.Config, timeout ...time.Duration) (net.Conn, error) {
    54  	var (
    55  		network = `tcp`
    56  		dialer  = &net.Dialer{
    57  			Timeout: defaultConnTimeout,
    58  		}
    59  	)
    60  	if len(timeout) > 0 {
    61  		dialer.Timeout = timeout[0]
    62  	}
    63  	conn, err := tls.DialWithDialer(dialer, network, address, tlsConfig)
    64  	if err != nil {
    65  		err = gerror.Wrapf(
    66  			err,
    67  			`tls.DialWithDialer failed with network "%s", address "%s", timeout "%s", tlsConfig "%v"`,
    68  			network, address, dialer.Timeout, tlsConfig,
    69  		)
    70  	}
    71  	return conn, err
    72  }
    73  
    74  // NewNetConnKeyCrt creates and returns a TLS net.Conn with given TLS certificate and key files
    75  // and address like "127.0.0.1:80". The optional parameter `timeout` specifies the timeout for
    76  // dialing connection.
    77  func NewNetConnKeyCrt(addr, crtFile, keyFile string, timeout ...time.Duration) (net.Conn, error) {
    78  	tlsConfig, err := LoadKeyCrt(crtFile, keyFile)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	return NewNetConnTLS(addr, tlsConfig, timeout...)
    83  }
    84  
    85  // Send creates connection to `address`, writes `data` to the connection and then closes the connection.
    86  // The optional parameter `retry` specifies the retry policy when fails in writing data.
    87  func Send(address string, data []byte, retry ...Retry) error {
    88  	conn, err := NewConn(address)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	defer conn.Close()
    93  	return conn.Send(data, retry...)
    94  }
    95  
    96  // SendRecv creates connection to `address`, writes `data` to the connection, receives response
    97  // and then closes the connection.
    98  //
    99  // The parameter `length` specifies the bytes count waiting to receive. It receives all buffer content
   100  // and returns if `length` is -1.
   101  //
   102  // The optional parameter `retry` specifies the retry policy when fails in writing data.
   103  func SendRecv(address string, data []byte, length int, retry ...Retry) ([]byte, error) {
   104  	conn, err := NewConn(address)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	defer conn.Close()
   109  	return conn.SendRecv(data, length, retry...)
   110  }
   111  
   112  // SendWithTimeout does Send logic with writing timeout limitation.
   113  func SendWithTimeout(address string, data []byte, timeout time.Duration, retry ...Retry) error {
   114  	conn, err := NewConn(address)
   115  	if err != nil {
   116  		return err
   117  	}
   118  	defer conn.Close()
   119  	return conn.SendWithTimeout(data, timeout, retry...)
   120  }
   121  
   122  // SendRecvWithTimeout does SendRecv logic with reading timeout limitation.
   123  func SendRecvWithTimeout(address string, data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {
   124  	conn, err := NewConn(address)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	defer conn.Close()
   129  	return conn.SendRecvWithTimeout(data, receive, timeout, retry...)
   130  }
   131  
   132  // isTimeout checks whether given `err` is a timeout error.
   133  func isTimeout(err error) bool {
   134  	if err == nil {
   135  		return false
   136  	}
   137  	if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
   138  		return true
   139  	}
   140  	return false
   141  }
   142  
   143  // LoadKeyCrt creates and returns a TLS configuration object with given certificate and key files.
   144  func LoadKeyCrt(crtFile, keyFile string) (*tls.Config, error) {
   145  	crtPath, err := gfile.Search(crtFile)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	keyPath, err := gfile.Search(keyFile)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	crt, err := tls.LoadX509KeyPair(crtPath, keyPath)
   154  	if err != nil {
   155  		return nil, gerror.Wrapf(err,
   156  			`tls.LoadX509KeyPair failed for certFile "%s" and keyFile "%s"`,
   157  			crtPath, keyPath,
   158  		)
   159  	}
   160  	tlsConfig := &tls.Config{}
   161  	tlsConfig.Certificates = []tls.Certificate{crt}
   162  	tlsConfig.Time = time.Now
   163  	tlsConfig.Rand = rand.Reader
   164  	return tlsConfig, nil
   165  }
   166  
   167  // MustGetFreePort performs as GetFreePort, but it panics is any error occurs.
   168  func MustGetFreePort() int {
   169  	port, err := GetFreePort()
   170  	if err != nil {
   171  		panic(err)
   172  	}
   173  	return port
   174  }
   175  
   176  // GetFreePort retrieves and returns a port that is free.
   177  func GetFreePort() (port int, err error) {
   178  	var (
   179  		network = `tcp`
   180  		address = `:0`
   181  	)
   182  	resolvedAddr, err := net.ResolveTCPAddr(network, address)
   183  	if err != nil {
   184  		return 0, gerror.Wrapf(
   185  			err,
   186  			`net.ResolveTCPAddr failed for network "%s", address "%s"`,
   187  			network, address,
   188  		)
   189  	}
   190  	l, err := net.ListenTCP(network, resolvedAddr)
   191  	if err != nil {
   192  		return 0, gerror.Wrapf(
   193  			err,
   194  			`net.ListenTCP failed for network "%s", address "%s"`,
   195  			network, resolvedAddr.String(),
   196  		)
   197  	}
   198  	port = l.Addr().(*net.TCPAddr).Port
   199  	if err = l.Close(); err != nil {
   200  		err = gerror.Wrapf(
   201  			err,
   202  			`close listening failed for network "%s", address "%s", port "%d"`,
   203  			network, resolvedAddr.String(), port,
   204  		)
   205  	}
   206  	return
   207  }
   208  
   209  // GetFreePorts retrieves and returns specified number of ports that are free.
   210  func GetFreePorts(count int) (ports []int, err error) {
   211  	var (
   212  		network = `tcp`
   213  		address = `:0`
   214  	)
   215  	for i := 0; i < count; i++ {
   216  		resolvedAddr, err := net.ResolveTCPAddr(network, address)
   217  		if err != nil {
   218  			return nil, gerror.Wrapf(
   219  				err,
   220  				`net.ResolveTCPAddr failed for network "%s", address "%s"`,
   221  				network, address,
   222  			)
   223  		}
   224  		l, err := net.ListenTCP(network, resolvedAddr)
   225  		if err != nil {
   226  			return nil, gerror.Wrapf(
   227  				err,
   228  				`net.ListenTCP failed for network "%s", address "%s"`,
   229  				network, resolvedAddr.String(),
   230  			)
   231  		}
   232  		ports = append(ports, l.Addr().(*net.TCPAddr).Port)
   233  		_ = l.Close()
   234  	}
   235  	return ports, nil
   236  }