14
14
*/
15
15
final class HappyEyeBallsConnectionBuilder
16
16
{
17
- const CONNECT_INTERVAL = 0.1 ;
18
- const RESOLVE_WAIT = 0.5 ;
17
+ /**
18
+ * As long as we haven't connected yet keep popping an IP address of the connect queue until one of them
19
+ * succeeds or they all fail. We will wait 100ms between connection attempts as per RFC.
20
+ *
21
+ * @link https://tools.ietf.org/html/rfc8305#section-5
22
+ */
23
+ const CONNECTION_ATTEMPT_DELAY = 0.1 ;
24
+
25
+ /**
26
+ * Delay `A` lookup by 50ms sending out connection to IPv4 addresses when IPv6 records haven't
27
+ * resolved yet as per RFC.
28
+ *
29
+ * @link https://tools.ietf.org/html/rfc8305#section-3
30
+ */
31
+ const RESOLUTION_DELAY = 0.05 ;
19
32
20
33
public $ loop ;
21
34
public $ connector ;
@@ -29,7 +42,7 @@ final class HappyEyeBallsConnectionBuilder
29
42
public $ resolverPromises = array ();
30
43
public $ connectionPromises = array ();
31
44
public $ connectQueue = array ();
32
- public $ timer ;
45
+ public $ nextAttemptTimer ;
33
46
public $ parts ;
34
47
public $ ipsCount = 0 ;
35
48
public $ failureCount = 0 ;
@@ -58,40 +71,28 @@ public function connect()
58
71
59
72
$ that ->mixIpsIntoConnectQueue ($ ips );
60
73
61
- if ($ that ->timer instanceof TimerInterface) {
74
+ if ($ that ->nextAttemptTimer instanceof TimerInterface) {
62
75
return ;
63
76
}
64
77
65
78
$ that ->check ($ resolve , $ reject );
66
79
};
67
80
};
68
81
69
- $ ipv4Deferred = null ;
70
- $ that ->resolverPromises [Message::TYPE_AAAA ] = $ that ->resolve (Message::TYPE_AAAA , $ reject )->then ($ lookupResolve (Message::TYPE_AAAA ))->then (function () use (&$ ipv4Deferred ) {
71
- if ($ ipv4Deferred instanceof Promise \Deferred) {
72
- $ ipv4Deferred ->resolve ();
73
- }
74
- });
75
- $ that ->resolverPromises [Message::TYPE_A ] = $ that ->resolve (Message::TYPE_A , $ reject )->then (function ($ ips ) use ($ that , &$ ipv4Deferred , &$ timer ) {
82
+ $ that ->resolverPromises [Message::TYPE_AAAA ] = $ that ->resolve (Message::TYPE_AAAA , $ reject )->then ($ lookupResolve (Message::TYPE_AAAA ));
83
+ $ that ->resolverPromises [Message::TYPE_A ] = $ that ->resolve (Message::TYPE_A , $ reject )->then (function ($ ips ) use ($ that , &$ timer ) {
84
+ // happy path: IPv6 has resolved already, continue with IPv4 addresses
76
85
if ($ that ->resolved [Message::TYPE_AAAA ] === true ) {
77
- return Promise \resolve ( $ ips) ;
86
+ return $ ips ;
78
87
}
79
88
80
- /**
81
- * Delay A lookup by 50ms sending out connection to IPv4 addresses when IPv6 records haven't
82
- * resolved yet as per RFC.
83
- *
84
- * @link https://tools.ietf.org/html/rfc8305#section-3
85
- */
86
- $ ipv4Deferred = new Promise \Deferred ();
89
+ // Otherwise delay processing IPv4 lookup until short timer passes or IPv6 resolves in the meantime
87
90
$ deferred = new Promise \Deferred ();
88
-
89
- $ timer = $ that ->loop ->addTimer ($ that ::RESOLVE_WAIT , function () use ($ deferred , $ ips ) {
90
- $ ipv4Deferred = null ;
91
+ $ timer = $ that ->loop ->addTimer ($ that ::RESOLUTION_DELAY , function () use ($ deferred , $ ips ) {
91
92
$ deferred ->resolve ($ ips );
92
93
});
93
94
94
- $ ipv4Deferred -> promise () ->then (function () use ($ that , & $ timer , $ deferred , $ ips ) {
95
+ $ that -> resolverPromises [Message:: TYPE_AAAA ] ->then (function () use ($ that , $ timer , $ deferred , $ ips ) {
95
96
$ that ->loop ->cancelTimer ($ timer );
96
97
$ deferred ->resolve ($ ips );
97
98
});
@@ -136,9 +137,9 @@ public function resolve($type, $reject)
136
137
*/
137
138
public function check ($ resolve , $ reject )
138
139
{
139
- if (\count ($ this ->connectQueue ) === 0 && $ this ->resolved [Message::TYPE_A ] === true && $ this ->resolved [Message::TYPE_AAAA ] === true && $ this ->timer instanceof TimerInterface) {
140
- $ this ->loop ->cancelTimer ($ this ->timer );
141
- $ this ->timer = null ;
140
+ if (\count ($ this ->connectQueue ) === 0 && $ this ->resolved [Message::TYPE_A ] === true && $ this ->resolved [Message::TYPE_AAAA ] === true && $ this ->nextAttemptTimer instanceof TimerInterface) {
141
+ $ this ->loop ->cancelTimer ($ this ->nextAttemptTimer );
142
+ $ this ->nextAttemptTimer = null ;
142
143
}
143
144
144
145
if (\count ($ this ->connectQueue ) === 0 ) {
@@ -176,8 +177,8 @@ public function check($resolve, $reject)
176
177
*
177
178
* @link https://tools.ietf.org/html/rfc8305#section-5
178
179
*/
179
- if ((\count ($ this ->connectQueue ) > 0 || ($ this ->resolved [Message::TYPE_A ] === false || $ this ->resolved [Message::TYPE_AAAA ] === false )) && $ this ->timer === null ) {
180
- $ this ->timer = $ this ->loop ->addPeriodicTimer (self ::CONNECT_INTERVAL , function () use ($ that , $ resolve , $ reject ) {
180
+ if ((\count ($ this ->connectQueue ) > 0 || ($ this ->resolved [Message::TYPE_A ] === false || $ this ->resolved [Message::TYPE_AAAA ] === false )) && $ this ->nextAttemptTimer === null ) {
181
+ $ this ->nextAttemptTimer = $ this ->loop ->addPeriodicTimer (self ::CONNECTION_ATTEMPT_DELAY , function () use ($ that , $ resolve , $ reject ) {
181
182
$ that ->check ($ resolve , $ reject );
182
183
});
183
184
}
@@ -239,22 +240,22 @@ public function attemptConnection($ip)
239
240
public function cleanUp ()
240
241
{
241
242
/** @var CancellablePromiseInterface $promise */
242
- foreach ($ this ->connectionPromises as $ index => $ connectionPromise ) {
243
+ foreach ($ this ->connectionPromises as $ connectionPromise ) {
243
244
if ($ connectionPromise instanceof CancellablePromiseInterface) {
244
245
$ connectionPromise ->cancel ();
245
246
}
246
247
}
247
248
248
249
/** @var CancellablePromiseInterface $promise */
249
- foreach ($ this ->resolverPromises as $ index => $ resolverPromise ) {
250
+ foreach ($ this ->resolverPromises as $ resolverPromise ) {
250
251
if ($ resolverPromise instanceof CancellablePromiseInterface) {
251
252
$ resolverPromise ->cancel ();
252
253
}
253
254
}
254
255
255
- if ($ this ->timer instanceof TimerInterface) {
256
- $ this ->loop ->cancelTimer ($ this ->timer );
257
- $ this ->timer = null ;
256
+ if ($ this ->nextAttemptTimer instanceof TimerInterface) {
257
+ $ this ->loop ->cancelTimer ($ this ->nextAttemptTimer );
258
+ $ this ->nextAttemptTimer = null ;
258
259
}
259
260
}
260
261
0 commit comments