#64 simplify messaging and #71 deserialize failed (#88)

* small lsp error fixes

* simplify messaging and remove serialize/deserialize
- messaging is reverted to API requests and responses only
- remove serialize and deserialize functions
- implement shared memory (pshm) for overlay callback return values

* fix memory leak

Fix #64 and #71
This commit is contained in:
Levi Neely 2025-02-25 09:46:46 +01:00 committed by GitHub
parent 5a5dec975f
commit 5ecece7547
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 332 additions and 526 deletions

2
.gitignore vendored
View File

@ -15,7 +15,7 @@ a.out
cmd/pcloudcc/build/pcloudcc
**/*/.cache/
compile_commands.json
compile_commands.events.json
/cmd/pcloudcc/build/
/.cache/
/lib/poverlay_linux/overlay_client

View File

@ -41,7 +41,8 @@
#include "pclsync/overlay_client.h"
#include "pclsync_lib.h"
#include "psynclib.h"
#include "pclsync/psynclib.h"
#include "pclsync/pshm.h"
#include "CLI11.hpp"
@ -60,62 +61,10 @@ enum command_ids_ {
STOPSYNC
};
std::pair<std::string, std::string> split_paths(const std::string &input) {
std::string path1, path2;
bool in_quotes = false;
bool escaped = false;
std::string current_path;
for (char c : input) {
if (escaped) {
current_path += c;
escaped = false;
} else if (c == '\\') {
escaped = true;
} else if (c == '"') {
in_quotes = !in_quotes;
current_path += c;
} else if (c == ' ' && !in_quotes) {
if (!current_path.empty()) {
if (path1.empty()) {
path1 = current_path;
} else {
path2 = current_path;
break;
}
current_path.clear();
}
} else {
current_path += c;
}
}
if (!current_path.empty()) {
if (path1.empty()) {
path1 = current_path;
} else if (path2.empty()) {
path2 = current_path;
}
}
auto remove_quotes = [](std::string &s) {
if (s.size() >= 2 && s.front() == '"' && s.back() == '"') {
s = s.substr(1, s.size() - 2);
}
};
remove_quotes(path1);
remove_quotes(path2);
return {path1, path2};
}
int list_sync_folders() {
int ret;
char *errm;
size_t errmsz;
void *rep;
size_t repsz;
int result;
psync_folder_list_t *flist;
psync_folder_t *folder;
@ -123,51 +72,50 @@ int list_sync_folders() {
errm = NULL;
errmsz = 0;
rep = NULL;
repsz = 0;
rval = 0;
result = SendCall(LISTSYNC, "", &ret, &errm, &errmsz, &rep, &repsz);
result = SendCall(LISTSYNC, "", &ret, &errm, &errmsz);
if (result != 0) {
std::cout << "List Sync Folders failed. return is " << ret
<< " and message is " << (errm ? errm : "no message")
<< std::endl;
rval = result;
} else if (rep && repsz > 0) {
flist = static_cast<psync_folder_list_t *>(rep);
}
if (repsz < sizeof(psync_folder_list_t)) {
std::cout << "Error: Insufficient data for folder list structure"
<< std::endl;
rval = -1;
} else {
const int id_width = 12;
const int path_width = 30;
if(pshm_read((void**)&flist, NULL)) {
const int id_width = 12;
const int path_width = 30;
if(flist->foldercnt > 0) {
std::cout << std::left << std::setw(id_width) << "Folder ID"
<< std::setw(path_width) << "Local Path"
<< std::setw(path_width) << "Remote Path" << std::endl;
std::cout << std::string(id_width, '-')
<< std::string(path_width - 1, '-')
<< std::string(path_width - 1, '-') << std::endl;
for (uint32_t i = 0; i < flist->foldercnt; i++) {
folder = &flist->folders[i];
std::cout << std::left << std::setw(id_width) << folder->folderid
<< std::setw(path_width) << folder->localpath
<< std::setw(path_width) << folder->remotepath << std::endl;
}
} else {
std::cout << "No synchronized folders found." << std::endl;
rval = ret;
}
} else {
std::cout << "No synchronized folders found." << std::endl;
rval = ret;
free(flist);
} else {
std::cout << "failed to read folder list from shm" << std::endl;
return -1;
}
if(errm) {
free(errm);
}
free(errm);
free(rep);
return rval;
}
@ -176,7 +124,8 @@ int start_crypto(const char *pass) {
char *errm;
size_t errm_size;
int result = SendCall(STARTCRYPTO, pass, &ret, &errm, &errm_size, NULL, NULL);
int result = SendCall(STARTCRYPTO, pass, &ret, &errm, &errm_size);
if (result != 0 || ret != 0) {
std::cout << "Start Crypto failed. return is " << ret << " and message is "
<< (errm ? errm : "no message") << std::endl;
@ -193,7 +142,7 @@ int stop_crypto() {
char *errm;
size_t errm_size;
int result = SendCall(STOPCRYPTO, "", &ret, &errm, &errm_size, NULL, NULL);
int result = SendCall(STOPCRYPTO, "", &ret, &errm, &errm_size);
if (result != 0) {
std::cout << "Stop Crypto failed. return is " << ret << " and message is "
<< (errm ? errm : "no message") << std::endl;
@ -217,7 +166,7 @@ int remove_sync_folder(const char *folderid) {
errmsz = 0;
rval = 0;
result = SendCall(STOPSYNC, folderid, &ret, &errm, &errmsz, NULL, NULL);
result = SendCall(STOPSYNC, folderid, &ret, &errm, &errmsz);
if (result != 0) {
std::cout << "Remove Sync Folder failed with unknown error. return is "
<< ret << " and message is " << (errm ? errm : "no message")
@ -227,7 +176,10 @@ int remove_sync_folder(const char *folderid) {
std::cout << "Successfully removed sync folder with folderid " << folderid
<< std::endl;
}
free(errm);
if(errm) {
free(errm);
}
return rval;
}
@ -237,20 +189,15 @@ int add_sync_folder(std::string localpath, std::string remotepath) {
int ret;
char *errm;
size_t errmsz;
void *rep;
size_t repsz;
int result;
int rval;
errm = NULL;
errmsz = 0;
rep = NULL;
repsz = 0;
rval = 0;
std::string combinedPaths = localpath + '|' + remotepath;
result = SendCall(ADDSYNC, combinedPaths.c_str(), &ret, &errm, &errmsz, &rep,
&repsz);
result = SendCall(ADDSYNC, combinedPaths.c_str(), &ret, &errm, &errmsz);
if (result != 0) {
if (result == -1) {
@ -262,22 +209,14 @@ int add_sync_folder(std::string localpath, std::string remotepath) {
<< std::endl;
}
rval = result;
} else if (rep && repsz > 0) {
if (repsz < sizeof(psync_syncid_t)) {
std::cout << "Error: Insufficient data for folder list structure"
<< std::endl;
rval = -1;
} else {
rval = ret;
}
} else {
std::cout << "Error: Did not get a syncid from add_sync_folder."
<< std::endl;
rval = ret;
}
free(errm);
free(rep);
if(errm) {
free(errm);
}
return rval;
}
@ -286,11 +225,12 @@ int finalize() {
char *errm;
size_t errm_size;
SendCall(FINALIZE, "", &ret, &errm, &errm_size, NULL, NULL);
SendCall(FINALIZE, "", &ret, &errm, &errm_size);
std::cout << "Exiting ..." << std::endl;
if (errm)
free(errm);
if (errm){
free(errm);
}
return ret;
}

View File

@ -26,8 +26,7 @@ that gets created when the server is started.
socket -> poverlay : request
poverlay -> poverlay : poverlay_handle_request
poverlay -> poverlay : poverlay_get_response
poverlay -> poverlay : serialize_response_message
poverlay -> socket : response (serialized)
poverlay -> socket : response
socket -> overlay_client : read_response
overlay_client -> control_tools : (msg, msgsz, payload, payloadsz)
control_tools -> user : print results

View File

@ -62,7 +62,7 @@
#include "overlay_client.h"
#include "poverlay_protocol.h"
#define POVERLAY_BUFSIZE 16 * 1024
#define POVERLAY_BUFSIZE 512
// for easier error tracing...
#define POVERLAY_SOCKET_CREATE_FAILED -100
@ -73,106 +73,8 @@
#define POVERLAY_READ_INCOMPLETE -105
#define POVERLAY_READ_INVALID_RESPONSE -106
response_message *deserialize_response_message(const char *buffer,
size_t buffer_size) {
if (buffer_size < 2 * sizeof(size_t) + sizeof(uint32_t) + sizeof(uint64_t)) {
debug(D_ERROR, "Buffer size too small: %zu", buffer_size);
return NULL;
}
const char *ptr = buffer;
// Allocate response_message
response_message *resp = (response_message *)malloc(sizeof(response_message));
if (resp == NULL) {
debug(D_ERROR, "Failed to allocate response_message");
return NULL;
}
// Get message size
size_t msg_size = be64toh(*(size_t *)ptr);
ptr += sizeof(size_t);
debug(D_ERROR, "Message size: %zu", msg_size);
if (msg_size < sizeof(uint32_t) + sizeof(uint64_t)) {
debug(D_ERROR, "Invalid message size: %zu", msg_size);
free(resp);
return NULL;
}
// Allocate message with extra space for the flexible array member
size_t alloc_size =
sizeof(message) + msg_size - sizeof(uint32_t) - sizeof(uint64_t);
resp->msg = (message *)malloc(alloc_size);
if (resp->msg == NULL) {
debug(D_ERROR, "Failed to allocate message");
free(resp);
return NULL;
}
resp->msg->type = ntohl(*(uint32_t *)ptr);
ptr += sizeof(uint32_t);
resp->msg->length = be64toh(*(uint64_t *)ptr);
ptr += sizeof(uint64_t);
debug(D_ERROR, "Message type: %u, length: %lu", resp->msg->type,
resp->msg->length);
// Calculate the size of the value array
size_t value_size = msg_size - sizeof(uint32_t) - sizeof(uint64_t);
if (value_size > 0) {
if (ptr + value_size > buffer + buffer_size) {
debug(D_ERROR, "Buffer overflow detected");
free(resp->msg);
free(resp);
return NULL;
}
memcpy(resp->msg->value, ptr, value_size);
ptr += value_size;
}
// Deserialize payload size
if (ptr + sizeof(size_t) > buffer + buffer_size) {
debug(D_ERROR, "Buffer overflow detected when reading payload size");
free(resp->msg);
free(resp);
return NULL;
}
resp->payloadsz = be64toh(*(size_t *)ptr);
ptr += sizeof(size_t);
debug(D_ERROR, "Payload size: %zu", resp->payloadsz);
// Deserialize payload
if (resp->payloadsz > 0) {
if (ptr + resp->payloadsz > buffer + buffer_size) {
debug(D_ERROR, "Buffer overflow detected when reading payload");
free(resp->msg);
free(resp);
return NULL;
}
resp->payload = malloc(resp->payloadsz);
if (resp->payload == NULL) {
debug(D_ERROR, "Failed to allocate payload");
free(resp->msg);
free(resp);
return NULL;
}
memcpy(resp->payload, ptr, resp->payloadsz);
} else {
resp->payload = NULL;
}
return resp;
}
void free_response_message(response_message *resp) {
void free_response_message(message *resp) {
if (resp) {
free(resp->msg);
free(resp->payload);
free(resp);
}
}
@ -182,7 +84,7 @@ int QueryState(pCloud_FileState *state, char *path) {
char *errm;
size_t errm_size;
if (!SendCall(4, path /*IN*/, &rep, &errm, &errm_size, NULL, NULL)) {
if (!SendCall(4, path /*IN*/, &rep, &errm, &errm_size)) {
debug(D_NOTICE, "QueryState responese rep[%d] path[%s]", rep, path);
if (errm)
debug(D_NOTICE, "The error is %s", errm);
@ -243,15 +145,15 @@ int write_request(int fd, int msgtype, const char *value, char **out,
int size;
char *buf;
const char *err;
request_message *request;
message *request;
char *curbuf;
*ret = 0; // Initialize ret to 0
len = strlen(value);
size = sizeof(request_message) + len + 1;
size = sizeof(message) + len + 1;
buf = (char *)malloc(size);
request = (request_message *)buf;
request = (message *)buf;
memset(request, 0, size);
request->type = msgtype;
strncpy(request->value, value, len + 1);
@ -288,122 +190,53 @@ int write_request(int fd, int msgtype, const char *value, char **out,
// write an error message OR an API response value to out (and its
// size to out_size), a "ret" value to ret (redundant?), and the
// callback's return data to payload and payloadsz.
int read_response(int fd, char **out, size_t *out_size, int *ret,
void **payload, size_t *payloadsz) {
char buffer[POVERLAY_BUFSIZE];
ssize_t bytes_read = read(fd, buffer, POVERLAY_BUFSIZE);
int read_response(int fd, char **out, size_t *out_size, int *ret) {
message *msg;
ssize_t bytes_read;
if (bytes_read <= 0) {
const char *error_msg =
(bytes_read == 0) ? "Connection closed" : strerror(errno);
*out = strdup(error_msg);
*out_size = strlen(error_msg) + 1;
*ret = -1;
return -1;
}
if (bytes_read < sizeof(response_message)) {
const char *error_msg = "Incomplete response";
*out = strdup(error_msg);
*out_size = strlen(error_msg) + 1;
*ret = -1;
return -1;
}
// response_message *resp = (response_message *)buffer;
response_message *resp = deserialize_response_message(buffer, bytes_read);
if (resp == NULL) {
const char *error_msg = "Failed to deserialize response";
*out = strdup(error_msg);
*out_size = strlen(error_msg) + 1;
*ret = -1;
return -1;
}
// Validate the response_message structure
if (resp->msg == NULL ||
(size_t)bytes_read < sizeof(response_message) + sizeof(message) ||
(size_t)bytes_read < sizeof(response_message) + resp->msg->length) {
const char *error_msg = "Invalid response structure";
*out = strdup(error_msg);
*out_size = strlen(error_msg) + 1;
*ret = -1;
return -1;
}
message *msg = resp->msg;
size_t value_size = msg->length - sizeof(message);
// Validate message length
if (msg->length < sizeof(message) ||
(size_t)bytes_read < sizeof(response_message) + msg->length) {
const char *error_msg = "Invalid message length";
*out = strdup(error_msg);
*out_size = strlen(error_msg) + 1;
*ret = -1;
return -1;
}
*out = malloc(value_size + 1);
if (*out == NULL) {
const char *error_msg = "Memory allocation failed";
*out = strdup(error_msg);
*out_size = strlen(error_msg) + 1;
*ret = -1;
free_response_message(resp);
return -1;
}
memcpy(*out, msg->value, value_size);
(*out)[value_size] = '\0';
*out_size = value_size + 1;
*ret = msg->type;
if (payload != NULL && payloadsz != NULL) {
if (resp->payload != NULL && resp->payloadsz > 0) {
*payload = malloc(resp->payloadsz);
if (*payload == NULL) {
const char *error_msg = "Memory allocation failed for payload";
free(*out);
msg = (message *)malloc(POVERLAY_BUFSIZE);
if (msg == NULL) {
const char *error_msg = "Memory allocation failed";
*out = strdup(error_msg);
*out_size = strlen(error_msg) + 1;
*ret = -1;
free_response_message(resp);
return -1;
}
memcpy(*payload, resp->payload, resp->payloadsz);
*payloadsz = resp->payloadsz;
} else {
*payload = NULL;
*payloadsz = 0;
}
}
free_response_message(resp);
return 0;
bytes_read = read(fd, msg, POVERLAY_BUFSIZE);
if (bytes_read <= 0) {
const char *error_msg = (bytes_read == 0) ? "Connection closed" : "Read error";
free(msg);
*out = strdup(error_msg);
*out_size = strlen(error_msg) + 1;
*ret = -1;
return -1;
}
*out = (char *)malloc(msg->length);
memcpy(*out, msg->value, msg->length);
*out_size = msg->length;
*ret = msg->type;
free(msg);
return 0;
}
int SendCall(int id /*IN*/, const char *path /*IN*/, int *ret /*OUT*/,
char **out /*OUT*/, size_t *out_size, void **reply_data,
size_t *reply_size) {
// path contains the input argument(s).
int SendCall(int id, const char *path, int *ret, char **errm, size_t *errmsz) {
int result;
int sockfd;
sockfd = -1;
result = 0;
*out = NULL;
*out_size = 0;
*errm = NULL;
*errmsz = 0;
*ret = 0;
// side effects: modify out, out_size, ret
sockfd = socket_connect(POVERLAY_SOCK_PATH, out, out_size, ret);
sockfd = socket_connect(POVERLAY_SOCK_PATH, errm, errmsz, ret);
if (sockfd >= 0) {
// side effects: modify out, out_size, ret
if ((result = write_request(sockfd, id, path, out, out_size, ret)) == 0) {
// side effects: modify out, out_size, ret, reply_data, reply_size
result =
read_response(sockfd, out, out_size, ret, reply_data, reply_size);
if ((result = write_request(sockfd, id, path, errm, errmsz, ret)) == 0) {
result = read_response(sockfd, errm, errmsz, ret);
}
close(sockfd);
} else {

View File

@ -48,11 +48,9 @@ typedef enum _pCloud_FileState {
FileStateInvalid
} pCloud_FileState;
int QueryState(pCloud_FileState *state /*OUT*/, char *path /*IN*/);
int QueryState(pCloud_FileState *, char *);
int SendCall(int id, const char *, int *, char **, size_t *);
int SendCall(int id /*IN*/, const char *path /*IN*/, int *ret /*OUT*/,
char **out /*OUT*/, size_t *out_size, void **reply_data,
size_t *reply_size);
#ifdef __cplusplus
}
#endif

View File

@ -925,3 +925,4 @@ psync_folder_list_t *psync_list_get_list(char *syncTypes) {
return ret;
}

View File

@ -55,47 +55,6 @@
int overlays_running = 1;
int callbacks_running = 1;
// Serialization function
size_t serialize_response_message(const response_message *resp,
char **out_buffer) {
// Calculate total size needed
size_t msg_size = sizeof(uint32_t) + sizeof(uint64_t) + resp->msg->length;
size_t total_size =
sizeof(size_t) + msg_size + sizeof(size_t) + resp->payloadsz;
// Allocate buffer
*out_buffer = (char *)malloc(total_size);
if (*out_buffer == NULL)
return 0;
char *ptr = *out_buffer;
// Serialize msg size
*(size_t *)ptr = htobe64(msg_size);
ptr += sizeof(size_t);
// Serialize msg
*(uint32_t *)ptr = htonl(resp->msg->type);
ptr += sizeof(uint32_t);
*(uint64_t *)ptr = htobe64(resp->msg->length);
ptr += sizeof(uint64_t);
memcpy(ptr, resp->msg->value, resp->msg->length);
ptr += resp->msg->length;
// Serialize payload size
*(size_t *)ptr = htobe64(resp->payloadsz);
ptr += sizeof(size_t);
// Serialize payload
if (resp->payloadsz > 0 && resp->payload != NULL) {
memcpy(ptr, resp->payload, resp->payloadsz);
}
return total_size;
}
void psync_overlay_main_loop() {
struct sockaddr_un addr;
int fd, cl;
@ -144,8 +103,8 @@ void psync_overlay_handle_request(void *lpvParam) {
int readbytes; // total bytes read from request
char rqbuf[POVERLAY_BUFSIZE]; // request buffer, contains the request message
char *rqbufp; // request buffer ptr, for convenient iteration
request_message *request; // request message
response_message *response; // response message and payload
message *request; // request message
message *response; // response message and payload
request = NULL;
response = NULL;
@ -159,7 +118,7 @@ void psync_overlay_handle_request(void *lpvParam) {
readbytes += rc;
rqbufp = rqbufp + rc;
if (readbytes > 12) {
request = (request_message *)rqbuf;
request = (message *)rqbuf;
if (request->length == (uint64_t)readbytes)
break;
}
@ -172,50 +131,23 @@ void psync_overlay_handle_request(void *lpvParam) {
goto cleanup;
}
// allocate and initialize response message
response = (response_message *)psync_malloc(sizeof(response_message));
memset(response, 0, sizeof(response_message));
response->msg = NULL;
response->payload = NULL;
response->payloadsz = 0;
// get the response for the request, and write the response to the
// sockfd.
request = (request_message *)rqbuf;
request = (message *)rqbuf;
response = (message *)malloc(POVERLAY_BUFSIZE);
if (request) {
psync_overlay_get_response(request, response);
char *rsbufp;
size_t bytes_written = 0;
size_t responsesz = serialize_response_message(response, &rsbufp);
if (responsesz <= 0) {
debug(D_ERROR, "failed to serialize response message");
return;
ssize_t total_size = sizeof(uint32_t) + sizeof(uint64_t) + response->length;
ssize_t bytes_written = write(*sockfd, response, total_size);
if (bytes_written == -1) {
debug(D_ERROR, "Failed to write to socket: %s", strerror(errno));
return;
} else if (bytes_written < total_size) {
debug(D_ERROR, "Incomplete write to socket: wrote %zd of %zd bytes", bytes_written, total_size);
return;
}
while (bytes_written < responsesz) {
ssize_t written =
write(*sockfd, rsbufp + bytes_written, responsesz - bytes_written);
if (written == -1) {
if (errno == EINTR) {
// Interrupted by signal, try again
continue;
}
debug(D_ERROR, "failed to write to socket: %s", strerror(errno));
break;
}
bytes_written += written;
}
free(rsbufp);
if (bytes_written < responsesz) {
debug(D_ERROR, "failed to write entire message to socket");
return;
}
debug(D_NOTICE,
"Successfully sent full reply: %zu bytes structure, %zu bytes "
"additional data",
response->msg->length, response->payloadsz);
debug(D_NOTICE, "Successfully wrote %zd bytes to socket", bytes_written);
} else {
debug(D_ERROR, "No valid request received");
}
@ -225,12 +157,6 @@ cleanup:
close(*sockfd);
}
if (response) {
if (response->msg) {
psync_free(response->msg);
}
if (response->payload) {
psync_free(response->payload);
}
psync_free(response);
}
@ -264,8 +190,8 @@ void psync_overlay_init_callbacks() {
memset(callbacks, 0, sizeof(poverlay_callback) * callbacks_size);
}
static void psync_overlay_get_status_response(request_message *request,
response_message *response,
static void psync_overlay_get_status_response(message *request,
message *response,
size_t available_space) {
psync_path_status_t stat;
@ -276,56 +202,24 @@ static void psync_overlay_get_status_response(request_message *request,
}
switch (psync_path_status_get_status(stat)) {
case PSYNC_PATH_STATUS_IN_SYNC:
response->msg->type = 10;
response->type = 10;
break;
case PSYNC_PATH_STATUS_IN_PROG:
response->msg->type = 12;
response->type = 12;
break;
case PSYNC_PATH_STATUS_PAUSED:
case PSYNC_PATH_STATUS_REMOTE_FULL:
case PSYNC_PATH_STATUS_LOCAL_FULL:
response->msg->type = 11;
response->type = 11;
break;
default:
response->msg->type = 13;
snprintf(response->msg->value, available_space, "No.");
response->type = 13;
snprintf(response->value, available_space, "No.");
}
}
static void
psync_overlay_get_overlay_response_payload(request_message *request,
response_message *response) {
if (!response->payload) {
response->payloadsz = 0;
debug(D_NOTICE, "Callback succeeded with no reply data");
return;
}
if (request->type == 23) {
// LISTSYNC
psync_folder_list_t *folders = (psync_folder_list_t *)response->payload;
response->payloadsz = sizeof(psync_folder_list_t) +
folders->foldercnt * sizeof(psync_folder_t);
} else if (request->type == 24) {
// ADDSYNC
response->payloadsz = sizeof(psync_syncid_t);
} else {
// default: response has no payload
response->payloadsz = 0;
}
if (response->payload == NULL) {
response->payloadsz = 0;
debug(D_NOTICE, "No reply data received");
return;
}
debug(D_NOTICE, "Callback succeeded with reply data, length: %zu",
response->payloadsz);
}
static void psync_overlay_get_overlay_response(request_message *request,
response_message *response,
static void psync_overlay_get_overlay_response(message *request,
message *response,
size_t available_space) {
int cbidx; // callback index (based on message type)
int cbret; // callback return value
@ -335,44 +229,40 @@ static void psync_overlay_get_overlay_response(request_message *request,
if (!callbacks_running || (request->type >= ((uint32_t)calbacks_lower_band +
(uint32_t)callbacks_size))) {
response->msg->type = 13;
snprintf(response->msg->value, available_space, "Invalid type.");
response->type = 13;
snprintf(response->value, available_space, "Invalid type.");
debug(D_NOTICE, "Invalid request type: %u", request->type);
return;
}
if (!callbacks[cbidx]) {
response->msg->type = 13;
snprintf(response->msg->value, available_space,
response->type = 13;
snprintf(response->value, available_space,
"No callback with this id registered.");
debug(D_NOTICE, "No callback registered for type: %u", request->type);
return;
}
cbret = callbacks[cbidx](request->value, &response->payload);
cbret = callbacks[cbidx](request->value);
if (cbret == 0) {
response->msg->type = 0;
psync_overlay_get_overlay_response_payload(request, response);
response->type = 0;
} else {
response->msg->type = cbret;
snprintf(response->msg->value, available_space,
response->type = cbret;
snprintf(response->value, available_space,
"Callback returned error code.");
debug(D_NOTICE, "Callback failed with return code: %d", cbret);
}
}
void psync_overlay_get_response(request_message *request,
response_message *response) {
void psync_overlay_get_response(message *request,
message *response) {
const char *dbgmsg; // debug messages
size_t value_avail; // space available to store value (flexible array)
dbgmsg = NULL;
response->msg = (message *)psync_malloc(POVERLAY_BUFSIZE);
memset(response->msg, 0, POVERLAY_BUFSIZE);
response->msg->length = 0;
response->payload = NULL;
response->payloadsz = 0;
memset(response, 0, POVERLAY_BUFSIZE);
response->length = 0;
value_avail = POVERLAY_BUFSIZE - sizeof(message);
// never print the crypto password to the logs in plain text
@ -388,21 +278,21 @@ void psync_overlay_get_response(request_message *request,
// a message with a type != 13 and a null string value after
// processing is considered successful. set value to "Ok."
if (response->msg->type != 13 && response->msg->value[0] == '\0') {
snprintf(response->msg->value, value_avail, "Ok.");
if (response->type != 13 && response->value[0] == '\0') {
snprintf(response->value, value_avail, "Ok.");
} else {
debug(D_WARNING,
"not updating value to Ok: response->msg->type=%d, "
"response->msg->value=%s",
response->msg->type, response->msg->value);
response->type, response->value);
}
// truncate messages that exceed the buffer boundaries
size_t value_length = strnlen(response->msg->value, value_avail);
response->msg->length = sizeof(message) + value_length + 1;
if (response->msg->length > POVERLAY_BUFSIZE) {
response->msg->length = POVERLAY_BUFSIZE;
response->msg->value[value_avail - 1] = '\0';
size_t value_length = strnlen(response->value, value_avail);
response->length = sizeof(message) + value_length + 1;
if (response->length > POVERLAY_BUFSIZE) {
response->length = POVERLAY_BUFSIZE;
response->value[value_avail - 1] = '\0';
debug(D_WARNING, "Response message truncated to fit buffer");
}
}

View File

@ -49,8 +49,7 @@ extern int callbacks_running;
void psync_overlay_main_loop(VOID);
void psync_overlay_handle_request(LPVOID);
void psync_overlay_get_response(request_message *rq /*IN*/,
response_message *rs /*OUT*/);
void psync_overlay_get_response(message*, message*);
void psync_overlay_stop_overlays();
void psync_overlay_start_overlays();
void psync_overlay_stop_overlay_callbacks();
@ -59,6 +58,6 @@ int psync_overlay_overlays_running();
int psync_overlay_callbacks_running();
void psync_overlay_init_callbacks();
int psync_overlay_register_callback(int id, poverlay_callback callback);
int psync_overlay_register_callback(int, poverlay_callback);
#endif // POVERLAY_H

View File

@ -10,22 +10,10 @@
#define POVERLAY_SOCK_PATH "/tmp/pcloud_unix_soc.sock"
#endif
typedef struct _message {
uint32_t type;
uint64_t length;
char value[];
} message;
// represents a request message
typedef message request_message;
// represents a response message; this includes the API response
// message and any payload data returned by the callback function.
typedef struct {
void *payload; // data returned by the callback function
size_t payloadsz; // size of payload
message *msg; // API response message
} response_message;
#endif

129
pclsync/pshm.c Normal file
View File

@ -0,0 +1,129 @@
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdbool.h>
#include <errno.h>
#include "debug.h"
#include "pshm.h"
key_t pshm_get_key() {
char path[PATH_MAX];
char *home;
home = getenv("HOME");
if (home == NULL) {
debug(D_ERROR, "HOME environment variable is not set");
return (key_t)-1;
}
snprintf(path, sizeof(path), "%s/.pcloud/data.db", home);
return ftok(path, 'A');
}
int pshm_getid() {
key_t key;
key = pshm_get_key();
if(key == -1) {
debug(D_ERROR, "failed to get ipc key");
return -1;
}
return shmget(key, PSYNC_SHM_SIZE, IPC_CREAT | 0666);
}
bool pshm_read(void **data, size_t *datasz) {
int shmid;
psync_shm *shm;
int flag;
char *dataArea;
shmid = pshm_getid();
if (shmid == -1) {
debug(D_ERROR, "Failed to get shared memory ID");
return false;
}
shm = (psync_shm*)shmat(shmid, NULL, 0);
if (shm == (void*)-1) {
debug(D_ERROR, "Failed to attach to shared memory: %s", strerror(errno));
return false;
}
__atomic_load(&shm->flag, &flag, __ATOMIC_SEQ_CST);
if(flag != 1) {
shmdt(shm);
return false;
}
if(datasz != NULL) {
*datasz = shm->datasz;
}
*data = malloc(shm->datasz);
if(*data == NULL) {
debug(D_ERROR, "Failed to allocate memory for shared data");
shmdt(shm);
return false;
}
dataArea = (char *)shm + sizeof(psync_shm);
memcpy(*data, dataArea, shm->datasz);
__atomic_store_n(&shm->flag, 0, __ATOMIC_SEQ_CST);
shmdt(shm);
return true;
}
void pshm_write(const void *data, size_t datasz) {
int shmid;
psync_shm* shm;
char *dataArea;
if (datasz > PSYNC_SHM_SIZE - sizeof(psync_shm)) {
debug(D_ERROR, "Data size exceeds available shared memory size");
return;
}
shmid = pshm_getid();
if (shmid == -1) {
debug(D_ERROR, "Failed to get shared memory ID");
return;
}
shm = (psync_shm*)shmat(shmid, NULL, 0);
if (shm == (void*)-1) {
debug(D_ERROR, "Failed to attach to shared memory: %s", strerror(errno));
return;
}
if (shm->flag == 0 && shm->datasz == 0) {
debug(D_NOTICE, "Initializing shared memory segment");
// Clear the structure first
memset(shm, 0, sizeof(psync_shm));
// Data area starts right after the structure
shm->data = (char *)shm + sizeof(psync_shm);
shm->datasz = 0;
shm->flag = 0;
}
dataArea = (char *)shm + sizeof(psync_shm);
memcpy(dataArea, data, datasz);
shm->datasz = datasz;
__atomic_store_n(&shm->flag, 1, __ATOMIC_SEQ_CST);
if (shmdt(shm) == -1) {
debug(D_ERROR, "Failed to detach from shared memory: %s", strerror(errno));
}
}
int pshm_cleanup() {
return shmctl(pshm_getid(), IPC_RMID, NULL);
}

33
pclsync/pshm.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef __PSHM_H
#define __PSHM_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include <sys/ipc.h>
#define PSYNC_SHM_SIZE 4096
// shm is used to get the return values from the underlying pcloud functions
// called by the overlay client. this is needed for cases such as
// list_sync_folders, where the result should be presented to the user in the
// CLI.
typedef struct _psync_shm {
void *data; // overlay callback return value
size_t datasz; // overlay return value size
volatile int flag; // new data available
} psync_shm;
void pshm_write(const void *data, size_t datasz);
bool pshm_read(void **data, size_t *datasz);
int pshm_cleanup();
#ifdef __cplusplus
}
#endif
#endif

View File

@ -71,6 +71,7 @@
#include "ppathstatus.h"
#include "pscanner.h"
#include "psettings.h"
#include "pshm.h"
#include "pssl.h"
#include "pstatus.h"
#include "psyncer.h"
@ -355,6 +356,9 @@ uint32_t psync_download_state() { return 0; }
void psync_destroy() {
psync_do_run = 0;
if (pshm_cleanup() == -1) {
debug(D_ERROR, "failed to cleanup shm");
}
psync_fs_stop();
psync_terminate_status_waiters();
psync_send_status_update();

View File

@ -1809,7 +1809,7 @@ void psync_get_folder_ownerid(psync_folderid_t folderid,
// void** pointer is null, then do not write any data back out for
// the client.
//
typedef int (*poverlay_callback)(const char *, void **);
typedef int (*poverlay_callback)(const char *);
/* Registers file manager extension callback that will be called when packet
* with id equals to the give one had arrived from extension. The id must be

View File

@ -41,12 +41,15 @@
#include "poverlay.h"
#include "psynclib.h"
#include "pshm.h"
#include "pclsync_lib.h"
namespace cc = console_client;
namespace clib = cc::clibrary;
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static const std::string client_name = "pCloud CC v3.0.0";
clib::pclsync_lib::pclsync_lib()
@ -331,16 +334,13 @@ static void status_change(pstatus_t *status) {
psync_free(err);
}
int clib::pclsync_lib::start_crypto(const char *pass, void **payload) {
(void)payload;
int clib::pclsync_lib::start_crypto(const char *pass) {
std::cout << "calling startcrypto pass: " << pass << std::endl;
get_lib().crypto_pass_ = pass;
return lib_setup_cripto();
}
int clib::pclsync_lib::stop_crypto(const char *path, void **payload) {
(void)payload;
int clib::pclsync_lib::stop_crypto(const char *path) {
(void)path;
psync_crypto_stop();
@ -348,20 +348,15 @@ int clib::pclsync_lib::stop_crypto(const char *path, void **payload) {
return 0;
}
int clib::pclsync_lib::finalize(const char *path, void **payload) {
(void)payload;
int clib::pclsync_lib::finalize(const char *path) {
(void)path;
psync_destroy();
exit(0);
}
int clib::pclsync_lib::add_sync_folder(const char *path, void **payload) {
if (payload == nullptr) {
std::cerr << "Error: payload pointer is null" << std::endl;
return -255;
}
// path is the local and remote path delimited by '|'
int clib::pclsync_lib::add_sync_folder(const char *path) {
if (path == nullptr) {
std::cerr << "Error: path is nullptr" << std::endl;
return -255;
@ -377,53 +372,48 @@ int clib::pclsync_lib::add_sync_folder(const char *path, void **payload) {
std::string localpath = combined.substr(0, delimiter_pos);
std::string remotepath = combined.substr(delimiter_pos + 1);
psync_syncid_t syncid = psync_add_sync_by_path(localpath.c_str(), remotepath.c_str(), PSYNC_FULL);
psync_syncid_t syncid =
psync_add_sync_by_path(localpath.c_str(), remotepath.c_str(), PSYNC_FULL);
uint64_t *payload_ptr =
static_cast<uint64_t *>(psync_malloc(sizeof(uint64_t)));
if (payload_ptr == nullptr) {
std::cerr << "Error: Failed to allocate memory for payload" << std::endl;
return -255;
}
pthread_mutex_lock(&mtx);
if (syncid == PSYNC_INVALID_SYNCID) {
std::cerr << "psync_add_sync_by_path returned PSYNC_INVALID_SYNCID"
<< std::endl;
*payload_ptr = (static_cast<uint64_t>(1) << 32) |
static_cast<uint32_t>(PSYNC_INVALID_SYNCID);
return -1;
} else {
*payload_ptr = static_cast<uint64_t>(syncid);
std::cerr << "psync_add_sync_by_path returned PSYNC_INVALID_SYNCID" << std::endl;
uint64_t error_value = (static_cast<uint64_t>(1) << 32) | PSYNC_INVALID_SYNCID;
pshm_write(&error_value, sizeof(uint64_t));
pthread_mutex_unlock(&mtx);
return -1;
}
*payload = payload_ptr;
pshm_write(&syncid, sizeof(psync_syncid_t));
pthread_mutex_unlock(&mtx);
return 0;
}
int clib::pclsync_lib::remove_sync_folder(const char *path, void **payload) {
(void)payload;
// path is the folderid to remove
int clib::pclsync_lib::remove_sync_folder(const char *path) {
psync_folderid_t folderid;
folderid = static_cast<psync_folderid_t>(std::stoull(path, nullptr, 10));
return psync_delete_sync_by_folderid(folderid);
}
int clib::pclsync_lib::list_sync_folders(const char *path, void **payload) {
// path is not used
int clib::pclsync_lib::list_sync_folders(const char *path) {
(void)path;
psync_folder_list_t *folders = psync_get_sync_list();
psync_folder_list_t *folders;
size_t folderssz;
folders = psync_get_sync_list();
if (!folders) {
return -1;
}
size_t alloc_size =
sizeof(*folders) + folders->foldercnt * sizeof(psync_folder_t);
*payload = psync_malloc(alloc_size);
if (*payload == NULL) {
psync_free(folders);
return -1;
}
memcpy(*payload, folders, alloc_size);
folderssz =
sizeof(psync_folder_list_t) + (folders->foldercnt * sizeof(psync_folder_t));
pthread_mutex_lock(&mtx);
pshm_write(folders, folderssz);
pthread_mutex_unlock(&mtx);
psync_free(folders);
return 0;
}

View File

@ -29,12 +29,13 @@
/*
Dependencies:
- <string>
- pclsync_lib_c.h
*/
#ifndef PCLSYNC_LIB_H
#define PCLSYNC_LIB_H
#include <string>
struct pstatus_struct_;
typedef void (*status_callback_t)(int status, const char *stat_string);
@ -88,12 +89,12 @@ public:
int init();
// std::string& username, std::string& password, std::string*
// crypto_pass, int setup_crypto = 1, int usesrypto_userpass = 0);
static int start_crypto(const char *pass, void **rep);
static int stop_crypto(const char *path, void **rep);
static int finalize(const char *path, void **rep);
static int list_sync_folders(const char *path, void **rep);
static int add_sync_folder(const char *path, void **rep);
static int remove_sync_folder(const char *path, void **rep);
static int start_crypto(const char *pass);
static int stop_crypto(const char *path);
static int finalize(const char *path);
static int list_sync_folders(const char *path);
static int add_sync_folder(const char *path);
static int remove_sync_folder(const char *path);
char *get_token();
int logout();
@ -107,6 +108,7 @@ private:
std::string crypto_pass_;
std::string mount_;
bool to_set_mount_;
bool daemon_;