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

     1  package swarm
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	conn "github.com/jbenet/go-ipfs/net/conn"
     8  	msg "github.com/jbenet/go-ipfs/net/message"
     9  
    10  	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
    11  	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
    12  )
    13  
    14  // Open listeners for each network the swarm should listen on
    15  func (s *Swarm) listen(addrs []ma.Multiaddr) error {
    16  	hasErr := false
    17  	retErr := &ListenErr{
    18  		Errors: make([]error, len(addrs)),
    19  	}
    20  
    21  	// listen on every address
    22  	for i, addr := range addrs {
    23  		err := s.connListen(addr)
    24  		if err != nil {
    25  			hasErr = true
    26  			retErr.Errors[i] = err
    27  			log.Errorf("Failed to listen on: %s - %s", addr, err)
    28  		}
    29  	}
    30  
    31  	if hasErr {
    32  		return retErr
    33  	}
    34  	return nil
    35  }
    36  
    37  // Listen for new connections on the given multiaddr
    38  func (s *Swarm) connListen(maddr ma.Multiaddr) error {
    39  
    40  	resolved, err := resolveUnspecifiedAddresses([]ma.Multiaddr{maddr})
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	list, err := conn.Listen(s.Context(), maddr, s.local, s.peers)
    46  	if err != nil {
    47  		return err
    48  	}
    49  
    50  	// add resolved local addresses to peer
    51  	for _, addr := range resolved {
    52  		s.local.AddAddress(addr)
    53  	}
    54  
    55  	// make sure port can be reused. TOOD this doesn't work...
    56  	// if err := setSocketReuse(list); err != nil {
    57  	// 	return err
    58  	// }
    59  
    60  	// NOTE: this may require a lock around it later. currently, only run on setup
    61  	s.listeners = append(s.listeners, list)
    62  
    63  	// Accept and handle new connections on this listener until it errors
    64  	// this listener is a child.
    65  	s.Children().Add(1)
    66  	go func() {
    67  		defer s.Children().Done()
    68  
    69  		for {
    70  			select {
    71  			case <-s.Closing():
    72  				return
    73  
    74  			case conn := <-list.Accept():
    75  				// handler also a child.
    76  				s.Children().Add(1)
    77  				go s.handleIncomingConn(conn)
    78  			}
    79  		}
    80  	}()
    81  
    82  	return nil
    83  }
    84  
    85  // Handle getting ID from this peer, handshake, and adding it into the map
    86  func (s *Swarm) handleIncomingConn(nconn conn.Conn) {
    87  	// this handler is a child. added by caller.
    88  	defer s.Children().Done()
    89  
    90  	// Setup the new connection
    91  	_, err := s.connSetup(nconn)
    92  	if err != nil && err != ErrAlreadyOpen {
    93  		s.errChan <- err
    94  		nconn.Close()
    95  	}
    96  }
    97  
    98  // connSetup adds the passed in connection to its peerMap and starts
    99  // the fanInSingle routine for that connection
   100  func (s *Swarm) connSetup(c conn.Conn) (conn.Conn, error) {
   101  	if c == nil {
   102  		return nil, errors.New("Tried to start nil connection.")
   103  	}
   104  
   105  	log.Debugf("%s Started connection: %s", c.LocalPeer(), c.RemotePeer())
   106  
   107  	// add address of connection to Peer. Maybe it should happen in connSecure.
   108  	// NOT adding this address here, because the incoming address in TCP
   109  	// is an EPHEMERAL address, and not the address we want to keep around.
   110  	// addresses should be figured out through the DHT.
   111  	// c.Remote.AddAddress(c.Conn.RemoteMultiaddr())
   112  
   113  	// handshake3
   114  	ctxT, _ := context.WithTimeout(c.Context(), conn.HandshakeTimeout)
   115  	h3result, err := conn.Handshake3(ctxT, c)
   116  	if err != nil {
   117  		c.Close()
   118  		return nil, fmt.Errorf("Handshake3 failed: %s", err)
   119  	}
   120  
   121  	// check for nats. you know, just in case.
   122  	if h3result.LocalObservedAddress != nil {
   123  		s.checkNATWarning(h3result.LocalObservedAddress)
   124  	} else {
   125  		log.Warningf("Received nil observed address from %s", c.RemotePeer())
   126  	}
   127  
   128  	// add to conns
   129  	s.connsLock.Lock()
   130  
   131  	mc, found := s.conns[c.RemotePeer().Key()]
   132  	if !found {
   133  		// multiconn doesn't exist, make a new one.
   134  		conns := []conn.Conn{c}
   135  		mc, err := conn.NewMultiConn(s.Context(), s.local, c.RemotePeer(), conns)
   136  		if err != nil {
   137  			log.Errorf("error creating multiconn: %s", err)
   138  			c.Close()
   139  			return nil, err
   140  		}
   141  
   142  		s.conns[c.RemotePeer().Key()] = mc
   143  		s.connsLock.Unlock()
   144  
   145  		// kick off reader goroutine
   146  		s.Children().Add(1)
   147  		mc.Children().Add(1) // child of Conn as well.
   148  		go s.fanInSingle(mc)
   149  		log.Debugf("added new multiconn: %s", mc)
   150  	} else {
   151  		s.connsLock.Unlock() // unlock before adding new conn
   152  
   153  		mc.Add(c)
   154  		log.Debugf("multiconn found: %s", mc)
   155  	}
   156  
   157  	log.Debugf("multiconn added new conn %s", c)
   158  	return c, nil
   159  }
   160  
   161  // Handles the unwrapping + sending of messages to the right connection.
   162  func (s *Swarm) fanOut() {
   163  	defer s.Children().Done()
   164  
   165  	i := 0
   166  	for {
   167  		select {
   168  		case <-s.Closing():
   169  			return // told to close.
   170  
   171  		case msg, ok := <-s.Outgoing:
   172  			if !ok {
   173  				log.Infof("%s outgoing channel closed", s)
   174  				return
   175  			}
   176  			if len(msg.Data()) >= conn.MaxMessageSize {
   177  				log.Critical("Attempted to send message bigger than max size.")
   178  			}
   179  
   180  			s.connsLock.RLock()
   181  			c, found := s.conns[msg.Peer().Key()]
   182  			s.connsLock.RUnlock()
   183  
   184  			if !found {
   185  				e := fmt.Errorf("Sent msg to peer without open conn: %v", msg.Peer())
   186  				s.errChan <- e
   187  				log.Error(e)
   188  				continue
   189  			}
   190  
   191  			i++
   192  			log.Debugf("%s sent message to %s (%d)", s.local, msg.Peer(), i)
   193  			// queue it in the connection's buffer
   194  			c.Out() <- msg.Data()
   195  		}
   196  	}
   197  }
   198  
   199  // Handles the receiving + wrapping of messages, per conn.
   200  // Consider using reflect.Select with one goroutine instead of n.
   201  func (s *Swarm) fanInSingle(c conn.Conn) {
   202  	// cleanup all data associated with this child Connection.
   203  	defer func() {
   204  		// remove it from the map.
   205  		s.connsLock.Lock()
   206  		delete(s.conns, c.RemotePeer().Key())
   207  		s.connsLock.Unlock()
   208  
   209  		s.Children().Done()
   210  		c.Children().Done() // child of Conn as well.
   211  	}()
   212  
   213  	i := 0
   214  	for {
   215  		select {
   216  		case <-s.Closing(): // Swarm closing
   217  			return
   218  
   219  		case <-c.Closing(): // Conn closing
   220  			return
   221  
   222  		case data, ok := <-c.In():
   223  			if !ok {
   224  				log.Infof("%s in channel closed", c)
   225  				return // channel closed.
   226  			}
   227  			i++
   228  			log.Debugf("%s received message from %s (%d)", s.local, c.RemotePeer(), i)
   229  			s.Incoming <- msg.New(c.RemotePeer(), data)
   230  		}
   231  	}
   232  }
   233  
   234  // Commenting out because it's platform specific
   235  // func setSocketReuse(l manet.Listener) error {
   236  // 	nl := l.NetListener()
   237  //
   238  // 	// for now only TCP. TODO change this when more networks.
   239  // 	file, err := nl.(*net.TCPListener).File()
   240  // 	if err != nil {
   241  // 		return err
   242  // 	}
   243  //
   244  // 	fd := file.Fd()
   245  // 	err = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
   246  // 	if err != nil {
   247  // 		return err
   248  // 	}
   249  //
   250  // 	err = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
   251  // 	if err != nil {
   252  // 		return err
   253  // 	}
   254  //
   255  // 	return nil
   256  // }