github.com/braveheart12/insolar-09-08-19@v0.8.7/network/transport/base.go (about)

     1  /*
     2   * The Clear BSD License
     3   *
     4   * Copyright (c) 2019 Insolar Technologies
     5   *
     6   * All rights reserved.
     7   *
     8   * Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met:
     9   *
    10   *  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    11   *  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    12   *  Neither the name of Insolar Technologies nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
    13   *
    14   * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    15   *
    16   */
    17  
    18  package transport
    19  
    20  import (
    21  	"context"
    22  	"io"
    23  	"sync"
    24  
    25  	"github.com/insolar/insolar/instrumentation/inslogger"
    26  	"github.com/insolar/insolar/metrics"
    27  	"github.com/insolar/insolar/network"
    28  	"github.com/insolar/insolar/network/transport/packet"
    29  	"github.com/insolar/insolar/network/transport/relay"
    30  	"github.com/pkg/errors"
    31  )
    32  
    33  type transportSerializer interface {
    34  	SerializePacket(q *packet.Packet) ([]byte, error)
    35  	DeserializePacket(conn io.Reader) (*packet.Packet, error)
    36  }
    37  
    38  type baseSerializer struct{}
    39  
    40  func (b *baseSerializer) SerializePacket(q *packet.Packet) ([]byte, error) {
    41  	return packet.SerializePacket(q)
    42  }
    43  
    44  func (b *baseSerializer) DeserializePacket(conn io.Reader) (*packet.Packet, error) {
    45  	return packet.DeserializePacket(conn)
    46  }
    47  
    48  type baseTransport struct {
    49  	futureManager futureManager
    50  	serializer    transportSerializer
    51  	proxy         relay.Proxy
    52  	packetHandler packetHandler
    53  
    54  	disconnectStarted  chan bool
    55  	disconnectFinished chan bool
    56  
    57  	mutex *sync.RWMutex
    58  
    59  	publicAddress string
    60  	sendFunc      func(recvAddress string, data []byte) error
    61  }
    62  
    63  func newBaseTransport(proxy relay.Proxy, publicAddress string) baseTransport {
    64  	futureManager := newFutureManager()
    65  	return baseTransport{
    66  		futureManager: futureManager,
    67  		packetHandler: newPacketHandler(futureManager),
    68  		proxy:         proxy,
    69  		serializer:    &baseSerializer{},
    70  
    71  		mutex: &sync.RWMutex{},
    72  
    73  		disconnectStarted:  make(chan bool, 1),
    74  		disconnectFinished: make(chan bool, 1),
    75  
    76  		publicAddress: publicAddress,
    77  	}
    78  }
    79  
    80  // SendRequest sends request packet and returns future.
    81  func (t *baseTransport) SendRequest(ctx context.Context, msg *packet.Packet) (Future, error) {
    82  	future := t.futureManager.Create(msg)
    83  	err := t.SendPacket(ctx, msg)
    84  	if err != nil {
    85  		future.Cancel()
    86  		return nil, errors.Wrap(err, "Failed to send transport packet")
    87  	}
    88  	metrics.NetworkPacketSentTotal.WithLabelValues(msg.Type.String()).Inc()
    89  	return future, nil
    90  }
    91  
    92  // SendResponse sends response packet.
    93  func (t *baseTransport) SendResponse(ctx context.Context, requestID network.RequestID, msg *packet.Packet) error {
    94  	msg.RequestID = requestID
    95  
    96  	return t.SendPacket(ctx, msg)
    97  }
    98  
    99  // Close closes packet channels.
   100  func (t *baseTransport) Close() {
   101  	t.mutex.Lock()
   102  	defer t.mutex.Unlock()
   103  
   104  	close(t.disconnectFinished)
   105  }
   106  
   107  // Packets returns incoming packets channel.
   108  func (t *baseTransport) Packets() <-chan *packet.Packet {
   109  	return t.packetHandler.Received()
   110  }
   111  
   112  // Stopped checks if networking is stopped already.
   113  func (t *baseTransport) Stopped() <-chan bool {
   114  	t.mutex.RLock()
   115  	defer t.mutex.RUnlock()
   116  
   117  	return t.disconnectStarted
   118  }
   119  
   120  func (t *baseTransport) prepareDisconnect() {
   121  	t.disconnectStarted <- true
   122  	close(t.disconnectStarted)
   123  }
   124  
   125  // PublicAddress returns transport public ip address
   126  func (t *baseTransport) PublicAddress() string {
   127  	return t.publicAddress
   128  }
   129  
   130  func (t *baseTransport) SendPacket(ctx context.Context, p *packet.Packet) error {
   131  	var recvAddress string
   132  	if t.proxy.ProxyHostsCount() > 0 {
   133  		recvAddress = t.proxy.GetNextProxyAddress()
   134  	}
   135  	if len(recvAddress) == 0 {
   136  		recvAddress = p.Receiver.Address.String()
   137  	}
   138  
   139  	data, err := t.serializer.SerializePacket(p)
   140  	if err != nil {
   141  		return errors.Wrap(err, "Failed to serialize packet")
   142  	}
   143  
   144  	inslogger.FromContext(ctx).Debugf("Send %s packet to %s with RequestID = %d", p.Type, recvAddress, p.RequestID)
   145  	return t.sendFunc(recvAddress, data)
   146  }