mirror of
https://github.com/akuker/RASCSI.git
synced 2024-06-02 11:41:34 +00:00
419dca3c4c
* Fixed buster compile-time issue
* Host services inherit from ModePageDevice
* Call base class
* Visibility update
* Updated includes
* Updated dispatcher
* Added TODOs
* Logging update
* Code cleanup
* Use namespace instead of class for ScsiDefs
* Renaming
* Cleanup
* Use dispatcher template in order to remove duplicate code
* Updated all dispatchers
* Clean up commands
* Removed duplicate code
* Removed duplicate code
* Updated template definition
* Fixed typo
* Fixed warning
* Code cleanup
* Device list must be static
* Cleanup
* Logging update
* Added comments
* Cleanup
* Base class update
* SCSIBR is not a subclass of Disk anymore, but of PrimaryDevice
* Updated includes
* Fixed compile-time issue on the Pi
* Header file cleanup
* Interface cleanup
* Removed wrong override
* include file cleanup
* Removed obsolete usage of streams
* Removed more stream usages
* Stream usage cleanup
* Include cleanup
* Renaming
* Include cleanup
* Interface update
* SCLP device skeleton
* Initial RELEASE/RESERVE UNIT
* Added full set of commands
* Extracted command phase code
* Stripped SCSI controller code
* Removed unused code
* Commented out code
* Initial naive implementation
* Added debug output
* Disable printing for now
* Updated file handling
* Updated DataOut()
* Added comment
* Updated assertion
* Comment update
* Updated assertion
* Code cleanup
* Reset bytes to transfer
* Reverted change
* Refactoring
* Moved assertion
* Updated ReceiveBytes()
* Removed override
* Added interface
* Code cleanup
* Updated TEST UNIT READY
* Added flag for byte-oriented transfer
* Updated TEST UNIT READY
* Length handling update
* Updated bytecount handling
* Fixed warning
* Added TODO
* Updated assertion
* Enabled priting
* Updated error handling
* Code cleanup
* Logging update
* First working version
* Use temporary file
* Logging update
* Handle parameters
* Updated format string
* Updated logging
* File handling update
* Code cleanup
* Fixed buffer size
* Updated file handling
* Manpage update
* Initial reservation handling
* Updated reservation handling
* Initial reservation testing
* Remember initiator ID
* Extract initiator ID
* Updated SCSI initiator ID handling
* Logging update
* Added reservation timeout
* Updated timeout handling
* Code cleanup
* Only pass initiator ID to *SCSI* controller
* Added comments
* Added comment
* Implemented STOP PRINT
* Comment update
* Comment update
* Comment update
* Added comment
* Comment update
* Removed useless comments
* Updated printer parameter handling
* Updated parameter handling
* Manpage update
* Manpage update
* Comment update
* Default printer product name update
* Renaming
* Updated logging
* Logging update
* Logging update
* Comment update
* Code cleanup
* Added printer shortcut
* Comment update
* Comment update
* Output formatting update
* Updated error handling
* Code cleanup
* More cleanup
* Revert "More cleanup"
This reverts commit 05708986ee
.
* Output formatting update
* Output format update
* Sort parameters
* Comment update
* Improved parsing of parameters
* Manpage update
* Updated SCSI level
* Removed magic constants
* Removed magic constant
* Template update
* Template usage update
* Get rid of SASIDEV for printer
* Get rid of SASIDEV for host services
* Moved initiator_id field
* Moved field
* Moved field
* Added comment
* Error handling must use effective LUN
* Removed obsolete casts
* Removed unused method declarations
* Comment update
* Code cleanup
* More code cleanup
* Optimization
* Removed duplicate code
* Logging update
* Fixed warning
* Code cleanup
* Added TODOs
* TODO update
* Backwards compatibility update
* Comment update
200 lines
5.4 KiB
C++
200 lines
5.4 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// SCSI Target Emulator RaSCSI (*^..^*)
|
|
// for Raspberry Pi
|
|
//
|
|
// Copyright (C) 2021 Uwe Seimet
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <unistd.h>
|
|
#include "os.h"
|
|
#include "log.h"
|
|
#include "rascsi_interface.pb.h"
|
|
#include "localizer.h"
|
|
#include "exceptions.h"
|
|
#include "protobuf_util.h"
|
|
|
|
using namespace std;
|
|
using namespace rascsi_interface;
|
|
|
|
#define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ )
|
|
|
|
#define COMPONENT_SEPARATOR ':'
|
|
#define KEY_VALUE_SEPARATOR '='
|
|
|
|
Localizer localizer;
|
|
|
|
void protobuf_util::ParseParameters(PbDeviceDefinition& device, const string& params)
|
|
{
|
|
if (!params.empty()) {
|
|
if (params.find(KEY_VALUE_SEPARATOR) != string::npos) {
|
|
stringstream ss(params);
|
|
string p;
|
|
while (getline(ss, p, COMPONENT_SEPARATOR)) {
|
|
if (!p.empty()) {
|
|
size_t separator_pos = p.find(KEY_VALUE_SEPARATOR);
|
|
if (separator_pos != string::npos) {
|
|
AddParam(device, p.substr(0, separator_pos), p.substr(separator_pos + 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Old style parameters, for backwards compatibility only.
|
|
// Only one of these parameters will be used by rascsi, depending on the device type.
|
|
else {
|
|
AddParam(device, "file", params);
|
|
if (params != "bridge" && params != "daynaport" && params != "printer" && params != "services") {
|
|
AddParam(device, "interfaces", params);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const string protobuf_util::GetParam(const PbCommand& command, const string& key)
|
|
{
|
|
auto map = command.params();
|
|
return map[key];
|
|
}
|
|
|
|
const string protobuf_util::GetParam(const PbDeviceDefinition& device, const string& key)
|
|
{
|
|
auto map = device.params();
|
|
return map[key];
|
|
}
|
|
|
|
void protobuf_util::AddParam(PbCommand& command, const string& key, const string& value)
|
|
{
|
|
if (!key.empty() && !value.empty()) {
|
|
auto& map = *command.mutable_params();
|
|
map[key] = value;
|
|
}
|
|
}
|
|
|
|
void protobuf_util::AddParam(PbDevice& device, const string& key, const string& value)
|
|
{
|
|
if (!key.empty() && !value.empty()) {
|
|
auto& map = *device.mutable_params();
|
|
map[key] = value;
|
|
}
|
|
}
|
|
|
|
void protobuf_util::AddParam(PbDeviceDefinition& device, const string& key, const string& value)
|
|
{
|
|
if (!key.empty() && !value.empty()) {
|
|
auto& map = *device.mutable_params();
|
|
map[key] = value;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Serialize/Deserialize protobuf message: Length followed by the actual data.
|
|
// Little endian is assumed.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void protobuf_util::SerializeMessage(int fd, const google::protobuf::Message& message)
|
|
{
|
|
string data;
|
|
message.SerializeToString(&data);
|
|
|
|
// Write the size of the protobuf data as a header
|
|
int32_t size = data.length();
|
|
if (write(fd, &size, sizeof(size)) != sizeof(size)) {
|
|
throw io_exception("Can't write protobuf message header");
|
|
}
|
|
|
|
// Write the actual protobuf data
|
|
if (write(fd, data.data(), size) != size) {
|
|
throw io_exception("Can't write protobuf message data");
|
|
}
|
|
}
|
|
|
|
void protobuf_util::DeserializeMessage(int fd, google::protobuf::Message& message)
|
|
{
|
|
// Read the header with the size of the protobuf data
|
|
uint8_t header_buf[4];
|
|
int bytes_read = ReadNBytes(fd, header_buf, sizeof(header_buf));
|
|
if (bytes_read < (int)sizeof(header_buf)) {
|
|
return;
|
|
}
|
|
int32_t size = (header_buf[3] << 24) + (header_buf[2] << 16) + (header_buf[1] << 8) + header_buf[0];
|
|
if (size <= 0) {
|
|
throw io_exception("Broken protobuf message header");
|
|
}
|
|
|
|
// Read the binary protobuf data
|
|
uint8_t data_buf[size];
|
|
bytes_read = ReadNBytes(fd, data_buf, size);
|
|
if (bytes_read < size) {
|
|
throw io_exception("Missing protobuf message data");
|
|
}
|
|
|
|
// Create protobuf message
|
|
string data((const char *)data_buf, size);
|
|
message.ParseFromString(data);
|
|
}
|
|
|
|
int protobuf_util::ReadNBytes(int fd, uint8_t *buf, int n)
|
|
{
|
|
int offset = 0;
|
|
while (offset < n) {
|
|
ssize_t len = read(fd, buf + offset, n - offset);
|
|
if (!len) {
|
|
break;
|
|
}
|
|
|
|
offset += len;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
bool protobuf_util::ReturnLocalizedError(const CommandContext& context, const LocalizationKey key,
|
|
const string& arg1, const string& arg2, const string& arg3)
|
|
{
|
|
return ReturnLocalizedError(context, key, NO_ERROR_CODE, arg1, arg2, arg3);
|
|
}
|
|
|
|
bool protobuf_util::ReturnLocalizedError(const CommandContext& context, const LocalizationKey key,
|
|
const PbErrorCode error_code, const string& arg1, const string& arg2, const string& arg3)
|
|
{
|
|
// For the logfile always use English
|
|
LOGERROR("%s", localizer.Localize(key, "en", arg1, arg2, arg3).c_str());
|
|
|
|
return ReturnStatus(context, false, localizer.Localize(key, context.locale, arg1, arg2, arg3), error_code, false);
|
|
}
|
|
|
|
bool protobuf_util::ReturnStatus(const CommandContext& context, bool status, const string& msg,
|
|
const PbErrorCode error_code, bool log)
|
|
{
|
|
// Do not log twice if logging has already been done in the localized error handling above
|
|
if (log && !status && !msg.empty()) {
|
|
LOGERROR("%s", msg.c_str());
|
|
}
|
|
|
|
if (context.fd == -1) {
|
|
if (!msg.empty()) {
|
|
if (status) {
|
|
FPRT(stderr, "Error: ");
|
|
FPRT(stderr, "%s", msg.c_str());
|
|
FPRT(stderr, "\n");
|
|
}
|
|
else {
|
|
FPRT(stdout, "%s", msg.c_str());
|
|
FPRT(stderr, "\n");
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
PbResult result;
|
|
result.set_status(status);
|
|
result.set_error_code(error_code);
|
|
result.set_msg(msg);
|
|
SerializeMessage(context.fd, result);
|
|
}
|
|
|
|
return status;
|
|
}
|