@@ -3,23 +3,33 @@ package conn
3
3
import (
4
4
"fmt"
5
5
"math/rand"
6
- "net"
7
6
"strings"
8
- "syscall "
7
+ "time "
9
8
10
9
ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
11
10
manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
12
- reuseport "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"
13
11
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14
12
lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
15
13
14
+ ci "github.com/ipfs/go-ipfs/p2p/crypto"
16
15
addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
16
+ transport "github.com/ipfs/go-ipfs/p2p/net/transport"
17
17
peer "github.com/ipfs/go-ipfs/p2p/peer"
18
18
)
19
19
20
+ type WrapFunc func (transport.Conn ) transport.Conn
21
+
22
+ func NewDialer (p peer.ID , pk ci.PrivKey , tout time.Duration , wrap WrapFunc ) * Dialer {
23
+ return & Dialer {
24
+ LocalPeer : p ,
25
+ PrivateKey : pk ,
26
+ Wrapper : wrap ,
27
+ }
28
+ }
29
+
20
30
// String returns the string rep of d.
21
31
func (d * Dialer ) String () string {
22
- return fmt .Sprintf ("<Dialer %s %s ...>" , d .LocalPeer , d . LocalAddrs [ 0 ] )
32
+ return fmt .Sprintf ("<Dialer %s ...>" , d .LocalPeer )
23
33
}
24
34
25
35
// Dial connects to a peer over a particular address
@@ -95,112 +105,34 @@ func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (
95
105
return connOut , nil
96
106
}
97
107
98
- // rawConnDial dials the underlying net.Conn + manet.Conns
99
- func (d * Dialer ) rawConnDial (ctx context.Context , raddr ma.Multiaddr , remote peer.ID ) (manet.Conn , error ) {
100
-
101
- // before doing anything, check we're going to be able to dial.
102
- // we may not support the given address.
103
- if _ , _ , err := manet .DialArgs (raddr ); err != nil {
104
- return nil , err
105
- }
106
-
107
- if strings .HasPrefix (raddr .String (), "/ip4/0.0.0.0" ) {
108
- log .Event (ctx , "connDialZeroAddr" , lgbl .Dial ("conn" , d .LocalPeer , remote , nil , raddr ))
109
- return nil , fmt .Errorf ("Attempted to connect to zero address: %s" , raddr )
110
- }
111
-
112
- // get local addr to use.
113
- laddr := pickLocalAddr (d .LocalAddrs , raddr )
114
- logdial := lgbl .Dial ("conn" , d .LocalPeer , remote , laddr , raddr )
115
- defer log .EventBegin (ctx , "connDialRawConn" , logdial ).Done ()
116
-
117
- // make a copy of the manet.Dialer, we may need to change its timeout.
118
- madialer := d .Dialer
119
-
120
- if laddr != nil && reuseportIsAvailable () {
121
- // we're perhaps going to dial twice. half the timeout, so we can afford to.
122
- // otherwise our context would expire right after the first dial.
123
- madialer .Dialer .Timeout = (madialer .Dialer .Timeout / 2 )
124
-
125
- // dial using reuseport.Dialer, because we're probably reusing addrs.
126
- // this is optimistic, as the reuseDial may fail to bind the port.
127
- rpev := log .EventBegin (ctx , "connDialReusePort" , logdial )
128
- if nconn , retry , reuseErr := reuseDial (madialer .Dialer , laddr , raddr ); reuseErr == nil {
129
- // if it worked, wrap the raw net.Conn with our manet.Conn
130
- logdial ["reuseport" ] = "success"
131
- rpev .Done ()
132
- return manet .WrapNetConn (nconn )
133
- } else if ! retry {
134
- // reuseDial is sure this is a legitimate dial failure, not a reuseport failure.
135
- logdial ["reuseport" ] = "failure"
136
- logdial ["error" ] = reuseErr
137
- rpev .Done ()
138
- return nil , reuseErr
139
- } else {
140
- // this is a failure to reuse port. log it.
141
- logdial ["reuseport" ] = "retry"
142
- logdial ["error" ] = reuseErr
143
- rpev .Done ()
144
- }
145
- }
146
-
147
- defer log .EventBegin (ctx , "connDialManet" , logdial ).Done ()
148
- return madialer .Dial (raddr )
108
+ func (d * Dialer ) AddDialer (pd transport.Dialer ) {
109
+ d .Dialers = append (d .Dialers , pd )
149
110
}
150
111
151
- func reuseDial (dialer net.Dialer , laddr , raddr ma.Multiaddr ) (conn net.Conn , retry bool , err error ) {
152
- if laddr == nil {
153
- // if we're given no local address no sense in using reuseport to dial, dial out as usual.
154
- return nil , true , reuseport .ErrReuseFailed
155
- }
156
-
157
- // give reuse.Dialer the manet.Dialer's Dialer.
158
- // (wow, Dialer should've so been an interface...)
159
- rd := reuseport.Dialer {dialer }
160
-
161
- // get the local net.Addr manually
162
- rd .D .LocalAddr , err = manet .ToNetAddr (laddr )
163
- if err != nil {
164
- return nil , true , err // something wrong with laddr. retry without.
165
- }
166
-
167
- // get the raddr dial args for rd.dial
168
- network , netraddr , err := manet .DialArgs (raddr )
169
- if err != nil {
170
- return nil , true , err // something wrong with laddr. retry without.
112
+ // returns dialer that can dial the given address
113
+ func (d * Dialer ) subDialerForAddr (raddr ma.Multiaddr ) transport.Dialer {
114
+ for _ , pd := range d .Dialers {
115
+ if pd .Matches (raddr ) {
116
+ return pd
117
+ }
171
118
}
172
119
173
- // rd.Dial gets us a net.Conn with SO_REUSEPORT and SO_REUSEADDR set.
174
- conn , err = rd .Dial (network , netraddr )
175
- return conn , reuseErrShouldRetry (err ), err // hey! it worked!
120
+ return nil
176
121
}
177
122
178
- // reuseErrShouldRetry diagnoses whether to retry after a reuse error.
179
- // if we failed to bind, we should retry. if bind worked and this is a
180
- // real dial error (remote end didnt answer) then we should not retry.
181
- func reuseErrShouldRetry (err error ) bool {
182
- if err == nil {
183
- return false // hey, it worked! no need to retry.
184
- }
185
-
186
- // if it's a network timeout error, it's a legitimate failure.
187
- if nerr , ok := err .(net.Error ); ok && nerr .Timeout () {
188
- return false
123
+ // rawConnDial dials the underlying net.Conn + manet.Conns
124
+ func (d * Dialer ) rawConnDial (ctx context.Context , raddr ma.Multiaddr , remote peer.ID ) (transport.Conn , error ) {
125
+ if strings .HasPrefix (raddr .String (), "/ip4/0.0.0.0" ) {
126
+ log .Event (ctx , "connDialZeroAddr" , lgbl .Dial ("conn" , d .LocalPeer , remote , nil , raddr ))
127
+ return nil , fmt .Errorf ("Attempted to connect to zero address: %s" , raddr )
189
128
}
190
129
191
- errno , ok := err .(syscall. Errno )
192
- if ! ok { // not an errno? who knows what this is. retry.
193
- return true
130
+ sd := d . subDialerForAddr ( raddr )
131
+ if sd == nil {
132
+ return nil , fmt . Errorf ( "no dialer for %s" , raddr )
194
133
}
195
134
196
- switch errno {
197
- case syscall .EADDRINUSE , syscall .EADDRNOTAVAIL :
198
- return true // failure to bind. retry.
199
- case syscall .ECONNREFUSED :
200
- return false // real dial error
201
- default :
202
- return true // optimistically default to retry.
203
- }
135
+ return sd .Dial (raddr )
204
136
}
205
137
206
138
func pickLocalAddr (laddrs []ma.Multiaddr , raddr ma.Multiaddr ) (laddr ma.Multiaddr ) {
0 commit comments