Mercurial > vim
comparison src/channel.c @ 8096:882ba5080c5c v7.4.1342
commit https://github.com/vim/vim/commit/e74e8e7d758e9312165a931f176185f07a64231a
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Feb 16 22:01:30 2016 +0100
patch 7.4.1342
Problem: On Mac OS/X the waittime must be > 0 for connect to work.
Solution: Use select() in a different way. (partly by Kazunobu Kuriyama)
Always use a waittime of 1 or more.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Tue, 16 Feb 2016 22:15:04 +0100 |
parents | 18a3f0f05244 |
children | 4aea0b0aa714 |
comparison
equal
deleted
inserted
replaced
8095:f73de5f10aa2 | 8096:882ba5080c5c |
---|---|
251 | 251 |
252 if (channel == NULL) | 252 if (channel == NULL) |
253 return NULL; | 253 return NULL; |
254 | 254 |
255 channel->ch_id = next_ch_id++; | 255 channel->ch_id = next_ch_id++; |
256 ch_log(channel, "Opening channel\n"); | 256 ch_log(channel, "Created channel\n"); |
257 | 257 |
258 #ifdef CHANNEL_PIPES | 258 #ifdef CHANNEL_PIPES |
259 for (which = CHAN_SOCK; which <= CHAN_IN; ++which) | 259 for (which = CHAN_SOCK; which <= CHAN_IN; ++which) |
260 #else | 260 #else |
261 which = CHAN_SOCK; | 261 which = CHAN_SOCK; |
456 } | 456 } |
457 } | 457 } |
458 | 458 |
459 #endif | 459 #endif |
460 | 460 |
461 static char *e_cannot_connect = N_("E902: Cannot connect to port"); | |
462 | |
461 /* | 463 /* |
462 * Open a socket channel to "hostname":"port". | 464 * Open a socket channel to "hostname":"port". |
465 * "waittime" is the time in msec to wait for the connection. | |
466 * When negative wait forever. | |
463 * Returns the channel for success. | 467 * Returns the channel for success. |
464 * Returns NULL for failure. | 468 * Returns NULL for failure. |
465 */ | 469 */ |
466 channel_T * | 470 channel_T * |
467 channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) | 471 channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void)) |
490 return NULL; | 494 return NULL; |
491 } | 495 } |
492 | 496 |
493 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) | 497 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) |
494 { | 498 { |
495 ch_error(NULL, "in socket() in channel_open().\n"); | 499 ch_error(channel, "in socket() in channel_open().\n"); |
496 PERROR("E898: socket() in channel_open()"); | 500 PERROR("E898: socket() in channel_open()"); |
497 channel_free(channel); | 501 channel_free(channel); |
498 return NULL; | 502 return NULL; |
499 } | 503 } |
500 | 504 |
503 vim_memset((char *)&server, 0, sizeof(server)); | 507 vim_memset((char *)&server, 0, sizeof(server)); |
504 server.sin_family = AF_INET; | 508 server.sin_family = AF_INET; |
505 server.sin_port = htons(port); | 509 server.sin_port = htons(port); |
506 if ((host = gethostbyname(hostname)) == NULL) | 510 if ((host = gethostbyname(hostname)) == NULL) |
507 { | 511 { |
508 ch_error(NULL, "in gethostbyname() in channel_open()\n"); | 512 ch_error(channel, "in gethostbyname() in channel_open()\n"); |
509 PERROR("E901: gethostbyname() in channel_open()"); | 513 PERROR("E901: gethostbyname() in channel_open()"); |
510 sock_close(sd); | 514 sock_close(sd); |
511 channel_free(channel); | 515 channel_free(channel); |
512 return NULL; | 516 return NULL; |
513 } | 517 } |
523 fcntl(sd, F_SETFL, O_NONBLOCK) < 0 | 527 fcntl(sd, F_SETFL, O_NONBLOCK) < 0 |
524 #endif | 528 #endif |
525 ) | 529 ) |
526 { | 530 { |
527 SOCK_ERRNO; | 531 SOCK_ERRNO; |
528 ch_errorn(NULL, "channel_open: Connect failed with errno %d\n", | 532 ch_errorn(channel, "channel_open: Connect failed with errno %d\n", |
529 errno); | 533 errno); |
530 sock_close(sd); | 534 sock_close(sd); |
531 channel_free(channel); | 535 channel_free(channel); |
532 return NULL; | 536 return NULL; |
533 } | 537 } |
534 } | 538 } |
535 | 539 |
536 /* Try connecting to the server. */ | 540 /* Try connecting to the server. */ |
537 ch_logsn(NULL, "Connecting to %s port %d", hostname, port); | 541 ch_logsn(channel, "Connecting to %s port %d\n", hostname, port); |
538 ret = connect(sd, (struct sockaddr *)&server, sizeof(server)); | 542 ret = connect(sd, (struct sockaddr *)&server, sizeof(server)); |
539 SOCK_ERRNO; | 543 SOCK_ERRNO; |
540 if (ret < 0) | 544 if (ret < 0) |
541 { | 545 { |
542 if (errno != EWOULDBLOCK | 546 if (errno != EWOULDBLOCK |
543 #ifdef EINPROGRESS | 547 #ifdef EINPROGRESS |
544 && errno != EINPROGRESS | 548 && errno != EINPROGRESS |
545 #endif | 549 #endif |
546 ) | 550 ) |
547 { | 551 { |
548 ch_errorn(NULL, "channel_open: Connect failed with errno %d\n", | 552 ch_errorn(channel, "channel_open: Connect failed with errno %d\n", |
549 errno); | 553 errno); |
550 PERROR(_("E902: Cannot connect to port")); | 554 PERROR(_(e_cannot_connect)); |
551 sock_close(sd); | 555 sock_close(sd); |
552 channel_free(channel); | 556 channel_free(channel); |
553 return NULL; | 557 return NULL; |
554 } | 558 } |
555 } | 559 } |
556 | 560 |
557 if (waittime >= 0 && ret < 0) | 561 if (waittime >= 0 && ret < 0) |
558 { | 562 { |
559 struct timeval tv; | 563 struct timeval tv; |
560 fd_set wfds; | 564 fd_set wfds; |
561 | 565 #if defined(__APPLE__) && __APPLE__ == 1 |
566 # define PASS_RFDS | |
567 fd_set rfds; | |
568 | |
569 FD_ZERO(&rfds); | |
570 FD_SET(sd, &rfds); | |
571 /* On Mac a zero timeout almost never works. At least wait one | |
572 * millisecond. */ | |
573 if (waittime == 0) | |
574 waittime = 1; | |
575 #endif | |
562 FD_ZERO(&wfds); | 576 FD_ZERO(&wfds); |
563 FD_SET(sd, &wfds); | 577 FD_SET(sd, &wfds); |
564 tv.tv_sec = waittime / 1000; | 578 tv.tv_sec = waittime / 1000; |
565 tv.tv_usec = (waittime % 1000) * 1000; | 579 tv.tv_usec = (waittime % 1000) * 1000; |
566 ret = select((int)sd + 1, NULL, &wfds, NULL, &tv); | 580 |
581 ch_logn(channel, "Waiting for connection (timeout %d msec)...\n", | |
582 waittime); | |
583 ret = select((int)sd + 1, | |
584 #ifdef PASS_RFDS | |
585 &rfds, | |
586 #else | |
587 NULL, | |
588 #endif | |
589 &wfds, NULL, &tv); | |
590 | |
567 if (ret < 0) | 591 if (ret < 0) |
568 { | 592 { |
569 SOCK_ERRNO; | 593 SOCK_ERRNO; |
570 ch_errorn(NULL, "channel_open: Connect failed with errno %d\n", | 594 ch_errorn(channel, "channel_open: Connect failed with errno %d\n", |
571 errno); | 595 errno); |
572 PERROR(_("E902: Cannot connect to port")); | 596 PERROR(_(e_cannot_connect)); |
573 sock_close(sd); | 597 sock_close(sd); |
574 channel_free(channel); | 598 channel_free(channel); |
575 return NULL; | 599 return NULL; |
576 } | 600 } |
577 if (!FD_ISSET(sd, &wfds)) | 601 #ifdef PASS_RFDS |
578 { | 602 if (ret == 0 && FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds)) |
579 /* don't give an error, we just timed out. */ | 603 { |
604 /* For OS X, this implies error. See tcp(4). */ | |
605 ch_error(channel, "channel_open: Connect failed\n"); | |
606 EMSG(_(e_cannot_connect)); | |
580 sock_close(sd); | 607 sock_close(sd); |
581 channel_free(channel); | 608 channel_free(channel); |
582 return NULL; | 609 return NULL; |
583 } | 610 } |
611 #endif | |
612 if (!FD_ISSET(sd, &wfds)) | |
613 { | |
614 /* don't give an error, we just timed out. */ | |
615 ch_error(channel, "Connection timed out\n"); | |
616 sock_close(sd); | |
617 channel_free(channel); | |
618 return NULL; | |
619 } | |
620 ch_log(channel, "Connection made\n"); | |
584 } | 621 } |
585 | 622 |
586 if (waittime >= 0) | 623 if (waittime >= 0) |
587 { | 624 { |
588 #ifdef _WIN32 | 625 #ifdef _WIN32 |
598 { | 635 { |
599 sock_close(sd); | 636 sock_close(sd); |
600 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) | 637 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) |
601 { | 638 { |
602 SOCK_ERRNO; | 639 SOCK_ERRNO; |
603 ch_log(NULL, "socket() retry in channel_open()\n"); | 640 ch_log(channel, "socket() retry in channel_open()\n"); |
604 PERROR("E900: socket() retry in channel_open()"); | 641 PERROR("E900: socket() retry in channel_open()"); |
605 channel_free(channel); | 642 channel_free(channel); |
606 return NULL; | 643 return NULL; |
607 } | 644 } |
608 if (connect(sd, (struct sockaddr *)&server, sizeof(server))) | 645 if (connect(sd, (struct sockaddr *)&server, sizeof(server))) |
612 | 649 |
613 SOCK_ERRNO; | 650 SOCK_ERRNO; |
614 while (retries-- && ((errno == ECONNREFUSED) | 651 while (retries-- && ((errno == ECONNREFUSED) |
615 || (errno == EINTR))) | 652 || (errno == EINTR))) |
616 { | 653 { |
617 ch_log(NULL, "retrying...\n"); | 654 ch_log(channel, "retrying...\n"); |
618 mch_delay(3000L, TRUE); | 655 mch_delay(3000L, TRUE); |
619 ui_breakcheck(); | 656 ui_breakcheck(); |
620 if (got_int) | 657 if (got_int) |
621 { | 658 { |
622 errno = EINTR; | 659 errno = EINTR; |
631 SOCK_ERRNO; | 668 SOCK_ERRNO; |
632 } | 669 } |
633 if (!success) | 670 if (!success) |
634 { | 671 { |
635 /* Get here when the server can't be found. */ | 672 /* Get here when the server can't be found. */ |
636 ch_error(NULL, "Cannot connect to port after retry\n"); | 673 ch_error(channel, "Cannot connect to port after retry\n"); |
637 PERROR(_("E899: Cannot connect to port after retry")); | 674 PERROR(_("E899: Cannot connect to port after retry")); |
638 sock_close(sd); | 675 sock_close(sd); |
639 channel_free(channel); | 676 channel_free(channel); |
640 return NULL; | 677 return NULL; |
641 } | 678 } |
1432 struct timeval tval; | 1469 struct timeval tval; |
1433 fd_set rfds; | 1470 fd_set rfds; |
1434 int ret; | 1471 int ret; |
1435 | 1472 |
1436 if (timeout > 0) | 1473 if (timeout > 0) |
1437 ch_logn(channel, "Waiting for %d msec\n", timeout); | 1474 ch_logn(channel, "Waiting for up to %d msec\n", timeout); |
1438 | 1475 |
1439 | 1476 |
1440 # ifdef WIN32 | 1477 # ifdef WIN32 |
1441 if (channel->CH_SOCK == CHAN_FD_INVALID) | 1478 if (channel->CH_SOCK == CHAN_FD_INVALID) |
1442 { | 1479 { |
1445 DWORD deadline = GetTickCount() + timeout; | 1482 DWORD deadline = GetTickCount() + timeout; |
1446 | 1483 |
1447 /* reading from a pipe, not a socket */ | 1484 /* reading from a pipe, not a socket */ |
1448 while (TRUE) | 1485 while (TRUE) |
1449 { | 1486 { |
1450 if (PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &nread, NULL) && nread > 0) | 1487 if (PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &nread, NULL) |
1488 && nread > 0) | |
1451 return OK; | 1489 return OK; |
1452 diff = deadline - GetTickCount(); | 1490 diff = deadline - GetTickCount(); |
1453 if (diff < 0) | 1491 if (diff < 0) |
1454 break; | 1492 break; |
1455 /* Wait for 5 msec. | 1493 /* Wait for 5 msec. |