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() {} 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 int reason = 0; 106 #if defined(_WIN32) 107 if (descriptor.m_is_socket) 108 reason = WSAGetLastError(); 109 else 110 reason = errno; 111 #else 112 reason = errno; 113 if (reason == EINTR || reason == EAGAIN) 114 continue; 115 #endif 116 117 if (log) 118 *log << "Error " << reason << " reading from input file.\n"; 119 return false; 120 } 121 122 assert(bytes_read >= 0 && (size_t)bytes_read <= length); 123 ptr += bytes_read; 124 length -= bytes_read; 125 } 126 text += data; 127 return true; 128 } 129 130 bool InputStream::read_line(std::ofstream *log, std::string &line) { 131 line.clear(); 132 while (true) { 133 if (!read_full(log, 1, line)) 134 return false; 135 136 if (llvm::StringRef(line).endswith("\r\n")) 137 break; 138 } 139 line.erase(line.size() - 2); 140 return true; 141 } 142 143 bool InputStream::read_expected(std::ofstream *log, llvm::StringRef expected) { 144 std::string result; 145 if (!read_full(log, expected.size(), result)) 146 return false; 147 if (expected != result) { 148 if (log) 149 *log << "Warning: Expected '" << expected.str() << "', got '" << result 150 << "\n"; 151 } 152 return true; 153 } 154