25
25
/* Hold state for a single connection request. */
26
26
struct uvTcpConnect
27
27
{
28
- struct UvTcp * t ; /* Transport implementation */
29
- struct raft_uv_connect * req ; /* User request */
30
- uv_buf_t handshake ; /* Handshake data */
31
- struct uv_tcp_s * tcp ; /* TCP connection socket handle */
32
- struct uv_connect_s connect ; /* TCP connection request */
33
- struct uv_write_s write ; /* TCP handshake request */
34
- int status ; /* Returned to the request callback */
35
- queue queue ; /* Pending connect queue */
28
+ struct UvTcp * t ; /* Transport implementation */
29
+ struct raft_uv_connect * req ; /* User request */
30
+ uv_buf_t handshake ; /* Handshake data */
31
+ struct uv_tcp_s * tcp ; /* TCP connection socket handle */
32
+ struct uv_getaddrinfo_s getaddrinfo ; /* DNS resolve request */
33
+ struct uv_connect_s connect ; /* TCP connection request */
34
+ struct uv_write_s write ; /* TCP handshake request */
35
+ uv_check_t delayedtcpclose ; /* A check handle required to delay closing tcp */
36
+ int status ; /* Returned to the request callback */
37
+ queue queue ; /* Pending connect queue */
36
38
};
37
39
38
40
/* Encode an handshake message into the given buffer. */
@@ -64,7 +66,9 @@ static void uvTcpConnectFinish(struct uvTcpConnect *connect)
64
66
struct raft_uv_connect * req = connect -> req ;
65
67
int status = connect -> status ;
66
68
QUEUE_REMOVE (& connect -> queue );
69
+ uv_close ((struct uv_handle_s * )& connect -> delayedtcpclose , NULL );
67
70
RaftHeapFree (connect -> handshake .base );
71
+ uv_freeaddrinfo (connect -> getaddrinfo .addrinfo );
68
72
raft_free (connect );
69
73
req -> cb (req , stream , status );
70
74
}
@@ -83,12 +87,29 @@ static void uvTcpConnectUvCloseCb(struct uv_handle_s *handle)
83
87
UvTcpMaybeFireCloseCb (t );
84
88
}
85
89
90
+ static void uvTcpConnectCheckMayClose (uv_check_t * handle )
91
+ {
92
+ struct uvTcpConnect * connect = handle -> data ;
93
+ if (connect -> status || uv_is_active ((uv_handle_t * )connect -> tcp )) {
94
+ uv_check_stop (& connect -> delayedtcpclose );
95
+ uv_close ((struct uv_handle_s * )connect -> tcp , uvTcpConnectUvCloseCb );
96
+ }
97
+ }
98
+
86
99
/* Abort a connection request. */
87
100
static void uvTcpConnectAbort (struct uvTcpConnect * connect )
88
101
{
89
102
QUEUE_REMOVE (& connect -> queue );
90
103
QUEUE_PUSH (& connect -> t -> aborting , & connect -> queue );
91
- uv_close ((struct uv_handle_s * )connect -> tcp , uvTcpConnectUvCloseCb );
104
+ if (uv_cancel ((struct uv_req_s * )& connect -> getaddrinfo ) == 0 ||
105
+ !uv_is_active ((uv_handle_t * )connect -> tcp )) {
106
+ /* If canceling the addrinfo call was not successfull, but the tcp
107
+ handle is not active the getaddrinfo is in progress and we need to
108
+ delay closing the tcp handle until it's finished */
109
+ uv_check_start (& connect -> delayedtcpclose , uvTcpConnectCheckMayClose );
110
+ } else {
111
+ uv_close ((struct uv_handle_s * )connect -> tcp , uvTcpConnectUvCloseCb );
112
+ }
92
113
}
93
114
94
115
/* The handshake TCP write completes. Fire the connect callback. */
@@ -146,43 +167,93 @@ static void uvTcpConnectUvConnectCb(struct uv_connect_s *req, int status)
146
167
uvTcpConnectAbort (connect );
147
168
}
148
169
149
- /* Create a new TCP handle and submit a connection request to the event loop. */
150
- static int uvTcpConnectStart (struct uvTcpConnect * r , const char * address )
170
+ static void uvGetAddrInfoCb (uv_getaddrinfo_t * req ,
171
+ int status ,
172
+ struct addrinfo * res )
151
173
{
152
- struct UvTcp * t = r -> t ;
153
- struct sockaddr_in addr ;
174
+ struct uvTcpConnect * connect = req -> data ;
175
+ struct UvTcp * t = connect -> t ;
154
176
int rv ;
155
177
156
- rv = uvIpParse (address , & addr );
178
+ if (t -> closing || status == UV_ECANCELED ) {
179
+ connect -> status = RAFT_CANCELED ;
180
+ return ;
181
+ }
182
+
183
+ if (status < 0 ) {
184
+ ErrMsgPrintf (t -> transport -> errmsg , "uv_getaddrinfo(): %s" ,
185
+ uv_err_name (status ));
186
+ connect -> status = RAFT_NOCONNECTION ;
187
+ goto err ;
188
+ }
189
+ rv = uv_tcp_connect (& connect -> connect , connect -> tcp ,
190
+ (const struct sockaddr * )res -> ai_addr ,
191
+ uvTcpConnectUvConnectCb );
157
192
if (rv != 0 ) {
193
+ /* UNTESTED: since parsing succeed, this should fail only because of
194
+ * lack of system resources */
195
+ ErrMsgPrintf (t -> transport -> errmsg , "uv_tcp_connect(): %s" ,
196
+ uv_strerror (rv ));
197
+ connect -> status = RAFT_NOCONNECTION ;
158
198
goto err ;
159
199
}
160
200
201
+ return ;
202
+
203
+ err :
204
+ uvTcpConnectAbort (connect );
205
+ }
206
+ /* Create a new TCP handle and submit a connection request to the event loop. */
207
+ static int uvTcpConnectStart (struct uvTcpConnect * r , const char * address )
208
+ {
209
+ static struct addrinfo hints = {
210
+ .ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICHOST ,
211
+ .ai_family = AF_INET ,
212
+ .ai_socktype = SOCK_STREAM ,
213
+ .ai_protocol = 0 };
214
+ struct UvTcp * t = r -> t ;
215
+ char hostname [NI_MAXHOST ];
216
+ char service [NI_MAXSERV ];
217
+ int rv ;
218
+
219
+ r -> handshake .base = NULL ;
220
+
161
221
/* Initialize the handshake buffer. */
162
222
rv = uvTcpEncodeHandshake (t -> id , t -> address , & r -> handshake );
163
223
if (rv != 0 ) {
164
224
assert (rv == RAFT_NOMEM );
165
- ErrMsgOom (r -> t -> transport -> errmsg );
225
+ ErrMsgOom (t -> transport -> errmsg );
166
226
goto err ;
167
227
}
168
228
169
229
r -> tcp = RaftHeapMalloc (sizeof * r -> tcp );
170
230
if (r -> tcp == NULL ) {
171
231
ErrMsgOom (t -> transport -> errmsg );
172
232
rv = RAFT_NOMEM ;
173
- goto err_after_encode_handshake ;
233
+ goto err ;
174
234
}
175
235
236
+ rv = uv_check_init (t -> loop , & r -> delayedtcpclose );
237
+ assert (rv == 0 );
238
+
176
239
rv = uv_tcp_init (r -> t -> loop , r -> tcp );
177
240
assert (rv == 0 );
178
241
r -> tcp -> data = r ;
179
242
180
- rv = uv_tcp_connect (& r -> connect , r -> tcp , (struct sockaddr * )& addr ,
181
- uvTcpConnectUvConnectCb );
182
- if (rv != 0 ) {
183
- /* UNTESTED: since parsing succeed, this should fail only because of
184
- * lack of system resources */
185
- ErrMsgPrintf (t -> transport -> errmsg , "uv_tcp_connect(): %s" ,
243
+ rv = uvIpAddrSplit (address , hostname , sizeof (hostname ), service ,
244
+ sizeof (service ));
245
+ if (rv ) {
246
+ ErrMsgPrintf (t -> transport -> errmsg ,
247
+ "uv_tcp_connect(): Cannot split %s into host and service" ,
248
+ address );
249
+ rv = RAFT_NOCONNECTION ;
250
+ goto err_after_tcp_init ;
251
+ }
252
+ rv = uv_getaddrinfo (r -> t -> loop , & r -> getaddrinfo , & uvGetAddrInfoCb , hostname ,
253
+ service , & hints );
254
+ if (rv ) {
255
+ ErrMsgPrintf (t -> transport -> errmsg ,
256
+ "uv_tcp_connect(): Cannot initiate getaddrinfo %s" ,
186
257
uv_strerror (rv ));
187
258
rv = RAFT_NOCONNECTION ;
188
259
goto err_after_tcp_init ;
@@ -192,9 +263,11 @@ static int uvTcpConnectStart(struct uvTcpConnect *r, const char *address)
192
263
193
264
err_after_tcp_init :
194
265
uv_close ((uv_handle_t * )r -> tcp , (uv_close_cb )RaftHeapFree );
195
- err_after_encode_handshake :
196
- RaftHeapFree ( r -> handshake . base );
266
+ uv_close (( uv_handle_t * ) & r -> delayedtcpclose , NULL );
267
+
197
268
err :
269
+ RaftHeapFree (r -> handshake .base );
270
+
198
271
return rv ;
199
272
}
200
273
@@ -221,8 +294,9 @@ int UvTcpConnect(struct raft_uv_transport *transport,
221
294
r -> req = req ;
222
295
r -> status = 0 ;
223
296
r -> write .data = r ;
297
+ r -> getaddrinfo .data = r ;
224
298
r -> connect .data = r ;
225
-
299
+ r -> delayedtcpclose . data = r ;
226
300
req -> cb = cb ;
227
301
228
302
/* Keep track of the pending request */
0 commit comments