xref: /src/contrib/llvm-project/lldb/source/Core/Communication.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1cfca06d7SDimitry Andric //===-- Communication.cpp -------------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste 
9f034231aSEd Maste #include "lldb/Core/Communication.h"
1074a628f7SDimitry Andric 
111b306c26SDimitry Andric #include "lldb/Utility/Connection.h"
12145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
1374a628f7SDimitry Andric #include "lldb/Utility/Log.h"
1494994d37SDimitry Andric #include "lldb/Utility/Status.h"
1574a628f7SDimitry Andric 
1694994d37SDimitry Andric #include "llvm/Support/Compiler.h"
1774a628f7SDimitry Andric 
1894994d37SDimitry Andric #include <algorithm>
1974a628f7SDimitry Andric #include <cstring>
2094994d37SDimitry Andric #include <memory>
2174a628f7SDimitry Andric 
22344a3780SDimitry Andric #include <cerrno>
23344a3780SDimitry Andric #include <cinttypes>
24344a3780SDimitry Andric #include <cstdio>
25f034231aSEd Maste 
26f034231aSEd Maste using namespace lldb;
27f034231aSEd Maste using namespace lldb_private;
28f034231aSEd Maste 
Communication()29e3b55780SDimitry Andric Communication::Communication()
30e3b55780SDimitry Andric     : m_connection_sp(), m_write_mutex(), m_close_on_eof(true) {
31f034231aSEd Maste }
32f034231aSEd Maste 
~Communication()3314f1b3e8SDimitry Andric Communication::~Communication() {
34f034231aSEd Maste   Clear();
35f034231aSEd Maste }
36f034231aSEd Maste 
Clear()3714f1b3e8SDimitry Andric void Communication::Clear() {
38cfca06d7SDimitry Andric   Disconnect(nullptr);
39f034231aSEd Maste }
40f034231aSEd Maste 
Connect(const char * url,Status * error_ptr)41b76161e4SDimitry Andric ConnectionStatus Communication::Connect(const char *url, Status *error_ptr) {
42f034231aSEd Maste   Clear();
43f034231aSEd Maste 
44145449b1SDimitry Andric   LLDB_LOG(GetLog(LLDBLog::Communication),
45ead24645SDimitry Andric            "{0} Communication::Connect (url = {1})", this, url);
46f034231aSEd Maste 
47f034231aSEd Maste   lldb::ConnectionSP connection_sp(m_connection_sp);
48f3fbd1c0SDimitry Andric   if (connection_sp)
49f034231aSEd Maste     return connection_sp->Connect(url, error_ptr);
50f034231aSEd Maste   if (error_ptr)
51f034231aSEd Maste     error_ptr->SetErrorString("Invalid connection.");
52f034231aSEd Maste   return eConnectionStatusNoConnection;
53f034231aSEd Maste }
54f034231aSEd Maste 
Disconnect(Status * error_ptr)55b76161e4SDimitry Andric ConnectionStatus Communication::Disconnect(Status *error_ptr) {
56145449b1SDimitry Andric   LLDB_LOG(GetLog(LLDBLog::Communication), "{0} Communication::Disconnect ()",
57145449b1SDimitry Andric            this);
58f034231aSEd Maste 
59f034231aSEd Maste   lldb::ConnectionSP connection_sp(m_connection_sp);
6014f1b3e8SDimitry Andric   if (connection_sp) {
61f034231aSEd Maste     ConnectionStatus status = connection_sp->Disconnect(error_ptr);
62f73363f1SDimitry Andric     // We currently don't protect connection_sp with any mutex for multi-
63f73363f1SDimitry Andric     // threaded environments. So lets not nuke our connection class without
64f73363f1SDimitry Andric     // putting some multi-threaded protections in. We also probably don't want
65f73363f1SDimitry Andric     // to pay for the overhead it might cause if every time we access the
66f73363f1SDimitry Andric     // connection we have to take a lock.
67f034231aSEd Maste     //
68f73363f1SDimitry Andric     // This unique pointer will cleanup after itself when this object goes
69f73363f1SDimitry Andric     // away, so there is no need to currently have it destroy itself
70f73363f1SDimitry Andric     // immediately upon disconnect.
71f034231aSEd Maste     // connection_sp.reset();
72f034231aSEd Maste     return status;
73f034231aSEd Maste   }
74f034231aSEd Maste   return eConnectionStatusNoConnection;
75f034231aSEd Maste }
76f034231aSEd Maste 
IsConnected() const7714f1b3e8SDimitry Andric bool Communication::IsConnected() const {
78f034231aSEd Maste   lldb::ConnectionSP connection_sp(m_connection_sp);
79f3fbd1c0SDimitry Andric   return (connection_sp ? connection_sp->IsConnected() : false);
80f034231aSEd Maste }
81f034231aSEd Maste 
HasConnection() const8214f1b3e8SDimitry Andric bool Communication::HasConnection() const {
83f3fbd1c0SDimitry Andric   return m_connection_sp.get() != nullptr;
84f034231aSEd Maste }
85f034231aSEd Maste 
Read(void * dst,size_t dst_len,const Timeout<std::micro> & timeout,ConnectionStatus & status,Status * error_ptr)8614f1b3e8SDimitry Andric size_t Communication::Read(void *dst, size_t dst_len,
8714f1b3e8SDimitry Andric                            const Timeout<std::micro> &timeout,
88b76161e4SDimitry Andric                            ConnectionStatus &status, Status *error_ptr) {
89145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Communication);
9074a628f7SDimitry Andric   LLDB_LOG(
9174a628f7SDimitry Andric       log,
9274a628f7SDimitry Andric       "this = {0}, dst = {1}, dst_len = {2}, timeout = {3}, connection = {4}",
9374a628f7SDimitry Andric       this, dst, dst_len, timeout, m_connection_sp.get());
94f034231aSEd Maste 
9514f1b3e8SDimitry Andric   return ReadFromConnection(dst, dst_len, timeout, status, error_ptr);
96f034231aSEd Maste }
97f034231aSEd Maste 
Write(const void * src,size_t src_len,ConnectionStatus & status,Status * error_ptr)9814f1b3e8SDimitry Andric size_t Communication::Write(const void *src, size_t src_len,
99b76161e4SDimitry Andric                             ConnectionStatus &status, Status *error_ptr) {
100f034231aSEd Maste   lldb::ConnectionSP connection_sp(m_connection_sp);
101f034231aSEd Maste 
102f3fbd1c0SDimitry Andric   std::lock_guard<std::mutex> guard(m_write_mutex);
103145449b1SDimitry Andric   LLDB_LOG(GetLog(LLDBLog::Communication),
104c0981da4SDimitry Andric            "{0} Communication::Write (src = {1}, src_len = {2}"
105c0981da4SDimitry Andric            ") connection = {3}",
10614f1b3e8SDimitry Andric            this, src, (uint64_t)src_len, connection_sp.get());
107f034231aSEd Maste 
108f3fbd1c0SDimitry Andric   if (connection_sp)
109f034231aSEd Maste     return connection_sp->Write(src, src_len, status, error_ptr);
110f034231aSEd Maste 
111f034231aSEd Maste   if (error_ptr)
112f034231aSEd Maste     error_ptr->SetErrorString("Invalid connection.");
113f034231aSEd Maste   status = eConnectionStatusNoConnection;
114f034231aSEd Maste   return 0;
115f034231aSEd Maste }
116f034231aSEd Maste 
WriteAll(const void * src,size_t src_len,ConnectionStatus & status,Status * error_ptr)117c0981da4SDimitry Andric size_t Communication::WriteAll(const void *src, size_t src_len,
118c0981da4SDimitry Andric                                ConnectionStatus &status, Status *error_ptr) {
119c0981da4SDimitry Andric   size_t total_written = 0;
120c0981da4SDimitry Andric   do
121c0981da4SDimitry Andric     total_written += Write(static_cast<const char *>(src) + total_written,
122c0981da4SDimitry Andric                            src_len - total_written, status, error_ptr);
123c0981da4SDimitry Andric   while (status == eConnectionStatusSuccess && total_written < src_len);
124c0981da4SDimitry Andric   return total_written;
125c0981da4SDimitry Andric }
126c0981da4SDimitry Andric 
ReadFromConnection(void * dst,size_t dst_len,const Timeout<std::micro> & timeout,ConnectionStatus & status,Status * error_ptr)12714f1b3e8SDimitry Andric size_t Communication::ReadFromConnection(void *dst, size_t dst_len,
12814f1b3e8SDimitry Andric                                          const Timeout<std::micro> &timeout,
129f034231aSEd Maste                                          ConnectionStatus &status,
130b76161e4SDimitry Andric                                          Status *error_ptr) {
131f034231aSEd Maste   lldb::ConnectionSP connection_sp(m_connection_sp);
13214f1b3e8SDimitry Andric   if (connection_sp)
13314f1b3e8SDimitry Andric     return connection_sp->Read(dst, dst_len, timeout, status, error_ptr);
13414f1b3e8SDimitry Andric 
13514f1b3e8SDimitry Andric   if (error_ptr)
13614f1b3e8SDimitry Andric     error_ptr->SetErrorString("Invalid connection.");
13714f1b3e8SDimitry Andric   status = eConnectionStatusNoConnection;
13814f1b3e8SDimitry Andric   return 0;
139f034231aSEd Maste }
140f034231aSEd Maste 
SetConnection(std::unique_ptr<Connection> connection)141cfca06d7SDimitry Andric void Communication::SetConnection(std::unique_ptr<Connection> connection) {
142f3fbd1c0SDimitry Andric   Disconnect(nullptr);
143cfca06d7SDimitry Andric   m_connection_sp = std::move(connection);
144f034231aSEd Maste }
145f034231aSEd Maste 
146b60736ecSDimitry Andric std::string
ConnectionStatusAsString(lldb::ConnectionStatus status)147b60736ecSDimitry Andric Communication::ConnectionStatusAsString(lldb::ConnectionStatus status) {
14814f1b3e8SDimitry Andric   switch (status) {
14914f1b3e8SDimitry Andric   case eConnectionStatusSuccess:
15014f1b3e8SDimitry Andric     return "success";
15114f1b3e8SDimitry Andric   case eConnectionStatusError:
15214f1b3e8SDimitry Andric     return "error";
15314f1b3e8SDimitry Andric   case eConnectionStatusTimedOut:
15414f1b3e8SDimitry Andric     return "timed out";
15514f1b3e8SDimitry Andric   case eConnectionStatusNoConnection:
15614f1b3e8SDimitry Andric     return "no connection";
15714f1b3e8SDimitry Andric   case eConnectionStatusLostConnection:
15814f1b3e8SDimitry Andric     return "lost connection";
15914f1b3e8SDimitry Andric   case eConnectionStatusEndOfFile:
16014f1b3e8SDimitry Andric     return "end of file";
16114f1b3e8SDimitry Andric   case eConnectionStatusInterrupted:
16214f1b3e8SDimitry Andric     return "interrupted";
163f034231aSEd Maste   }
164f034231aSEd Maste 
165b60736ecSDimitry Andric   return "@" + std::to_string(status);
166f034231aSEd Maste }
167