passenger 6.0.27 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +11 -1
  3. data/CONTRIBUTORS +2 -0
  4. data/bin/passenger-install-apache2-module +6 -3
  5. data/bin/passenger-install-nginx-module +8 -3
  6. data/build/support/cxx_dependency_map.rb +3 -621
  7. data/dev/index_cxx_dependencies.rb +4 -0
  8. data/package.json +1 -1
  9. data/src/agent/Core/ApplicationPool/Implementation.cpp +1 -1
  10. data/src/agent/Core/ApplicationPool/Socket.h +3 -3
  11. data/src/agent/Core/ApplicationPool/TestSession.h +3 -4
  12. data/src/agent/Core/Config.h +1 -6
  13. data/src/agent/Core/Controller/Config.h +1 -1
  14. data/src/agent/Core/CoreMain.cpp +1 -0
  15. data/src/agent/Core/SecurityUpdateChecker.h +10 -1
  16. data/src/agent/Core/SpawningKit/Exceptions.h +0 -1
  17. data/src/agent/Core/SpawningKit/Handshake/Perform.h +13 -2
  18. data/src/agent/Shared/Fundamentals/AbortHandler.cpp +23 -5
  19. data/src/agent/Shared/Fundamentals/AbortHandler.h +10 -22
  20. data/src/agent/Shared/Fundamentals/Initialization.cpp +1 -0
  21. data/src/agent/Watchdog/Config.h +1 -1
  22. data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +5 -0
  23. data/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp +5 -0
  24. data/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp +14 -0
  25. data/src/apache2_module/DirConfig/AutoGeneratedCreateFunction.cpp +3 -0
  26. data/src/apache2_module/DirConfig/AutoGeneratedHeaderSerialization.cpp +3 -0
  27. data/src/apache2_module/DirConfig/AutoGeneratedManifestGeneration.cpp +11 -0
  28. data/src/apache2_module/DirConfig/AutoGeneratedMergeFunction.cpp +7 -0
  29. data/src/apache2_module/DirConfig/AutoGeneratedStruct.h +17 -0
  30. data/src/apache2_module/Hooks.cpp +0 -6
  31. data/src/cxx_supportlib/ConfigKit/IN_PRACTICE.md +2 -12
  32. data/src/cxx_supportlib/ConfigKit/Store.h +1 -6
  33. data/src/cxx_supportlib/Constants.h +1 -1
  34. data/src/cxx_supportlib/DataStructures/StringKeyTable.h +1 -7
  35. data/src/cxx_supportlib/Exceptions.cpp +178 -0
  36. data/src/cxx_supportlib/Exceptions.h +62 -177
  37. data/src/cxx_supportlib/IOTools/IOUtils.cpp +255 -228
  38. data/src/cxx_supportlib/IOTools/IOUtils.h +84 -121
  39. data/src/cxx_supportlib/ServerKit/Config.h +1 -6
  40. data/src/cxx_supportlib/ServerKit/FileBufferedChannel.h +1 -1
  41. data/src/cxx_supportlib/StaticString.h +1 -6
  42. data/src/cxx_supportlib/Utils/Curl.h +1 -6
  43. data/src/cxx_supportlib/Utils/ScopeGuard.h +0 -32
  44. data/src/cxx_supportlib/oxt/implementation.cpp +2 -2
  45. data/src/cxx_supportlib/oxt/spin_lock.hpp +94 -23
  46. data/src/ruby_supportlib/phusion_passenger/platform_info/compiler.rb +6 -10
  47. data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +2 -2
  48. data/src/ruby_supportlib/phusion_passenger/rack_handler.rb +2 -2
  49. data/src/ruby_supportlib/phusion_passenger.rb +1 -1
  50. metadata +3 -7
  51. data/src/cxx_supportlib/oxt/detail/spin_lock_darwin.hpp +0 -75
  52. data/src/cxx_supportlib/oxt/detail/spin_lock_gcc_x86.hpp +0 -85
  53. data/src/cxx_supportlib/oxt/detail/spin_lock_portable.hpp +0 -38
  54. data/src/cxx_supportlib/oxt/detail/spin_lock_pthreads.hpp +0 -111
@@ -29,6 +29,7 @@
29
29
  // https://bugzilla.redhat.com/show_bug.cgi?id=165427
30
30
  // Also needed for SO_PEERCRED.
31
31
  #define _GNU_SOURCE
32
+ #include <exception>
32
33
  #endif
33
34
 
34
35
  #include <oxt/system_calls.hpp>
@@ -86,18 +87,7 @@ using namespace oxt;
86
87
  static WritevFunction writevFunction = syscalls::writev;
87
88
 
88
89
 
89
- bool
90
- purgeStdio(FILE *f) {
91
- #if defined(HAVE_FPURGE)
92
- fpurge(f);
93
- return true;
94
- #elif defined(HAVE___FPURGE)
95
- __fpurge(f);
96
- return true;
97
- #else
98
- return false;
99
- #endif
100
- }
90
+ /****** Server address types support ******/
101
91
 
102
92
  ServerAddressType
103
93
  getSocketAddressType(const StaticString &address) {
@@ -182,67 +172,8 @@ isLocalSocketAddress(const StaticString &address) {
182
172
  }
183
173
  }
184
174
 
185
- void
186
- setBlocking(int fd) {
187
- int flags, ret;
188
-
189
- do {
190
- flags = fcntl(fd, F_GETFL);
191
- } while (flags == -1 && errno == EINTR);
192
- if (flags == -1) {
193
- int e = errno;
194
- throw SystemException("Cannot set socket to blocking mode: "
195
- "cannot get socket flags",
196
- e);
197
- }
198
- do {
199
- ret = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
200
- } while (ret == -1 && errno == EINTR);
201
- if (ret == -1) {
202
- int e = errno;
203
- throw SystemException("Cannot set socket to blocking mode: "
204
- "cannot set socket flags",
205
- e);
206
- }
207
- }
208
175
 
209
- void
210
- setNonBlocking(int fd) {
211
- int flags, ret;
212
-
213
- do {
214
- flags = fcntl(fd, F_GETFL);
215
- } while (flags == -1 && errno == EINTR);
216
- if (flags == -1) {
217
- int e = errno;
218
- throw SystemException("Cannot set socket to non-blocking mode: "
219
- "cannot get socket flags",
220
- e);
221
- }
222
- do {
223
- ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
224
- } while (ret == -1 && errno == EINTR);
225
- if (ret == -1) {
226
- int e = errno;
227
- throw SystemException("Cannot set socket to non-blocking mode: "
228
- "cannot set socket flags",
229
- e);
230
- }
231
- }
232
-
233
- int
234
- callAccept4(int sock, struct sockaddr *addr, socklen_t *addr_len, int options) {
235
- #if defined(HAVE_ACCEPT4)
236
- int ret;
237
- do {
238
- ret = ::accept4(sock, addr, addr_len, options);
239
- } while (ret == -1 && errno == EINTR);
240
- return ret;
241
- #else
242
- errno = ENOSYS;
243
- return -1;
244
- #endif
245
- }
176
+ /****** Server socket creation ******/
246
177
 
247
178
  int
248
179
  createServer(const StaticString &address, unsigned int backlogSize, bool autoDelete,
@@ -285,7 +216,7 @@ createUnixServer(const StaticString &filename, unsigned int backlogSize, bool au
285
216
  throw SystemException("Cannot create a Unix socket file descriptor", e);
286
217
  }
287
218
 
288
- FdGuard guard(fd, file, line, true);
219
+ FdGuard guard(fd, file, line);
289
220
  addr.sun_family = AF_LOCAL;
290
221
  strncpy(addr.sun_path, filename.c_str(), filename.size());
291
222
  addr.sun_path[filename.size()] = '\0';
@@ -376,7 +307,7 @@ createTcpServer(const char *address, unsigned short port, unsigned int backlogSi
376
307
  }
377
308
  // Ignore SO_REUSEADDR error, it's not fatal.
378
309
 
379
- FdGuard guard(fd, file, line, true);
310
+ FdGuard guard(fd, file, line);
380
311
  if (family == AF_INET) {
381
312
  ret = syscalls::bind(fd, (const struct sockaddr *) &addr.v4, sizeof(struct sockaddr_in));
382
313
  } else {
@@ -408,6 +339,9 @@ createTcpServer(const char *address, unsigned short port, unsigned int backlogSi
408
339
  return fd;
409
340
  }
410
341
 
342
+
343
+ /****** Socket connection establishment (blocking) ******/
344
+
411
345
  int
412
346
  connectToServer(const StaticString &address, const char *file, unsigned int line) {
413
347
  TRACE_POINT();
@@ -436,7 +370,7 @@ connectToUnixServer(const StaticString &filename, const char *file,
436
370
  throw SystemException("Cannot create a Unix socket file descriptor", e);
437
371
  }
438
372
 
439
- FdGuard guard(fd, file, line, true);
373
+ FdGuard guard(fd, file, line);
440
374
  int ret;
441
375
  struct sockaddr_un addr;
442
376
 
@@ -486,54 +420,6 @@ connectToUnixServer(const StaticString &filename, const char *file,
486
420
  abort(); // Never reached.
487
421
  }
488
422
 
489
- void
490
- setupNonBlockingUnixSocket(NUnix_State &state, const StaticString &filename,
491
- const char *file, unsigned int line)
492
- {
493
- state.fd.assign(syscalls::socket(PF_UNIX, SOCK_STREAM, 0), file, line);
494
- if (state.fd == -1) {
495
- int e = errno;
496
- throw SystemException("Cannot create a Unix socket file descriptor", e);
497
- }
498
-
499
- state.filename = filename;
500
- setNonBlocking(state.fd);
501
- }
502
-
503
- bool
504
- connectToUnixServer(NUnix_State &state) {
505
- struct sockaddr_un addr;
506
- int ret;
507
-
508
- if (state.filename.size() > sizeof(addr.sun_path) - 1) {
509
- string message = "Cannot connect to Unix socket '";
510
- message.append(state.filename.data(), state.filename.size());
511
- message.append("': filename is too long.");
512
- throw RuntimeException(message);
513
- }
514
-
515
- addr.sun_family = AF_UNIX;
516
- memcpy(addr.sun_path, state.filename.data(), state.filename.size());
517
- addr.sun_path[state.filename.size()] = '\0';
518
-
519
- ret = syscalls::connect(state.fd, (const sockaddr *) &addr, sizeof(addr));
520
- if (ret == -1) {
521
- if (errno == EINPROGRESS || errno == EWOULDBLOCK) {
522
- return false;
523
- } else if (errno == EISCONN) {
524
- return true;
525
- } else {
526
- int e = errno;
527
- string message = "Cannot connect to Unix socket '";
528
- message.append(state.filename.data(), state.filename.size());
529
- message.append("'");
530
- throw SystemException(message, e);
531
- }
532
- } else {
533
- return true;
534
- }
535
- }
536
-
537
423
  int
538
424
  connectToTcpServer(const StaticString &hostname, unsigned int port,
539
425
  const char *file, unsigned int line)
@@ -591,145 +477,285 @@ connectToTcpServer(const StaticString &hostname, unsigned int port,
591
477
  return fd;
592
478
  }
593
479
 
594
- void
595
- setupNonBlockingTcpSocket(NTCP_State &state, const StaticString &hostname, int port,
596
- const char *file, unsigned int line)
597
- {
480
+
481
+ /****** Socket connection establishment (non-blocking) ******/
482
+
483
+ std::pair<int, bool>
484
+ createNonBlockingSocketConnection(const StaticString &address, const char *file, unsigned int line) {
485
+ TRACE_POINT();
486
+ switch (getSocketAddressType(address)) {
487
+ case SAT_UNIX:
488
+ return createNonBlockingUnixSocketConnection(parseUnixSocketAddress(address), file, line);
489
+ case SAT_TCP: {
490
+ string host;
491
+ unsigned short port;
492
+
493
+ parseTcpSocketAddress(address, host, port);
494
+ return createNonBlockingTcpSocketConnection(host, port, file, line);
495
+ }
496
+ default:
497
+ throw ArgumentException(string("Unknown address type for '") + address + "'");
498
+ }
499
+ }
500
+
501
+ std::pair<int, bool>
502
+ createNonBlockingUnixSocketConnection(const StaticString &filename, const char *file, unsigned int line) {
503
+ struct sockaddr_un addr;
504
+
505
+ if (filename.size() > sizeof(addr.sun_path) - 1) {
506
+ string message = "Cannot connect to Unix socket '";
507
+ message.append(filename.data(), filename.size());
508
+ message.append("': filename is too long.");
509
+ throw ArgumentException(message);
510
+ }
511
+
512
+
513
+ int fd = syscalls::socket(PF_UNIX, SOCK_STREAM, 0);
514
+ if (fd == -1) {
515
+ int e = errno;
516
+ throw SystemException("Cannot create a Unix socket file descriptor", e);
517
+ }
518
+
598
519
  int ret;
520
+ FdGuard guard(fd, nullptr, 0);
521
+ P_LOG_FILE_DESCRIPTOR_OPEN4(fd, file, line, "NonBlockingUnixSocketConnection");
522
+ setNonBlocking(fd);
599
523
 
600
- memset(&state.hints, 0, sizeof(state.hints));
601
- state.hints.ai_family = PF_UNSPEC;
602
- state.hints.ai_socktype = SOCK_STREAM;
603
- ret = getaddrinfo(hostname.toString().c_str(), toString(port).c_str(),
604
- &state.hints, &state.res);
524
+ addr.sun_family = AF_UNIX;
525
+ memcpy(addr.sun_path, filename.data(), filename.size());
526
+ addr.sun_path[filename.size()] = '\0';
527
+
528
+ ret = syscalls::connect(fd, (const sockaddr *) &addr, sizeof(addr));
529
+ if (ret == -1) {
530
+ if (errno == EINPROGRESS || errno == EWOULDBLOCK) {
531
+ guard.clear();
532
+ return std::make_pair(fd, false);
533
+ } else if (errno == EISCONN) {
534
+ guard.clear();
535
+ return std::make_pair(fd, true);
536
+ } else {
537
+ int e = errno;
538
+ string message = "Cannot connect to Unix socket '";
539
+ message.append(filename.data(), filename.size());
540
+ message.append("'");
541
+ throw SystemException(message, e);
542
+ }
543
+ } else {
544
+ guard.clear();
545
+ return std::make_pair(fd, true);
546
+ }
547
+ }
548
+
549
+ std::pair<int, bool>
550
+ createNonBlockingTcpSocketConnection(const StaticString &hostname, unsigned int port, const char *file, unsigned int line) {
551
+ const string hostnameCopy = string(hostname.data(), hostname.size());
552
+ const string portString = toString(port);
553
+ struct addrinfo hints, *res;
554
+ int ret;
555
+
556
+ memset(&hints, 0, sizeof(hints));
557
+ hints.ai_family = PF_UNSPEC;
558
+ hints.ai_socktype = SOCK_STREAM;
559
+ ret = getaddrinfo(hostnameCopy.c_str(), portString.c_str(),
560
+ &hints, &res);
605
561
  if (ret != 0) {
606
562
  string message = "Cannot resolve IP address '";
607
563
  message.append(hostname.data(), hostname.size());
608
564
  message.append(":");
609
- message.append(toString(port));
565
+ message.append(portString);
610
566
  message.append("': ");
611
567
  message.append(gai_strerror(ret));
612
568
  throw IOException(message);
613
569
  }
614
570
 
615
- state.fd.assign(syscalls::socket(PF_INET, SOCK_STREAM, 0), file, line);
616
- if (state.fd == -1) {
571
+
572
+ int fd = syscalls::socket(PF_INET, SOCK_STREAM, 0);
573
+ if (fd == -1) {
617
574
  int e = errno;
618
575
  throw SystemException("Cannot create a TCP socket file descriptor", e);
619
576
  }
620
577
 
621
- state.hostname = hostname;
622
- state.port = port;
623
- setNonBlocking(state.fd);
624
- }
578
+ FdGuard guard(fd, nullptr, 0);
579
+ P_LOG_FILE_DESCRIPTOR_OPEN4(fd, file, line, "NonBlockingTcpSocketConnection");
580
+ setNonBlocking(fd);
625
581
 
626
- bool
627
- connectToTcpServer(NTCP_State &state) {
628
- int ret;
629
582
 
630
- ret = syscalls::connect(state.fd, state.res->ai_addr, state.res->ai_addrlen);
583
+ ret = syscalls::connect(fd, res->ai_addr, res->ai_addrlen);
631
584
  if (ret == -1) {
632
585
  if (errno == EINPROGRESS || errno == EWOULDBLOCK) {
633
- return false;
586
+ guard.clear();
587
+ return make_pair(fd, false);
634
588
  } else if (errno == EISCONN) {
635
- freeaddrinfo(state.res);
636
- state.res = NULL;
637
- return true;
589
+ freeaddrinfo(res);
590
+ guard.clear();
591
+ return make_pair(fd, true);
638
592
  } else {
639
593
  int e = errno;
640
594
  string message = "Cannot connect to TCP socket '";
641
- message.append(state.hostname);
595
+ message.append(hostname);
642
596
  message.append(":");
643
- message.append(toString(state.port));
597
+ message.append(portString);
644
598
  message.append("'");
645
599
  throw SystemException(message, e);
646
600
  }
647
601
  } else {
648
- freeaddrinfo(state.res);
649
- state.res = NULL;
650
- return true;
602
+ freeaddrinfo(res);
603
+ guard.clear();
604
+ return make_pair(fd, true);
651
605
  }
652
606
  }
653
607
 
654
- NConnect_State::NConnect_State(const StaticString &address, const char *file, unsigned int line)
608
+
609
+ /****** Scope guards ******/
610
+
611
+ FdGuard::FdGuard(FdGuard &&other)
612
+ : mFd(other.mFd)
655
613
  {
656
- TRACE_POINT();
657
- type = getSocketAddressType(address);
658
- switch (type) {
659
- case SAT_UNIX:
660
- setupNonBlockingUnixSocket(s_unix, parseUnixSocketAddress(address),
661
- file, line);
662
- break;
663
- case SAT_TCP: {
664
- string host;
665
- unsigned short port;
614
+ other.mFd = -1;
615
+ }
666
616
 
667
- parseTcpSocketAddress(address, host, port);
668
- setupNonBlockingTcpSocket(s_tcp, host, port, file, line);
669
- break;
617
+ FdGuard::FdGuard(int fd, const char *sourceFile, unsigned int sourceLine)
618
+ : mFd(fd)
619
+ {
620
+ if (mFd != -1 && sourceFile != nullptr) {
621
+ P_LOG_FILE_DESCRIPTOR_OPEN3(fd, sourceFile, sourceLine);
670
622
  }
671
- default:
672
- throw ArgumentException(string("Unknown address type for '") + address + "'");
623
+ }
624
+
625
+ FdGuard::~FdGuard() noexcept(false) {
626
+ if (mFd != -1) {
627
+ try {
628
+ safelyClose(mFd);
629
+ } catch (const std::exception &e) {
630
+ bool uncaughtException =
631
+ #if __cplusplus >= 201703L
632
+ std::uncaught_exceptions() > 0;
633
+ #else
634
+ std::uncaught_exception();
635
+ #endif
636
+ if (uncaughtException) {
637
+ P_WARN("Error closing file descriptor " << mFd << ": " << e.what());
638
+ return;
639
+ } else {
640
+ throw e;
641
+ }
642
+ }
643
+ P_LOG_FILE_DESCRIPTOR_CLOSE(mFd);
673
644
  }
674
645
  }
675
646
 
676
- bool
677
- NConnect_State::connectToServer() {
678
- switch (type) {
679
- case SAT_UNIX:
680
- return connectToUnixServer(s_unix);
681
- case SAT_TCP:
682
- return connectToTcpServer(s_tcp);
683
- default:
684
- throw RuntimeException("Unknown address type");
647
+ FdGuard &
648
+ FdGuard::operator=(FdGuard &&other) {
649
+ if (this != &other) {
650
+ if (mFd != -1) {
651
+ safelyClose(mFd);
652
+ P_LOG_FILE_DESCRIPTOR_CLOSE(mFd);
653
+ }
654
+ mFd = other.mFd;
655
+ other.mFd = -1;
685
656
  }
657
+ return *this;
686
658
  }
687
659
 
688
- FileDescriptor &
689
- NConnect_State::getFd() {
690
- switch (type) {
691
- case SAT_UNIX:
692
- return s_unix.fd;
693
- case SAT_TCP:
694
- return s_tcp.fd;
695
- default:
696
- throw RuntimeException("Unknown address type");
660
+ void
661
+ FdGuard::clear() noexcept {
662
+ mFd = -1;
663
+ }
664
+
665
+ void
666
+ FdGuard::runNow() noexcept(false) {
667
+ if (mFd != -1) {
668
+ safelyClose(mFd);
669
+ P_LOG_FILE_DESCRIPTOR_CLOSE(mFd);
670
+ mFd = -1;
697
671
  }
698
672
  }
699
673
 
700
- NUnix_State &
701
- NConnect_State::asNUnix_State() {
702
- // When we're ready for C++14:
703
- // if (type == SAT_UNIX) {
704
- // return *reinterpret_cast<NUnix_State *>(storage);
705
- // } else {
706
- // P_BUG("Address type is not TCP");
707
- // }
708
- return s_unix;
674
+
675
+ /****** Other ******/
676
+
677
+ bool
678
+ purgeStdio(FILE *f) {
679
+ #if defined(HAVE_FPURGE)
680
+ fpurge(f);
681
+ return true;
682
+ #elif defined(HAVE___FPURGE)
683
+ __fpurge(f);
684
+ return true;
685
+ #else
686
+ return false;
687
+ #endif
709
688
  }
710
689
 
711
- NTCP_State &
712
- NConnect_State::asNTCP_State() {
713
- // When we're ready for C++14:
714
- // if (type == SAT_TCP) {
715
- // return *reinterpret_cast<NTCP_State *>(storage);
716
- // } else {
717
- // P_BUG("Address type is not TCP");
718
- // }
719
- return s_tcp;
690
+ void
691
+ setBlocking(int fd) {
692
+ int flags, ret;
693
+
694
+ do {
695
+ flags = fcntl(fd, F_GETFL);
696
+ } while (flags == -1 && errno == EINTR);
697
+ if (flags == -1) {
698
+ int e = errno;
699
+ throw SystemException("Cannot set socket to blocking mode: "
700
+ "cannot get socket flags",
701
+ e);
702
+ }
703
+ do {
704
+ ret = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
705
+ } while (ret == -1 && errno == EINTR);
706
+ if (ret == -1) {
707
+ int e = errno;
708
+ throw SystemException("Cannot set socket to blocking mode: "
709
+ "cannot set socket flags",
710
+ e);
711
+ }
712
+ }
713
+
714
+ void
715
+ setNonBlocking(int fd) {
716
+ int flags, ret;
717
+
718
+ do {
719
+ flags = fcntl(fd, F_GETFL);
720
+ } while (flags == -1 && errno == EINTR);
721
+ if (flags == -1) {
722
+ int e = errno;
723
+ throw SystemException("Cannot set socket to non-blocking mode: "
724
+ "cannot get socket flags",
725
+ e);
726
+ }
727
+ do {
728
+ ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
729
+ } while (ret == -1 && errno == EINTR);
730
+ if (ret == -1) {
731
+ int e = errno;
732
+ throw SystemException("Cannot set socket to non-blocking mode: "
733
+ "cannot set socket flags",
734
+ e);
735
+ }
736
+ }
737
+
738
+ int
739
+ callAccept4(int sock, struct sockaddr *addr, socklen_t *addr_len, int options) {
740
+ #if defined(HAVE_ACCEPT4)
741
+ int ret;
742
+ do {
743
+ ret = ::accept4(sock, addr, addr_len, options);
744
+ } while (ret == -1 && errno == EINTR);
745
+ return ret;
746
+ #else
747
+ errno = ENOSYS;
748
+ return -1;
749
+ #endif
720
750
  }
721
751
 
722
752
  bool
723
753
  pingTcpServer(const StaticString &host, unsigned int port, unsigned long long *timeout) {
724
754
  TRACE_POINT();
725
- NTCP_State state;
726
-
727
- setupNonBlockingTcpSocket(state, host, port, __FILE__, __LINE__);
755
+ std::pair<int, bool> nbcResult;
728
756
 
729
757
  try {
730
- if (connectToTcpServer(state)) {
731
- return true;
732
- }
758
+ nbcResult = createNonBlockingTcpSocketConnection(host, port, __FILE__, __LINE__);
733
759
  } catch (const SystemException &e) {
734
760
  if (e.code() == ECONNREFUSED) {
735
761
  return false;
@@ -737,13 +763,17 @@ pingTcpServer(const StaticString &host, unsigned int port, unsigned long long *t
737
763
  throw e;
738
764
  }
739
765
  }
766
+ FdGuard guard(nbcResult.first, nullptr, 0);
767
+ if (nbcResult.second) {
768
+ return true;
769
+ }
740
770
 
741
771
  // Cannot connect to the port yet, but that may not mean the
742
772
  // port is unavailable. So poll the socket.
743
773
 
744
774
  bool connectable;
745
775
  try {
746
- connectable = waitUntilWritable(state.fd, timeout);
776
+ connectable = waitUntilWritable(nbcResult.first, timeout);
747
777
  } catch (const SystemException &e) {
748
778
  throw SystemException("Error polling TCP socket "
749
779
  + host + ":" + toString(port), e.code());
@@ -753,24 +783,21 @@ pingTcpServer(const StaticString &host, unsigned int port, unsigned long long *t
753
783
  return false;
754
784
  }
755
785
 
756
- // Try to connect the socket one last time.
786
+ // Now check the final connection establishment status.
757
787
 
758
- try {
759
- return connectToTcpServer(state);
760
- } catch (const SystemException &e) {
761
- if (e.code() == ECONNREFUSED) {
762
- return false;
763
- } else if (e.code() == EISCONN || e.code() == EINVAL) {
764
- #ifdef __FreeBSD__
765
- // Work around bug in FreeBSD (discovered on
766
- // January 20 2013 in daemon_controller)
767
- return false;
768
- #else
769
- throw e;
770
- #endif
771
- } else {
772
- throw e;
773
- }
788
+ int connectError = 0;
789
+ socklen_t connectErrorLen = sizeof(connectError);
790
+ if (getsockopt(nbcResult.first, SOL_SOCKET, SO_ERROR, &connectError, &connectErrorLen) == -1) {
791
+ throw SystemException("Error checking TCP socket " + host + ":" + toString(port)
792
+ + " connection establishment status", connectError);
793
+ }
794
+ if (connectError == 0) {
795
+ return true;
796
+ } else if (connectError == ECONNREFUSED) {
797
+ return false;
798
+ } else {
799
+ throw SystemException("Error connecting to TCP socket " + host + ":"
800
+ + toString(port), connectError);
774
801
  }
775
802
  }
776
803