1dda28197Spatrick //===-- Communication.cpp -------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Core/Communication.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Utility/Connection.h"
12*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
13061da546Spatrick #include "lldb/Utility/Log.h"
14061da546Spatrick #include "lldb/Utility/Status.h"
15061da546Spatrick
16061da546Spatrick #include "llvm/Support/Compiler.h"
17061da546Spatrick
18061da546Spatrick #include <algorithm>
19061da546Spatrick #include <cstring>
20061da546Spatrick #include <memory>
21061da546Spatrick
22be691f3bSpatrick #include <cerrno>
23be691f3bSpatrick #include <cinttypes>
24be691f3bSpatrick #include <cstdio>
25061da546Spatrick
26061da546Spatrick using namespace lldb;
27061da546Spatrick using namespace lldb_private;
28061da546Spatrick
Communication()29*f6aab3d8Srobert Communication::Communication()
30*f6aab3d8Srobert : m_connection_sp(), m_write_mutex(), m_close_on_eof(true) {
31061da546Spatrick }
32061da546Spatrick
~Communication()33061da546Spatrick Communication::~Communication() {
34061da546Spatrick Clear();
35061da546Spatrick }
36061da546Spatrick
Clear()37061da546Spatrick void Communication::Clear() {
38dda28197Spatrick Disconnect(nullptr);
39061da546Spatrick }
40061da546Spatrick
Connect(const char * url,Status * error_ptr)41061da546Spatrick ConnectionStatus Communication::Connect(const char *url, Status *error_ptr) {
42061da546Spatrick Clear();
43061da546Spatrick
44*f6aab3d8Srobert LLDB_LOG(GetLog(LLDBLog::Communication),
45061da546Spatrick "{0} Communication::Connect (url = {1})", this, url);
46061da546Spatrick
47061da546Spatrick lldb::ConnectionSP connection_sp(m_connection_sp);
48061da546Spatrick if (connection_sp)
49061da546Spatrick return connection_sp->Connect(url, error_ptr);
50061da546Spatrick if (error_ptr)
51061da546Spatrick error_ptr->SetErrorString("Invalid connection.");
52061da546Spatrick return eConnectionStatusNoConnection;
53061da546Spatrick }
54061da546Spatrick
Disconnect(Status * error_ptr)55061da546Spatrick ConnectionStatus Communication::Disconnect(Status *error_ptr) {
56*f6aab3d8Srobert LLDB_LOG(GetLog(LLDBLog::Communication), "{0} Communication::Disconnect ()",
57*f6aab3d8Srobert this);
58061da546Spatrick
59061da546Spatrick lldb::ConnectionSP connection_sp(m_connection_sp);
60061da546Spatrick if (connection_sp) {
61061da546Spatrick ConnectionStatus status = connection_sp->Disconnect(error_ptr);
62061da546Spatrick // We currently don't protect connection_sp with any mutex for multi-
63061da546Spatrick // threaded environments. So lets not nuke our connection class without
64061da546Spatrick // putting some multi-threaded protections in. We also probably don't want
65061da546Spatrick // to pay for the overhead it might cause if every time we access the
66061da546Spatrick // connection we have to take a lock.
67061da546Spatrick //
68061da546Spatrick // This unique pointer will cleanup after itself when this object goes
69061da546Spatrick // away, so there is no need to currently have it destroy itself
70061da546Spatrick // immediately upon disconnect.
71061da546Spatrick // connection_sp.reset();
72061da546Spatrick return status;
73061da546Spatrick }
74061da546Spatrick return eConnectionStatusNoConnection;
75061da546Spatrick }
76061da546Spatrick
IsConnected() const77061da546Spatrick bool Communication::IsConnected() const {
78061da546Spatrick lldb::ConnectionSP connection_sp(m_connection_sp);
79061da546Spatrick return (connection_sp ? connection_sp->IsConnected() : false);
80061da546Spatrick }
81061da546Spatrick
HasConnection() const82061da546Spatrick bool Communication::HasConnection() const {
83061da546Spatrick return m_connection_sp.get() != nullptr;
84061da546Spatrick }
85061da546Spatrick
Read(void * dst,size_t dst_len,const Timeout<std::micro> & timeout,ConnectionStatus & status,Status * error_ptr)86061da546Spatrick size_t Communication::Read(void *dst, size_t dst_len,
87061da546Spatrick const Timeout<std::micro> &timeout,
88061da546Spatrick ConnectionStatus &status, Status *error_ptr) {
89*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Communication);
90061da546Spatrick LLDB_LOG(
91061da546Spatrick log,
92061da546Spatrick "this = {0}, dst = {1}, dst_len = {2}, timeout = {3}, connection = {4}",
93061da546Spatrick this, dst, dst_len, timeout, m_connection_sp.get());
94061da546Spatrick
95061da546Spatrick return ReadFromConnection(dst, dst_len, timeout, status, error_ptr);
96061da546Spatrick }
97061da546Spatrick
Write(const void * src,size_t src_len,ConnectionStatus & status,Status * error_ptr)98061da546Spatrick size_t Communication::Write(const void *src, size_t src_len,
99061da546Spatrick ConnectionStatus &status, Status *error_ptr) {
100061da546Spatrick lldb::ConnectionSP connection_sp(m_connection_sp);
101061da546Spatrick
102061da546Spatrick std::lock_guard<std::mutex> guard(m_write_mutex);
103*f6aab3d8Srobert LLDB_LOG(GetLog(LLDBLog::Communication),
104*f6aab3d8Srobert "{0} Communication::Write (src = {1}, src_len = {2}"
105*f6aab3d8Srobert ") connection = {3}",
106061da546Spatrick this, src, (uint64_t)src_len, connection_sp.get());
107061da546Spatrick
108061da546Spatrick if (connection_sp)
109061da546Spatrick return connection_sp->Write(src, src_len, status, error_ptr);
110061da546Spatrick
111061da546Spatrick if (error_ptr)
112061da546Spatrick error_ptr->SetErrorString("Invalid connection.");
113061da546Spatrick status = eConnectionStatusNoConnection;
114061da546Spatrick return 0;
115061da546Spatrick }
116061da546Spatrick
WriteAll(const void * src,size_t src_len,ConnectionStatus & status,Status * error_ptr)117*f6aab3d8Srobert size_t Communication::WriteAll(const void *src, size_t src_len,
118*f6aab3d8Srobert ConnectionStatus &status, Status *error_ptr) {
119*f6aab3d8Srobert size_t total_written = 0;
120*f6aab3d8Srobert do
121*f6aab3d8Srobert total_written += Write(static_cast<const char *>(src) + total_written,
122*f6aab3d8Srobert src_len - total_written, status, error_ptr);
123*f6aab3d8Srobert while (status == eConnectionStatusSuccess && total_written < src_len);
124*f6aab3d8Srobert return total_written;
125061da546Spatrick }
126061da546Spatrick
ReadFromConnection(void * dst,size_t dst_len,const Timeout<std::micro> & timeout,ConnectionStatus & status,Status * error_ptr)127061da546Spatrick size_t Communication::ReadFromConnection(void *dst, size_t dst_len,
128061da546Spatrick const Timeout<std::micro> &timeout,
129061da546Spatrick ConnectionStatus &status,
130061da546Spatrick Status *error_ptr) {
131061da546Spatrick lldb::ConnectionSP connection_sp(m_connection_sp);
132061da546Spatrick if (connection_sp)
133061da546Spatrick return connection_sp->Read(dst, dst_len, timeout, status, error_ptr);
134061da546Spatrick
135061da546Spatrick if (error_ptr)
136061da546Spatrick error_ptr->SetErrorString("Invalid connection.");
137061da546Spatrick status = eConnectionStatusNoConnection;
138061da546Spatrick return 0;
139061da546Spatrick }
140061da546Spatrick
SetConnection(std::unique_ptr<Connection> connection)141dda28197Spatrick void Communication::SetConnection(std::unique_ptr<Connection> connection) {
142061da546Spatrick Disconnect(nullptr);
143dda28197Spatrick m_connection_sp = std::move(connection);
144061da546Spatrick }
145061da546Spatrick
146be691f3bSpatrick std::string
ConnectionStatusAsString(lldb::ConnectionStatus status)147be691f3bSpatrick Communication::ConnectionStatusAsString(lldb::ConnectionStatus status) {
148061da546Spatrick switch (status) {
149061da546Spatrick case eConnectionStatusSuccess:
150061da546Spatrick return "success";
151061da546Spatrick case eConnectionStatusError:
152061da546Spatrick return "error";
153061da546Spatrick case eConnectionStatusTimedOut:
154061da546Spatrick return "timed out";
155061da546Spatrick case eConnectionStatusNoConnection:
156061da546Spatrick return "no connection";
157061da546Spatrick case eConnectionStatusLostConnection:
158061da546Spatrick return "lost connection";
159061da546Spatrick case eConnectionStatusEndOfFile:
160061da546Spatrick return "end of file";
161061da546Spatrick case eConnectionStatusInterrupted:
162061da546Spatrick return "interrupted";
163061da546Spatrick }
164061da546Spatrick
165be691f3bSpatrick return "@" + std::to_string(status);
166061da546Spatrick }
167