func (ids *IDService) IdentifyConn(c inet.Conn) { ids.currmu.Lock() if wait, found := ids.currid[c]; found { ids.currmu.Unlock() log.Debugf("IdentifyConn called twice on: %s", c) <-wait // already identifying it. wait for it. return } ch := make(chan struct{}) ids.currid[c] = ch ids.currmu.Unlock() defer close(ch) s, err := c.NewStream() if err != nil { log.Debugf("error opening initial stream for %s: %s", ID, err) log.Event(context.TODO(), "IdentifyOpenFailed", c.RemotePeer()) c.Close() return } bwc := ids.Host.GetBandwidthReporter() s = mstream.WrapStream(s, ID, bwc) // ok give the response to our handler. if err := msmux.SelectProtoOrFail(ID, s); err != nil { log.Debugf("error writing stream header for %s", ID) log.Event(context.TODO(), "IdentifyOpenFailed", c.RemotePeer()) s.Close() return } ids.ResponseHandler(s) ids.currmu.Lock() _, found := ids.currid[c] delete(ids.currid, c) ids.currmu.Unlock() if !found { log.Debugf("IdentifyConn failed to find channel (programmer error) for %s", c) return } }
// Dial connects to a peer over a particular address // Ensures raddr is part of peer.Addresses() // Example: d.DialAddr(ctx, peer.Addresses()[0], peer) func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) { logdial := lgbl.Dial("conn", d.LocalPeer, remote, nil, raddr) logdial["encrypted"] = (d.PrivateKey != nil) // log wether this will be an encrypted dial or not. defer log.EventBegin(ctx, "connDial", logdial).Done() var connOut Conn var errOut error done := make(chan struct{}) // do it async to ensure we respect don contexteone go func() { defer func() { select { case done <- struct{}{}: case <-ctx.Done(): } }() maconn, err := d.rawConnDial(ctx, raddr, remote) if err != nil { errOut = err return } if d.Wrapper != nil { maconn = d.Wrapper(maconn) } cryptoProtoChoice := SecioTag if !EncryptConnections { cryptoProtoChoice = NoEncryptionTag } maconn.SetReadDeadline(time.Now().Add(NegotiateReadTimeout)) err = msmux.SelectProtoOrFail(cryptoProtoChoice, maconn) if err != nil { errOut = err return } maconn.SetReadDeadline(time.Time{}) c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn) if err != nil { maconn.Close() errOut = err return } if d.PrivateKey == nil || EncryptConnections == false { log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr) connOut = c return } c2, err := newSecureConn(ctx, d.PrivateKey, c) if err != nil { errOut = err c.Close() return } connOut = c2 }() select { case <-ctx.Done(): logdial["error"] = ctx.Err() logdial["dial"] = "failure" return nil, ctx.Err() case <-done: // whew, finished. } if errOut != nil { logdial["error"] = errOut logdial["dial"] = "failure" return nil, errOut } logdial["dial"] = "success" return connOut, nil }