xref: /llvm-project/lldb/tools/lldb-dap/IOStream.cpp (revision 09c258ef6a2fcca2161488b214d53ef39891fa22)
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