package net import ( "crypto/tls" "fmt" "net" "time" ) type Client struct { Name string Network string Address string TLSConfig *tls.Config HandshakeTimeout time.Duration KeepAlive time.Duration LocalAddress net.Addr MaxConnections int } func (c *Client) Dial() (net.Conn, error) { if err := c.Validate(); nil != err { return nil, err } var deadline time.Time if 0 != c.HandshakeTimeout { deadline = time.Now().Add(c.HandshakeTimeout) } d := &net.Dialer{ KeepAlive: c.KeepAlive, Deadline: deadline, LocalAddr: c.LocalAddress, } conn, err := d.Dial(c.Network, c.Address) if nil != err { return nil, err } if nil != c.TLSConfig { cfg := c.TLSConfig.Clone() tlsConn := tls.Client(conn, cfg) if err := tlsConn.Handshake(); err != nil { tlsConn.Close() return nil, err } if !cfg.InsecureSkipVerify { if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { return nil, err } } conn = tlsConn } return conn, nil } func (c *Client) Validate() error { if "" == c.Name { c.Name = "Client" } if "" == c.Network { return fmt.Errorf("Client: Network is not valid") } if "" == c.Address { return fmt.Errorf("Client: Address is not valid") } if 0 >= c.MaxConnections { c.MaxConnections = 1 } if 0 >= c.KeepAlive { c.KeepAlive = DefaultKeepAlive } if 0 >= c.HandshakeTimeout { c.HandshakeTimeout = DefaultHandshakeTimeout } return nil }