blob: 755301d2b21b872073aaf1445caf4b4f8fbabf52 [file] [log] [blame]
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "message_file.hpp"
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <format>
namespace google
{
namespace hoth
{
MessageFile::MessageFile(const std::string& path, const internal::Sys* sys) :
sys(sys)
{
fd = sys->open(path.c_str(), O_RDWR);
if (fd < 0)
{
throw internal::errnoException(
std::format("Error opening Hoth interface \"{}\"", path));
}
}
MessageFile::~MessageFile()
{
sys->close(fd);
}
void MessageFile::send(const uint8_t* buf, size_t size, size_t seek)
{
if (sys->lseek(fd, static_cast<off_t>(seek), SEEK_SET) < 0)
{
throw internal::errnoException("Error seeking on Hoth interface");
}
ssize_t ret = -1;
do
{
ret = sys->write(fd, buf, size);
// Retry if interrupted
} while (ret < 0 && errno == EINTR);
if (ret < 0)
{
throw internal::errnoException("Error writing to Hoth interface");
}
if (static_cast<size_t>(ret) != size)
{
// Fail on incomplete writes because they can confuse Hoth
throw std::runtime_error(std::format(
"Tried to send message of size {} but could only send {} bytes",
size, ret));
}
}
void MessageFile::recv(uint8_t* buf, size_t size, size_t seek)
{
if (sys->lseek(fd, static_cast<off_t>(seek), SEEK_SET) < 0)
{
throw internal::errnoException("Error seeking on Hoth interface");
}
while (size > 0)
{
auto ret = sys->read(fd, buf, size);
if (ret < 0)
{
if (errno == EINTR)
{
continue; // interrupted; try again
}
throw internal::errnoException("Error reading from Hoth interface");
}
if (ret == 0)
{
// EOF hit
throw std::runtime_error("Hit EOF while expecting data");
} // ret > 0
buf += ret;
size -= ret;
};
}
} // namespace hoth
} // namespace google