github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/gossip/comm/comm_impl.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 comm 18 19 import ( 20 "bytes" 21 "crypto/tls" 22 "errors" 23 "fmt" 24 "net" 25 "reflect" 26 "sync" 27 "sync/atomic" 28 "time" 29 30 "github.com/hyperledger/fabric/gossip/api" 31 "github.com/hyperledger/fabric/gossip/common" 32 "github.com/hyperledger/fabric/gossip/identity" 33 "github.com/hyperledger/fabric/gossip/util" 34 proto "github.com/hyperledger/fabric/protos/gossip" 35 "github.com/op/go-logging" 36 "github.com/spf13/viper" 37 "golang.org/x/net/context" 38 "google.golang.org/grpc" 39 "google.golang.org/grpc/credentials" 40 "google.golang.org/grpc/peer" 41 ) 42 43 const ( 44 defDialTimeout = time.Second * time.Duration(3) 45 defConnTimeout = time.Second * time.Duration(2) 46 defRecvBuffSize = 20 47 defSendBuffSize = 20 48 sendOverflowErr = "Send buffer overflow" 49 ) 50 51 var errSendOverflow = errors.New(sendOverflowErr) 52 53 // SetDialTimeout sets the dial timeout 54 func SetDialTimeout(timeout time.Duration) { 55 viper.Set("peer.gossip.dialTimeout", timeout) 56 } 57 58 func (c *commImpl) SetDialOpts(opts ...grpc.DialOption) { 59 if len(opts) == 0 { 60 c.logger.Warning("Given an empty set of grpc.DialOption, aborting") 61 return 62 } 63 c.opts = opts 64 } 65 66 // NewCommInstanceWithServer creates a comm instance that creates an underlying gRPC server 67 func NewCommInstanceWithServer(port int, idMapper identity.Mapper, peerIdentity api.PeerIdentityType, 68 secureDialOpts api.PeerSecureDialOpts, dialOpts ...grpc.DialOption) (Comm, error) { 69 70 var ll net.Listener 71 var s *grpc.Server 72 var certHash []byte 73 74 if len(dialOpts) == 0 { 75 dialOpts = []grpc.DialOption{grpc.WithTimeout(util.GetDurationOrDefault("peer.gossip.dialTimeout", defDialTimeout))} 76 } 77 78 if port > 0 { 79 s, ll, secureDialOpts, certHash = createGRPCLayer(port) 80 } 81 82 commInst := &commImpl{ 83 selfCertHash: certHash, 84 PKIID: idMapper.GetPKIidOfCert(peerIdentity), 85 idMapper: idMapper, 86 logger: util.GetLogger(util.LoggingCommModule, fmt.Sprintf("%d", port)), 87 peerIdentity: peerIdentity, 88 opts: dialOpts, 89 secureDialOpts: secureDialOpts, 90 port: port, 91 lsnr: ll, 92 gSrv: s, 93 msgPublisher: NewChannelDemultiplexer(), 94 lock: &sync.RWMutex{}, 95 deadEndpoints: make(chan common.PKIidType, 100), 96 stopping: int32(0), 97 exitChan: make(chan struct{}, 1), 98 subscriptions: make([]chan proto.ReceivedMessage, 0), 99 } 100 commInst.connStore = newConnStore(commInst, commInst.logger) 101 102 if port > 0 { 103 commInst.stopWG.Add(1) 104 go func() { 105 defer commInst.stopWG.Done() 106 s.Serve(ll) 107 }() 108 proto.RegisterGossipServer(s, commInst) 109 } 110 111 return commInst, nil 112 } 113 114 // NewCommInstance creates a new comm instance that binds itself to the given gRPC server 115 func NewCommInstance(s *grpc.Server, cert *tls.Certificate, idStore identity.Mapper, 116 peerIdentity api.PeerIdentityType, secureDialOpts api.PeerSecureDialOpts, 117 dialOpts ...grpc.DialOption) (Comm, error) { 118 119 dialOpts = append(dialOpts, grpc.WithTimeout(util.GetDurationOrDefault("peer.gossip.dialTimeout", defDialTimeout))) 120 commInst, err := NewCommInstanceWithServer(-1, idStore, peerIdentity, secureDialOpts, dialOpts...) 121 if err != nil { 122 return nil, err 123 } 124 125 if cert != nil { 126 inst := commInst.(*commImpl) 127 if len(cert.Certificate) == 0 { 128 inst.logger.Panic("Certificate supplied but certificate chain is empty") 129 } else { 130 inst.selfCertHash = certHashFromRawCert(cert.Certificate[0]) 131 } 132 } 133 134 proto.RegisterGossipServer(s, commInst.(*commImpl)) 135 136 return commInst, nil 137 } 138 139 type commImpl struct { 140 selfCertHash []byte 141 peerIdentity api.PeerIdentityType 142 idMapper identity.Mapper 143 logger *logging.Logger 144 opts []grpc.DialOption 145 secureDialOpts func() []grpc.DialOption 146 connStore *connectionStore 147 PKIID []byte 148 deadEndpoints chan common.PKIidType 149 msgPublisher *ChannelDeMultiplexer 150 lock *sync.RWMutex 151 lsnr net.Listener 152 gSrv *grpc.Server 153 exitChan chan struct{} 154 stopWG sync.WaitGroup 155 subscriptions []chan proto.ReceivedMessage 156 port int 157 stopping int32 158 } 159 160 func (c *commImpl) createConnection(endpoint string, expectedPKIID common.PKIidType) (*connection, error) { 161 var err error 162 var cc *grpc.ClientConn 163 var stream proto.Gossip_GossipStreamClient 164 var pkiID common.PKIidType 165 var connInfo *proto.ConnectionInfo 166 var dialOpts []grpc.DialOption 167 168 c.logger.Debug("Entering", endpoint, expectedPKIID) 169 defer c.logger.Debug("Exiting") 170 171 if c.isStopping() { 172 return nil, errors.New("Stopping") 173 } 174 dialOpts = append(dialOpts, c.secureDialOpts()...) 175 dialOpts = append(dialOpts, grpc.WithBlock()) 176 dialOpts = append(dialOpts, c.opts...) 177 cc, err = grpc.Dial(endpoint, dialOpts...) 178 if err != nil { 179 return nil, err 180 } 181 182 cl := proto.NewGossipClient(cc) 183 184 if _, err = cl.Ping(context.Background(), &proto.Empty{}); err != nil { 185 cc.Close() 186 return nil, err 187 } 188 189 ctx, cf := context.WithCancel(context.Background()) 190 if stream, err = cl.GossipStream(ctx); err == nil { 191 connInfo, err = c.authenticateRemotePeer(stream) 192 if err == nil { 193 pkiID = connInfo.ID 194 if expectedPKIID != nil && !bytes.Equal(pkiID, expectedPKIID) { 195 // PKIID is nil when we don't know the remote PKI id's 196 c.logger.Warning("Remote endpoint claims to be a different peer, expected", expectedPKIID, "but got", pkiID) 197 cc.Close() 198 return nil, errors.New("Authentication failure") 199 } 200 conn := newConnection(cl, cc, stream, nil) 201 conn.pkiID = pkiID 202 conn.info = connInfo 203 conn.logger = c.logger 204 conn.cancel = cf 205 206 h := func(m *proto.SignedGossipMessage) { 207 c.logger.Debug("Got message:", m) 208 c.msgPublisher.DeMultiplex(&ReceivedMessageImpl{ 209 conn: conn, 210 lock: conn, 211 SignedGossipMessage: m, 212 connInfo: connInfo, 213 }) 214 } 215 conn.handler = h 216 return conn, nil 217 } 218 c.logger.Warning("Authentication failed:", err) 219 } 220 cc.Close() 221 return nil, err 222 } 223 224 func (c *commImpl) Send(msg *proto.SignedGossipMessage, peers ...*RemotePeer) { 225 if c.isStopping() || len(peers) == 0 { 226 return 227 } 228 229 c.logger.Debug("Entering, sending", msg, "to ", len(peers), "peers") 230 231 for _, peer := range peers { 232 go func(peer *RemotePeer, msg *proto.SignedGossipMessage) { 233 c.sendToEndpoint(peer, msg) 234 }(peer, msg) 235 } 236 } 237 238 func (c *commImpl) sendToEndpoint(peer *RemotePeer, msg *proto.SignedGossipMessage) { 239 if c.isStopping() { 240 return 241 } 242 c.logger.Debug("Entering, Sending to", peer.Endpoint, ", msg:", msg) 243 defer c.logger.Debug("Exiting") 244 var err error 245 246 conn, err := c.connStore.getConnection(peer) 247 if err == nil { 248 disConnectOnErr := func(err error) { 249 c.logger.Warning(peer, "isn't responsive:", err) 250 c.disconnect(peer.PKIID) 251 } 252 conn.send(msg, disConnectOnErr) 253 return 254 } 255 c.logger.Warning("Failed obtaining connection for", peer, "reason:", err) 256 c.disconnect(peer.PKIID) 257 } 258 259 func (c *commImpl) isStopping() bool { 260 return atomic.LoadInt32(&c.stopping) == int32(1) 261 } 262 263 func (c *commImpl) Probe(remotePeer *RemotePeer) error { 264 var dialOpts []grpc.DialOption 265 endpoint := remotePeer.Endpoint 266 pkiID := remotePeer.PKIID 267 if c.isStopping() { 268 return errors.New("Stopping") 269 } 270 c.logger.Debug("Entering, endpoint:", endpoint, "PKIID:", pkiID) 271 dialOpts = append(dialOpts, c.secureDialOpts()...) 272 dialOpts = append(dialOpts, grpc.WithBlock()) 273 dialOpts = append(dialOpts, c.opts...) 274 275 cc, err := grpc.Dial(remotePeer.Endpoint, dialOpts...) 276 if err != nil { 277 c.logger.Debug("Returning", err) 278 return err 279 } 280 defer cc.Close() 281 cl := proto.NewGossipClient(cc) 282 _, err = cl.Ping(context.Background(), &proto.Empty{}) 283 c.logger.Debug("Returning", err) 284 return err 285 } 286 287 func (c *commImpl) Handshake(remotePeer *RemotePeer) (api.PeerIdentityType, error) { 288 var dialOpts []grpc.DialOption 289 dialOpts = append(dialOpts, c.secureDialOpts()...) 290 dialOpts = append(dialOpts, grpc.WithBlock()) 291 dialOpts = append(dialOpts, c.opts...) 292 293 cc, err := grpc.Dial(remotePeer.Endpoint, dialOpts...) 294 if err != nil { 295 return nil, err 296 } 297 defer cc.Close() 298 299 cl := proto.NewGossipClient(cc) 300 if _, err = cl.Ping(context.Background(), &proto.Empty{}); err != nil { 301 return nil, err 302 } 303 304 stream, err := cl.GossipStream(context.Background()) 305 if err != nil { 306 return nil, err 307 } 308 connInfo, err := c.authenticateRemotePeer(stream) 309 if err != nil { 310 c.logger.Warning("Authentication failed:", err) 311 return nil, err 312 } 313 if len(remotePeer.PKIID) > 0 && !bytes.Equal(connInfo.ID, remotePeer.PKIID) { 314 return nil, errors.New("PKI-ID of remote peer doesn't match expected PKI-ID") 315 } 316 return connInfo.Identity, nil 317 } 318 319 func (c *commImpl) Accept(acceptor common.MessageAcceptor) <-chan proto.ReceivedMessage { 320 genericChan := c.msgPublisher.AddChannel(acceptor) 321 specificChan := make(chan proto.ReceivedMessage, 10) 322 323 if c.isStopping() { 324 c.logger.Warning("Accept() called but comm module is stopping, returning empty channel") 325 return specificChan 326 } 327 328 c.lock.Lock() 329 c.subscriptions = append(c.subscriptions, specificChan) 330 c.lock.Unlock() 331 332 go func() { 333 defer c.logger.Debug("Exiting Accept() loop") 334 defer func() { 335 recover() 336 }() 337 338 c.stopWG.Add(1) 339 defer c.stopWG.Done() 340 341 for { 342 select { 343 case msg := <-genericChan: 344 specificChan <- msg.(*ReceivedMessageImpl) 345 case s := <-c.exitChan: 346 c.exitChan <- s 347 return 348 } 349 } 350 }() 351 return specificChan 352 } 353 354 func (c *commImpl) PresumedDead() <-chan common.PKIidType { 355 return c.deadEndpoints 356 } 357 358 func (c *commImpl) CloseConn(peer *RemotePeer) { 359 c.logger.Debug("Closing connection for", peer) 360 c.connStore.closeConn(peer) 361 } 362 363 func (c *commImpl) emptySubscriptions() { 364 c.lock.Lock() 365 defer c.lock.Unlock() 366 for _, ch := range c.subscriptions { 367 close(ch) 368 } 369 } 370 371 func (c *commImpl) Stop() { 372 if c.isStopping() { 373 return 374 } 375 atomic.StoreInt32(&c.stopping, int32(1)) 376 c.logger.Info("Stopping") 377 defer c.logger.Info("Stopped") 378 if c.gSrv != nil { 379 c.gSrv.Stop() 380 } 381 if c.lsnr != nil { 382 c.lsnr.Close() 383 } 384 c.connStore.shutdown() 385 c.logger.Debug("Shut down connection store, connection count:", c.connStore.connNum()) 386 c.exitChan <- struct{}{} 387 c.msgPublisher.Close() 388 c.logger.Debug("Shut down publisher") 389 c.emptySubscriptions() 390 c.logger.Debug("Closed subscriptions, waiting for goroutines to stop...") 391 c.stopWG.Wait() 392 } 393 394 func (c *commImpl) GetPKIid() common.PKIidType { 395 return c.PKIID 396 } 397 398 func extractRemoteAddress(stream stream) string { 399 var remoteAddress string 400 p, ok := peer.FromContext(stream.Context()) 401 if ok { 402 if address := p.Addr; address != nil { 403 remoteAddress = address.String() 404 } 405 } 406 return remoteAddress 407 } 408 409 func (c *commImpl) authenticateRemotePeer(stream stream) (*proto.ConnectionInfo, error) { 410 ctx := stream.Context() 411 remoteAddress := extractRemoteAddress(stream) 412 remoteCertHash := extractCertificateHashFromContext(ctx) 413 var err error 414 var cMsg *proto.SignedGossipMessage 415 var signer proto.Signer 416 useTLS := c.selfCertHash != nil 417 418 // If TLS is enabled, sign the connection message in order to bind 419 // the TLS session to the peer's identity 420 if useTLS { 421 signer = func(msg []byte) ([]byte, error) { 422 return c.idMapper.Sign(msg) 423 } 424 } else { // If we don't use TLS, we have no unique text to sign, 425 // so don't sign anything 426 signer = func(msg []byte) ([]byte, error) { 427 return msg, nil 428 } 429 } 430 431 // TLS enabled but not detected on other side 432 if useTLS && len(remoteCertHash) == 0 { 433 c.logger.Warningf("%s didn't send TLS certificate", remoteAddress) 434 return nil, errors.New("No TLS certificate") 435 } 436 437 cMsg, err = c.createConnectionMsg(c.PKIID, c.selfCertHash, c.peerIdentity, signer) 438 if err != nil { 439 return nil, err 440 } 441 442 c.logger.Debug("Sending", cMsg, "to", remoteAddress) 443 stream.Send(cMsg.Envelope) 444 m, err := readWithTimeout(stream, util.GetDurationOrDefault("peer.gossip.connTimeout", defConnTimeout), remoteAddress) 445 if err != nil { 446 c.logger.Warningf("Failed reading messge from %s, reason: %v", remoteAddress, err) 447 return nil, err 448 } 449 receivedMsg := m.GetConn() 450 if receivedMsg == nil { 451 c.logger.Warning("Expected connection message from", remoteAddress, "but got", receivedMsg) 452 return nil, errors.New("Wrong type") 453 } 454 455 if receivedMsg.PkiId == nil { 456 c.logger.Warning("%s didn't send a pkiID", remoteAddress) 457 return nil, errors.New("No PKI-ID") 458 } 459 460 c.logger.Debug("Received", receivedMsg, "from", remoteAddress) 461 err = c.idMapper.Put(receivedMsg.PkiId, receivedMsg.Identity) 462 if err != nil { 463 c.logger.Warning("Identity store rejected", remoteAddress, ":", err) 464 return nil, err 465 } 466 467 connInfo := &proto.ConnectionInfo{ 468 ID: receivedMsg.PkiId, 469 Identity: receivedMsg.Identity, 470 Endpoint: remoteAddress, 471 } 472 473 // if TLS is enabled and detected, verify remote peer 474 if useTLS { 475 // If the remote peer sent its TLS certificate, make sure it actually matches the TLS cert 476 // that the peer used. 477 if !bytes.Equal(remoteCertHash, receivedMsg.TlsCertHash) { 478 return nil, fmt.Errorf("Expected %v in remote hash of TLS cert, but got %v", remoteCertHash, receivedMsg.TlsCertHash) 479 } 480 verifier := func(peerIdentity []byte, signature, message []byte) error { 481 pkiID := c.idMapper.GetPKIidOfCert(api.PeerIdentityType(peerIdentity)) 482 return c.idMapper.Verify(pkiID, signature, message) 483 } 484 err = m.Verify(receivedMsg.Identity, verifier) 485 if err != nil { 486 c.logger.Error("Failed verifying signature from", remoteAddress, ":", err) 487 return nil, err 488 } 489 connInfo.Auth = &proto.AuthInfo{ 490 Signature: m.Signature, 491 SignedData: m.Payload, 492 } 493 } 494 495 c.logger.Debug("Authenticated", remoteAddress) 496 497 return connInfo, nil 498 } 499 500 func (c *commImpl) GossipStream(stream proto.Gossip_GossipStreamServer) error { 501 if c.isStopping() { 502 return errors.New("Shutting down") 503 } 504 connInfo, err := c.authenticateRemotePeer(stream) 505 if err != nil { 506 c.logger.Error("Authentication failed:", err) 507 return err 508 } 509 c.logger.Debug("Servicing", extractRemoteAddress(stream)) 510 511 conn := c.connStore.onConnected(stream, connInfo) 512 513 // if connStore denied the connection, it means we already have a connection to that peer 514 // so close this stream 515 if conn == nil { 516 return nil 517 } 518 519 h := func(m *proto.SignedGossipMessage) { 520 c.msgPublisher.DeMultiplex(&ReceivedMessageImpl{ 521 conn: conn, 522 lock: conn, 523 SignedGossipMessage: m, 524 connInfo: connInfo, 525 }) 526 } 527 528 conn.handler = h 529 530 defer func() { 531 c.logger.Debug("Client", extractRemoteAddress(stream), " disconnected") 532 c.connStore.closeByPKIid(connInfo.ID) 533 conn.close() 534 }() 535 536 return conn.serviceConnection() 537 } 538 539 func (c *commImpl) Ping(context.Context, *proto.Empty) (*proto.Empty, error) { 540 return &proto.Empty{}, nil 541 } 542 543 func (c *commImpl) disconnect(pkiID common.PKIidType) { 544 if c.isStopping() { 545 return 546 } 547 c.deadEndpoints <- pkiID 548 c.connStore.closeByPKIid(pkiID) 549 } 550 551 func readWithTimeout(stream interface{}, timeout time.Duration, address string) (*proto.SignedGossipMessage, error) { 552 incChan := make(chan *proto.SignedGossipMessage, 1) 553 errChan := make(chan error, 1) 554 go func() { 555 if srvStr, isServerStr := stream.(proto.Gossip_GossipStreamServer); isServerStr { 556 if m, err := srvStr.Recv(); err == nil { 557 msg, err := m.ToGossipMessage() 558 if err != nil { 559 errChan <- err 560 return 561 } 562 incChan <- msg 563 } 564 } else if clStr, isClientStr := stream.(proto.Gossip_GossipStreamClient); isClientStr { 565 if m, err := clStr.Recv(); err == nil { 566 msg, err := m.ToGossipMessage() 567 if err != nil { 568 errChan <- err 569 return 570 } 571 incChan <- msg 572 } 573 } else { 574 panic(fmt.Errorf("Stream isn't a GossipStreamServer or a GossipStreamClient, but %v. Aborting", reflect.TypeOf(stream))) 575 } 576 }() 577 select { 578 case <-time.NewTicker(timeout).C: 579 return nil, fmt.Errorf("Timed out waiting for connection message from %s", address) 580 case m := <-incChan: 581 return m, nil 582 case err := <-errChan: 583 return nil, err 584 } 585 } 586 587 func (c *commImpl) createConnectionMsg(pkiID common.PKIidType, certHash []byte, cert api.PeerIdentityType, signer proto.Signer) (*proto.SignedGossipMessage, error) { 588 m := &proto.GossipMessage{ 589 Tag: proto.GossipMessage_EMPTY, 590 Nonce: 0, 591 Content: &proto.GossipMessage_Conn{ 592 Conn: &proto.ConnEstablish{ 593 TlsCertHash: certHash, 594 Identity: cert, 595 PkiId: pkiID, 596 }, 597 }, 598 } 599 sMsg := &proto.SignedGossipMessage{ 600 GossipMessage: m, 601 } 602 _, err := sMsg.Sign(signer) 603 return sMsg, err 604 } 605 606 type stream interface { 607 Send(envelope *proto.Envelope) error 608 Recv() (*proto.Envelope, error) 609 grpc.Stream 610 } 611 612 func createGRPCLayer(port int) (*grpc.Server, net.Listener, api.PeerSecureDialOpts, []byte) { 613 var returnedCertHash []byte 614 var s *grpc.Server 615 var ll net.Listener 616 var err error 617 var serverOpts []grpc.ServerOption 618 var dialOpts []grpc.DialOption 619 620 cert := GenerateCertificatesOrPanic() 621 returnedCertHash = certHashFromRawCert(cert.Certificate[0]) 622 623 tlsConf := &tls.Config{ 624 Certificates: []tls.Certificate{cert}, 625 ClientAuth: tls.RequestClientCert, 626 InsecureSkipVerify: true, 627 } 628 serverOpts = append(serverOpts, grpc.Creds(credentials.NewTLS(tlsConf))) 629 ta := credentials.NewTLS(&tls.Config{ 630 Certificates: []tls.Certificate{cert}, 631 InsecureSkipVerify: true, 632 }) 633 dialOpts = append(dialOpts, grpc.WithTransportCredentials(ta)) 634 635 listenAddress := fmt.Sprintf("%s:%d", "", port) 636 ll, err = net.Listen("tcp", listenAddress) 637 if err != nil { 638 panic(err) 639 } 640 secureDialOpts := func() []grpc.DialOption { 641 return dialOpts 642 } 643 s = grpc.NewServer(serverOpts...) 644 return s, ll, secureDialOpts, returnedCertHash 645 }