github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/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 transforms an envelope of type CONFIG_UPDATE to another type
    37  	Process(envConfigUpdate *cb.Envelope) (*cb.Envelope, error)
    38  }
    39  
    40  // Handler defines an interface which handles broadcasts
    41  type Handler interface {
    42  	// Handle starts a service thread for a given gRPC connection and services the broadcast connection
    43  	Handle(srv ab.AtomicBroadcast_BroadcastServer) error
    44  }
    45  
    46  // SupportManager provides a way for the Handler to look up the Support for a chain
    47  type SupportManager interface {
    48  	ConfigUpdateProcessor
    49  
    50  	// GetChain gets the chain support for a given ChannelId
    51  	GetChain(chainID string) (Support, bool)
    52  }
    53  
    54  // Support provides the backing resources needed to support broadcast on a chain
    55  type Support interface {
    56  	// Enqueue accepts a message and returns true on acceptance, or false on shutdown
    57  	Enqueue(env *cb.Envelope) bool
    58  
    59  	// Filters returns the set of broadcast filters for this chain
    60  	Filters() *filter.RuleSet
    61  }
    62  
    63  type handlerImpl struct {
    64  	sm SupportManager
    65  }
    66  
    67  // NewHandlerImpl constructs a new implementation of the Handler interface
    68  func NewHandlerImpl(sm SupportManager) Handler {
    69  	return &handlerImpl{
    70  		sm: sm,
    71  	}
    72  }
    73  
    74  // Handle starts a service thread for a given gRPC connection and services the broadcast connection
    75  func (bh *handlerImpl) Handle(srv ab.AtomicBroadcast_BroadcastServer) error {
    76  	logger.Debugf("Starting new broadcast loop")
    77  	for {
    78  		msg, err := srv.Recv()
    79  		if err == io.EOF {
    80  			logger.Debugf("Received EOF, hangup")
    81  			return nil
    82  		}
    83  		if err != nil {
    84  			logger.Warningf("Error reading from stream: %s", err)
    85  			return err
    86  		}
    87  
    88  		payload, err := utils.UnmarshalPayload(msg.Payload)
    89  		if err != nil {
    90  			logger.Warningf("Received malformed message, dropping connection: %s", err)
    91  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST})
    92  		}
    93  
    94  		if payload.Header == nil {
    95  			logger.Warningf("Received malformed message, with missing header, dropping connection")
    96  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST})
    97  		}
    98  
    99  		chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   100  		if err != nil {
   101  			logger.Warningf("Received malformed message (bad channel header), dropping connection: %s", err)
   102  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST})
   103  		}
   104  
   105  		if chdr.Type == int32(cb.HeaderType_CONFIG_UPDATE) {
   106  			logger.Debugf("Preprocessing CONFIG_UPDATE")
   107  			msg, err = bh.sm.Process(msg)
   108  			if err != nil {
   109  				logger.Warningf("Rejecting CONFIG_UPDATE because: %s", err)
   110  				return srv.Send(&ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST})
   111  			}
   112  
   113  			err = proto.Unmarshal(msg.Payload, payload)
   114  			if err != nil || payload.Header == nil {
   115  				logger.Criticalf("Generated bad transaction after CONFIG_UPDATE processing")
   116  				return srv.Send(&ab.BroadcastResponse{Status: cb.Status_INTERNAL_SERVER_ERROR})
   117  			}
   118  
   119  			chdr, err = utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   120  			if err != nil {
   121  				logger.Criticalf("Generated bad transaction after CONFIG_UPDATE processing (bad channel header): %s", err)
   122  				return srv.Send(&ab.BroadcastResponse{Status: cb.Status_INTERNAL_SERVER_ERROR})
   123  			}
   124  
   125  			if chdr.ChannelId == "" {
   126  				logger.Criticalf("Generated bad transaction after CONFIG_UPDATE processing (empty channel ID)")
   127  				return srv.Send(&ab.BroadcastResponse{Status: cb.Status_INTERNAL_SERVER_ERROR})
   128  			}
   129  		}
   130  
   131  		support, ok := bh.sm.GetChain(chdr.ChannelId)
   132  		if !ok {
   133  			logger.Warningf("Rejecting broadcast because channel %s was not found", chdr.ChannelId)
   134  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_NOT_FOUND})
   135  		}
   136  
   137  		logger.Debugf("[channel: %s] Broadcast is filtering message of type %s", chdr.ChannelId, cb.HeaderType_name[chdr.Type])
   138  
   139  		// Normal transaction for existing chain
   140  		_, filterErr := support.Filters().Apply(msg)
   141  
   142  		if filterErr != nil {
   143  			logger.Warningf("[channel: %s] Rejecting broadcast message because of filter error: %s", chdr.ChannelId, filterErr)
   144  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_BAD_REQUEST})
   145  		}
   146  
   147  		if !support.Enqueue(msg) {
   148  			return srv.Send(&ab.BroadcastResponse{Status: cb.Status_SERVICE_UNAVAILABLE})
   149  		}
   150  
   151  		if logger.IsEnabledFor(logging.DEBUG) {
   152  			logger.Debugf("[channel: %s] Broadcast has successfully enqueued message of type %s", chdr.ChannelId, cb.HeaderType_name[chdr.Type])
   153  		}
   154  
   155  		err = srv.Send(&ab.BroadcastResponse{Status: cb.Status_SUCCESS})
   156  		if err != nil {
   157  			logger.Warningf("[channel: %s] Error sending to stream: %s", chdr.ChannelId, err)
   158  			return err
   159  		}
   160  	}
   161  }