2017-11-30 09:13:58 +00:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
2017-12-01 03:42:03 +00:00
|
|
|
"crypto/tls"
|
2017-11-30 09:13:58 +00:00
|
|
|
"net"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"git.loafle.net/commons_go/logging"
|
2017-11-30 09:36:59 +00:00
|
|
|
cuc "git.loafle.net/commons_go/util/context"
|
2017-11-30 09:13:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Socket interface {
|
|
|
|
Context() SocketContext
|
|
|
|
|
|
|
|
net.Conn
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewSocket(sb SocketBuilder, parentContext cuc.Context) (Socket, error) {
|
|
|
|
if nil == sb {
|
2018-03-21 11:07:11 +00:00
|
|
|
logging.Logger().Panicf("Client Socket: SocketBuilder must be specified")
|
2017-11-30 09:13:58 +00:00
|
|
|
}
|
|
|
|
sb.Validate()
|
|
|
|
|
|
|
|
sc := sb.SocketContext(parentContext)
|
|
|
|
if nil == sc {
|
2018-03-21 11:07:11 +00:00
|
|
|
logging.Logger().Panicf("Client Socket: SocketContext must be specified")
|
2017-11-30 09:13:58 +00:00
|
|
|
}
|
|
|
|
|
2017-12-05 07:21:32 +00:00
|
|
|
sh := sb.GetSocketHandler()
|
2017-11-30 09:13:58 +00:00
|
|
|
if nil == sh {
|
2018-03-21 11:07:11 +00:00
|
|
|
logging.Logger().Panicf("Client Socket: SocketHandler must be specified")
|
2017-11-30 09:13:58 +00:00
|
|
|
}
|
|
|
|
sh.Validate()
|
|
|
|
|
|
|
|
network := sb.GetNetwork()
|
|
|
|
address := sb.GetAddress()
|
|
|
|
|
2017-12-01 03:42:03 +00:00
|
|
|
conn, err := sb.Dial(network, address)
|
2017-11-30 09:13:58 +00:00
|
|
|
if nil != err {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-12-01 03:42:03 +00:00
|
|
|
tlsConfig := sb.GetTLSConfig()
|
|
|
|
if nil != tlsConfig {
|
|
|
|
cfg := 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
|
|
|
|
}
|
|
|
|
|
2017-11-30 09:13:58 +00:00
|
|
|
sh.OnConnect(sc, conn)
|
|
|
|
|
|
|
|
s := retainSocket()
|
2017-11-30 10:25:12 +00:00
|
|
|
s.Conn = conn
|
2017-11-30 09:13:58 +00:00
|
|
|
s.ctx = sc
|
|
|
|
s.sh = sh
|
|
|
|
|
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type netSocket struct {
|
|
|
|
net.Conn
|
|
|
|
|
|
|
|
ctx SocketContext
|
|
|
|
sh SocketHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *netSocket) Context() SocketContext {
|
|
|
|
return s.ctx
|
|
|
|
}
|
|
|
|
|
2018-03-22 14:09:11 +00:00
|
|
|
func (s *netSocket) Read(b []byte) (n int, err error) {
|
|
|
|
n, err = s.Conn.Read(b)
|
|
|
|
|
|
|
|
logging.Logger().Debugf("Client Socket: read message[%s]", string(b))
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *netSocket) Write(b []byte) (n int, err error) {
|
|
|
|
logging.Logger().Debugf("Client Socket: write message[%s]", string(b))
|
|
|
|
return s.Conn.Write(b)
|
|
|
|
}
|
|
|
|
|
2017-11-30 09:13:58 +00:00
|
|
|
func (s *netSocket) Close() error {
|
|
|
|
err := s.Conn.Close()
|
|
|
|
s.sh.OnDisconnect(s)
|
|
|
|
releaseSocket(s)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var socketPool sync.Pool
|
|
|
|
|
|
|
|
func retainSocket() *netSocket {
|
|
|
|
v := socketPool.Get()
|
|
|
|
if v == nil {
|
|
|
|
return &netSocket{}
|
|
|
|
}
|
|
|
|
return v.(*netSocket)
|
|
|
|
}
|
|
|
|
|
|
|
|
func releaseSocket(s *netSocket) {
|
|
|
|
s.sh = nil
|
|
|
|
s.ctx = nil
|
|
|
|
|
|
|
|
socketPool.Put(s)
|
|
|
|
}
|