1 //===-- IOStream.cpp --------------------------------------------*- C++ -*-===// 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 "IOStream.h" 10 11 #if defined(_WIN32) 12 #include <io.h> 13 #else 14 #include <netinet/in.h> 15 #include <sys/socket.h> 16 #include <unistd.h> 17 #endif 18 19 #include <fstream> 20 #include <string> 21 22 using namespace lldb_dap; 23 24 StreamDescriptor::StreamDescriptor() = default; 25 26 StreamDescriptor::StreamDescriptor(StreamDescriptor &&other) { 27 *this = std::move(other); 28 } 29 30 StreamDescriptor::~StreamDescriptor() { 31 if (!m_close) 32 return; 33 34 if (m_is_socket) 35 #if defined(_WIN32) 36 ::closesocket(m_socket); 37 #else 38 ::close(m_socket); 39 #endif 40 else 41 ::close(m_fd); 42 } 43 44 StreamDescriptor &StreamDescriptor::operator=(StreamDescriptor &&other) { 45 m_close = other.m_close; 46 other.m_close = false; 47 m_is_socket = other.m_is_socket; 48 if (m_is_socket) 49 m_socket = other.m_socket; 50 else 51 m_fd = other.m_fd; 52 return *this; 53 } 54 55 StreamDescriptor StreamDescriptor::from_socket(SOCKET s, bool close) { 56 StreamDescriptor sd; 57 sd.m_is_socket = true; 58 sd.m_socket = s; 59 sd.m_close = close; 60 return sd; 61 } 62 63 StreamDescriptor StreamDescriptor::from_file(int fd, bool close) { 64 StreamDescriptor sd; 65 sd.m_is_socket = false; 66 sd.m_fd = fd; 67 sd.m_close = close; 68 return sd; 69 } 70 71 bool OutputStream::write_full(llvm::StringRef str) { 72 while (!str.empty()) { 73 int bytes_written = 0; 74 if (descriptor.m_is_socket) 75 bytes_written = ::send(descriptor.m_socket, str.data(), str.size(), 0); 76 else 77 bytes_written = ::write(descriptor.m_fd, str.data(), str.size()); 78 79 if (bytes_written < 0) { 80 if (errno == EINTR || errno == EAGAIN) 81 continue; 82 return false; 83 } 84 str = str.drop_front(bytes_written); 85 } 86 87 return true; 88 } 89 90 bool InputStream::read_full(std::ofstream *log, size_t length, 91 std::string &text) { 92 std::string data; 93 data.resize(length); 94 95 char *ptr = &data[0]; 96 while (length != 0) { 97 int bytes_read = 0; 98 if (descriptor.m_is_socket) 99 bytes_read = ::recv(descriptor.m_socket, ptr, length, 0); 100 else 101 bytes_read = ::read(descriptor.m_fd, ptr, length); 102 103 if (bytes_read == 0) { 104 if (log) 105 *log << "End of file (EOF) reading from input file.\n"; 106 return false; 107 } 108 if (bytes_read < 0) { 109 int reason = 0; 110 #if defined(_WIN32) 111 if (descriptor.m_is_socket) 112 reason = WSAGetLastError(); 113 else 114 reason = errno; 115 #else 116 reason = errno; 117 if (reason == EINTR || reason == EAGAIN) 118 continue; 119 #endif 120 121 if (log) 122 *log << "Error " << reason << " reading from input file.\n"; 123 return false; 124 } 125 126 assert(bytes_read >= 0 && (size_t)bytes_read <= length); 127 ptr += bytes_read; 128 length -= bytes_read; 129 } 130 text += data; 131 return true; 132 } 133 134 bool InputStream::read_line(std::ofstream *log, std::string &line) { 135 line.clear(); 136 while (true) { 137 if (!read_full(log, 1, line)) 138 return false; 139 140 if (llvm::StringRef(line).ends_with("\r\n")) 141 break; 142 } 143 line.erase(line.size() - 2); 144 return true; 145 } 146 147 bool InputStream::read_expected(std::ofstream *log, llvm::StringRef expected) { 148 std::string result; 149 if (!read_full(log, expected.size(), result)) 150 return false; 151 if (expected != result) { 152 if (log) 153 *log << "Warning: Expected '" << expected.str() << "', got '" << result 154 << "\n"; 155 } 156 return true; 157 } 158