in channel.go [600:666]
func (ch *Channel) Connect(ctx context.Context, hostPort string) (*Connection, error) {
switch state := ch.State(); state {
case ChannelClient, ChannelListening:
break
default:
ch.log.Debugf("Connect rejecting new connection as state is %v", state)
return nil, errInvalidStateForOp
}
// The context timeout applies to the whole call, but users may want a lower
// connect timeout (e.g. for streams).
if params := getTChannelParams(ctx); params != nil && params.connectTimeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, params.connectTimeout)
defer cancel()
}
events := connectionEvents{
OnActive: ch.outboundConnectionActive,
OnCloseStateChange: ch.connectionCloseStateChange,
OnExchangeUpdated: ch.exchangeUpdated,
}
if err := ctx.Err(); err != nil {
return nil, GetContextError(err)
}
timeout := getTimeout(ctx)
tcpConn, err := ch.dialer(ctx, hostPort)
if err != nil {
if ne, ok := err.(net.Error); ok && ne.Timeout() {
ch.log.WithFields(
LogField{"remoteHostPort", hostPort},
LogField{"timeout", timeout},
).Info("Outbound net.Dial timed out.")
err = ErrTimeout
} else if ctx.Err() == context.Canceled {
ch.log.WithFields(
LogField{"remoteHostPort", hostPort},
).Info("Outbound net.Dial was cancelled.")
err = GetContextError(ErrRequestCancelled)
} else {
ch.log.WithFields(
ErrField(err),
LogField{"remoteHostPort", hostPort},
).Info("Outbound net.Dial failed.")
}
return nil, err
}
conn, err := ch.outboundHandshake(ctx, tcpConn, hostPort, events)
if conn != nil {
// It's possible that the connection we just created responds with a host:port
// that is not what we tried to connect to. E.g., we may have connected to
// 127.0.0.1:1234, but the returned host:port may be 10.0.0.1:1234.
// In this case, the connection won't be added to 127.0.0.1:1234 peer
// and so future calls to that peer may end up creating new connections. To
// avoid this issue, and to avoid clients being aware of any TCP relays, we
// add the connection to the intended peer.
if hostPort != conn.remotePeerInfo.HostPort {
conn.log.Debugf("Outbound connection host:port mismatch, adding to peer %v", conn.remotePeerInfo.HostPort)
ch.addConnectionToPeer(hostPort, conn, outbound)
}
}
return conn, err
}