180814287SRaphael Isemann //===-- ConnectionFileDescriptorPosix.cpp ---------------------------------===//
293a66fc1SZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
693a66fc1SZachary Turner //
793a66fc1SZachary Turner //===----------------------------------------------------------------------===//
893a66fc1SZachary Turner
993a66fc1SZachary Turner #if defined(__APPLE__)
1093a66fc1SZachary Turner // Enable this special support for Apple builds where we can have unlimited
1193a66fc1SZachary Turner // select bounds. We tried switching to poll() and kqueue and we were panicing
1293a66fc1SZachary Turner // the kernel, so we have to stick with select for now.
1393a66fc1SZachary Turner #define _DARWIN_UNLIMITED_SELECT
1493a66fc1SZachary Turner #endif
1593a66fc1SZachary Turner
16c34698a8SPavel Labath #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
1793a66fc1SZachary Turner #include "lldb/Host/Config.h"
1893a66fc1SZachary Turner #include "lldb/Host/Socket.h"
19b9c1b51eSKate Stone #include "lldb/Host/SocketAddress.h"
20c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
21ee1f578dSGreg Clayton #include "lldb/Utility/SelectHelper.h"
224ccd9954SPavel Labath #include "lldb/Utility/Timeout.h"
2393a66fc1SZachary Turner
2476e47d48SRaphael Isemann #include <cerrno>
2576e47d48SRaphael Isemann #include <cstdlib>
2676e47d48SRaphael Isemann #include <cstring>
2793a66fc1SZachary Turner #include <fcntl.h>
2893a66fc1SZachary Turner #include <sys/types.h>
2993a66fc1SZachary Turner
303011d55fSJonas Devlieghere #if LLDB_ENABLE_POSIX
3193a66fc1SZachary Turner #include <termios.h>
32b6dbe9a9SPavel Labath #include <unistd.h>
3393a66fc1SZachary Turner #endif
3493a66fc1SZachary Turner
35796ac80bSJonas Devlieghere #include <memory>
3654971856SOleksiy Vyalov #include <sstream>
3754971856SOleksiy Vyalov
3810c41f37SPavel Labath #include "llvm/Support/Errno.h"
3993a66fc1SZachary Turner #include "llvm/Support/ErrorHandling.h"
4093a66fc1SZachary Turner #if defined(__APPLE__)
4193a66fc1SZachary Turner #include "llvm/ADT/SmallVector.h"
4293a66fc1SZachary Turner #endif
4393a66fc1SZachary Turner #include "lldb/Host/Host.h"
4493a66fc1SZachary Turner #include "lldb/Host/Socket.h"
45e98628ceSOleksiy Vyalov #include "lldb/Host/common/TCPSocket.h"
46c9e6b701SPavel Labath #include "lldb/Host/common/UDPSocket.h"
476f9e6901SZachary Turner #include "lldb/Utility/Log.h"
48bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
4938d0632eSPavel Labath #include "lldb/Utility/Timer.h"
5093a66fc1SZachary Turner
5193a66fc1SZachary Turner using namespace lldb;
5293a66fc1SZachary Turner using namespace lldb_private;
5393a66fc1SZachary Turner
ConnectionFileDescriptor(bool child_processes_inherit)54477e42a6SOleksiy Vyalov ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit)
55b9c1b51eSKate Stone : Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
569494c510SJonas Devlieghere
57b9c1b51eSKate Stone m_child_processes_inherit(child_processes_inherit) {
58a007a6d8SPavel Labath Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object));
5963e5fb76SJonas Devlieghere LLDB_LOGF(log, "%p ConnectionFileDescriptor::ConnectionFileDescriptor ()",
60b9c1b51eSKate Stone static_cast<void *>(this));
6193a66fc1SZachary Turner }
6293a66fc1SZachary Turner
ConnectionFileDescriptor(int fd,bool owns_fd)6393a66fc1SZachary Turner ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd)
64b9c1b51eSKate Stone : Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
6558d28b93SMichał Górny m_child_processes_inherit(false) {
66fee461b1SMichał Górny m_io_sp =
67dcb0e687SMichał Górny std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, owns_fd);
6893a66fc1SZachary Turner
69a007a6d8SPavel Labath Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object));
7063e5fb76SJonas Devlieghere LLDB_LOGF(log,
7163e5fb76SJonas Devlieghere "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = "
72b9c1b51eSKate Stone "%i, owns_fd = %i)",
7316ff8604SSaleem Abdulrasool static_cast<void *>(this), fd, owns_fd);
7493a66fc1SZachary Turner OpenCommandPipe();
7593a66fc1SZachary Turner }
7693a66fc1SZachary Turner
ConnectionFileDescriptor(Socket * socket)77a0e70cd4SRobert Flack ConnectionFileDescriptor::ConnectionFileDescriptor(Socket *socket)
78b9c1b51eSKate Stone : Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
7958d28b93SMichał Górny m_child_processes_inherit(false) {
80a0e70cd4SRobert Flack InitializeSocket(socket);
81a0e70cd4SRobert Flack }
82a0e70cd4SRobert Flack
~ConnectionFileDescriptor()83b9c1b51eSKate Stone ConnectionFileDescriptor::~ConnectionFileDescriptor() {
84a007a6d8SPavel Labath Log *log(GetLog(LLDBLog::Connection | LLDBLog::Object));
8563e5fb76SJonas Devlieghere LLDB_LOGF(log, "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()",
86b9c1b51eSKate Stone static_cast<void *>(this));
87248a1305SKonrad Kleine Disconnect(nullptr);
8893a66fc1SZachary Turner CloseCommandPipe();
8993a66fc1SZachary Turner }
9093a66fc1SZachary Turner
OpenCommandPipe()91b9c1b51eSKate Stone void ConnectionFileDescriptor::OpenCommandPipe() {
9293a66fc1SZachary Turner CloseCommandPipe();
9393a66fc1SZachary Turner
94a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Connection);
9593a66fc1SZachary Turner // Make the command file descriptor here:
9697206d57SZachary Turner Status result = m_pipe.CreateNew(m_child_processes_inherit);
97b9c1b51eSKate Stone if (!result.Success()) {
9863e5fb76SJonas Devlieghere LLDB_LOGF(log,
9963e5fb76SJonas Devlieghere "%p ConnectionFileDescriptor::OpenCommandPipe () - could not "
100b9c1b51eSKate Stone "make pipe: %s",
101b9c1b51eSKate Stone static_cast<void *>(this), result.AsCString());
102b9c1b51eSKate Stone } else {
10363e5fb76SJonas Devlieghere LLDB_LOGF(log,
10463e5fb76SJonas Devlieghere "%p ConnectionFileDescriptor::OpenCommandPipe() - success "
105b9c1b51eSKate Stone "readfd=%d writefd=%d",
106b9c1b51eSKate Stone static_cast<void *>(this), m_pipe.GetReadFileDescriptor(),
107b9c1b51eSKate Stone m_pipe.GetWriteFileDescriptor());
10893a66fc1SZachary Turner }
10993a66fc1SZachary Turner }
11093a66fc1SZachary Turner
CloseCommandPipe()111b9c1b51eSKate Stone void ConnectionFileDescriptor::CloseCommandPipe() {
112a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Connection);
11363e5fb76SJonas Devlieghere LLDB_LOGF(log, "%p ConnectionFileDescriptor::CloseCommandPipe()",
114b9c1b51eSKate Stone static_cast<void *>(this));
11593a66fc1SZachary Turner
11693a66fc1SZachary Turner m_pipe.Close();
11793a66fc1SZachary Turner }
11893a66fc1SZachary Turner
IsConnected() const119b9c1b51eSKate Stone bool ConnectionFileDescriptor::IsConnected() const {
120fee461b1SMichał Górny return m_io_sp && m_io_sp->IsValid();
12193a66fc1SZachary Turner }
12293a66fc1SZachary Turner
Connect(llvm::StringRef path,Status * error_ptr)1233165945aSZachary Turner ConnectionStatus ConnectionFileDescriptor::Connect(llvm::StringRef path,
12497206d57SZachary Turner Status *error_ptr) {
125*9aa6a479SJonas Devlieghere return Connect(
126*9aa6a479SJonas Devlieghere path, [](llvm::StringRef) {}, error_ptr);
12758d28b93SMichał Górny }
12858d28b93SMichał Górny
12958d28b93SMichał Górny ConnectionStatus
Connect(llvm::StringRef path,socket_id_callback_type socket_id_callback,Status * error_ptr)13058d28b93SMichał Górny ConnectionFileDescriptor::Connect(llvm::StringRef path,
13158d28b93SMichał Górny socket_id_callback_type socket_id_callback,
13258d28b93SMichał Górny Status *error_ptr) {
13316ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_mutex);
134a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Connection);
13563e5fb76SJonas Devlieghere LLDB_LOGF(log, "%p ConnectionFileDescriptor::Connect (url = '%s')",
1363165945aSZachary Turner static_cast<void *>(this), path.str().c_str());
13793a66fc1SZachary Turner
13893a66fc1SZachary Turner OpenCommandPipe();
13993a66fc1SZachary Turner
1404b46a413SMichał Górny if (path.empty()) {
1414b46a413SMichał Górny if (error_ptr)
1424b46a413SMichał Górny error_ptr->SetErrorString("invalid connect arguments");
1434b46a413SMichał Górny return eConnectionStatusError;
1444b46a413SMichał Górny }
1454b46a413SMichał Górny
1464b46a413SMichał Górny llvm::StringRef scheme;
1474b46a413SMichał Górny std::tie(scheme, path) = path.split("://");
1484b46a413SMichał Górny
1493165945aSZachary Turner if (!path.empty()) {
1504b46a413SMichał Górny auto method =
1514b46a413SMichał Górny llvm::StringSwitch<ConnectionStatus (ConnectionFileDescriptor::*)(
15258d28b93SMichał Górny llvm::StringRef, socket_id_callback_type, Status *)>(scheme)
153e50f02baSMichał Górny .Case("listen", &ConnectionFileDescriptor::AcceptTCP)
1544b46a413SMichał Górny .Cases("accept", "unix-accept",
155e50f02baSMichał Górny &ConnectionFileDescriptor::AcceptNamedSocket)
15658d28b93SMichał Górny .Case("unix-abstract-accept",
157e50f02baSMichał Górny &ConnectionFileDescriptor::AcceptAbstractSocket)
1584b46a413SMichał Górny .Cases("connect", "tcp-connect",
1594b46a413SMichał Górny &ConnectionFileDescriptor::ConnectTCP)
1604b46a413SMichał Górny .Case("udp", &ConnectionFileDescriptor::ConnectUDP)
161e50f02baSMichał Górny .Case("unix-connect", &ConnectionFileDescriptor::ConnectNamedSocket)
1624b46a413SMichał Górny .Case("unix-abstract-connect",
163e50f02baSMichał Górny &ConnectionFileDescriptor::ConnectAbstractSocket)
1643011d55fSJonas Devlieghere #if LLDB_ENABLE_POSIX
1654b46a413SMichał Górny .Case("fd", &ConnectionFileDescriptor::ConnectFD)
1664b46a413SMichał Górny .Case("file", &ConnectionFileDescriptor::ConnectFile)
1674a7b4beaSMichał Górny .Case("serial", &ConnectionFileDescriptor::ConnectSerialPort)
16893a66fc1SZachary Turner #endif
1694b46a413SMichał Górny .Default(nullptr);
1704b46a413SMichał Górny
171e50f02baSMichał Górny if (method) {
172e50f02baSMichał Górny if (error_ptr)
173e50f02baSMichał Górny *error_ptr = Status();
17458d28b93SMichał Górny return (this->*method)(path, socket_id_callback, error_ptr);
1754b46a413SMichał Górny }
176e50f02baSMichał Górny }
1774b46a413SMichał Górny
17893a66fc1SZachary Turner if (error_ptr)
179b9c1b51eSKate Stone error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'",
1803165945aSZachary Turner path.str().c_str());
18193a66fc1SZachary Turner return eConnectionStatusError;
18293a66fc1SZachary Turner }
18393a66fc1SZachary Turner
InterruptRead()184b9c1b51eSKate Stone bool ConnectionFileDescriptor::InterruptRead() {
1850b9d3eefSZachary Turner size_t bytes_written = 0;
18697206d57SZachary Turner Status result = m_pipe.Write("i", 1, bytes_written);
1870b9d3eefSZachary Turner return result.Success();
18893a66fc1SZachary Turner }
18993a66fc1SZachary Turner
Disconnect(Status * error_ptr)19097206d57SZachary Turner ConnectionStatus ConnectionFileDescriptor::Disconnect(Status *error_ptr) {
191a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Connection);
19263e5fb76SJonas Devlieghere LLDB_LOGF(log, "%p ConnectionFileDescriptor::Disconnect ()",
193b9c1b51eSKate Stone static_cast<void *>(this));
19493a66fc1SZachary Turner
19593a66fc1SZachary Turner ConnectionStatus status = eConnectionStatusSuccess;
19693a66fc1SZachary Turner
197b9c1b51eSKate Stone if (!IsConnected()) {
19863e5fb76SJonas Devlieghere LLDB_LOGF(
19963e5fb76SJonas Devlieghere log, "%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect",
200b9c1b51eSKate Stone static_cast<void *>(this));
20193a66fc1SZachary Turner return eConnectionStatusSuccess;
20293a66fc1SZachary Turner }
20393a66fc1SZachary Turner
204fee461b1SMichał Górny if (m_io_sp->GetFdType() == IOObject::eFDTypeSocket)
205fee461b1SMichał Górny static_cast<Socket &>(*m_io_sp).PreDisconnect();
20693a66fc1SZachary Turner
20705097246SAdrian Prantl // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is
20805097246SAdrian Prantl // quite likely because somebody is doing a blocking read on our file
20905097246SAdrian Prantl // descriptor. If that's the case, then send the "q" char to the command
21005097246SAdrian Prantl // file channel so the read will wake up and the connection will then know to
21105097246SAdrian Prantl // shut down.
21216ff8604SSaleem Abdulrasool std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock);
213b9c1b51eSKate Stone if (!locker.try_lock()) {
214b9c1b51eSKate Stone if (m_pipe.CanWrite()) {
2150b9d3eefSZachary Turner size_t bytes_written = 0;
21697206d57SZachary Turner Status result = m_pipe.Write("q", 1, bytes_written);
21763e5fb76SJonas Devlieghere LLDB_LOGF(log,
21863e5fb76SJonas Devlieghere "%p ConnectionFileDescriptor::Disconnect(): Couldn't get "
219b9c1b51eSKate Stone "the lock, sent 'q' to %d, error = '%s'.",
220b9c1b51eSKate Stone static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(),
221b9c1b51eSKate Stone result.AsCString());
222b9c1b51eSKate Stone } else if (log) {
22363e5fb76SJonas Devlieghere LLDB_LOGF(log,
22463e5fb76SJonas Devlieghere "%p ConnectionFileDescriptor::Disconnect(): Couldn't get the "
225b9c1b51eSKate Stone "lock, but no command pipe is available.",
22693a66fc1SZachary Turner static_cast<void *>(this));
22793a66fc1SZachary Turner }
22816ff8604SSaleem Abdulrasool locker.lock();
22993a66fc1SZachary Turner }
23093a66fc1SZachary Turner
231ece176e0SJonas Devlieghere // Prevents reads and writes during shutdown.
232ece176e0SJonas Devlieghere m_shutting_down = true;
233ece176e0SJonas Devlieghere
234fee461b1SMichał Górny Status error = m_io_sp->Close();
235fee461b1SMichał Górny if (error.Fail())
23693a66fc1SZachary Turner status = eConnectionStatusError;
23793a66fc1SZachary Turner if (error_ptr)
238fee461b1SMichał Górny *error_ptr = error;
23993a66fc1SZachary Turner
2405df78fa3SGreg Clayton // Close any pipes we were using for async interrupts
2415df78fa3SGreg Clayton m_pipe.Close();
2425df78fa3SGreg Clayton
243eb303ee5SVince Harron m_uri.clear();
24493a66fc1SZachary Turner m_shutting_down = false;
24593a66fc1SZachary Turner return status;
24693a66fc1SZachary Turner }
24793a66fc1SZachary Turner
Read(void * dst,size_t dst_len,const Timeout<std::micro> & timeout,ConnectionStatus & status,Status * error_ptr)248b9c1b51eSKate Stone size_t ConnectionFileDescriptor::Read(void *dst, size_t dst_len,
2492f159a5fSPavel Labath const Timeout<std::micro> &timeout,
250b9c1b51eSKate Stone ConnectionStatus &status,
25197206d57SZachary Turner Status *error_ptr) {
252a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Connection);
25393a66fc1SZachary Turner
25416ff8604SSaleem Abdulrasool std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock);
255b9c1b51eSKate Stone if (!locker.try_lock()) {
25663e5fb76SJonas Devlieghere LLDB_LOGF(log,
25763e5fb76SJonas Devlieghere "%p ConnectionFileDescriptor::Read () failed to get the "
258b9c1b51eSKate Stone "connection lock.",
259b9c1b51eSKate Stone static_cast<void *>(this));
26093a66fc1SZachary Turner if (error_ptr)
26193a66fc1SZachary Turner error_ptr->SetErrorString("failed to get the connection lock for read.");
26293a66fc1SZachary Turner
26393a66fc1SZachary Turner status = eConnectionStatusTimedOut;
26493a66fc1SZachary Turner return 0;
26593a66fc1SZachary Turner }
26632c7265aSChaoren Lin
267b9c1b51eSKate Stone if (m_shutting_down) {
268ece176e0SJonas Devlieghere if (error_ptr)
269ece176e0SJonas Devlieghere error_ptr->SetErrorString("shutting down");
27032c7265aSChaoren Lin status = eConnectionStatusError;
27132c7265aSChaoren Lin return 0;
27232c7265aSChaoren Lin }
27393a66fc1SZachary Turner
2742f159a5fSPavel Labath status = BytesAvailable(timeout, error_ptr);
27593a66fc1SZachary Turner if (status != eConnectionStatusSuccess)
27693a66fc1SZachary Turner return 0;
27793a66fc1SZachary Turner
27897206d57SZachary Turner Status error;
279ef984e7dSPavel Labath size_t bytes_read = dst_len;
280fee461b1SMichał Górny error = m_io_sp->Read(dst, bytes_read);
281ef984e7dSPavel Labath
282b9c1b51eSKate Stone if (log) {
28363e5fb76SJonas Devlieghere LLDB_LOGF(log,
28463e5fb76SJonas Devlieghere "%p ConnectionFileDescriptor::Read() fd = %" PRIu64
285b9c1b51eSKate Stone ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s",
286b9c1b51eSKate Stone static_cast<void *>(this),
287fee461b1SMichał Górny static_cast<uint64_t>(m_io_sp->GetWaitableHandle()),
288b9c1b51eSKate Stone static_cast<void *>(dst), static_cast<uint64_t>(dst_len),
289b9c1b51eSKate Stone static_cast<uint64_t>(bytes_read), error.AsCString());
29093a66fc1SZachary Turner }
291ef984e7dSPavel Labath
292b9c1b51eSKate Stone if (bytes_read == 0) {
293b9c1b51eSKate Stone error.Clear(); // End-of-file. Do not automatically close; pass along for
294b9c1b51eSKate Stone // the end-of-file handlers.
29593a66fc1SZachary Turner status = eConnectionStatusEndOfFile;
29693a66fc1SZachary Turner }
29793a66fc1SZachary Turner
29893a66fc1SZachary Turner if (error_ptr)
29993a66fc1SZachary Turner *error_ptr = error;
30093a66fc1SZachary Turner
301b9c1b51eSKate Stone if (error.Fail()) {
30293a66fc1SZachary Turner uint32_t error_value = error.GetError();
303b9c1b51eSKate Stone switch (error_value) {
304b9c1b51eSKate Stone case EAGAIN: // The file was marked for non-blocking I/O, and no data were
305b9c1b51eSKate Stone // ready to be read.
306fee461b1SMichał Górny if (m_io_sp->GetFdType() == IOObject::eFDTypeSocket)
30793a66fc1SZachary Turner status = eConnectionStatusTimedOut;
30893a66fc1SZachary Turner else
30993a66fc1SZachary Turner status = eConnectionStatusSuccess;
31093a66fc1SZachary Turner return 0;
31193a66fc1SZachary Turner
31293a66fc1SZachary Turner case EFAULT: // Buf points outside the allocated address space.
313b9c1b51eSKate Stone case EINTR: // A read from a slow device was interrupted before any data
314b9c1b51eSKate Stone // arrived by the delivery of a signal.
31593a66fc1SZachary Turner case EINVAL: // The pointer associated with fildes was negative.
31693a66fc1SZachary Turner case EIO: // An I/O error occurred while reading from the file system.
31793a66fc1SZachary Turner // The process group is orphaned.
31805097246SAdrian Prantl // The file is a regular file, nbyte is greater than 0, the
31905097246SAdrian Prantl // starting position is before the end-of-file, and the
32005097246SAdrian Prantl // starting position is greater than or equal to the offset
32105097246SAdrian Prantl // maximum established for the open file descriptor
32205097246SAdrian Prantl // associated with fildes.
32393a66fc1SZachary Turner case EISDIR: // An attempt is made to read a directory.
32493a66fc1SZachary Turner case ENOBUFS: // An attempt to allocate a memory buffer fails.
32593a66fc1SZachary Turner case ENOMEM: // Insufficient memory is available.
32693a66fc1SZachary Turner status = eConnectionStatusError;
32793a66fc1SZachary Turner break; // Break to close....
32893a66fc1SZachary Turner
32993a66fc1SZachary Turner case ENOENT: // no such file or directory
330b9c1b51eSKate Stone case EBADF: // fildes is not a valid file or socket descriptor open for
331b9c1b51eSKate Stone // reading.
33293a66fc1SZachary Turner case ENXIO: // An action is requested of a device that does not exist..
33393a66fc1SZachary Turner // A requested action cannot be performed by the device.
334b9c1b51eSKate Stone case ECONNRESET: // The connection is closed by the peer during a read
335b9c1b51eSKate Stone // attempt on a socket.
33693a66fc1SZachary Turner case ENOTCONN: // A read is attempted on an unconnected socket.
33793a66fc1SZachary Turner status = eConnectionStatusLostConnection;
33893a66fc1SZachary Turner break; // Break to close....
33993a66fc1SZachary Turner
340b9c1b51eSKate Stone case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a
341b9c1b51eSKate Stone // socket.
34293a66fc1SZachary Turner status = eConnectionStatusTimedOut;
34393a66fc1SZachary Turner return 0;
34493a66fc1SZachary Turner
34593a66fc1SZachary Turner default:
34610c41f37SPavel Labath LLDB_LOG(log, "this = {0}, unexpected error: {1}", this,
34710c41f37SPavel Labath llvm::sys::StrError(error_value));
34893a66fc1SZachary Turner status = eConnectionStatusError;
34993a66fc1SZachary Turner break; // Break to close....
35093a66fc1SZachary Turner }
35193a66fc1SZachary Turner
35293a66fc1SZachary Turner return 0;
35393a66fc1SZachary Turner }
354ef984e7dSPavel Labath return bytes_read;
35593a66fc1SZachary Turner }
35693a66fc1SZachary Turner
Write(const void * src,size_t src_len,ConnectionStatus & status,Status * error_ptr)357b9c1b51eSKate Stone size_t ConnectionFileDescriptor::Write(const void *src, size_t src_len,
358b9c1b51eSKate Stone ConnectionStatus &status,
35997206d57SZachary Turner Status *error_ptr) {
360a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Connection);
36163e5fb76SJonas Devlieghere LLDB_LOGF(log,
36263e5fb76SJonas Devlieghere "%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64
36363e5fb76SJonas Devlieghere ")",
364b9c1b51eSKate Stone static_cast<void *>(this), static_cast<const void *>(src),
365b9c1b51eSKate Stone static_cast<uint64_t>(src_len));
36693a66fc1SZachary Turner
367b9c1b51eSKate Stone if (!IsConnected()) {
36893a66fc1SZachary Turner if (error_ptr)
36993a66fc1SZachary Turner error_ptr->SetErrorString("not connected");
37093a66fc1SZachary Turner status = eConnectionStatusNoConnection;
37193a66fc1SZachary Turner return 0;
37293a66fc1SZachary Turner }
37393a66fc1SZachary Turner
374ece176e0SJonas Devlieghere if (m_shutting_down) {
375ece176e0SJonas Devlieghere if (error_ptr)
376ece176e0SJonas Devlieghere error_ptr->SetErrorString("shutting down");
377ece176e0SJonas Devlieghere status = eConnectionStatusError;
378ece176e0SJonas Devlieghere return 0;
379ece176e0SJonas Devlieghere }
380ece176e0SJonas Devlieghere
38197206d57SZachary Turner Status error;
38293a66fc1SZachary Turner
38393a66fc1SZachary Turner size_t bytes_sent = src_len;
384fee461b1SMichał Górny error = m_io_sp->Write(src, bytes_sent);
38593a66fc1SZachary Turner
386b9c1b51eSKate Stone if (log) {
38763e5fb76SJonas Devlieghere LLDB_LOGF(log,
38863e5fb76SJonas Devlieghere "%p ConnectionFileDescriptor::Write(fd = %" PRIu64
38963e5fb76SJonas Devlieghere ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",
390b9c1b51eSKate Stone static_cast<void *>(this),
391fee461b1SMichał Górny static_cast<uint64_t>(m_io_sp->GetWaitableHandle()),
392b9c1b51eSKate Stone static_cast<const void *>(src), static_cast<uint64_t>(src_len),
393b9c1b51eSKate Stone static_cast<uint64_t>(bytes_sent), error.AsCString());
39493a66fc1SZachary Turner }
39593a66fc1SZachary Turner
39693a66fc1SZachary Turner if (error_ptr)
39793a66fc1SZachary Turner *error_ptr = error;
39893a66fc1SZachary Turner
399b9c1b51eSKate Stone if (error.Fail()) {
400b9c1b51eSKate Stone switch (error.GetError()) {
40193a66fc1SZachary Turner case EAGAIN:
40293a66fc1SZachary Turner case EINTR:
40393a66fc1SZachary Turner status = eConnectionStatusSuccess;
40493a66fc1SZachary Turner return 0;
40593a66fc1SZachary Turner
406b9c1b51eSKate Stone case ECONNRESET: // The connection is closed by the peer during a read
407b9c1b51eSKate Stone // attempt on a socket.
40893a66fc1SZachary Turner case ENOTCONN: // A read is attempted on an unconnected socket.
40993a66fc1SZachary Turner status = eConnectionStatusLostConnection;
41093a66fc1SZachary Turner break; // Break to close....
41193a66fc1SZachary Turner
41293a66fc1SZachary Turner default:
41393a66fc1SZachary Turner status = eConnectionStatusError;
41493a66fc1SZachary Turner break; // Break to close....
41593a66fc1SZachary Turner }
41693a66fc1SZachary Turner
41793a66fc1SZachary Turner return 0;
41893a66fc1SZachary Turner }
41993a66fc1SZachary Turner
42093a66fc1SZachary Turner status = eConnectionStatusSuccess;
42193a66fc1SZachary Turner return bytes_sent;
42293a66fc1SZachary Turner }
42393a66fc1SZachary Turner
GetURI()424b9c1b51eSKate Stone std::string ConnectionFileDescriptor::GetURI() { return m_uri; }
425eb303ee5SVince Harron
426b9c1b51eSKate Stone // This ConnectionFileDescriptor::BytesAvailable() uses select() via
427b9c1b51eSKate Stone // SelectHelper
42893a66fc1SZachary Turner //
42993a66fc1SZachary Turner // PROS:
43093a66fc1SZachary Turner // - select is consistent across most unix platforms
43193a66fc1SZachary Turner // - The Apple specific version allows for unlimited fds in the fd_sets by
43293a66fc1SZachary Turner // setting the _DARWIN_UNLIMITED_SELECT define prior to including the
43393a66fc1SZachary Turner // required header files.
43493a66fc1SZachary Turner // CONS:
43593a66fc1SZachary Turner // - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE.
43693a66fc1SZachary Turner // This implementation will assert if it runs into that hard limit to let
43793a66fc1SZachary Turner // users know that another ConnectionFileDescriptor::BytesAvailable() should
43893a66fc1SZachary Turner // be used or a new version of ConnectionFileDescriptor::BytesAvailable()
43993a66fc1SZachary Turner // should be written for the system that is running into the limitations.
44093a66fc1SZachary Turner
4412f159a5fSPavel Labath ConnectionStatus
BytesAvailable(const Timeout<std::micro> & timeout,Status * error_ptr)4422f159a5fSPavel Labath ConnectionFileDescriptor::BytesAvailable(const Timeout<std::micro> &timeout,
44397206d57SZachary Turner Status *error_ptr) {
444b9c1b51eSKate Stone // Don't need to take the mutex here separately since we are only called from
44505097246SAdrian Prantl // Read. If we ever get used more generally we will need to lock here as
44605097246SAdrian Prantl // well.
44793a66fc1SZachary Turner
448a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Connection);
449d02b1c83SPavel Labath LLDB_LOG(log, "this = {0}, timeout = {1}", this, timeout);
45093a66fc1SZachary Turner
45105097246SAdrian Prantl // Make a copy of the file descriptors to make sure we don't have another
45205097246SAdrian Prantl // thread change these values out from under us and cause problems in the
45305097246SAdrian Prantl // loop below where like in FS_SET()
454fee461b1SMichał Górny const IOObject::WaitableHandle handle = m_io_sp->GetWaitableHandle();
45593a66fc1SZachary Turner const int pipe_fd = m_pipe.GetReadFileDescriptor();
45693a66fc1SZachary Turner
457b9c1b51eSKate Stone if (handle != IOObject::kInvalidHandleValue) {
458ee1f578dSGreg Clayton SelectHelper select_helper;
4592f159a5fSPavel Labath if (timeout)
4602f159a5fSPavel Labath select_helper.SetTimeout(*timeout);
461ee1f578dSGreg Clayton
462ee1f578dSGreg Clayton select_helper.FDSetRead(handle);
4638b98f12aSMartin Storsjo #if defined(_WIN32)
464b9c1b51eSKate Stone // select() won't accept pipes on Windows. The entire Windows codepath
46505097246SAdrian Prantl // needs to be converted over to using WaitForMultipleObjects and event
46605097246SAdrian Prantl // HANDLEs, but for now at least this will allow ::select() to not return
46705097246SAdrian Prantl // an error.
46893a66fc1SZachary Turner const bool have_pipe_fd = false;
46993a66fc1SZachary Turner #else
47093a66fc1SZachary Turner const bool have_pipe_fd = pipe_fd >= 0;
471ee1f578dSGreg Clayton #endif
47293a66fc1SZachary Turner if (have_pipe_fd)
473ee1f578dSGreg Clayton select_helper.FDSetRead(pipe_fd);
474ee1f578dSGreg Clayton
475fee461b1SMichał Górny while (handle == m_io_sp->GetWaitableHandle()) {
47693a66fc1SZachary Turner
47797206d57SZachary Turner Status error = select_helper.Select();
47893a66fc1SZachary Turner
47993a66fc1SZachary Turner if (error_ptr)
48093a66fc1SZachary Turner *error_ptr = error;
48193a66fc1SZachary Turner
482b9c1b51eSKate Stone if (error.Fail()) {
483b9c1b51eSKate Stone switch (error.GetError()) {
484b9c1b51eSKate Stone case EBADF: // One of the descriptor sets specified an invalid
485b9c1b51eSKate Stone // descriptor.
48693a66fc1SZachary Turner return eConnectionStatusLostConnection;
48793a66fc1SZachary Turner
488b9c1b51eSKate Stone case EINVAL: // The specified time limit is invalid. One of its
489b9c1b51eSKate Stone // components is negative or too large.
49093a66fc1SZachary Turner default: // Other unknown error
49193a66fc1SZachary Turner return eConnectionStatusError;
49293a66fc1SZachary Turner
493ee1f578dSGreg Clayton case ETIMEDOUT:
494ee1f578dSGreg Clayton return eConnectionStatusTimedOut;
495ee1f578dSGreg Clayton
49693a66fc1SZachary Turner case EAGAIN: // The kernel was (perhaps temporarily) unable to
49705097246SAdrian Prantl // allocate the requested number of file descriptors, or
49805097246SAdrian Prantl // we have non-blocking IO
49993a66fc1SZachary Turner case EINTR: // A signal was delivered before the time limit
50005097246SAdrian Prantl // expired and before any of the selected events occurred.
50193a66fc1SZachary Turner break; // Lets keep reading to until we timeout
50293a66fc1SZachary Turner }
503b9c1b51eSKate Stone } else {
504ee1f578dSGreg Clayton if (select_helper.FDIsSetRead(handle))
50593a66fc1SZachary Turner return eConnectionStatusSuccess;
506ee1f578dSGreg Clayton
507b9c1b51eSKate Stone if (select_helper.FDIsSetRead(pipe_fd)) {
50805097246SAdrian Prantl // There is an interrupt or exit command in the command pipe Read the
50905097246SAdrian Prantl // data from that pipe:
510c1a6b128SPavel Labath char c;
511b9bd6af2SVince Harron
51258d28b93SMichał Górny ssize_t bytes_read =
51358d28b93SMichał Górny llvm::sys::RetryAfterSignal(-1, ::read, pipe_fd, &c, 1);
514c1a6b128SPavel Labath assert(bytes_read == 1);
515c1a6b128SPavel Labath (void)bytes_read;
516c1a6b128SPavel Labath switch (c) {
51793a66fc1SZachary Turner case 'q':
51863e5fb76SJonas Devlieghere LLDB_LOGF(log,
51963e5fb76SJonas Devlieghere "%p ConnectionFileDescriptor::BytesAvailable() "
520b9bd6af2SVince Harron "got data: %c from the command channel.",
521c1a6b128SPavel Labath static_cast<void *>(this), c);
52293a66fc1SZachary Turner return eConnectionStatusEndOfFile;
52393a66fc1SZachary Turner case 'i':
52493a66fc1SZachary Turner // Interrupt the current read
52593a66fc1SZachary Turner return eConnectionStatusInterrupted;
52693a66fc1SZachary Turner }
52793a66fc1SZachary Turner }
52893a66fc1SZachary Turner }
52993a66fc1SZachary Turner }
53093a66fc1SZachary Turner }
53193a66fc1SZachary Turner
53293a66fc1SZachary Turner if (error_ptr)
53393a66fc1SZachary Turner error_ptr->SetErrorString("not connected");
53493a66fc1SZachary Turner return eConnectionStatusLostConnection;
53593a66fc1SZachary Turner }
53693a66fc1SZachary Turner
AcceptSocket(Socket::SocketProtocol socket_protocol,llvm::StringRef socket_name,llvm::function_ref<void (Socket &)> post_listen_callback,Status * error_ptr)537e50f02baSMichał Górny lldb::ConnectionStatus ConnectionFileDescriptor::AcceptSocket(
538e50f02baSMichał Górny Socket::SocketProtocol socket_protocol, llvm::StringRef socket_name,
539e50f02baSMichał Górny llvm::function_ref<void(Socket &)> post_listen_callback,
54097206d57SZachary Turner Status *error_ptr) {
54158d28b93SMichał Górny Status error;
542e50f02baSMichał Górny std::unique_ptr<Socket> listening_socket =
543e50f02baSMichał Górny Socket::Create(socket_protocol, m_child_processes_inherit, error);
5448dbbe335SMed Ismail Bennani Socket *accepted_socket;
545e50f02baSMichał Górny
546e50f02baSMichał Górny if (!error.Fail())
547e50f02baSMichał Górny error = listening_socket->Listen(socket_name, 5);
548e50f02baSMichał Górny
549e50f02baSMichał Górny if (!error.Fail()) {
550e50f02baSMichał Górny post_listen_callback(*listening_socket);
551e50f02baSMichał Górny error = listening_socket->Accept(accepted_socket);
552e50f02baSMichał Górny }
553e50f02baSMichał Górny
554e50f02baSMichał Górny if (!error.Fail()) {
555e50f02baSMichał Górny m_io_sp.reset(accepted_socket);
556e50f02baSMichał Górny m_uri.assign(socket_name.str());
557e50f02baSMichał Górny return eConnectionStatusSuccess;
558e50f02baSMichał Górny }
559e50f02baSMichał Górny
5608dbbe335SMed Ismail Bennani if (error_ptr)
5618dbbe335SMed Ismail Bennani *error_ptr = error;
5628dbbe335SMed Ismail Bennani return eConnectionStatusError;
563e50f02baSMichał Górny }
5648dbbe335SMed Ismail Bennani
565e50f02baSMichał Górny lldb::ConnectionStatus
ConnectSocket(Socket::SocketProtocol socket_protocol,llvm::StringRef socket_name,Status * error_ptr)566e50f02baSMichał Górny ConnectionFileDescriptor::ConnectSocket(Socket::SocketProtocol socket_protocol,
567e50f02baSMichał Górny llvm::StringRef socket_name,
568e50f02baSMichał Górny Status *error_ptr) {
569e50f02baSMichał Górny Status error;
570e50f02baSMichał Górny std::unique_ptr<Socket> socket =
571e50f02baSMichał Górny Socket::Create(socket_protocol, m_child_processes_inherit, error);
572e50f02baSMichał Górny
573e50f02baSMichał Górny if (!error.Fail())
574e50f02baSMichał Górny error = socket->Connect(socket_name);
575e50f02baSMichał Górny
576e50f02baSMichał Górny if (!error.Fail()) {
577e50f02baSMichał Górny m_io_sp = std::move(socket);
578e50f02baSMichał Górny m_uri.assign(socket_name.str());
5798dbbe335SMed Ismail Bennani return eConnectionStatusSuccess;
580eb303ee5SVince Harron }
581e1acadb6SMichał Górny
582e50f02baSMichał Górny if (error_ptr)
583e50f02baSMichał Górny *error_ptr = error;
584e50f02baSMichał Górny return eConnectionStatusError;
585e50f02baSMichał Górny }
586e50f02baSMichał Górny
AcceptNamedSocket(llvm::StringRef socket_name,socket_id_callback_type socket_id_callback,Status * error_ptr)587e50f02baSMichał Górny ConnectionStatus ConnectionFileDescriptor::AcceptNamedSocket(
588e50f02baSMichał Górny llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,
589e50f02baSMichał Górny Status *error_ptr) {
590e50f02baSMichał Górny return AcceptSocket(
591e50f02baSMichał Górny Socket::ProtocolUnixDomain, socket_name,
592e50f02baSMichał Górny [socket_id_callback, socket_name](Socket &listening_socket) {
593e50f02baSMichał Górny socket_id_callback(socket_name);
594e50f02baSMichał Górny },
595e50f02baSMichał Górny error_ptr);
596e50f02baSMichał Górny }
597e50f02baSMichał Górny
ConnectNamedSocket(llvm::StringRef socket_name,socket_id_callback_type socket_id_callback,Status * error_ptr)598e50f02baSMichał Górny ConnectionStatus ConnectionFileDescriptor::ConnectNamedSocket(
599e50f02baSMichał Górny llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,
600e50f02baSMichał Górny Status *error_ptr) {
601e50f02baSMichał Górny return ConnectSocket(Socket::ProtocolUnixDomain, socket_name, error_ptr);
602e50f02baSMichał Górny }
603e50f02baSMichał Górny
AcceptAbstractSocket(llvm::StringRef socket_name,socket_id_callback_type socket_id_callback,Status * error_ptr)604e50f02baSMichał Górny ConnectionStatus ConnectionFileDescriptor::AcceptAbstractSocket(
605e50f02baSMichał Górny llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,
606e50f02baSMichał Górny Status *error_ptr) {
607e50f02baSMichał Górny return AcceptSocket(
608e50f02baSMichał Górny Socket::ProtocolUnixAbstract, socket_name,
609e50f02baSMichał Górny [socket_id_callback, socket_name](Socket &listening_socket) {
610e50f02baSMichał Górny socket_id_callback(socket_name);
611e50f02baSMichał Górny },
612e50f02baSMichał Górny error_ptr);
613e50f02baSMichał Górny }
614e50f02baSMichał Górny
ConnectAbstractSocket(llvm::StringRef socket_name,socket_id_callback_type socket_id_callback,Status * error_ptr)615e50f02baSMichał Górny lldb::ConnectionStatus ConnectionFileDescriptor::ConnectAbstractSocket(
616e50f02baSMichał Górny llvm::StringRef socket_name, socket_id_callback_type socket_id_callback,
617e50f02baSMichał Górny Status *error_ptr) {
618e50f02baSMichał Górny return ConnectSocket(Socket::ProtocolUnixAbstract, socket_name, error_ptr);
619e50f02baSMichał Górny }
620e50f02baSMichał Górny
621e1acadb6SMichał Górny ConnectionStatus
AcceptTCP(llvm::StringRef socket_name,socket_id_callback_type socket_id_callback,Status * error_ptr)622e50f02baSMichał Górny ConnectionFileDescriptor::AcceptTCP(llvm::StringRef socket_name,
623e1acadb6SMichał Górny socket_id_callback_type socket_id_callback,
624e1acadb6SMichał Górny Status *error_ptr) {
625e50f02baSMichał Górny ConnectionStatus ret = AcceptSocket(
626e50f02baSMichał Górny Socket::ProtocolTcp, socket_name,
627e50f02baSMichał Górny [socket_id_callback](Socket &listening_socket) {
628e50f02baSMichał Górny uint16_t port =
629e50f02baSMichał Górny static_cast<TCPSocket &>(listening_socket).GetLocalPortNumber();
630e50f02baSMichał Górny socket_id_callback(std::to_string(port));
631e50f02baSMichał Górny },
632e50f02baSMichał Górny error_ptr);
633e50f02baSMichał Górny if (ret == eConnectionStatusSuccess)
634e50f02baSMichał Górny m_uri.assign(
635e50f02baSMichał Górny static_cast<TCPSocket *>(m_io_sp.get())->GetRemoteConnectionURI());
636e50f02baSMichał Górny return ret;
6378dbbe335SMed Ismail Bennani }
638e50f02baSMichał Górny
639e50f02baSMichał Górny ConnectionStatus
ConnectTCP(llvm::StringRef socket_name,socket_id_callback_type socket_id_callback,Status * error_ptr)640e50f02baSMichał Górny ConnectionFileDescriptor::ConnectTCP(llvm::StringRef socket_name,
641e50f02baSMichał Górny socket_id_callback_type socket_id_callback,
642e50f02baSMichał Górny Status *error_ptr) {
643e50f02baSMichał Górny return ConnectSocket(Socket::ProtocolTcp, socket_name, error_ptr);
64493a66fc1SZachary Turner }
64593a66fc1SZachary Turner
64658d28b93SMichał Górny ConnectionStatus
ConnectUDP(llvm::StringRef s,socket_id_callback_type socket_id_callback,Status * error_ptr)64758d28b93SMichał Górny ConnectionFileDescriptor::ConnectUDP(llvm::StringRef s,
64858d28b93SMichał Górny socket_id_callback_type socket_id_callback,
64997206d57SZachary Turner Status *error_ptr) {
65093a66fc1SZachary Turner if (error_ptr)
651c9e6b701SPavel Labath *error_ptr = Status();
652c9e6b701SPavel Labath llvm::Expected<std::unique_ptr<UDPSocket>> socket =
653c9e6b701SPavel Labath Socket::UdpConnect(s, m_child_processes_inherit);
654c9e6b701SPavel Labath if (!socket) {
655c9e6b701SPavel Labath if (error_ptr)
656c9e6b701SPavel Labath *error_ptr = socket.takeError();
657c9e6b701SPavel Labath else
658a007a6d8SPavel Labath LLDB_LOG_ERROR(GetLog(LLDBLog::Connection), socket.takeError(),
659a007a6d8SPavel Labath "tcp connect failed: {0}");
660eb303ee5SVince Harron return eConnectionStatusError;
661eb303ee5SVince Harron }
662fee461b1SMichał Górny m_io_sp = std::move(*socket);
663adcd0268SBenjamin Kramer m_uri.assign(std::string(s));
664eb303ee5SVince Harron return eConnectionStatusSuccess;
66593a66fc1SZachary Turner }
66693a66fc1SZachary Turner
66758d28b93SMichał Górny ConnectionStatus
ConnectFD(llvm::StringRef s,socket_id_callback_type socket_id_callback,Status * error_ptr)66858d28b93SMichał Górny ConnectionFileDescriptor::ConnectFD(llvm::StringRef s,
66958d28b93SMichał Górny socket_id_callback_type socket_id_callback,
6704b46a413SMichał Górny Status *error_ptr) {
6714b46a413SMichał Górny #if LLDB_ENABLE_POSIX
6724b46a413SMichał Górny // Just passing a native file descriptor within this current process that
6734b46a413SMichał Górny // is already opened (possibly from a service or other source).
6744b46a413SMichał Górny int fd = -1;
6754b46a413SMichał Górny
6764b46a413SMichał Górny if (!s.getAsInteger(0, fd)) {
6774b46a413SMichał Górny // We have what looks to be a valid file descriptor, but we should make
6784b46a413SMichał Górny // sure it is. We currently are doing this by trying to get the flags
6794b46a413SMichał Górny // from the file descriptor and making sure it isn't a bad fd.
6804b46a413SMichał Górny errno = 0;
6814b46a413SMichał Górny int flags = ::fcntl(fd, F_GETFL, 0);
6824b46a413SMichał Górny if (flags == -1 || errno == EBADF) {
6834b46a413SMichał Górny if (error_ptr)
6844b46a413SMichał Górny error_ptr->SetErrorStringWithFormat("stale file descriptor: %s",
6854b46a413SMichał Górny s.str().c_str());
686fee461b1SMichał Górny m_io_sp.reset();
6874b46a413SMichał Górny return eConnectionStatusError;
6884b46a413SMichał Górny } else {
6894b46a413SMichał Górny // Don't take ownership of a file descriptor that gets passed to us
6904b46a413SMichał Górny // since someone else opened the file descriptor and handed it to us.
6914b46a413SMichał Górny // TODO: Since are using a URL to open connection we should
6924b46a413SMichał Górny // eventually parse options using the web standard where we have
6934b46a413SMichał Górny // "fd://123?opt1=value;opt2=value" and we can have an option be
6944b46a413SMichał Górny // "owns=1" or "owns=0" or something like this to allow us to specify
6954b46a413SMichał Górny // this. For now, we assume we must assume we don't own it.
6964b46a413SMichał Górny
6974b46a413SMichał Górny std::unique_ptr<TCPSocket> tcp_socket;
6984b46a413SMichał Górny tcp_socket = std::make_unique<TCPSocket>(fd, false, false);
6994b46a413SMichał Górny // Try and get a socket option from this file descriptor to see if
7004b46a413SMichał Górny // this is a socket and set m_is_socket accordingly.
7014b46a413SMichał Górny int resuse;
7024b46a413SMichał Górny bool is_socket =
7034b46a413SMichał Górny !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
704fee461b1SMichał Górny if (is_socket)
705fee461b1SMichał Górny m_io_sp = std::move(tcp_socket);
706fee461b1SMichał Górny else
707fee461b1SMichał Górny m_io_sp =
7084b46a413SMichał Górny std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, false);
7094b46a413SMichał Górny m_uri = s.str();
7104b46a413SMichał Górny return eConnectionStatusSuccess;
7114b46a413SMichał Górny }
7124b46a413SMichał Górny }
7134b46a413SMichał Górny
7144b46a413SMichał Górny if (error_ptr)
7154b46a413SMichał Górny error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"",
7164b46a413SMichał Górny s.str().c_str());
717fee461b1SMichał Górny m_io_sp.reset();
7184b46a413SMichał Górny return eConnectionStatusError;
7194b46a413SMichał Górny #endif // LLDB_ENABLE_POSIX
7204b46a413SMichał Górny llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");
7214b46a413SMichał Górny }
7224b46a413SMichał Górny
ConnectFile(llvm::StringRef s,socket_id_callback_type socket_id_callback,Status * error_ptr)72358d28b93SMichał Górny ConnectionStatus ConnectionFileDescriptor::ConnectFile(
72458d28b93SMichał Górny llvm::StringRef s, socket_id_callback_type socket_id_callback,
7254b46a413SMichał Górny Status *error_ptr) {
7264b46a413SMichał Górny #if LLDB_ENABLE_POSIX
7274b46a413SMichał Górny std::string addr_str = s.str();
7284b46a413SMichał Górny // file:///PATH
7294b46a413SMichał Górny int fd = llvm::sys::RetryAfterSignal(-1, ::open, addr_str.c_str(), O_RDWR);
7304b46a413SMichał Górny if (fd == -1) {
7314b46a413SMichał Górny if (error_ptr)
7324b46a413SMichał Górny error_ptr->SetErrorToErrno();
7334b46a413SMichał Górny return eConnectionStatusError;
7344b46a413SMichał Górny }
7354b46a413SMichał Górny
7364b46a413SMichał Górny if (::isatty(fd)) {
7374b46a413SMichał Górny // Set up serial terminal emulation
7384b46a413SMichał Górny struct termios options;
7394b46a413SMichał Górny ::tcgetattr(fd, &options);
7404b46a413SMichał Górny
7414b46a413SMichał Górny // Set port speed to maximum
7424b46a413SMichał Górny ::cfsetospeed(&options, B115200);
7434b46a413SMichał Górny ::cfsetispeed(&options, B115200);
7444b46a413SMichał Górny
7454b46a413SMichał Górny // Raw input, disable echo and signals
7464b46a413SMichał Górny options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
7474b46a413SMichał Górny
7484b46a413SMichał Górny // Make sure only one character is needed to return from a read
7494b46a413SMichał Górny options.c_cc[VMIN] = 1;
7504b46a413SMichał Górny options.c_cc[VTIME] = 0;
7514b46a413SMichał Górny
7524b46a413SMichał Górny llvm::sys::RetryAfterSignal(-1, ::tcsetattr, fd, TCSANOW, &options);
7534b46a413SMichał Górny }
7544b46a413SMichał Górny
75558d28b93SMichał Górny m_io_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionReadWrite, true);
7564b46a413SMichał Górny return eConnectionStatusSuccess;
7574b46a413SMichał Górny #endif // LLDB_ENABLE_POSIX
7584b46a413SMichał Górny llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");
7594b46a413SMichał Górny }
7604b46a413SMichał Górny
ConnectSerialPort(llvm::StringRef s,socket_id_callback_type socket_id_callback,Status * error_ptr)76158d28b93SMichał Górny ConnectionStatus ConnectionFileDescriptor::ConnectSerialPort(
76258d28b93SMichał Górny llvm::StringRef s, socket_id_callback_type socket_id_callback,
7634a7b4beaSMichał Górny Status *error_ptr) {
7644a7b4beaSMichał Górny #if LLDB_ENABLE_POSIX
7654a7b4beaSMichał Górny llvm::StringRef path, qs;
7664a7b4beaSMichał Górny // serial:///PATH?k1=v1&k2=v2...
7674a7b4beaSMichał Górny std::tie(path, qs) = s.split('?');
7684a7b4beaSMichał Górny
7694a7b4beaSMichał Górny llvm::Expected<SerialPort::Options> serial_options =
7704a7b4beaSMichał Górny SerialPort::OptionsFromURL(qs);
7714a7b4beaSMichał Górny if (!serial_options) {
7724a7b4beaSMichał Górny if (error_ptr)
7734a7b4beaSMichał Górny *error_ptr = serial_options.takeError();
7744a7b4beaSMichał Górny else
7754a7b4beaSMichał Górny llvm::consumeError(serial_options.takeError());
7764a7b4beaSMichał Górny return eConnectionStatusError;
7774a7b4beaSMichał Górny }
7784a7b4beaSMichał Górny
7794a7b4beaSMichał Górny int fd = llvm::sys::RetryAfterSignal(-1, ::open, path.str().c_str(), O_RDWR);
7804a7b4beaSMichał Górny if (fd == -1) {
7814a7b4beaSMichał Górny if (error_ptr)
7824a7b4beaSMichał Górny error_ptr->SetErrorToErrno();
7834a7b4beaSMichał Górny return eConnectionStatusError;
7844a7b4beaSMichał Górny }
7854a7b4beaSMichał Górny
7864a7b4beaSMichał Górny llvm::Expected<std::unique_ptr<SerialPort>> serial_sp = SerialPort::Create(
7874a7b4beaSMichał Górny fd, File::eOpenOptionReadWrite, serial_options.get(), true);
7884a7b4beaSMichał Górny if (!serial_sp) {
7894a7b4beaSMichał Górny if (error_ptr)
7904a7b4beaSMichał Górny *error_ptr = serial_sp.takeError();
7914a7b4beaSMichał Górny else
7924a7b4beaSMichał Górny llvm::consumeError(serial_sp.takeError());
7934a7b4beaSMichał Górny return eConnectionStatusError;
7944a7b4beaSMichał Górny }
7954a7b4beaSMichał Górny m_io_sp = std::move(serial_sp.get());
7964a7b4beaSMichał Górny
7974a7b4beaSMichał Górny return eConnectionStatusSuccess;
7984a7b4beaSMichał Górny #endif // LLDB_ENABLE_POSIX
7994a7b4beaSMichał Górny llvm_unreachable("this function should be only called w/ LLDB_ENABLE_POSIX");
8004a7b4beaSMichał Górny }
8014a7b4beaSMichał Górny
GetChildProcessesInherit() const802b9c1b51eSKate Stone bool ConnectionFileDescriptor::GetChildProcessesInherit() const {
803477e42a6SOleksiy Vyalov return m_child_processes_inherit;
804477e42a6SOleksiy Vyalov }
805477e42a6SOleksiy Vyalov
SetChildProcessesInherit(bool child_processes_inherit)806b9c1b51eSKate Stone void ConnectionFileDescriptor::SetChildProcessesInherit(
807b9c1b51eSKate Stone bool child_processes_inherit) {
808477e42a6SOleksiy Vyalov m_child_processes_inherit = child_processes_inherit;
809477e42a6SOleksiy Vyalov }
810a0e70cd4SRobert Flack
InitializeSocket(Socket * socket)811b9c1b51eSKate Stone void ConnectionFileDescriptor::InitializeSocket(Socket *socket) {
812fee461b1SMichał Górny m_io_sp.reset(socket);
813d5560951SAntonio Afonso m_uri = socket->GetRemoteConnectionURI();
814a0e70cd4SRobert Flack }
815