github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/gossip/comm/conn.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 "errors" 21 "sync" 22 "sync/atomic" 23 24 "github.com/hyperledger/fabric/gossip/common" 25 "github.com/hyperledger/fabric/gossip/util" 26 proto "github.com/hyperledger/fabric/protos/gossip" 27 "github.com/op/go-logging" 28 "golang.org/x/net/context" 29 "google.golang.org/grpc" 30 ) 31 32 type handler func(message *proto.SignedGossipMessage) 33 34 type connFactory interface { 35 createConnection(endpoint string, pkiID common.PKIidType) (*connection, error) 36 } 37 38 type connectionStore struct { 39 logger *logging.Logger // logger 40 isClosing bool // whether this connection store is shutting down 41 connFactory connFactory // creates a connection to remote peer 42 sync.RWMutex // synchronize access to shared variables 43 pki2Conn map[string]*connection // mapping between pkiID to connections 44 destinationLocks map[string]*sync.RWMutex //mapping between pkiIDs and locks, 45 // used to prevent concurrent connection establishment to the same remote endpoint 46 } 47 48 func newConnStore(connFactory connFactory, logger *logging.Logger) *connectionStore { 49 return &connectionStore{ 50 connFactory: connFactory, 51 isClosing: false, 52 pki2Conn: make(map[string]*connection), 53 destinationLocks: make(map[string]*sync.RWMutex), 54 logger: logger, 55 } 56 } 57 58 func (cs *connectionStore) getConnection(peer *RemotePeer) (*connection, error) { 59 cs.RLock() 60 isClosing := cs.isClosing 61 cs.RUnlock() 62 63 if isClosing { 64 return nil, errors.New("Shutting down") 65 } 66 67 pkiID := peer.PKIID 68 endpoint := peer.Endpoint 69 70 cs.Lock() 71 destinationLock, hasConnected := cs.destinationLocks[string(pkiID)] 72 if !hasConnected { 73 destinationLock = &sync.RWMutex{} 74 cs.destinationLocks[string(pkiID)] = destinationLock 75 } 76 cs.Unlock() 77 78 destinationLock.Lock() 79 80 cs.RLock() 81 conn, exists := cs.pki2Conn[string(pkiID)] 82 if exists { 83 cs.RUnlock() 84 destinationLock.Unlock() 85 return conn, nil 86 } 87 cs.RUnlock() 88 89 createdConnection, err := cs.connFactory.createConnection(endpoint, pkiID) 90 91 destinationLock.Unlock() 92 93 cs.RLock() 94 isClosing = cs.isClosing 95 cs.RUnlock() 96 if isClosing { 97 return nil, errors.New("ConnStore is closing") 98 } 99 100 cs.Lock() 101 delete(cs.destinationLocks, string(pkiID)) 102 defer cs.Unlock() 103 104 // check again, maybe someone connected to us during the connection creation? 105 conn, exists = cs.pki2Conn[string(pkiID)] 106 107 if exists { 108 if createdConnection != nil { 109 createdConnection.close() 110 } 111 return conn, nil 112 } 113 114 // no one connected to us AND we failed connecting! 115 if err != nil { 116 return nil, err 117 } 118 119 // at this point in the code, we created a connection to a remote peer 120 conn = createdConnection 121 cs.pki2Conn[string(createdConnection.pkiID)] = conn 122 123 go conn.serviceConnection() 124 125 return conn, nil 126 } 127 128 func (cs *connectionStore) connNum() int { 129 cs.RLock() 130 defer cs.RUnlock() 131 return len(cs.pki2Conn) 132 } 133 134 func (cs *connectionStore) closeConn(peer *RemotePeer) { 135 cs.Lock() 136 defer cs.Unlock() 137 138 if conn, exists := cs.pki2Conn[string(peer.PKIID)]; exists { 139 conn.close() 140 delete(cs.pki2Conn, string(conn.pkiID)) 141 } 142 } 143 144 func (cs *connectionStore) shutdown() { 145 cs.Lock() 146 cs.isClosing = true 147 pkiIds2conn := cs.pki2Conn 148 149 var connections2Close []*connection 150 for _, conn := range pkiIds2conn { 151 connections2Close = append(connections2Close, conn) 152 } 153 cs.Unlock() 154 155 wg := sync.WaitGroup{} 156 for _, conn := range connections2Close { 157 wg.Add(1) 158 go func(conn *connection) { 159 cs.closeByPKIid(conn.pkiID) 160 wg.Done() 161 }(conn) 162 } 163 wg.Wait() 164 } 165 166 func (cs *connectionStore) onConnected(serverStream proto.Gossip_GossipStreamServer, connInfo *proto.ConnectionInfo) *connection { 167 cs.Lock() 168 defer cs.Unlock() 169 170 if c, exists := cs.pki2Conn[string(connInfo.Identity)]; exists { 171 c.close() 172 } 173 174 return cs.registerConn(connInfo, serverStream) 175 } 176 177 func (cs *connectionStore) registerConn(connInfo *proto.ConnectionInfo, serverStream proto.Gossip_GossipStreamServer) *connection { 178 conn := newConnection(nil, nil, nil, serverStream) 179 conn.pkiID = connInfo.ID 180 conn.info = connInfo 181 conn.logger = cs.logger 182 cs.pki2Conn[string(connInfo.ID)] = conn 183 return conn 184 } 185 186 func (cs *connectionStore) closeByPKIid(pkiID common.PKIidType) { 187 cs.Lock() 188 defer cs.Unlock() 189 if conn, exists := cs.pki2Conn[string(pkiID)]; exists { 190 conn.close() 191 delete(cs.pki2Conn, string(pkiID)) 192 } 193 } 194 195 func newConnection(cl proto.GossipClient, c *grpc.ClientConn, cs proto.Gossip_GossipStreamClient, ss proto.Gossip_GossipStreamServer) *connection { 196 connection := &connection{ 197 outBuff: make(chan *msgSending, util.GetIntOrDefault("peer.gossip.sendBuffSize", defSendBuffSize)), 198 cl: cl, 199 conn: c, 200 clientStream: cs, 201 serverStream: ss, 202 stopFlag: int32(0), 203 stopChan: make(chan struct{}, 1), 204 } 205 206 return connection 207 } 208 209 type connection struct { 210 cancel context.CancelFunc 211 info *proto.ConnectionInfo 212 outBuff chan *msgSending 213 logger *logging.Logger // logger 214 pkiID common.PKIidType // pkiID of the remote endpoint 215 handler handler // function to invoke upon a message reception 216 conn *grpc.ClientConn // gRPC connection to remote endpoint 217 cl proto.GossipClient // gRPC stub of remote endpoint 218 clientStream proto.Gossip_GossipStreamClient // client-side stream to remote endpoint 219 serverStream proto.Gossip_GossipStreamServer // server-side stream to remote endpoint 220 stopFlag int32 // indicates whether this connection is in process of stopping 221 stopChan chan struct{} // a method to stop the server-side gRPC call from a different go-routine 222 sync.RWMutex // synchronizes access to shared variables 223 } 224 225 func (conn *connection) close() { 226 if conn.toDie() { 227 return 228 } 229 230 amIFirst := atomic.CompareAndSwapInt32(&conn.stopFlag, int32(0), int32(1)) 231 if !amIFirst { 232 return 233 } 234 235 conn.stopChan <- struct{}{} 236 237 conn.Lock() 238 239 if conn.clientStream != nil { 240 conn.clientStream.CloseSend() 241 } 242 if conn.conn != nil { 243 conn.conn.Close() 244 } 245 246 if conn.cancel != nil { 247 conn.cancel() 248 } 249 250 conn.Unlock() 251 252 } 253 254 func (conn *connection) toDie() bool { 255 return atomic.LoadInt32(&(conn.stopFlag)) == int32(1) 256 } 257 258 func (conn *connection) send(msg *proto.SignedGossipMessage, onErr func(error)) { 259 conn.Lock() 260 defer conn.Unlock() 261 262 if len(conn.outBuff) == util.GetIntOrDefault("peer.gossip.sendBuffSize", defSendBuffSize) { 263 go onErr(errSendOverflow) 264 return 265 } 266 267 m := &msgSending{ 268 envelope: msg.Envelope, 269 onErr: onErr, 270 } 271 272 conn.outBuff <- m 273 } 274 275 func (conn *connection) serviceConnection() error { 276 errChan := make(chan error, 1) 277 msgChan := make(chan *proto.SignedGossipMessage, util.GetIntOrDefault("peer.gossip.recvBuffSize", defRecvBuffSize)) 278 defer close(msgChan) 279 280 // Call stream.Recv() asynchronously in readFromStream(), 281 // and wait for either the Recv() call to end, 282 // or a signal to close the connection, which exits 283 // the method and makes the Recv() call to fail in the 284 // readFromStream() method 285 go conn.readFromStream(errChan, msgChan) 286 287 go conn.writeToStream() 288 289 for !conn.toDie() { 290 select { 291 case stop := <-conn.stopChan: 292 conn.logger.Debug("Closing reading from stream") 293 conn.stopChan <- stop 294 return nil 295 case err := <-errChan: 296 return err 297 case msg := <-msgChan: 298 conn.handler(msg) 299 } 300 } 301 return nil 302 } 303 304 func (conn *connection) writeToStream() { 305 for !conn.toDie() { 306 stream := conn.getStream() 307 if stream == nil { 308 conn.logger.Error(conn.pkiID, "Stream is nil, aborting!") 309 return 310 } 311 select { 312 case m := <-conn.outBuff: 313 err := stream.Send(m.envelope) 314 if err != nil { 315 go m.onErr(err) 316 return 317 } 318 case stop := <-conn.stopChan: 319 conn.logger.Debug("Closing writing to stream") 320 conn.stopChan <- stop 321 return 322 } 323 } 324 } 325 326 func (conn *connection) readFromStream(errChan chan error, msgChan chan *proto.SignedGossipMessage) { 327 defer func() { 328 recover() 329 }() // msgChan might be closed 330 for !conn.toDie() { 331 stream := conn.getStream() 332 if stream == nil { 333 conn.logger.Error(conn.pkiID, "Stream is nil, aborting!") 334 errChan <- errors.New("Stream is nil") 335 return 336 } 337 envelope, err := stream.Recv() 338 if conn.toDie() { 339 conn.logger.Debug(conn.pkiID, "canceling read because closing") 340 return 341 } 342 if err != nil { 343 errChan <- err 344 conn.logger.Debug(conn.pkiID, "Got error, aborting:", err) 345 return 346 } 347 msg, err := envelope.ToGossipMessage() 348 if err != nil { 349 errChan <- err 350 conn.logger.Warning(conn.pkiID, "Got error, aborting:", err) 351 } 352 msgChan <- msg 353 } 354 } 355 356 func (conn *connection) getStream() stream { 357 conn.Lock() 358 defer conn.Unlock() 359 360 if conn.clientStream != nil && conn.serverStream != nil { 361 e := "Both client and server stream are not nil, something went wrong" 362 conn.logger.Error(e) 363 } 364 365 if conn.clientStream != nil { 366 return conn.clientStream 367 } 368 369 if conn.serverStream != nil { 370 return conn.serverStream 371 } 372 373 return nil 374 } 375 376 type msgSending struct { 377 envelope *proto.Envelope 378 onErr func(error) 379 }