func (wrapper *secureSessionConnection) Write(b []byte) (n int, err error) {
	wrapper.mutex.Lock()
	if wrapper.closed {
		wrapper.mutex.Unlock()
		return 0, io.EOF
	}
	encryptedData, err := wrapper.session.Wrap(b)
	if err != nil {
		wrapper.mutex.Unlock()
		return 0, err
	}
	wrapper.mutex.Unlock()
	err = utils.SendData(encryptedData, wrapper.Conn)
	return len(b), nil
}
Write encrypt data with secure session and send it to wrapped connection
package network
import (
	"bytes"
	"context"
	"go.opencensus.io/trace"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/peer"
	"io"
	"net"
	"sync"
	"errors"
	"github.com/cossacklabs/acra/keystore"
	"github.com/cossacklabs/acra/logging"
	"github.com/cossacklabs/acra/utils"
	"github.com/cossacklabs/themis/gothemis/keys"
	"github.com/cossacklabs/themis/gothemis/session"
	log "github.com/sirupsen/logrus"
	"time"
)
const (
	sessionInitTimeout = time.Second * 5
)
type secureSessionGRPCClientIDExtractor struct{}
func NewSecureSessionGRPCClientIDExtractor() (secureSessionGRPCClientIDExtractor, error) {
	return secureSessionGRPCClientIDExtractor{}, nil
}
func (extractor secureSessionGRPCClientIDExtractor) ExtractClientID(ctx context.Context) ([]byte, error) {
	info, ok := peer.FromContext(ctx)
	if !ok {
		return nil, ErrCantExtractClientID
	}
	authInfo, ok := info.AuthInfo.(SecureSessionInfo)
	if !ok {
		return nil, ErrIncorrectGRPCConnectionAuthInfo
	}
	return authInfo.ClientID(), nil
}
type SessionCallback struct {
	keystorage keystore.SecureSessionKeyStore
	expectedID []byte
}
func (callback *SessionCallback) GetPublicKeyForId(ss *session.SecureSession, id []byte) *keys.PublicKey {
	if !bytes.Equal(id, callback.expectedID) {
		log.WithField("client_id", string(id)).Warningln("Come secure session connection with unexpected id")
		return nil
	}
	log.Infof("Load public key for id <%v>", string(id))
	key, err := callback.keystorage.GetPeerPublicKey(id)
	if err != nil {
		log.WithError(err).WithField(logging.FieldKeyEventCode, logging.EventCodeErrorCantReadKeys).
			Errorf("Can't load public key for id <%v>", string(id))
		return nil
	}
	return key
}
func (callback *SessionCallback) StateChanged(ss *session.SecureSession, state int) {}
func NewSessionCallback(expectedID []byte, keystorage keystore.SecureSessionKeyStore) (*SessionCallback, error) {
	return &SessionCallback{keystorage: keystorage, expectedID: expectedID}, nil
}
type secureSessionConnection struct {
	keystore keystore.SecureSessionKeyStore
	session  *session.SecureSession
	net.Conn
	currentData   []byte
	returnedIndex int
	closed        bool
	clientID      []byte
	mutex         *sync.Mutex
}
func newSecureSessionConnection(keystore keystore.SecureSessionKeyStore, conn net.Conn) (*secureSessionConnection, error) {
	return &secureSessionConnection{keystore: keystore, session: nil, Conn: conn, currentData: nil, returnedIndex: 0, closed: false, clientID: nil, mutex: &sync.Mutex{}}, nil
}
func (wrapper *secureSessionConnection) Read(b []byte) (n int, err error) {
	if wrapper.currentData != nil {
		n = copy(b, wrapper.currentData[wrapper.returnedIndex:])
		wrapper.returnedIndex += n
		if wrapper.returnedIndex >= cap(wrapper.currentData) {
			wrapper.currentData = nil
		}
		return n, err
	}
	data, err := utils.ReadData(wrapper.Conn)
	if err != nil {
		return len(data), err
	}
	wrapper.mutex.Lock()
	defer wrapper.mutex.Unlock()
	if wrapper.closed {
		return 0, io.EOF
	}
	decryptedData, _, err := wrapper.session.Unwrap(data)
	if err != nil {
		return len(data), err
	}
	n = copy(b, decryptedData)
	if n != len(decryptedData) {
		wrapper.currentData = decryptedData
		wrapper.returnedIndex = n
	}
	return n, nil
}