func (c *Client) Dial() (*tls.Conn, error) {
	if len(c.certs.Cert.Certificate) == 0 {
		return nil, fmt.Errorf("%s\n", NoKeyPairLoadError)
	}
	config := &tls.Config{
		Certificates:       []tls.Certificate{c.certs.Cert},
		InsecureSkipVerify: false,
		RootCAs:            c.certs.Pool,
	}
	service := c.options.Host + ":" + strconv.Itoa(c.options.Port)
	conn, err := tls.Dial("tcp", service, config)
	if err != nil {
		return nil, fmt.Errorf("fail to dial with server: %v\n", err)
	}
	c.logger.Log("dial to "+service+" - ok", LogLevelInfo)
	return conn, nil
}
Dial - function for start connection with server.
package herots
import (
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io"
	"net"
	"os"
	"strconv"
)
type LogHandlerFunc func(message string, lvl LogLevelType)
type LogLevelType int
const (
	LogLevelNone LogLevelType = iota
	LogLevelNotice
	LogLevelInfo
	LogLevelError
)
type log struct {
	LogLevel       LogLevelType
	LogDestination io.Writer
	Handler        LogHandlerFunc
}
func (l *log) Log(message string, lvl LogLevelType) {
	if l.Handler != nil {
		l.Handler(message, lvl)
		return
	}
	if l.LogLevel == 0 {
		return
	}
	if lvl <= l.LogLevel {
		fmt.Fprintf(l.LogDestination, "herots: %s\n", message)
	}
}
func loadKeyPair(cert, key []byte) (tls.Certificate, *x509.Certificate, error) {
	c, err := tls.X509KeyPair(cert, key)
	if err != nil {
		return tls.Certificate{}, &x509.Certificate{}, err
	}
	pemData, _ := pem.Decode(cert)
	ca, err := x509.ParseCertificate(pemData.Bytes)
	if err != nil {
		return tls.Certificate{}, &x509.Certificate{}, err
	}
	return c, ca, nil
}
type Options struct {
	Host string
	Port int
	LogLevel LogLevelType
	LogDestination io.Writer
	LogHandler LogHandlerFunc
	TLSAuthType tls.ClientAuthType
}
const (
	LoadKeyPairError   = "load key pair error"
	NoKeyPairLoadError = "no load key pair (use LoadKeyPair func)"
)
type Server struct {
	options *Options
	certs   struct {
		Cert tls.Certificate
		Pool *x509.CertPool
	}
	listener net.Listener
	logger   *log
}
func NewServer(o *Options) *Server {
	s := &Server{}
	if o.LogDestination == nil {
		o.LogDestination = os.Stdout
	}
	if o.Port == 0 {
		o.Port = 9000
	}
	if o.TLSAuthType == 0 {
		o.TLSAuthType = tls.RequireAnyClientCert
	}
	l := &log{
		LogLevel:       o.LogLevel,
		LogDestination: o.LogDestination,
		Handler:        o.LogHandler,
	}
	s.options = o
	s.logger = l
	return s
}
func (s *Server) LoadKeyPair(cert, key []byte) error {
	c, ca, err := loadKeyPair(cert, key)
	if err != nil {
		return fmt.Errorf("%s: %v\n", LoadKeyPairError, err)
	}
	s.certs.Cert = c
	s.certs.Pool = x509.NewCertPool()
	s.certs.Pool.AddCert(ca)
	s.logger.Log("load key pair - ok", LogLevelInfo)
	return nil
}
func (s *Server) AddClientCACert(cert []byte) error {
	pemData, _ := pem.Decode(cert)
	ca, err := x509.ParseCertificate(pemData.Bytes)
	if err != nil {
		return fmt.Errorf("load client CA cert error: %v\n", err)
	}
	s.certs.Pool.AddCert(ca)
	s.logger.Log("load client CA cert - ok", LogLevelInfo)
	return nil
}
func (s *Server) Accept() (net.Conn, error) {
	conn, err := s.listener.Accept()
	if err != nil {
		s.logger.Log("accept conn error: "+err.Error(), LogLevelError)
		return conn, fmt.Errorf("connection accept fail: %v\n", err)
	}
	s.logger.Log("accepted conn from "+conn.RemoteAddr().String(), LogLevelInfo)
	return conn, nil
}
func (s *Server) Start() error {
	if len(s.certs.Cert.Certificate) == 0 {
		return fmt.Errorf("%s\n", NoKeyPairLoadError)
	}
	config := tls.Config{
		ClientAuth:   s.options.TLSAuthType,
		Certificates: []tls.Certificate{s.certs.Cert},
		ClientCAs:    s.certs.Pool,
		Rand:         rand.Reader,
	}
	service := s.options.Host + ":" + strconv.Itoa(s.options.Port)
	listener, err := tls.Listen("tcp", service, &config)
	if err != nil {
		return fmt.Errorf("start tls server fail: %v\n", err)
	}
	s.listener = listener
	s.logger.Log("listening on "+service, LogLevelNotice)
	return nil
}
type Client struct {
	options *Options
	certs   struct {
		Cert tls.Certificate
		Pool *x509.CertPool
	}
	logger *log
}
func NewClient(o *Options) *Client {
	c := &Client{}
	if o.LogDestination == nil {
		o.LogDestination = os.Stdout
	}
	if o.Port == 0 {
		o.Port = 9000
	}
	l := &log{
		LogLevel:       o.LogLevel,
		LogDestination: o.LogDestination,
		Handler:        o.LogHandler,
	}
	c.options = o
	c.logger = l
	c.certs.Pool = x509.NewCertPool()
	return c
}
func (c *Client) LoadKeyPair(cert, key []byte) error {
	c0, ca, err := loadKeyPair(cert, key)
	if err != nil {
		return fmt.Errorf("%s: %v\n", LoadKeyPairError, err)
	}
	c.certs.Cert = c0
	c.certs.Pool.AddCert(ca)
	c.logger.Log("load key pair - ok", LogLevelInfo)
	return nil
}
func (c *Client) AddCertToRootCA(cert []byte) error {
	pemData, _ := pem.Decode(cert)
	ca, err := x509.ParseCertificate(pemData.Bytes)
	if err != nil {
		return fmt.Errorf("load CA cert error: %v\n", err)
	}
	c.certs.Pool.AddCert(ca)
	c.logger.Log("add cert to root CA - ok", LogLevelInfo)
	return nil
}