Allow rasctl to connect from a different host (#134)

* Set hostname

* Added option for hostname

* Support connecting from a different host

* Squashed commit of the following:

commit 6698b8b90a
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Mon Jul 19 01:19:41 2021 -0500

    Remove extraneous carriage return (#135)

    Co-authored-by: Tony Kuker <akuker@gmail.com>

commit af6e311e6e
Author: uweseimet <48174652+uweseimet@users.noreply.github.com>
Date:   Mon Jul 19 00:15:13 2021 +0200

    protobuf-based rasctl/rascsi command interface (#129)

    * Initial protobuf definition

    * protobuf result message draft

    * Merge with develop branch

    * Makefile generates protobuf-based source files

    * Interface update

    * Fixed typo

    * Fixed typo

    * Updated returning status

    * Serialize return data

    * Use correct descriptor

    * Made interface fields required

    * Deserialize result

    * Serialization update

    * Updated serialization

    * Serialization update

    * Updated deserialization

    * status handling update

    * Evaluate status

    * Revert "Evaluate status"

    This reverts commit 3d8f2c3252.

    * Completed sense_key enum

    * Renaming

    * Added protobuf Command

    * Updated command evaluation

    * Interface update

    * Interface update

    * Added DeviceType enum

    * Improved type-safety

    * Fixed typo

    * Type-safety update

    * Fixed typo

    * Error handling update

    * Updated list handling

    * Error handling update

    * Use more C++ strings

    * protobuf enums can provide their names

    * Fixed listing devices

    * Updated logging

    * Enum usage cleanup

    * More enum cleanup

    * Fixed command check

    * Updated type check

    * Updated enums

    * Removed unused variable

    * Removed goto, added exception

    * Socket handling cleanup

    * Code locality cleanup

    * Added helper method

    * Extracted code

    * Updated socket/file handling

    * Use C++ I/O

    * Use tolower()

    * Renaming

    * Simplified has_suffix

    * Fixed typo

    * Use spdlog namespace

    * Simplified formatting (endl) of error messages

    * Added -s option for changing the runtime log level to rasctl

    * Renaming

    * Renaming

    * Updated error reporting

    * Fixed log string formatting

    * String conversion cleanup

    * Fixed typo

    * Log mmap error (happens on 64 bit)

    * Improved proto3 compatibility, updated error handling

    * CHanges based on review

    * Fixed comment

    * Comment update

    * Updated ListDevice to not directly write to the stream

    * Use size_t

    * Renaming

    * Buffering update

    * MapController should not use fp

    * Use fd, not fp

    * rasctl has to display *all* results

    * rasctl has to display *all* results

    * Error handling update

    * Updated to proto3 protocol

    * Optimization by using protobuf-lite

    * RaspBian outdated protoc does not support _Name

    * Added protobuf-compiler to easyinstall.sh

    Co-authored-by: akuker <34318535+akuker@users.noreply.github.com>

* Resolved merge conflicts

* Updated help message

* Re-added CR/LF

* Updated error handling

* Use fd instead of fp

* Removed CR/LF

* Comment update

* Fixed data types

* Data type update

* Updated help message

* Added new option to usage info, rascsi: use -s instead of -l for consistency

* Display name of (remote) host in error message

* Fixed buffer overflow, cfilesystem.cpp:1185 assumes size of 11 bytes

* Revert "Fixed buffer overflow, cfilesystem.cpp:1185 assumes size of 11 bytes"

This reverts commit 126592d411.
This commit is contained in:
uweseimet
2021-07-20 01:41:00 +02:00
committed by GitHub
parent 6698b8b90a
commit 0032ce5010
4 changed files with 94 additions and 79 deletions

View File

@@ -104,12 +104,14 @@ void Banner(int argc, char* argv[])
if ((argc > 1 && strcmp(argv[1], "-h") == 0) || if ((argc > 1 && strcmp(argv[1], "-h") == 0) ||
(argc > 1 && strcmp(argv[1], "--help") == 0)){ (argc > 1 && strcmp(argv[1], "--help") == 0)){
FPRT(stdout,"\n"); FPRT(stdout,"\n");
FPRT(stdout,"Usage: %s [-IDn FILE] ...\n\n", argv[0]); FPRT(stdout,"Usage: %s [-IDn FILE] [-s LOG_LEVEL] ...\n\n", argv[0]);
FPRT(stdout," n is SCSI identification number(0-7).\n"); FPRT(stdout," n is SCSI identification number(0-7).\n");
FPRT(stdout," FILE is disk image file.\n\n"); FPRT(stdout," FILE is disk image file.\n");
FPRT(stdout,"Usage: %s [-HDn FILE] ...\n\n", argv[0]); FPRT(stdout," LOG_LEVEL is {trace|debug|info|warn|err|critical|off}, default is 'trace'\n\n");
FPRT(stdout,"Usage: %s [-HDn FILE] [-s LOG_LEVEL] ...\n\n", argv[0]);
FPRT(stdout," n is X68000 SASI HD number(0-15).\n"); FPRT(stdout," n is X68000 SASI HD number(0-15).\n");
FPRT(stdout," FILE is disk image file, \"daynaport\", or \"bridge\".\n\n"); FPRT(stdout," FILE is disk image file, \"daynaport\", or \"bridge\".\n");
FPRT(stdout," LOG_LEVEL is {trace|debug|info|warn|err|critical|off}, default is 'trace'\n\n");
FPRT(stdout," Image type is detected based on file extension.\n"); FPRT(stdout," Image type is detected based on file extension.\n");
FPRT(stdout," hdf : SASI HD image(XM6 SASI HD image)\n"); FPRT(stdout," hdf : SASI HD image(XM6 SASI HD image)\n");
FPRT(stdout," hds : SCSI HD image(XM6 SCSI HD image)\n"); FPRT(stdout," hds : SCSI HD image(XM6 SCSI HD image)\n");
@@ -144,9 +146,9 @@ BOOL Init()
} }
// Create socket for monitor // Create socket for monitor
monsocket = socket(PF_INET, SOCK_STREAM, 0); monsocket = socket(AF_INET, SOCK_STREAM, 0);
memset(&server, 0, sizeof(server)); memset(&server, 0, sizeof(server));
server.sin_family = PF_INET; server.sin_family = AF_INET;
server.sin_port = htons(6868); server.sin_port = htons(6868);
server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_addr.s_addr = htonl(INADDR_ANY);
@@ -457,20 +459,27 @@ bool MapController(Disk **map)
return status; return status;
} }
bool ReturnStatus(FILE *fp, bool status = true, const string msg = "") { bool ReturnStatus(int fd, bool status = true, const string msg = "") {
#ifdef BAREMETAL #ifdef BAREMETAL
if (msg.length()) { if (msg.length()) {
FPRT(fp, msg.c_str()); FPRT(stderr, msg.c_str());
FPRT(fp, "\n"); FPRT(stderr, "\n");
} }
#else #else
Result result; if (fd == -1) {
result.set_msg(msg); if (msg.length()) {
result.set_status(status); FPRT(stderr, msg.c_str());
FPRT(stderr, "\n");
}
}
else {
Result result;
result.set_status(status);
string data; string data;
result.SerializeToString(&data); result.SerializeToString(&data);
SerializeProtobufData(fp, data); SerializeProtobufData(fd, data);
}
#endif #endif
return status; return status;
@@ -506,10 +515,10 @@ void SetLogLevel(const string& log_level) {
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// //
// Command Processing // Command Processing. If fd is -1 error messages are displayed on the console.
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool ProcessCmd(FILE *fp, const Command &command) bool ProcessCmd(int fd, const Command &command)
{ {
Disk *map[CtrlMax * UnitNum]; Disk *map[CtrlMax * UnitNum];
Filepath filepath; Filepath filepath;
@@ -531,12 +540,12 @@ bool ProcessCmd(FILE *fp, const Command &command)
// Check the Controller Number // Check the Controller Number
if (id < 0 || id >= CtrlMax) { if (id < 0 || id >= CtrlMax) {
return ReturnStatus(fp, false, "Error : Invalid ID"); return ReturnStatus(fd, false, "Error : Invalid ID");
} }
// Check the Unit Number // Check the Unit Number
if (un < 0 || un >= UnitNum) { if (un < 0 || un >= UnitNum) {
return ReturnStatus(fp, false, "Error : Invalid unit number"); return ReturnStatus(fd, false, "Error : Invalid unit number");
} }
// Connect Command // Connect Command
@@ -548,7 +557,7 @@ bool ProcessCmd(FILE *fp, const Command &command)
// Check the extension // Check the extension
int len = params.length(); int len = params.length();
if (len < 5 || params[len - 4] != '.') { if (len < 5 || params[len - 4] != '.') {
return ReturnStatus(fp, false); return ReturnStatus(fd, false);
} }
// If the extension is not SASI type, replace with SCSI // If the extension is not SASI type, replace with SCSI
@@ -591,7 +600,7 @@ bool ProcessCmd(FILE *fp, const Command &command)
default: default:
ostringstream msg; ostringstream msg;
msg << "rasctl sent a command for an invalid drive type: " << type; msg << "rasctl sent a command for an invalid drive type: " << type;
return ReturnStatus(fp, false, msg.str()); return ReturnStatus(fd, false, msg.str());
} }
// drive checks files // drive checks files
@@ -610,7 +619,7 @@ bool ProcessCmd(FILE *fp, const Command &command)
ostringstream msg; ostringstream msg;
msg << "Error : File open error [" << file << "]"; msg << "Error : File open error [" << file << "]";
return ReturnStatus(fp, false, msg.str()); return ReturnStatus(fd, false, msg.str());
} }
} }
@@ -632,14 +641,14 @@ bool ProcessCmd(FILE *fp, const Command &command)
LOGINFO("rasctl added new %s device. ID: %d UN: %d", type_str, id, un); LOGINFO("rasctl added new %s device. ID: %d UN: %d", type_str, id, un);
} }
return ReturnStatus(fp, status, status ? "" : "Error : SASI and SCSI can't be mixed\n"); return ReturnStatus(fd, status, status ? "" : "Error : SASI and SCSI can't be mixed\n");
} }
// Does the controller exist? // Does the controller exist?
if (ctrl[id] == NULL) { if (ctrl[id] == NULL) {
LOGWARN("rasctl sent a command for invalid controller %d", id); LOGWARN("rasctl sent a command for invalid controller %d", id);
return ReturnStatus(fp, false, "Error : No such device"); return ReturnStatus(fd, false, "Error : No such device");
} }
// Does the unit exist? // Does the unit exist?
@@ -647,7 +656,7 @@ bool ProcessCmd(FILE *fp, const Command &command)
if (pUnit == NULL) { if (pUnit == NULL) {
LOGWARN("rasctl sent a command for invalid unit ID %d UN %d", id, un); LOGWARN("rasctl sent a command for invalid unit ID %d UN %d", id, un);
return ReturnStatus(fp, false, "Error : No such device"); return ReturnStatus(fd, false, "Error : No such device");
} }
type_str[0] = (char)(pUnit->GetID() >> 24); type_str[0] = (char)(pUnit->GetID() >> 24);
@@ -665,7 +674,7 @@ bool ProcessCmd(FILE *fp, const Command &command)
// Re-map the controller // Re-map the controller
bool status = MapController(map); bool status = MapController(map);
return ReturnStatus(fp, status, status ? "" : "Error : SASI and SCSI can't be mixed\n"); return ReturnStatus(fd, status, status ? "" : "Error : SASI and SCSI can't be mixed\n");
} }
// Valid only for MO or CD // Valid only for MO or CD
@@ -675,7 +684,7 @@ bool ProcessCmd(FILE *fp, const Command &command)
ostringstream msg; ostringstream msg;
msg << "Error : Operation denied (Device type " << type_str << " isn't removable)"; msg << "Error : Operation denied (Device type " << type_str << " isn't removable)";
return ReturnStatus(fp, false, msg.str()); return ReturnStatus(fd, false, msg.str());
} }
switch (cmd) { switch (cmd) {
@@ -687,7 +696,7 @@ bool ProcessCmd(FILE *fp, const Command &command)
ostringstream msg; ostringstream msg;
msg << "Error : File open error [" << params << "]"; msg << "Error : File open error [" << params << "]";
return ReturnStatus(fp, false, msg.str()); return ReturnStatus(fd, false, msg.str());
} }
break; break;
@@ -700,7 +709,7 @@ bool ProcessCmd(FILE *fp, const Command &command)
if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O')) { if (pUnit->GetID() != MAKEID('S', 'C', 'M', 'O')) {
LOGWARN("rasctl sent an invalid PROTECT command for %s ID: %d UN: %d", type_str, id, un); LOGWARN("rasctl sent an invalid PROTECT command for %s ID: %d UN: %d", type_str, id, un);
return ReturnStatus(fp, false, "Error : Operation denied (Device isn't MO)"); return ReturnStatus(fd, false, "Error : Operation denied (Device isn't MO)");
} }
LOGINFO("rasctl is setting write protect to %d for %s ID: %d UN: %d",!pUnit->IsWriteP(), type_str, id, un); LOGINFO("rasctl is setting write protect to %d for %s ID: %d UN: %d",!pUnit->IsWriteP(), type_str, id, un);
pUnit->WriteP(!pUnit->IsWriteP()); pUnit->WriteP(!pUnit->IsWriteP());
@@ -710,10 +719,10 @@ bool ProcessCmd(FILE *fp, const Command &command)
ostringstream msg; ostringstream msg;
msg << "Received unknown command from rasctl: " << cmd; msg << "Received unknown command from rasctl: " << cmd;
LOGWARN("%s", msg.str().c_str()); LOGWARN("%s", msg.str().c_str());
return ReturnStatus(fp, false, msg.str()); return ReturnStatus(fd, false, msg.str());
} }
return ReturnStatus(fp, true); return ReturnStatus(fd, true);
} }
bool has_suffix(const string& filename, const string& suffix) { bool has_suffix(const string& filename, const string& suffix) {
@@ -875,7 +884,7 @@ BOOL ParseConfig(int argc, char* argv[])
command.set_cmd(0); command.set_cmd(0);
command.set_type(type); command.set_type(type);
command.set_file(argPath); command.set_file(argPath);
if (!ProcessCmd(stderr, command)) { if (!ProcessCmd(-1, command)) {
goto parse_error; goto parse_error;
} }
} }
@@ -904,7 +913,7 @@ bool ParseArgument(int argc, char* argv[])
string log_level = "trace"; string log_level = "trace";
int opt; int opt;
while ((opt = getopt(argc, argv, "-IiHhL:l:D:d:")) != -1) { while ((opt = getopt(argc, argv, "-IiHhL:s:D:d:")) != -1) {
switch (tolower(opt)) { switch (tolower(opt)) {
case 'i': case 'i':
is_sasi = false; is_sasi = false;
@@ -918,7 +927,7 @@ bool ParseArgument(int argc, char* argv[])
id = -1; id = -1;
continue; continue;
case 'l': case 's':
log_level = optarg; log_level = optarg;
continue; continue;
@@ -978,7 +987,7 @@ bool ParseArgument(int argc, char* argv[])
command.set_cmd(ATTACH); command.set_cmd(ATTACH);
command.set_type(type); command.set_type(type);
command.set_params(path); command.set_params(path);
if (!ProcessCmd(stderr, command)) { if (!ProcessCmd(-1, command)) {
return false; return false;
} }
id = -1; id = -1;
@@ -1022,7 +1031,6 @@ void FixCpu(int cpu)
static void *MonThread(void *param) static void *MonThread(void *param)
{ {
int fd; int fd;
FILE *fp;
// Scheduler Settings // Scheduler Settings
struct sched_param schedparam; struct sched_param schedparam;
@@ -1052,11 +1060,6 @@ static void *MonThread(void *param)
} }
// Fetch the command // Fetch the command
fp = fdopen(fd, "r+");
if (!fp) {
throw ioexception("fdopen() failed");
}
Command command; Command command;
command.ParseFromString(DeserializeProtobufData(fd)); command.ParseFromString(DeserializeProtobufData(fd));
@@ -1068,7 +1071,7 @@ static void *MonThread(void *param)
string data; string data;
result.SerializeToString(&data); result.SerializeToString(&data);
SerializeProtobufData(fp, data); SerializeProtobufData(fd, data);
} }
else if (command.cmd() == LOG_LEVEL) { else if (command.cmd() == LOG_LEVEL) {
SetLogLevel(command.params()); SetLogLevel(command.params());
@@ -1079,11 +1082,9 @@ static void *MonThread(void *param)
usleep(500 * 1000); usleep(500 * 1000);
} }
ProcessCmd(fp, command); ProcessCmd(fd, command);
} }
fclose(fp);
fp = NULL;
close(fd); close(fd);
fd = -1; fd = -1;
} }
@@ -1094,9 +1095,6 @@ static void *MonThread(void *param)
// Fall through // Fall through
} }
if (fp) {
fclose(fp);
}
if (fd >= 0) { if (fd >= 0) {
close(fd); close(fd);
} }
@@ -1120,6 +1118,8 @@ int startrascsi(void)
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
#endif // BAREMETAL #endif // BAREMETAL
GOOGLE_PROTOBUF_VERIFY_VERSION;
int i; int i;
int actid; int actid;
DWORD now; DWORD now;

View File

@@ -9,6 +9,7 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <netdb.h>
#include "os.h" #include "os.h"
#include "rascsi_version.h" #include "rascsi_version.h"
#include "exceptions.h" #include "exceptions.h"
@@ -23,32 +24,38 @@ using namespace rasctl_interface;
// Send Command // Send Command
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool SendCommand(const Command& command) BOOL SendCommand(const char *hostname, const Command& command)
{ {
// Create a socket to send the command // Create a socket to send the command
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server; struct sockaddr_in server;
memset(&server, 0, sizeof(server)); memset(&server, 0, sizeof(server));
server.sin_family = PF_INET; server.sin_family = AF_INET;
server.sin_port = htons(6868); server.sin_port = htons(6868);
server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
int fd = socket(PF_INET, SOCK_STREAM, 0);
struct hostent *host = gethostbyname(hostname);
if(!host) {
fprintf(stderr, "Error : Can't resolve hostname '%s'\n", hostname);
return false;
}
memcpy((char *)&server.sin_addr.s_addr, (char *)host->h_addr, host->h_length);
// Connect
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) { if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
cerr << "Error : Can't connect to rascsi process" << endl; fprintf(stderr, "Error : Can't connect to rascsi process on host '%s'\n", hostname);
return false; return false;
} }
// Send the command
FILE *fp = fdopen(fd, "r+");
string data; string data;
command.SerializeToString(&data); command.SerializeToString(&data);
SerializeProtobufData(fp, data);
// Receive the message // Receive the message
bool status = true; bool status = true;
try { try {
Result result; SerializeProtobufData(fd, data);
Result result;
result.ParseFromString(DeserializeProtobufData(fd)); result.ParseFromString(DeserializeProtobufData(fd));
status = result.status(); status = result.status();
@@ -63,8 +70,7 @@ bool SendCommand(const Command& command)
// Fall through // Fall through
} }
fclose(fp); close(fd);
close(fd);
return status; return status;
} }
@@ -76,17 +82,20 @@ bool SendCommand(const Command& command)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
GOOGLE_PROTOBUF_VERIFY_VERSION;
// Display help // Display help
if (argc < 2) { if (argc < 2) {
cerr << "SCSI Target Emulator RaSCSI Controller" << endl; cerr << "SCSI Target Emulator RaSCSI Controller" << endl;
cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl; cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl;
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE] [-s LOG_LEVEL]" << endl; cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE] [-h HOSTNAME] [-s LOG_LEVEL]" << endl;
cerr << " where ID := {0|1|2|3|4|5|6|7}" << endl; cerr << " where ID := {0|1|2|3|4|5|6|7}" << endl;
cerr << " UNIT := {0|1} default setting is 0." << endl; cerr << " UNIT := {0|1} default setting is 0." << endl;
cerr << " CMD := {attach|detach|insert|eject|protect}" << endl; cerr << " CMD := {attach|detach|insert|eject|protect}" << endl;
cerr << " TYPE := {hd|mo|cd|bridge|daynaport}" << endl; cerr << " TYPE := {hd|mo|cd|bridge|daynaport}" << endl;
cerr << " FILE := image file path" << endl; cerr << " FILE := image file path" << endl;
cerr << " LOG_LEVEL := log level" << endl; cerr << " HOSTNAME := rascsi host to connect to, default is 'localhost'" << endl;
cerr << " LOG_LEVEL := log level {trace|debug|info|warn|err|critical|off}, default is 'trace'" << endl;
cerr << " If CMD is 'attach' or 'insert' the FILE parameter is required." << endl; cerr << " If CMD is 'attach' or 'insert' the FILE parameter is required." << endl;
cerr << "Usage: " << argv[0] << " -l" << endl; cerr << "Usage: " << argv[0] << " -l" << endl;
cerr << " Print device list." << endl; cerr << " Print device list." << endl;
@@ -100,10 +109,10 @@ int main(int argc, char* argv[])
int un = 0; int un = 0;
Operation cmd = LIST; Operation cmd = LIST;
DeviceType type = UNDEFINED; DeviceType type = UNDEFINED;
const char *hostname = "localhost";
string params; string params;
opterr = 0; opterr = 0;
while ((opt = getopt(argc, argv, "i:u:c:t:f:h:s:l")) != -1) {
while ((opt = getopt(argc, argv, "i:u:c:t:f:s:l")) != -1) {
switch (opt) { switch (opt) {
case 'i': case 'i':
id = optarg[0] - '0'; id = optarg[0] - '0';
@@ -177,6 +186,10 @@ int main(int argc, char* argv[])
cmd = LIST; cmd = LIST;
break; break;
case 'h':
hostname = optarg;
break;
case 's': case 's':
cmd = LOG_LEVEL; cmd = LOG_LEVEL;
params = optarg; params = optarg;
@@ -189,14 +202,14 @@ int main(int argc, char* argv[])
if (cmd == LOG_LEVEL) { if (cmd == LOG_LEVEL) {
command.set_cmd(LOG_LEVEL); command.set_cmd(LOG_LEVEL);
command.set_params(params); command.set_params(params);
SendCommand(command); SendCommand(hostname, command);
exit(0); exit(0);
} }
// List display only // List display only
if (cmd == LIST || (id < 0 && type == UNDEFINED && params.empty())) { if (cmd == LIST || (id < 0 && type == UNDEFINED && params.empty())) {
command.set_cmd(LIST); command.set_cmd(LIST);
SendCommand(command); SendCommand(hostname, command);
exit(0); exit(0);
} }
@@ -248,7 +261,7 @@ int main(int argc, char* argv[])
if (!params.empty()) { if (!params.empty()) {
command.set_params(params); command.set_params(params);
} }
if (!SendCommand(command)) { if (!SendCommand(hostname, command)) {
exit(ENOTCONN); exit(ENOTCONN);
} }

View File

@@ -10,7 +10,6 @@
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <cstring> #include <cstring>
#include <cstdlib>
#include <unistd.h> #include <unistd.h>
#include "exceptions.h" #include "exceptions.h"
#include "rasutil.h" #include "rasutil.h"
@@ -23,17 +22,22 @@ using namespace std;
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void SerializeProtobufData(FILE *fp, const string& data) void SerializeProtobufData(int fd, const string& data)
{ {
// Write the size of the protobuf data as a header // Write the size of the protobuf data as a header
size_t size = data.length(); int32_t size = data.length();
fwrite(&size, sizeof(size), 1, fp); if (write(fd, &size, sizeof(size)) != sizeof(size)) {
throw ioexception("Cannot write protobuf header");
}
// Write the actual protobuf data // Write the actual protobuf data
void *buf = malloc(size); void *buf = malloc(size);
memcpy(buf, data.data(), size); memcpy(buf, data.data(), size);
fwrite(buf, size, 1, fp); if (write(fd, buf, size) != size) {
fflush(fp); free(buf);
throw ioexception("Cannot write protobuf data");
}
free(buf); free(buf);
} }
@@ -41,17 +45,15 @@ void SerializeProtobufData(FILE *fp, const string& data)
string DeserializeProtobufData(int fd) string DeserializeProtobufData(int fd)
{ {
// First read the header with the size of the protobuf data // First read the header with the size of the protobuf data
size_t size; int32_t size;
size_t res = read(fd, &size, sizeof(int)); if (read(fd, &size, sizeof(size)) != sizeof(size)) {
if (res != sizeof(int)) {
// No more data // No more data
return ""; return "";
} }
// Read the actual protobuf data // Read the actual protobuf data
void *buf = malloc(size); void *buf = malloc(size);
res = read(fd, buf, size); if (read(fd, buf, size) != (ssize_t)size) {
if (res != size) {
free(buf); free(buf);
throw ioexception("Missing protobuf data"); throw ioexception("Missing protobuf data");

View File

@@ -15,7 +15,7 @@
#include <cstdio> #include <cstdio>
#include <string> #include <string>
void SerializeProtobufData(FILE *fp, const std::string& data); void SerializeProtobufData(int fd, const std::string& data);
std::string DeserializeProtobufData(int fd); std::string DeserializeProtobufData(int fd);
#endif #endif