1 //===-- Communication.cpp -------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Core/Communication.h" 10 11 #include "lldb/Utility/Connection.h" 12 #include "lldb/Utility/LLDBLog.h" 13 #include "lldb/Utility/Log.h" 14 #include "lldb/Utility/Status.h" 15 16 #include "llvm/Support/Compiler.h" 17 18 #include <algorithm> 19 #include <cstring> 20 #include <memory> 21 22 #include <cerrno> 23 #include <cinttypes> 24 #include <cstdio> 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 Communication::Communication() 30 : m_connection_sp(), m_write_mutex(), m_close_on_eof(true) { 31 } 32 33 Communication::~Communication() { 34 Clear(); 35 } 36 37 void Communication::Clear() { 38 Disconnect(nullptr); 39 } 40 41 ConnectionStatus Communication::Connect(const char *url, Status *error_ptr) { 42 Clear(); 43 44 LLDB_LOG(GetLog(LLDBLog::Communication), 45 "{0} Communication::Connect (url = {1})", this, url); 46 47 lldb::ConnectionSP connection_sp(m_connection_sp); 48 if (connection_sp) 49 return connection_sp->Connect(url, error_ptr); 50 if (error_ptr) 51 error_ptr->SetErrorString("Invalid connection."); 52 return eConnectionStatusNoConnection; 53 } 54 55 ConnectionStatus Communication::Disconnect(Status *error_ptr) { 56 LLDB_LOG(GetLog(LLDBLog::Communication), "{0} Communication::Disconnect ()", 57 this); 58 59 lldb::ConnectionSP connection_sp(m_connection_sp); 60 if (connection_sp) { 61 ConnectionStatus status = connection_sp->Disconnect(error_ptr); 62 // We currently don't protect connection_sp with any mutex for multi- 63 // threaded environments. So lets not nuke our connection class without 64 // putting some multi-threaded protections in. We also probably don't want 65 // to pay for the overhead it might cause if every time we access the 66 // connection we have to take a lock. 67 // 68 // This unique pointer will cleanup after itself when this object goes 69 // away, so there is no need to currently have it destroy itself 70 // immediately upon disconnect. 71 // connection_sp.reset(); 72 return status; 73 } 74 return eConnectionStatusNoConnection; 75 } 76 77 bool Communication::IsConnected() const { 78 lldb::ConnectionSP connection_sp(m_connection_sp); 79 return (connection_sp ? connection_sp->IsConnected() : false); 80 } 81 82 bool Communication::HasConnection() const { 83 return m_connection_sp.get() != nullptr; 84 } 85 86 size_t Communication::Read(void *dst, size_t dst_len, 87 const Timeout<std::micro> &timeout, 88 ConnectionStatus &status, Status *error_ptr) { 89 Log *log = GetLog(LLDBLog::Communication); 90 LLDB_LOG( 91 log, 92 "this = {0}, dst = {1}, dst_len = {2}, timeout = {3}, connection = {4}", 93 this, dst, dst_len, timeout, m_connection_sp.get()); 94 95 return ReadFromConnection(dst, dst_len, timeout, status, error_ptr); 96 } 97 98 size_t Communication::Write(const void *src, size_t src_len, 99 ConnectionStatus &status, Status *error_ptr) { 100 lldb::ConnectionSP connection_sp(m_connection_sp); 101 102 std::lock_guard<std::mutex> guard(m_write_mutex); 103 LLDB_LOG(GetLog(LLDBLog::Communication), 104 "{0} Communication::Write (src = {1}, src_len = {2}" 105 ") connection = {3}", 106 this, src, (uint64_t)src_len, connection_sp.get()); 107 108 if (connection_sp) 109 return connection_sp->Write(src, src_len, status, error_ptr); 110 111 if (error_ptr) 112 error_ptr->SetErrorString("Invalid connection."); 113 status = eConnectionStatusNoConnection; 114 return 0; 115 } 116 117 size_t Communication::WriteAll(const void *src, size_t src_len, 118 ConnectionStatus &status, Status *error_ptr) { 119 size_t total_written = 0; 120 do 121 total_written += Write(static_cast<const char *>(src) + total_written, 122 src_len - total_written, status, error_ptr); 123 while (status == eConnectionStatusSuccess && total_written < src_len); 124 return total_written; 125 } 126 127 size_t Communication::ReadFromConnection(void *dst, size_t dst_len, 128 const Timeout<std::micro> &timeout, 129 ConnectionStatus &status, 130 Status *error_ptr) { 131 lldb::ConnectionSP connection_sp(m_connection_sp); 132 if (connection_sp) 133 return connection_sp->Read(dst, dst_len, timeout, status, error_ptr); 134 135 if (error_ptr) 136 error_ptr->SetErrorString("Invalid connection."); 137 status = eConnectionStatusNoConnection; 138 return 0; 139 } 140 141 void Communication::SetConnection(std::unique_ptr<Connection> connection) { 142 Disconnect(nullptr); 143 m_connection_sp = std::move(connection); 144 } 145 146 std::string 147 Communication::ConnectionStatusAsString(lldb::ConnectionStatus status) { 148 switch (status) { 149 case eConnectionStatusSuccess: 150 return "success"; 151 case eConnectionStatusError: 152 return "error"; 153 case eConnectionStatusTimedOut: 154 return "timed out"; 155 case eConnectionStatusNoConnection: 156 return "no connection"; 157 case eConnectionStatusLostConnection: 158 return "lost connection"; 159 case eConnectionStatusEndOfFile: 160 return "end of file"; 161 case eConnectionStatusInterrupted: 162 return "interrupted"; 163 } 164 165 return "@" + std::to_string(status); 166 } 167