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