1 //===-- ConnectionFileDescriptorPosix.cpp -----------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #if defined(__APPLE__)
11 // Enable this special support for Apple builds where we can have unlimited
12 // select bounds. We tried switching to poll() and kqueue and we were panicing
13 // the kernel, so we have to stick with select for now.
14 #define _DARWIN_UNLIMITED_SELECT
17 #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
18 #include "lldb/Host/Config.h"
19 #include "lldb/Host/IOObject.h"
20 #include "lldb/Host/SocketAddress.h"
21 #include "lldb/Host/Socket.h"
22 #include "lldb/Host/StringConvert.h"
29 #include <sys/types.h>
31 #ifndef LLDB_DISABLE_POSIX
38 // Other libraries and framework includes
39 #include "llvm/Support/ErrorHandling.h"
40 #if defined(__APPLE__)
41 #include "llvm/ADT/SmallVector.h"
44 #include "lldb/Core/Communication.h"
45 #include "lldb/Core/Log.h"
46 #include "lldb/Core/StreamString.h"
47 #include "lldb/Core/Timer.h"
48 #include "lldb/Host/Host.h"
49 #include "lldb/Host/Socket.h"
50 #include "lldb/Host/common/TCPSocket.h"
51 #include "lldb/Interpreter/Args.h"
54 using namespace lldb_private;
56 const char* ConnectionFileDescriptor::LISTEN_SCHEME = "listen";
57 const char* ConnectionFileDescriptor::ACCEPT_SCHEME = "accept";
58 const char* ConnectionFileDescriptor::UNIX_ACCEPT_SCHEME = "unix-accept";
59 const char* ConnectionFileDescriptor::CONNECT_SCHEME = "connect";
60 const char* ConnectionFileDescriptor::TCP_CONNECT_SCHEME = "tcp-connect";
61 const char* ConnectionFileDescriptor::UDP_SCHEME = "udp";
62 const char* ConnectionFileDescriptor::UNIX_CONNECT_SCHEME = "unix-connect";
63 const char* ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME = "unix-abstract-connect";
64 const char* ConnectionFileDescriptor::FD_SCHEME = "fd";
65 const char* ConnectionFileDescriptor::FILE_SCHEME = "file";
70 GetURLAddress(const char *url, const char *scheme)
72 const auto prefix = std::string(scheme) + "://";
73 if (strstr(url, prefix.c_str()) != url)
76 return url + prefix.size();
81 ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit)
85 m_shutting_down(false),
86 m_waiting_for_accept(false),
87 m_child_processes_inherit(child_processes_inherit)
89 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
91 log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", static_cast<void *>(this));
94 ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd)
98 m_shutting_down(false),
99 m_waiting_for_accept(false),
100 m_child_processes_inherit(false)
102 m_write_sp.reset(new File(fd, owns_fd));
103 m_read_sp.reset(new File(fd, false));
105 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
107 log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)",
108 static_cast<void *>(this), fd, owns_fd);
112 ConnectionFileDescriptor::ConnectionFileDescriptor(Socket *socket)
116 m_shutting_down(false),
117 m_waiting_for_accept(false),
118 m_child_processes_inherit(false)
120 InitializeSocket(socket);
123 ConnectionFileDescriptor::~ConnectionFileDescriptor()
125 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
127 log->Printf("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", static_cast<void *>(this));
133 ConnectionFileDescriptor::OpenCommandPipe()
137 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
138 // Make the command file descriptor here:
139 Error result = m_pipe.CreateNew(m_child_processes_inherit);
140 if (!result.Success())
143 log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not make pipe: %s", static_cast<void *>(this),
149 log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success readfd=%d writefd=%d", static_cast<void *>(this),
150 m_pipe.GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor());
155 ConnectionFileDescriptor::CloseCommandPipe()
157 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
159 log->Printf("%p ConnectionFileDescriptor::CloseCommandPipe()", static_cast<void *>(this));
165 ConnectionFileDescriptor::IsConnected() const
167 return (m_read_sp && m_read_sp->IsValid()) || (m_write_sp && m_write_sp->IsValid());
171 ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr)
173 std::lock_guard<std::recursive_mutex> guard(m_mutex);
174 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
176 log->Printf("%p ConnectionFileDescriptor::Connect (url = '%s')", static_cast<void *>(this), s);
182 const char *addr = nullptr;
183 if ((addr = GetURLAddress(s, LISTEN_SCHEME)))
185 // listen://HOST:PORT
186 return SocketListenAndAccept(addr, error_ptr);
188 else if ((addr = GetURLAddress(s, ACCEPT_SCHEME)))
191 return NamedSocketAccept(addr, error_ptr);
193 else if ((addr = GetURLAddress(s, UNIX_ACCEPT_SCHEME)))
196 return NamedSocketAccept(addr, error_ptr);
198 else if ((addr = GetURLAddress(s, CONNECT_SCHEME)))
200 return ConnectTCP(addr, error_ptr);
202 else if ((addr = GetURLAddress(s, TCP_CONNECT_SCHEME)))
204 return ConnectTCP(addr, error_ptr);
206 else if ((addr = GetURLAddress(s, UDP_SCHEME)))
208 return ConnectUDP(addr, error_ptr);
210 else if ((addr = GetURLAddress(s, UNIX_CONNECT_SCHEME)))
212 // unix-connect://SOCKNAME
213 return NamedSocketConnect(addr, error_ptr);
215 else if ((addr = GetURLAddress(s, UNIX_ABSTRACT_CONNECT_SCHEME)))
217 // unix-abstract-connect://SOCKNAME
218 return UnixAbstractSocketConnect(addr, error_ptr);
220 #ifndef LLDB_DISABLE_POSIX
221 else if ((addr = GetURLAddress(s, FD_SCHEME)))
223 // Just passing a native file descriptor within this current process
224 // that is already opened (possibly from a service or other source).
225 bool success = false;
226 int fd = StringConvert::ToSInt32(addr, -1, 0, &success);
230 // We have what looks to be a valid file descriptor, but we
231 // should make sure it is. We currently are doing this by trying to
232 // get the flags from the file descriptor and making sure it
235 int flags = ::fcntl(fd, F_GETFL, 0);
236 if (flags == -1 || errno == EBADF)
239 error_ptr->SetErrorStringWithFormat("stale file descriptor: %s", s);
242 return eConnectionStatusError;
246 // Don't take ownership of a file descriptor that gets passed
247 // to us since someone else opened the file descriptor and
249 // TODO: Since are using a URL to open connection we should
250 // eventually parse options using the web standard where we
251 // have "fd://123?opt1=value;opt2=value" and we can have an
252 // option be "owns=1" or "owns=0" or something like this to
253 // allow us to specify this. For now, we assume we must
254 // assume we don't own it.
256 std::unique_ptr<TCPSocket> tcp_socket;
257 tcp_socket.reset(new TCPSocket(fd, false));
258 // Try and get a socket option from this file descriptor to
259 // see if this is a socket and set m_is_socket accordingly.
261 bool is_socket = !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
264 m_read_sp = std::move(tcp_socket);
265 m_write_sp = m_read_sp;
269 m_read_sp.reset(new File(fd, false));
270 m_write_sp.reset(new File(fd, false));
273 return eConnectionStatusSuccess;
278 error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"", s);
281 return eConnectionStatusError;
283 else if ((addr = GetURLAddress(s, FILE_SCHEME)))
286 const char *path = addr;
290 fd = ::open(path, O_RDWR);
291 } while (fd == -1 && errno == EINTR);
296 error_ptr->SetErrorToErrno();
297 return eConnectionStatusError;
302 // Set up serial terminal emulation
303 struct termios options;
304 ::tcgetattr(fd, &options);
306 // Set port speed to maximum
307 ::cfsetospeed(&options, B115200);
308 ::cfsetispeed(&options, B115200);
310 // Raw input, disable echo and signals
311 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
313 // Make sure only one character is needed to return from a read
314 options.c_cc[VMIN] = 1;
315 options.c_cc[VTIME] = 0;
317 ::tcsetattr(fd, TCSANOW, &options);
320 int flags = ::fcntl(fd, F_GETFL, 0);
323 if ((flags & O_NONBLOCK) == 0)
326 ::fcntl(fd, F_SETFL, flags);
329 m_read_sp.reset(new File(fd, true));
330 m_write_sp.reset(new File(fd, false));
331 return eConnectionStatusSuccess;
335 error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", s);
336 return eConnectionStatusError;
339 error_ptr->SetErrorString("invalid connect arguments");
340 return eConnectionStatusError;
344 ConnectionFileDescriptor::InterruptRead()
346 size_t bytes_written = 0;
347 Error result = m_pipe.Write("i", 1, bytes_written);
348 return result.Success();
352 ConnectionFileDescriptor::Disconnect(Error *error_ptr)
354 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
356 log->Printf("%p ConnectionFileDescriptor::Disconnect ()", static_cast<void *>(this));
358 ConnectionStatus status = eConnectionStatusSuccess;
363 log->Printf("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", static_cast<void *>(this));
364 return eConnectionStatusSuccess;
367 if (m_read_sp && m_read_sp->IsValid() && m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
368 static_cast<Socket &>(*m_read_sp).PreDisconnect();
370 // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite likely
371 // because somebody is doing a blocking read on our file descriptor. If that's the case,
372 // then send the "q" char to the command file channel so the read will wake up and the connection
373 // will then know to shut down.
375 m_shutting_down = true;
377 std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock);
378 if (!locker.try_lock())
380 if (m_pipe.CanWrite())
382 size_t bytes_written = 0;
383 Error result = m_pipe.Write("q", 1, bytes_written);
385 log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, error = '%s'.",
386 static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString());
390 log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.",
391 static_cast<void *>(this));
396 Error error = m_read_sp->Close();
397 Error error2 = m_write_sp->Close();
398 if (error.Fail() || error2.Fail())
399 status = eConnectionStatusError;
401 *error_ptr = error.Fail() ? error : error2;
403 // Close any pipes we were using for async interrupts
407 m_shutting_down = false;
412 ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr)
414 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
416 std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock);
417 if (!locker.try_lock())
420 log->Printf("%p ConnectionFileDescriptor::Read () failed to get the connection lock.", static_cast<void *>(this));
422 error_ptr->SetErrorString("failed to get the connection lock for read.");
424 status = eConnectionStatusTimedOut;
430 status = eConnectionStatusError;
434 status = BytesAvailable(timeout_usec, error_ptr);
435 if (status != eConnectionStatusSuccess)
439 size_t bytes_read = dst_len;
440 error = m_read_sp->Read(dst, bytes_read);
444 log->Printf("%p ConnectionFileDescriptor::Read() fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s",
445 static_cast<void *>(this), static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), static_cast<void *>(dst),
446 static_cast<uint64_t>(dst_len), static_cast<uint64_t>(bytes_read), error.AsCString());
451 error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers.
452 status = eConnectionStatusEndOfFile;
460 uint32_t error_value = error.GetError();
463 case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read.
464 if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
465 status = eConnectionStatusTimedOut;
467 status = eConnectionStatusSuccess;
470 case EFAULT: // Buf points outside the allocated address space.
471 case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal.
472 case EINVAL: // The pointer associated with fildes was negative.
473 case EIO: // An I/O error occurred while reading from the file system.
474 // The process group is orphaned.
475 // The file is a regular file, nbyte is greater than 0,
476 // the starting position is before the end-of-file, and
477 // the starting position is greater than or equal to the
478 // offset maximum established for the open file
479 // descriptor associated with fildes.
480 case EISDIR: // An attempt is made to read a directory.
481 case ENOBUFS: // An attempt to allocate a memory buffer fails.
482 case ENOMEM: // Insufficient memory is available.
483 status = eConnectionStatusError;
484 break; // Break to close....
486 case ENOENT: // no such file or directory
487 case EBADF: // fildes is not a valid file or socket descriptor open for reading.
488 case ENXIO: // An action is requested of a device that does not exist..
489 // A requested action cannot be performed by the device.
490 case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket.
491 case ENOTCONN: // A read is attempted on an unconnected socket.
492 status = eConnectionStatusLostConnection;
493 break; // Break to close....
495 case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket.
496 status = eConnectionStatusTimedOut;
501 log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", static_cast<void *>(this),
502 strerror(error_value));
503 status = eConnectionStatusError;
504 break; // Break to close....
513 ConnectionFileDescriptor::Write(const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
515 Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
517 log->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", static_cast<void *>(this),
518 static_cast<const void *>(src), static_cast<uint64_t>(src_len));
523 error_ptr->SetErrorString("not connected");
524 status = eConnectionStatusNoConnection;
530 size_t bytes_sent = src_len;
531 error = m_write_sp->Write(src, bytes_sent);
535 log->Printf("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",
536 static_cast<void *>(this), static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), static_cast<const void *>(src),
537 static_cast<uint64_t>(src_len), static_cast<uint64_t>(bytes_sent), error.AsCString());
545 switch (error.GetError())
549 status = eConnectionStatusSuccess;
552 case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket.
553 case ENOTCONN: // A read is attempted on an unconnected socket.
554 status = eConnectionStatusLostConnection;
555 break; // Break to close....
558 status = eConnectionStatusError;
559 break; // Break to close....
565 status = eConnectionStatusSuccess;
570 ConnectionFileDescriptor::GetURI()
575 // This ConnectionFileDescriptor::BytesAvailable() uses select().
578 // - select is consistent across most unix platforms
579 // - The Apple specific version allows for unlimited fds in the fd_sets by
580 // setting the _DARWIN_UNLIMITED_SELECT define prior to including the
581 // required header files.
583 // - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE.
584 // This implementation will assert if it runs into that hard limit to let
585 // users know that another ConnectionFileDescriptor::BytesAvailable() should
586 // be used or a new version of ConnectionFileDescriptor::BytesAvailable()
587 // should be written for the system that is running into the limitations.
589 #if defined(__APPLE__)
590 #define FD_SET_DATA(fds) fds.data()
592 #define FD_SET_DATA(fds) &fds
596 ConnectionFileDescriptor::BytesAvailable(uint32_t timeout_usec, Error *error_ptr)
598 // Don't need to take the mutex here separately since we are only called from Read. If we
599 // ever get used more generally we will need to lock here as well.
601 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_CONNECTION));
603 log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", static_cast<void *>(this), timeout_usec);
605 struct timeval *tv_ptr;
607 if (timeout_usec == UINT32_MAX)
614 TimeValue time_value;
615 time_value.OffsetWithMicroSeconds(timeout_usec);
616 tv.tv_sec = time_value.seconds();
617 tv.tv_usec = time_value.microseconds();
621 // Make a copy of the file descriptors to make sure we don't
622 // have another thread change these values out from under us
623 // and cause problems in the loop below where like in FS_SET()
624 const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle();
625 const int pipe_fd = m_pipe.GetReadFileDescriptor();
627 if (handle != IOObject::kInvalidHandleValue)
629 #if defined(_MSC_VER)
630 // select() won't accept pipes on Windows. The entire Windows codepath needs to be
631 // converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least
632 // this will allow ::select() to not return an error.
633 const bool have_pipe_fd = false;
635 const bool have_pipe_fd = pipe_fd >= 0;
636 #if !defined(__APPLE__)
637 assert(handle < FD_SETSIZE);
639 assert(pipe_fd < FD_SETSIZE);
642 while (handle == m_read_sp->GetWaitableHandle())
644 const int nfds = std::max<int>(handle, pipe_fd) + 1;
645 #if defined(__APPLE__)
646 llvm::SmallVector<fd_set, 1> read_fds;
647 read_fds.resize((nfds / FD_SETSIZE) + 1);
648 for (size_t i = 0; i < read_fds.size(); ++i)
649 FD_ZERO(&read_fds[i]);
650 // FD_SET doesn't bounds check, it just happily walks off the end
651 // but we have taken care of making the extra storage with our
652 // SmallVector of fd_set objects
657 FD_SET(handle, FD_SET_DATA(read_fds));
659 FD_SET(pipe_fd, FD_SET_DATA(read_fds));
667 "%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
668 static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr));
670 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
671 static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr));
674 const int num_set_fds = ::select(nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr);
676 error.SetErrorToErrno();
683 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) "
685 static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr), num_set_fds,
688 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => "
690 static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr), num_set_fds, error.AsCString());
698 switch (error.GetError())
700 case EBADF: // One of the descriptor sets specified an invalid descriptor.
701 return eConnectionStatusLostConnection;
703 case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
704 default: // Other unknown error
705 return eConnectionStatusError;
707 case EAGAIN: // The kernel was (perhaps temporarily) unable to
708 // allocate the requested number of file descriptors,
709 // or we have non-blocking IO
710 case EINTR: // A signal was delivered before the time limit
711 // expired and before any of the selected events
713 break; // Lets keep reading to until we timeout
716 else if (num_set_fds == 0)
718 return eConnectionStatusTimedOut;
720 else if (num_set_fds > 0)
722 if (FD_ISSET(handle, FD_SET_DATA(read_fds)))
723 return eConnectionStatusSuccess;
724 if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds)))
726 // There is an interrupt or exit command in the command pipe
727 // Read the data from that pipe:
734 bytes_read = ::read(pipe_fd, buffer, sizeof(buffer));
735 } while (bytes_read < 0 && errno == EINTR);
741 log->Printf("%p ConnectionFileDescriptor::BytesAvailable() "
742 "got data: %c from the command channel.",
743 static_cast<void *>(this), buffer[0]);
744 return eConnectionStatusEndOfFile;
746 // Interrupt the current read
747 return eConnectionStatusInterrupted;
755 error_ptr->SetErrorString("not connected");
756 return eConnectionStatusLostConnection;
760 ConnectionFileDescriptor::NamedSocketAccept(const char *socket_name, Error *error_ptr)
762 Socket *socket = nullptr;
763 Error error = Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket);
766 m_write_sp.reset(socket);
767 m_read_sp = m_write_sp;
770 return eConnectionStatusError;
772 m_uri.assign(socket_name);
773 return eConnectionStatusSuccess;
777 ConnectionFileDescriptor::NamedSocketConnect(const char *socket_name, Error *error_ptr)
779 Socket *socket = nullptr;
780 Error error = Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket);
783 m_write_sp.reset(socket);
784 m_read_sp = m_write_sp;
787 return eConnectionStatusError;
789 m_uri.assign(socket_name);
790 return eConnectionStatusSuccess;
793 lldb::ConnectionStatus
794 ConnectionFileDescriptor::UnixAbstractSocketConnect(const char *socket_name, Error *error_ptr)
796 Socket *socket = nullptr;
797 Error error = Socket::UnixAbstractConnect(socket_name, m_child_processes_inherit, socket);
800 m_write_sp.reset(socket);
801 m_read_sp = m_write_sp;
804 return eConnectionStatusError;
806 m_uri.assign(socket_name);
807 return eConnectionStatusSuccess;
811 ConnectionFileDescriptor::SocketListenAndAccept(const char *s, Error *error_ptr)
813 m_port_predicate.SetValue(0, eBroadcastNever);
815 Socket *socket = nullptr;
816 m_waiting_for_accept = true;
817 Error error = Socket::TcpListen(s, m_child_processes_inherit, socket, &m_port_predicate);
821 return eConnectionStatusError;
823 std::unique_ptr<Socket> listening_socket_up;
825 listening_socket_up.reset(socket);
827 error = listening_socket_up->Accept(s, m_child_processes_inherit, socket);
828 listening_socket_up.reset();
832 return eConnectionStatusError;
834 InitializeSocket(socket);
835 return eConnectionStatusSuccess;
839 ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr)
841 Socket *socket = nullptr;
842 Error error = Socket::TcpConnect(s, m_child_processes_inherit, socket);
845 m_write_sp.reset(socket);
846 m_read_sp = m_write_sp;
849 return eConnectionStatusError;
852 return eConnectionStatusSuccess;
856 ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr)
858 Socket *send_socket = nullptr;
859 Socket *recv_socket = nullptr;
860 Error error = Socket::UdpConnect(s, m_child_processes_inherit, send_socket, recv_socket);
863 m_write_sp.reset(send_socket);
864 m_read_sp.reset(recv_socket);
867 return eConnectionStatusError;
870 return eConnectionStatusSuccess;
874 ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec)
876 uint16_t bound_port = 0;
877 if (timeout_sec == UINT32_MAX)
878 m_port_predicate.WaitForValueNotEqualTo(0, bound_port);
881 TimeValue timeout = TimeValue::Now();
882 timeout.OffsetWithSeconds(timeout_sec);
883 m_port_predicate.WaitForValueNotEqualTo(0, bound_port, &timeout);
889 ConnectionFileDescriptor::GetChildProcessesInherit() const
891 return m_child_processes_inherit;
895 ConnectionFileDescriptor::SetChildProcessesInherit(bool child_processes_inherit)
897 m_child_processes_inherit = child_processes_inherit;
901 ConnectionFileDescriptor::InitializeSocket(Socket* socket)
903 assert(socket->GetSocketProtocol() == Socket::ProtocolTcp);
904 TCPSocket* tcp_socket = static_cast<TCPSocket*>(socket);
906 m_write_sp.reset(socket);
907 m_read_sp = m_write_sp;
909 strm.Printf("connect://%s:%u",tcp_socket->GetRemoteIPAddress().c_str(), tcp_socket->GetRemotePortNumber());
910 m_uri.swap(strm.GetString());