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
118
119
120
121
122
123
124
125
126
127
|
// Copyright (C) 2022-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
#include <tcp/tcp_stream_msg.h>
#include <util/str.h>
#include <iomanip>
#include <sstream>
#include <functional>
namespace isc {
namespace tcp {
bool
TcpStreamRequest::needData() const {
return (!expected_size_ || (wire_data_.size() < expected_size_));
}
size_t
TcpStreamRequest::postBuffer(const void* buf, const size_t nbytes) {
if (!nbytes) {
// Nothing to do.
return (0);
}
const char* bufptr = static_cast<const char*>(buf);
size_t bytes_left = nbytes;
size_t wire_size = wire_data_.size();
size_t bytes_used = 0;
while (bytes_left) {
if (expected_size_) {
// We have the length, copy as much of what we still need as we can.
size_t need_bytes = expected_size_ - wire_size;
size_t copy_bytes = (need_bytes <= bytes_left ? need_bytes : bytes_left);
wire_data_.insert(wire_data_.end(), bufptr, bufptr + copy_bytes);
// bytes_left -= copy_bytes; // Since we break, we don't need to do this anymore.
bytes_used += copy_bytes;
break;
}
// Otherwise we don't know the length yet.
while (wire_size < 2 && bytes_left) {
wire_data_.push_back(*bufptr);
++bufptr;
--bytes_left;
++bytes_used;
++wire_size;
}
// If we have enough to do it, calculate the expected length.
if (wire_size == 2 ) {
const uint8_t* cp = static_cast<const uint8_t*>(wire_data_.data());
uint16_t len = static_cast<unsigned int>(cp[0]) << 8;
len |= static_cast<unsigned int>(cp[1]);
expected_size_ = len + sizeof(len);
}
}
// Return how much we used.
return (bytes_used);
}
std::string
TcpStreamRequest::logFormatRequest(const size_t limit) const {
std::stringstream output;
try {
size_t max = (limit && (limit < wire_data_.size()) ? limit : wire_data_.size());
output << "expected_size_: " << expected_size_ << ", current size: " << wire_data_.size()
<< ", data: "
<< isc::util::str::dumpAsHex(wire_data_.data(), max);
} catch (const std::exception& ex) {
std::stringstream output;
output << "logFormatRequest error: " << ex.what();
}
return (output.str());
}
void TcpStreamRequest::unpack() {
if (needData()) {
isc_throw(InvalidOperation, "Cannot unpack an incomplete request");
}
if (wire_data_.size() < sizeof(uint16_t)) {
isc_throw(Unexpected, "Request is malformed, too short");
}
request_ = std::vector<uint8_t>(wire_data_.begin() + sizeof(uint16_t), wire_data_.end());
}
void
TcpStreamResponse::setResponseData(const uint8_t* data, size_t length) {
response_.assign(data, data + length);
}
void
TcpStreamResponse::appendResponseData(const uint8_t* data, size_t length) {
response_.insert(response_.end(), data, data + length);
}
void
TcpStreamResponse::setResponseData(const std::string& str) {
response_.assign(str.begin(), str.end());
}
void
TcpStreamResponse::appendResponseData(const std::string& str) {
response_.insert(response_.end(), str.begin(), str.end());
}
void
TcpStreamResponse::pack() {
wire_data_.clear();
// Prepend the length of the request.
uint16_t size = static_cast<uint16_t>(response_.size());
wire_data_.push_back(static_cast<uint8_t>((size & 0xff00U) >> 8));
wire_data_.push_back(static_cast<uint8_t>(size & 0x00ffU));
wire_data_.insert(wire_data_.end(), response_.begin(), response_.end());
}
} // end of namespace isc::tcp
} // end of namespace isc
|