github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/net/conn/listen.go (about)

     1  package conn
     2  
     3  import (
     4  	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
     5  	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
     6  	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
     7  
     8  	peer "github.com/jbenet/go-ipfs/peer"
     9  	ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
    10  )
    11  
    12  // listener is an object that can accept connections. It implements Listener
    13  type listener struct {
    14  	manet.Listener
    15  
    16  	// chansize is the size of the internal channels for concurrency
    17  	chansize int
    18  
    19  	// channel of incoming conections
    20  	conns chan Conn
    21  
    22  	// Local multiaddr to listen on
    23  	maddr ma.Multiaddr
    24  
    25  	// LocalPeer is the identity of the local Peer.
    26  	local peer.Peer
    27  
    28  	// Peerstore is the set of peers we know about locally
    29  	peers peer.Peerstore
    30  
    31  	// Context for children Conn
    32  	ctx context.Context
    33  
    34  	// embedded ContextCloser
    35  	ctxc.ContextCloser
    36  }
    37  
    38  // disambiguate
    39  func (l *listener) Close() error {
    40  	return l.ContextCloser.Close()
    41  }
    42  
    43  // close called by ContextCloser.Close
    44  func (l *listener) close() error {
    45  	log.Info("listener closing: %s %s", l.local, l.maddr)
    46  	return l.Listener.Close()
    47  }
    48  
    49  func (l *listener) listen() {
    50  	defer l.Children().Done()
    51  
    52  	// handle at most chansize concurrent handshakes
    53  	sem := make(chan struct{}, l.chansize)
    54  
    55  	// handle is a goroutine work function that handles the handshake.
    56  	// it's here only so that accepting new connections can happen quickly.
    57  	handle := func(maconn manet.Conn) {
    58  		defer func() { <-sem }() // release
    59  
    60  		c, err := newSingleConn(l.ctx, l.local, nil, maconn)
    61  		if err != nil {
    62  			log.Errorf("Error accepting connection: %v", err)
    63  			return
    64  		}
    65  
    66  		sc, err := newSecureConn(l.ctx, c, l.peers)
    67  		if err != nil {
    68  			log.Errorf("Error securing connection: %v", err)
    69  			return
    70  		}
    71  
    72  		l.conns <- sc
    73  	}
    74  
    75  	for {
    76  		maconn, err := l.Listener.Accept()
    77  		if err != nil {
    78  
    79  			// if closing, we should exit.
    80  			select {
    81  			case <-l.Closing():
    82  				return // done.
    83  			default:
    84  			}
    85  
    86  			log.Errorf("Failed to accept connection: %v", err)
    87  			continue
    88  		}
    89  
    90  		sem <- struct{}{} // acquire
    91  		go handle(maconn)
    92  	}
    93  }
    94  
    95  // Accept waits for and returns the next connection to the listener.
    96  // Note that unfortunately this
    97  func (l *listener) Accept() <-chan Conn {
    98  	return l.conns
    99  }
   100  
   101  // Multiaddr is the identity of the local Peer.
   102  func (l *listener) Multiaddr() ma.Multiaddr {
   103  	return l.maddr
   104  }
   105  
   106  // LocalPeer is the identity of the local Peer.
   107  func (l *listener) LocalPeer() peer.Peer {
   108  	return l.local
   109  }
   110  
   111  // Peerstore is the set of peers we know about locally. The Listener needs it
   112  // because when an incoming connection is identified, we should reuse the
   113  // same peer objects (otherwise things get inconsistent).
   114  func (l *listener) Peerstore() peer.Peerstore {
   115  	return l.peers
   116  }
   117  
   118  // Listen listens on the particular multiaddr, with given peer and peerstore.
   119  func Listen(ctx context.Context, addr ma.Multiaddr, local peer.Peer, peers peer.Peerstore) (Listener, error) {
   120  
   121  	ml, err := manet.Listen(addr)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	// todo make this a variable
   127  	chansize := 10
   128  
   129  	l := &listener{
   130  		Listener: ml,
   131  		maddr:    addr,
   132  		peers:    peers,
   133  		local:    local,
   134  		conns:    make(chan Conn, chansize),
   135  		chansize: chansize,
   136  		ctx:      ctx,
   137  	}
   138  
   139  	// need a separate context to use for the context closer.
   140  	// This is because the parent context will be given to all connections too,
   141  	// and if we close the listener, the connections shouldn't share the fate.
   142  	ctx2, _ := context.WithCancel(ctx)
   143  	l.ContextCloser = ctxc.NewContextCloser(ctx2, l.close)
   144  
   145  	l.Children().Add(1)
   146  	go l.listen()
   147  
   148  	return l, nil
   149  }