Mercurial > vim
comparison src/channel.c @ 7935:3f2e0b62003d v7.4.1263
commit https://github.com/vim/vim/commit/4d919d748e4e435edb135aa5ccf6ee7de9212023
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Feb 5 22:36:41 2016 +0100
patch 7.4.1263
Problem: ch_open() hangs when the server isn't running.
Solution: Add a timeout. Use a dict to pass arguments. (Yasuhiro Matsumoto)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 05 Feb 2016 22:45:06 +0100 |
parents | 1f0743f4f88f |
children | 2e905dfc6999 |
comparison
equal
deleted
inserted
replaced
7934:1aab88611034 | 7935:3f2e0b62003d |
---|---|
40 /* WinSock API is separated from C API, thus we can't use read(), write(), | 40 /* WinSock API is separated from C API, thus we can't use read(), write(), |
41 * errno... */ | 41 * errno... */ |
42 # define SOCK_ERRNO errno = WSAGetLastError() | 42 # define SOCK_ERRNO errno = WSAGetLastError() |
43 # undef ECONNREFUSED | 43 # undef ECONNREFUSED |
44 # define ECONNREFUSED WSAECONNREFUSED | 44 # define ECONNREFUSED WSAECONNREFUSED |
45 # undef EWOULDBLOCK | |
46 # define EWOULDBLOCK WSAEWOULDBLOCK | |
45 # ifdef EINTR | 47 # ifdef EINTR |
46 # undef EINTR | 48 # undef EINTR |
47 # endif | 49 # endif |
48 # define EINTR WSAEINTR | 50 # define EINTR WSAEINTR |
49 # define sock_write(sd, buf, len) send(sd, buf, len, 0) | 51 # define sock_write(sd, buf, len) send(sd, buf, len, 0) |
117 char_u *ch_callback; /* function to call when a msg is not handled */ | 119 char_u *ch_callback; /* function to call when a msg is not handled */ |
118 cbq_T ch_cb_head; /* dummy node for pre-request callbacks */ | 120 cbq_T ch_cb_head; /* dummy node for pre-request callbacks */ |
119 | 121 |
120 int ch_json_mode; /* TRUE for a json channel */ | 122 int ch_json_mode; /* TRUE for a json channel */ |
121 jsonq_T ch_json_head; /* dummy node, header for circular queue */ | 123 jsonq_T ch_json_head; /* dummy node, header for circular queue */ |
124 | |
125 int ch_timeout; /* request timeout in msec */ | |
122 } channel_T; | 126 } channel_T; |
123 | 127 |
124 /* | 128 /* |
125 * Information about all channels. | 129 * Information about all channels. |
126 * There can be gaps for closed channels, they will be reused later. | 130 * There can be gaps for closed channels, they will be reused later. |
130 | 134 |
131 /* | 135 /* |
132 * TODO: open debug file when desired. | 136 * TODO: open debug file when desired. |
133 */ | 137 */ |
134 FILE *debugfd = NULL; | 138 FILE *debugfd = NULL; |
139 | |
140 #ifdef _WIN32 | |
141 # undef PERROR | |
142 # define PERROR(msg) (void)emsg3((char_u *)"%s: %s", \ | |
143 (char_u *)msg, (char_u *)strerror_win32(errno)) | |
144 | |
145 static char * | |
146 strerror_win32(int eno) | |
147 { | |
148 static LPVOID msgbuf = NULL; | |
149 char_u *ptr; | |
150 | |
151 if (msgbuf) | |
152 LocalFree(msgbuf); | |
153 FormatMessage( | |
154 FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
155 FORMAT_MESSAGE_FROM_SYSTEM | | |
156 FORMAT_MESSAGE_IGNORE_INSERTS, | |
157 NULL, | |
158 eno, | |
159 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), | |
160 (LPTSTR) &msgbuf, | |
161 0, | |
162 NULL); | |
163 /* chomp \r or \n */ | |
164 for (ptr = (char_u *)msgbuf; *ptr; ptr++) | |
165 switch (*ptr) | |
166 { | |
167 case '\r': | |
168 STRMOVE(ptr, ptr + 1); | |
169 ptr--; | |
170 break; | |
171 case '\n': | |
172 if (*(ptr + 1) == '\0') | |
173 *ptr = '\0'; | |
174 else | |
175 *ptr = ' '; | |
176 break; | |
177 } | |
178 return msgbuf; | |
179 } | |
180 #endif | |
135 | 181 |
136 /* | 182 /* |
137 * Add a new channel slot, return the index. | 183 * Add a new channel slot, return the index. |
138 * The channel isn't actually used into ch_fd is set >= 0; | 184 * The channel isn't actually used into ch_fd is set >= 0; |
139 * Returns -1 if all channels are in use. | 185 * Returns -1 if all channels are in use. |
179 ch->ch_head.prev = &ch->ch_head; | 225 ch->ch_head.prev = &ch->ch_head; |
180 ch->ch_cb_head.next = &ch->ch_cb_head; | 226 ch->ch_cb_head.next = &ch->ch_cb_head; |
181 ch->ch_cb_head.prev = &ch->ch_cb_head; | 227 ch->ch_cb_head.prev = &ch->ch_cb_head; |
182 ch->ch_json_head.next = &ch->ch_json_head; | 228 ch->ch_json_head.next = &ch->ch_json_head; |
183 ch->ch_json_head.prev = &ch->ch_json_head; | 229 ch->ch_json_head.prev = &ch->ch_json_head; |
230 | |
231 ch->ch_timeout = 2000; | |
184 | 232 |
185 return channel_count++; | 233 return channel_count++; |
186 } | 234 } |
187 | 235 |
188 #if defined(FEAT_GUI) || defined(PROTO) | 236 #if defined(FEAT_GUI) || defined(PROTO) |
301 * Open a channel to "hostname":"port". | 349 * Open a channel to "hostname":"port". |
302 * Returns the channel number for success. | 350 * Returns the channel number for success. |
303 * Returns a negative number for failure. | 351 * Returns a negative number for failure. |
304 */ | 352 */ |
305 int | 353 int |
306 channel_open(char *hostname, int port_in, void (*close_cb)(void)) | 354 channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) |
307 { | 355 { |
308 int sd; | 356 int sd; |
309 struct sockaddr_in server; | 357 struct sockaddr_in server; |
310 struct hostent * host; | 358 struct hostent * host; |
311 #ifdef WIN32 | 359 #ifdef WIN32 |
312 u_short port = port_in; | 360 u_short port = port_in; |
361 u_long val = 1; | |
313 #else | 362 #else |
314 int port = port_in; | 363 int port = port_in; |
315 #endif | 364 #endif |
316 int idx; | 365 int idx; |
366 int ret; | |
317 | 367 |
318 #ifdef WIN32 | 368 #ifdef WIN32 |
319 channel_init_winsock(); | 369 channel_init_winsock(); |
320 #endif | 370 #endif |
321 | 371 |
346 sock_close(sd); | 396 sock_close(sd); |
347 return -1; | 397 return -1; |
348 } | 398 } |
349 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length); | 399 memcpy((char *)&server.sin_addr, host->h_addr, host->h_length); |
350 | 400 |
351 /* Connect to server */ | 401 if (waittime >= 0) |
352 if (connect(sd, (struct sockaddr *)&server, sizeof(server))) | 402 { |
353 { | 403 /* Make connect non-blocking. */ |
354 SOCK_ERRNO; | 404 if ( |
355 CHERROR("channel_open: Connect failed with errno %d\n", errno); | 405 #ifdef _WIN32 |
356 if (errno == ECONNREFUSED) | 406 ioctlsocket(sd, FIONBIO, &val) < 0 |
357 { | 407 #else |
408 fcntl(sd, F_SETFL, O_NONBLOCK) < 0 | |
409 #endif | |
410 ) | |
411 { | |
412 SOCK_ERRNO; | |
413 CHERROR("channel_open: Connect failed with errno %d\n", errno); | |
358 sock_close(sd); | 414 sock_close(sd); |
359 if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1) | 415 return -1; |
360 { | 416 } |
361 SOCK_ERRNO; | 417 } |
362 CHERROR("socket() retry in channel_open()\n", ""); | 418 |
363 PERROR("E900: socket() retry in channel_open()"); | 419 /* Try connecting to the server. */ |
364 return -1; | 420 ret = connect(sd, (struct sockaddr *)&server, sizeof(server)); |
365 } | 421 SOCK_ERRNO; |
366 if (connect(sd, (struct sockaddr *)&server, sizeof(server))) | 422 if (ret < 0) |
367 { | 423 { |
368 int retries = 36; | 424 if (errno != EWOULDBLOCK && errno != EINPROGRESS) |
369 int success = FALSE; | 425 { |
370 | 426 CHERROR("channel_open: Connect failed with errno %d\n", errno); |
371 SOCK_ERRNO; | |
372 while (retries-- && ((errno == ECONNREFUSED) | |
373 || (errno == EINTR))) | |
374 { | |
375 CHERROR("retrying...\n", ""); | |
376 mch_delay(3000L, TRUE); | |
377 ui_breakcheck(); | |
378 if (got_int) | |
379 { | |
380 errno = EINTR; | |
381 break; | |
382 } | |
383 if (connect(sd, (struct sockaddr *)&server, | |
384 sizeof(server)) == 0) | |
385 { | |
386 success = TRUE; | |
387 break; | |
388 } | |
389 SOCK_ERRNO; | |
390 } | |
391 if (!success) | |
392 { | |
393 /* Get here when the server can't be found. */ | |
394 CHERROR("Cannot connect to port after retry\n", ""); | |
395 PERROR(_("E899: Cannot connect to port after retry2")); | |
396 sock_close(sd); | |
397 return -1; | |
398 } | |
399 } | |
400 } | |
401 else | |
402 { | |
403 CHERROR("Cannot connect to port\n", ""); | 427 CHERROR("Cannot connect to port\n", ""); |
404 PERROR(_("E902: Cannot connect to port")); | 428 PERROR(_("E902: Cannot connect to port")); |
405 sock_close(sd); | 429 sock_close(sd); |
406 return -1; | 430 return -1; |
407 } | 431 } |
408 } | 432 } |
409 | 433 |
434 if (waittime >= 0) | |
435 { | |
436 struct timeval tv; | |
437 fd_set rfds, wfds; | |
438 | |
439 FD_ZERO(&rfds); | |
440 FD_ZERO(&wfds); | |
441 FD_SET(sd, &rfds); | |
442 FD_SET(sd, &wfds); | |
443 tv.tv_sec = waittime; | |
444 tv.tv_usec = 0; | |
445 ret = select((int)sd+1, &rfds, &wfds, NULL, &tv); | |
446 if (ret < 0) | |
447 { | |
448 SOCK_ERRNO; | |
449 CHERROR("channel_open: Connect failed with errno %d\n", errno); | |
450 CHERROR("Cannot connect to port\n", ""); | |
451 PERROR(_("E902: Cannot connect to port")); | |
452 sock_close(sd); | |
453 return -1; | |
454 } | |
455 if (!FD_ISSET(sd, &rfds) && !FD_ISSET(sd, &wfds)) | |
456 { | |
457 errno = ECONNREFUSED; | |
458 CHERROR("Cannot connect to port\n", ""); | |
459 PERROR(_("E902: Cannot connect to port")); | |
460 sock_close(sd); | |
461 return -1; | |
462 } | |
463 | |
464 #ifdef _WIN32 | |
465 val = 0; | |
466 ioctlsocket(sd, FIONBIO, &val); | |
467 #else | |
468 fcntl(sd, F_SETFL, 0); | |
469 #endif | |
470 } | |
471 | |
472 if (errno == ECONNREFUSED) | |
473 { | |
474 sock_close(sd); | |
475 if ((sd = (sock_T)socket(AF_INET, SOCK_STREAM, 0)) == (sock_T)-1) | |
476 { | |
477 SOCK_ERRNO; | |
478 CHERROR("socket() retry in channel_open()\n", ""); | |
479 PERROR("E900: socket() retry in channel_open()"); | |
480 return -1; | |
481 } | |
482 if (connect(sd, (struct sockaddr *)&server, sizeof(server))) | |
483 { | |
484 int retries = 36; | |
485 int success = FALSE; | |
486 | |
487 SOCK_ERRNO; | |
488 while (retries-- && ((errno == ECONNREFUSED) | |
489 || (errno == EINTR))) | |
490 { | |
491 CHERROR("retrying...\n", ""); | |
492 mch_delay(3000L, TRUE); | |
493 ui_breakcheck(); | |
494 if (got_int) | |
495 { | |
496 errno = EINTR; | |
497 break; | |
498 } | |
499 if (connect(sd, (struct sockaddr *)&server, | |
500 sizeof(server)) == 0) | |
501 { | |
502 success = TRUE; | |
503 break; | |
504 } | |
505 SOCK_ERRNO; | |
506 } | |
507 if (!success) | |
508 { | |
509 /* Get here when the server can't be found. */ | |
510 CHERROR("Cannot connect to port after retry\n", ""); | |
511 PERROR(_("E899: Cannot connect to port after retry2")); | |
512 sock_close(sd); | |
513 return -1; | |
514 } | |
515 } | |
516 } | |
517 | |
410 channels[idx].ch_fd = sd; | 518 channels[idx].ch_fd = sd; |
411 channels[idx].ch_close_cb = close_cb; | 519 channels[idx].ch_close_cb = close_cb; |
412 | 520 |
413 #ifdef FEAT_GUI | 521 #ifdef FEAT_GUI |
414 channel_gui_register(idx); | 522 channel_gui_register(idx); |
422 */ | 530 */ |
423 void | 531 void |
424 channel_set_json_mode(int idx, int json_mode) | 532 channel_set_json_mode(int idx, int json_mode) |
425 { | 533 { |
426 channels[idx].ch_json_mode = json_mode; | 534 channels[idx].ch_json_mode = json_mode; |
535 } | |
536 | |
537 /* | |
538 * Set the read timeout of channel "idx". | |
539 */ | |
540 void | |
541 channel_set_timeout(int idx, int timeout) | |
542 { | |
543 channels[idx].ch_timeout = timeout; | |
427 } | 544 } |
428 | 545 |
429 /* | 546 /* |
430 * Set the callback for channel "idx". | 547 * Set the callback for channel "idx". |
431 */ | 548 */ |
896 #ifdef FEAT_GUI | 1013 #ifdef FEAT_GUI |
897 channel_gui_unregister(idx); | 1014 channel_gui_unregister(idx); |
898 #endif | 1015 #endif |
899 vim_free(channel->ch_callback); | 1016 vim_free(channel->ch_callback); |
900 channel->ch_callback = NULL; | 1017 channel->ch_callback = NULL; |
1018 channel->ch_timeout = 2000; | |
901 | 1019 |
902 while (channel_peek(idx) != NULL) | 1020 while (channel_peek(idx) != NULL) |
903 vim_free(channel_get(idx)); | 1021 vim_free(channel_get(idx)); |
904 | 1022 |
905 cbhead = &channel->ch_cb_head; | 1023 cbhead = &channel->ch_cb_head; |
1146 char_u * | 1264 char_u * |
1147 channel_read_block(int idx) | 1265 channel_read_block(int idx) |
1148 { | 1266 { |
1149 if (channel_peek(idx) == NULL) | 1267 if (channel_peek(idx) == NULL) |
1150 { | 1268 { |
1151 /* Wait for up to 2 seconds. | 1269 /* Wait for up to the channel timeout. */ |
1152 * TODO: use timeout set on the channel. */ | 1270 if (channel_wait(channels[idx].ch_fd, channels[idx].ch_timeout) == FAIL) |
1153 if (channel_wait(channels[idx].ch_fd, 2000) == FAIL) | |
1154 return NULL; | 1271 return NULL; |
1155 channel_read(idx); | 1272 channel_read(idx); |
1156 } | 1273 } |
1157 | 1274 |
1158 return channel_get_all(idx); | 1275 return channel_get_all(idx); |
1159 } | 1276 } |
1160 | 1277 |
1161 /* | 1278 /* |
1162 * Read one JSON message from channel "ch_idx" with ID "id" and store the | 1279 * Read one JSON message from channel "ch_idx" with ID "id" and store the |
1163 * result in "rettv". | 1280 * result in "rettv". |
1164 * Blocks until the message is received. | 1281 * Blocks until the message is received or the timeout is reached. |
1165 */ | 1282 */ |
1166 int | 1283 int |
1167 channel_read_json_block(int ch_idx, int id, typval_T **rettv) | 1284 channel_read_json_block(int ch_idx, int id, typval_T **rettv) |
1168 { | 1285 { |
1169 int more; | 1286 int more; |
1181 /* Handle any other messages in the queue. If done some more | 1298 /* Handle any other messages in the queue. If done some more |
1182 * messages may have arrived. */ | 1299 * messages may have arrived. */ |
1183 if (channel_parse_messages()) | 1300 if (channel_parse_messages()) |
1184 continue; | 1301 continue; |
1185 | 1302 |
1186 /* Wait for up to 2 seconds. | 1303 /* Wait for up to the channel timeout. */ |
1187 * TODO: use timeout set on the channel. */ | |
1188 if (channels[ch_idx].ch_fd < 0 | 1304 if (channels[ch_idx].ch_fd < 0 |
1189 || channel_wait(channels[ch_idx].ch_fd, 2000) == FAIL) | 1305 || channel_wait(channels[ch_idx].ch_fd, |
1306 channels[ch_idx].ch_timeout) == FAIL) | |
1190 break; | 1307 break; |
1191 channel_read(ch_idx); | 1308 channel_read(ch_idx); |
1192 } | 1309 } |
1193 } | 1310 } |
1194 return FAIL; | 1311 return FAIL; |