@@ -3,23 +3,32 @@ package conn
3
3
import (
4
4
"fmt"
5
5
"math/rand"
6
- "net"
7
6
"strings"
8
- "syscall"
9
7
10
8
ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
11
9
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
10
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14
11
lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
15
12
13
+ ci "github.com/ipfs/go-ipfs/p2p/crypto"
16
14
addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
15
+ transport "github.com/ipfs/go-ipfs/p2p/net/transport"
17
16
peer "github.com/ipfs/go-ipfs/p2p/peer"
18
17
)
19
18
19
+ type WrapFunc func (transport.Conn ) transport.Conn
20
+
21
+ func NewDialer (p peer.ID , pk ci.PrivKey , wrap WrapFunc ) * Dialer {
22
+ return & Dialer {
23
+ LocalPeer : p ,
24
+ PrivateKey : pk ,
25
+ Wrapper : wrap ,
26
+ }
27
+ }
28
+
20
29
// String returns the string rep of d.
21
30
func (d * Dialer ) String () string {
22
- return fmt .Sprintf ("<Dialer %s %s ...>" , d .LocalPeer , d . LocalAddrs [ 0 ] )
31
+ return fmt .Sprintf ("<Dialer %s ...>" , d .LocalPeer )
23
32
}
24
33
25
34
// Dial connects to a peer over a particular address
@@ -95,112 +104,34 @@ func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (
95
104
return connOut , nil
96
105
}
97
106
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 )
107
+ func (d * Dialer ) AddDialer (pd transport.Dialer ) {
108
+ d .Dialers = append (d .Dialers , pd )
149
109
}
150
110
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.
111
+ // returns dialer that can dial the given address
112
+ func (d * Dialer ) subDialerForAddr (raddr ma.Multiaddr ) transport.Dialer {
113
+ for _ , pd := range d .Dialers {
114
+ if pd .Matches (raddr ) {
115
+ return pd
116
+ }
171
117
}
172
118
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!
119
+ return nil
176
120
}
177
121
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
122
+ // rawConnDial dials the underlying net.Conn + manet.Conns
123
+ func (d * Dialer ) rawConnDial (ctx context.Context , raddr ma.Multiaddr , remote peer.ID ) (transport.Conn , error ) {
124
+ if strings .HasPrefix (raddr .String (), "/ip4/0.0.0.0" ) {
125
+ log .Event (ctx , "connDialZeroAddr" , lgbl .Dial ("conn" , d .LocalPeer , remote , nil , raddr ))
126
+ return nil , fmt .Errorf ("Attempted to connect to zero address: %s" , raddr )
189
127
}
190
128
191
- errno , ok := err .(syscall. Errno )
192
- if ! ok { // not an errno? who knows what this is. retry.
193
- return true
129
+ sd := d . subDialerForAddr ( raddr )
130
+ if sd == nil {
131
+ return nil , fmt . Errorf ( "no dialer for %s" , raddr )
194
132
}
195
133
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
- }
134
+ return sd .Dial (raddr )
204
135
}
205
136
206
137
func pickLocalAddr (laddrs []ma.Multiaddr , raddr ma.Multiaddr ) (laddr ma.Multiaddr ) {
0 commit comments