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 // }