blob: 9701eecebafe43de1e15ed15369922754698416d [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/connectivity/overnet/lib/protocol/unreliable_framer.h"
#include "third_party/zlib/zlib.h"
namespace overnet {
UnreliableFramer::UnreliableFramer() : StreamFramer(Border{2, 4}, 256) {}
UnreliableFramer::~UnreliableFramer() = default;
void UnreliableFramer::Push(Slice data) {
buffered_input_.Append(std::move(data));
}
StatusOr<Optional<Slice>> UnreliableFramer::Pop() {
using Sts = StatusOr<Optional<Slice>>;
const uint8_t *const begin = buffered_input_.begin();
const uint8_t *p = begin;
const uint8_t *const end = buffered_input_.end();
while (p != end) {
if (*p != kStartOfFrameMarker) {
++p;
continue;
}
if (end - p < 7) {
break;
}
uint32_t length = uint32_t(p[1]) + 1;
if (end - p < 2 + length + 4) {
break;
}
uint32_t sent_crc;
memcpy(&sent_crc, p + 2 + length, sizeof(sent_crc));
const uint32_t calc_crc = crc32(0, p + 2, length);
if (sent_crc != calc_crc) {
++p;
continue;
}
auto out = buffered_input_;
out.Trim(p + 2 - begin, end - (p + 2) - length);
buffered_input_.TrimBegin(p + 2 + length + 4 - begin);
return Sts(out);
}
buffered_input_.TrimBegin(p - begin);
return Sts(Nothing);
}
bool UnreliableFramer::InputEmpty() const {
return buffered_input_.length() == 0;
}
Optional<Slice> UnreliableFramer::SkipNoise() {
const uint8_t *const begin = buffered_input_.begin();
const uint8_t *p = begin;
const uint8_t *const end = buffered_input_.end();
if (p == end) {
return Nothing;
}
if (*p != kStartOfFrameMarker) {
return Nothing;
}
++p;
while (p != end) {
if (*p != kStartOfFrameMarker) {
++p;
continue;
}
if (end - p < 7) {
break;
}
uint32_t length = uint32_t(p[1]) + 1;
if (end - p < 2 + length + 4) {
break;
}
uint32_t sent_crc;
memcpy(&sent_crc, p + 2 + length, sizeof(sent_crc));
const uint32_t calc_crc = crc32(0, p + 2, length);
if (sent_crc != calc_crc) {
++p;
continue;
}
break;
}
return buffered_input_.TakeUntilPointer(p);
}
Slice UnreliableFramer::Frame(Slice data) {
const auto length = data.length();
if (length == 0) {
return data;
}
assert(length <= 256);
return data.WithBorders(Border{2, 4}, [length](uint8_t *p) {
p[0] = kStartOfFrameMarker;
p[1] = length - 1;
auto *s = p + 2 + length;
const uint32_t crc = crc32(0, p + 2, length);
memcpy(s, &crc, sizeof(crc));
});
}
} // namespace overnet