github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/orderer/common/broadcast/broadcast.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package broadcast
    18  
    19  import (
    20  	"github.com/hyperledger/fabric/orderer/common/filter"
    21  	cb "github.com/hyperledger/fabric/protos/common"
    22  	ab "github.com/hyperledger/fabric/protos/orderer"
    23  	"github.com/op/go-logging"
    24  
    25  	"io"
    26  
    27  	"github.com/golang/protobuf/proto"
    28  	"github.com/hyperledger/fabric/protos/utils"
    29  )
    30  
    31  var logger = logging.MustGetLogger("orderer/common/broadcast")
    32  
    33  // ConfigUpdateProcessor is used to transform CONFIG_UPDATE transactions which are used to generate other envelope
    34  // message types with preprocessing by the orderer
    35  type ConfigUpdateProcessor interface {
    36  	// Process takes in an envelope of type CONFIG_UPDATE and proceses it
    37  	// to transform it either into another envelope type
    38  	Process(envConfigUpdate *cb.Envelope) (*cb.Envelope, error)
    39  }
    40  
    41  // Handler defines an interface which handles broadcasts
    42  type Handler interface {
    43  	// Handle starts a service thread for a given gRPC connection and services the broadcast connection
    44  	Handle(srv ab.AtomicBroadcast_BroadcastServer) error
    45  }
    46  
    47  // SupportManager provides a way for the Handler to look up the Support for a chain
    48  type SupportManager interface {
    49  	ConfigUpdateProcessor
    50  
    51  	// GetChain gets the chain support for a given ChannelId
    52  	GetChain(chainID string) (Support, bool)
    53  }
    54  
    55  // Support provides the backing resources needed to support broadcast on a chain
    56  type Support interface {
    57  	// Enqueue accepts a message and returns true on acceptance, or false on shutdown
    58  	Enqueue(env *cb.Envelope) bool
    59  
    60  	// Filters returns the set of broadcast filters for this chain
    61  	Filters() *filter.RuleSet
    62  }
    63  
    64  type handlerImpl struct {
    65  	sm SupportManager
    66  }
    67  
    68  // NewHandlerImpl constructs a new implementation of the Handler interface
    69  func NewHandlerImpl(sm SupportManager) Handler {
    70  	return &handlerImpl{
    71  		sm: sm,
    72  	}
    73  }
    74  
    75  // Handle starts a service thread for a given gRPC connection and services the broadcast connection
    76  func (bh *handlerImpl) Handle(srv ab.AtomicBroadcast_BroadcastServer) error {
    77  	for {
    78  		msg, err := srv.Recv()
    79  		if err == io.EOF {
    80  			return nil
    81  		}
    82  		if err != nil {
    83  			return err
    84  		}
    85  
    86  		payload := &cb.Payload{}
    87  		err = proto.Unmarshal(msg.Payload, payload)
    88  		if payload.Header == nil /* || payload.Header.ChannelHeader == nil */ {
    89  			logger.Debugf("Received malformed message, dropping connection")
    90  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST})
    91  		}
    92  
    93  		chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
    94  		if err != nil {
    95  			logger.Debugf("Received malformed message (bad channel header), dropping connection")
    96  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST})
    97  		}
    98  
    99  		if chdr.Type == int32(cb.HeaderType_CONFIG_UPDATE) {
   100  			logger.Debugf("Preprocessing CONFIG_UPDATE")
   101  			msg, err = bh.sm.Process(msg)
   102  			if err != nil {
   103  				return srv.Send(&ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST})
   104  			}
   105  
   106  			err = proto.Unmarshal(msg.Payload, payload)
   107  			if payload.Header == nil {
   108  				logger.Criticalf("Generated bad transaction after CONFIG_UPDATE processing")
   109  				return srv.Send(&ab.BroadcastResponse{Status: cb.Status_INTERNAL_SERVER_ERROR})
   110  			}
   111  
   112  			chdr, err = utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   113  			if err != nil {
   114  				logger.Debugf("Generated bad transaction after CONFIG_UPDATE processing (bad channel header)")
   115  				return srv.Send(&ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST})
   116  			}
   117  
   118  			if chdr.ChannelId == "" {
   119  				logger.Criticalf("Generated bad transaction after CONFIG_UPDATE processing")
   120  				return srv.Send(&ab.BroadcastResponse{Status: cb.Status_INTERNAL_SERVER_ERROR})
   121  			}
   122  		}
   123  
   124  		support, ok := bh.sm.GetChain(chdr.ChannelId)
   125  		if !ok {
   126  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_NOT_FOUND})
   127  		}
   128  
   129  		if logger.IsEnabledFor(logging.DEBUG) {
   130  			logger.Debugf("Broadcast is filtering message for channel %s", chdr.ChannelId)
   131  		}
   132  
   133  		// Normal transaction for existing chain
   134  		_, filterErr := support.Filters().Apply(msg)
   135  
   136  		if filterErr != nil {
   137  			logger.Debugf("Rejecting broadcast message")
   138  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST})
   139  		}
   140  
   141  		if !support.Enqueue(msg) {
   142  			logger.Debugf("Consenter instructed us to shut down")
   143  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_SERVICE_UNAVAILABLE})
   144  		}
   145  
   146  		if logger.IsEnabledFor(logging.DEBUG) {
   147  			logger.Debugf("Broadcast is successfully enqueued message for chain %s", chdr.ChannelId)
   148  		}
   149  
   150  		err = srv.Send(&ab.BroadcastResponse{Status: cb.Status_SUCCESS})
   151  
   152  		if err != nil {
   153  			return err
   154  		}
   155  	}
   156  }