15ffd83dbSDimitry Andric //===-- Communication.cpp -------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Core/Communication.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "lldb/Utility/Connection.h"
1281ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
130b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
140b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
170b57cec5SDimitry Andric
180b57cec5SDimitry Andric #include <algorithm>
190b57cec5SDimitry Andric #include <cstring>
200b57cec5SDimitry Andric #include <memory>
210b57cec5SDimitry Andric
22fe6060f1SDimitry Andric #include <cerrno>
23fe6060f1SDimitry Andric #include <cinttypes>
24fe6060f1SDimitry Andric #include <cstdio>
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric using namespace lldb;
270b57cec5SDimitry Andric using namespace lldb_private;
280b57cec5SDimitry Andric
Communication()29bdd1243dSDimitry Andric Communication::Communication()
30bdd1243dSDimitry Andric : m_connection_sp(), m_write_mutex(), m_close_on_eof(true) {
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric
~Communication()330b57cec5SDimitry Andric Communication::~Communication() {
340b57cec5SDimitry Andric Clear();
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric
Clear()370b57cec5SDimitry Andric void Communication::Clear() {
385ffd83dbSDimitry Andric Disconnect(nullptr);
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric
Connect(const char * url,Status * error_ptr)410b57cec5SDimitry Andric ConnectionStatus Communication::Connect(const char *url, Status *error_ptr) {
420b57cec5SDimitry Andric Clear();
430b57cec5SDimitry Andric
4481ad6265SDimitry Andric LLDB_LOG(GetLog(LLDBLog::Communication),
459dba64beSDimitry Andric "{0} Communication::Connect (url = {1})", this, url);
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric lldb::ConnectionSP connection_sp(m_connection_sp);
480b57cec5SDimitry Andric if (connection_sp)
490b57cec5SDimitry Andric return connection_sp->Connect(url, error_ptr);
500b57cec5SDimitry Andric if (error_ptr)
510b57cec5SDimitry Andric error_ptr->SetErrorString("Invalid connection.");
520b57cec5SDimitry Andric return eConnectionStatusNoConnection;
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric
Disconnect(Status * error_ptr)550b57cec5SDimitry Andric ConnectionStatus Communication::Disconnect(Status *error_ptr) {
5681ad6265SDimitry Andric LLDB_LOG(GetLog(LLDBLog::Communication), "{0} Communication::Disconnect ()",
5781ad6265SDimitry Andric this);
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric lldb::ConnectionSP connection_sp(m_connection_sp);
600b57cec5SDimitry Andric if (connection_sp) {
610b57cec5SDimitry Andric ConnectionStatus status = connection_sp->Disconnect(error_ptr);
620b57cec5SDimitry Andric // We currently don't protect connection_sp with any mutex for multi-
630b57cec5SDimitry Andric // threaded environments. So lets not nuke our connection class without
640b57cec5SDimitry Andric // putting some multi-threaded protections in. We also probably don't want
650b57cec5SDimitry Andric // to pay for the overhead it might cause if every time we access the
660b57cec5SDimitry Andric // connection we have to take a lock.
670b57cec5SDimitry Andric //
680b57cec5SDimitry Andric // This unique pointer will cleanup after itself when this object goes
690b57cec5SDimitry Andric // away, so there is no need to currently have it destroy itself
700b57cec5SDimitry Andric // immediately upon disconnect.
710b57cec5SDimitry Andric // connection_sp.reset();
720b57cec5SDimitry Andric return status;
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric return eConnectionStatusNoConnection;
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric
IsConnected() const770b57cec5SDimitry Andric bool Communication::IsConnected() const {
780b57cec5SDimitry Andric lldb::ConnectionSP connection_sp(m_connection_sp);
790b57cec5SDimitry Andric return (connection_sp ? connection_sp->IsConnected() : false);
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric
HasConnection() const820b57cec5SDimitry Andric bool Communication::HasConnection() const {
830b57cec5SDimitry Andric return m_connection_sp.get() != nullptr;
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric
Read(void * dst,size_t dst_len,const Timeout<std::micro> & timeout,ConnectionStatus & status,Status * error_ptr)860b57cec5SDimitry Andric size_t Communication::Read(void *dst, size_t dst_len,
870b57cec5SDimitry Andric const Timeout<std::micro> &timeout,
880b57cec5SDimitry Andric ConnectionStatus &status, Status *error_ptr) {
8981ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Communication);
900b57cec5SDimitry Andric LLDB_LOG(
910b57cec5SDimitry Andric log,
920b57cec5SDimitry Andric "this = {0}, dst = {1}, dst_len = {2}, timeout = {3}, connection = {4}",
930b57cec5SDimitry Andric this, dst, dst_len, timeout, m_connection_sp.get());
940b57cec5SDimitry Andric
950b57cec5SDimitry Andric return ReadFromConnection(dst, dst_len, timeout, status, error_ptr);
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric
Write(const void * src,size_t src_len,ConnectionStatus & status,Status * error_ptr)980b57cec5SDimitry Andric size_t Communication::Write(const void *src, size_t src_len,
990b57cec5SDimitry Andric ConnectionStatus &status, Status *error_ptr) {
1000b57cec5SDimitry Andric lldb::ConnectionSP connection_sp(m_connection_sp);
1010b57cec5SDimitry Andric
1020b57cec5SDimitry Andric std::lock_guard<std::mutex> guard(m_write_mutex);
10381ad6265SDimitry Andric LLDB_LOG(GetLog(LLDBLog::Communication),
104349cc55cSDimitry Andric "{0} Communication::Write (src = {1}, src_len = {2}"
105349cc55cSDimitry Andric ") connection = {3}",
1060b57cec5SDimitry Andric this, src, (uint64_t)src_len, connection_sp.get());
1070b57cec5SDimitry Andric
1080b57cec5SDimitry Andric if (connection_sp)
1090b57cec5SDimitry Andric return connection_sp->Write(src, src_len, status, error_ptr);
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric if (error_ptr)
1120b57cec5SDimitry Andric error_ptr->SetErrorString("Invalid connection.");
1130b57cec5SDimitry Andric status = eConnectionStatusNoConnection;
1140b57cec5SDimitry Andric return 0;
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric
WriteAll(const void * src,size_t src_len,ConnectionStatus & status,Status * error_ptr)117349cc55cSDimitry Andric size_t Communication::WriteAll(const void *src, size_t src_len,
118349cc55cSDimitry Andric ConnectionStatus &status, Status *error_ptr) {
119349cc55cSDimitry Andric size_t total_written = 0;
120349cc55cSDimitry Andric do
121349cc55cSDimitry Andric total_written += Write(static_cast<const char *>(src) + total_written,
122349cc55cSDimitry Andric src_len - total_written, status, error_ptr);
123349cc55cSDimitry Andric while (status == eConnectionStatusSuccess && total_written < src_len);
124349cc55cSDimitry Andric return total_written;
125349cc55cSDimitry Andric }
126349cc55cSDimitry Andric
ReadFromConnection(void * dst,size_t dst_len,const Timeout<std::micro> & timeout,ConnectionStatus & status,Status * error_ptr)1270b57cec5SDimitry Andric size_t Communication::ReadFromConnection(void *dst, size_t dst_len,
1280b57cec5SDimitry Andric const Timeout<std::micro> &timeout,
1290b57cec5SDimitry Andric ConnectionStatus &status,
1300b57cec5SDimitry Andric Status *error_ptr) {
1310b57cec5SDimitry Andric lldb::ConnectionSP connection_sp(m_connection_sp);
1320b57cec5SDimitry Andric if (connection_sp)
1330b57cec5SDimitry Andric return connection_sp->Read(dst, dst_len, timeout, status, error_ptr);
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric if (error_ptr)
1360b57cec5SDimitry Andric error_ptr->SetErrorString("Invalid connection.");
1370b57cec5SDimitry Andric status = eConnectionStatusNoConnection;
1380b57cec5SDimitry Andric return 0;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
SetConnection(std::unique_ptr<Connection> connection)1415ffd83dbSDimitry Andric void Communication::SetConnection(std::unique_ptr<Connection> connection) {
1420b57cec5SDimitry Andric Disconnect(nullptr);
1435ffd83dbSDimitry Andric m_connection_sp = std::move(connection);
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric
146e8d8bef9SDimitry Andric std::string
ConnectionStatusAsString(lldb::ConnectionStatus status)147e8d8bef9SDimitry Andric Communication::ConnectionStatusAsString(lldb::ConnectionStatus status) {
1480b57cec5SDimitry Andric switch (status) {
1490b57cec5SDimitry Andric case eConnectionStatusSuccess:
1500b57cec5SDimitry Andric return "success";
1510b57cec5SDimitry Andric case eConnectionStatusError:
1520b57cec5SDimitry Andric return "error";
1530b57cec5SDimitry Andric case eConnectionStatusTimedOut:
1540b57cec5SDimitry Andric return "timed out";
1550b57cec5SDimitry Andric case eConnectionStatusNoConnection:
1560b57cec5SDimitry Andric return "no connection";
1570b57cec5SDimitry Andric case eConnectionStatusLostConnection:
1580b57cec5SDimitry Andric return "lost connection";
1590b57cec5SDimitry Andric case eConnectionStatusEndOfFile:
1600b57cec5SDimitry Andric return "end of file";
1610b57cec5SDimitry Andric case eConnectionStatusInterrupted:
1620b57cec5SDimitry Andric return "interrupted";
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric
165e8d8bef9SDimitry Andric return "@" + std::to_string(status);
1660b57cec5SDimitry Andric }
167