-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprotocol.cpp
More file actions
117 lines (105 loc) · 3.06 KB
/
protocol.cpp
File metadata and controls
117 lines (105 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "protocol.h"
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
namespace flexql {
namespace {
bool write_all(int fd, const void *buffer, std::size_t size) {
const char *cursor = static_cast<const char *>(buffer);
while (size > 0) {
ssize_t written = ::send(fd, cursor, size, 0);
if (written <= 0) {
return false;
}
cursor += written;
size -= static_cast<std::size_t>(written);
}
return true;
}
bool read_all(int fd, void *buffer, std::size_t size) {
char *cursor = static_cast<char *>(buffer);
while (size > 0) {
ssize_t received = ::recv(fd, cursor, size, 0);
if (received <= 0) {
return false;
}
cursor += received;
size -= static_cast<std::size_t>(received);
}
return true;
}
} // namespace
bool send_frame(int fd, const std::string &payload) {
std::uint32_t network_length = htonl(static_cast<std::uint32_t>(payload.size()));
return write_all(fd, &network_length, sizeof(network_length)) &&
write_all(fd, payload.data(), payload.size());
}
std::optional<std::string> recv_frame(int fd) {
std::uint32_t network_length = 0;
if (!read_all(fd, &network_length, sizeof(network_length))) {
return std::nullopt;
}
std::uint32_t length = ntohl(network_length);
std::string payload(length, '\0');
if (length > 0 && !read_all(fd, payload.data(), length)) {
return std::nullopt;
}
return payload;
}
std::string escape_field(const std::string &field) {
std::string escaped;
escaped.reserve(field.size());
for (char ch : field) {
if (ch == '\\' || ch == '\t' || ch == '\n') {
escaped.push_back('\\');
if (ch == '\t') {
escaped.push_back('t');
} else if (ch == '\n') {
escaped.push_back('n');
} else {
escaped.push_back(ch);
}
} else {
escaped.push_back(ch);
}
}
return escaped;
}
std::vector<std::string> split_fields(const std::string &line) {
std::vector<std::string> fields;
std::string current;
bool escaping = false;
for (char ch : line) {
if (escaping) {
if (ch == 't') {
current.push_back('\t');
} else if (ch == 'n') {
current.push_back('\n');
} else {
current.push_back(ch);
}
escaping = false;
continue;
}
if (ch == '\\') {
escaping = true;
continue;
}
if (ch == '\t') {
fields.push_back(current);
current.clear();
continue;
}
current.push_back(ch);
}
fields.push_back(current);
return fields;
}
std::string serialize_result_header(const QueryResult &result) {
std::string line = "RESULT";
for (const std::string &column : result.column_names) {
line.append("\t").append(escape_field(column));
}
return line;
}
} // namespace flexql