Implement add, remove, and list sync folder commands (#59)

* list_sync_folders seems to work

* list_sync_folders breaks with sync folders in db; message size problem?

* fixed sync folders list

* fix double free and buffer overflow

* wip: add and remove sync folder; need to fix request->value in instance_thread

* remove comment

* removed pclsync_lib_c.{h,cpp}

* cleanup get_answer_to_request

* update comment

* changed reply struct to type response containing payload and msg

* cleanup

* refactored overlay_client, and poverlay; added docs

* better naming

* sock path in poverlay_protocol.h

* clarify comment

* refactor psync_overlay_get_response

* clarifications

* response_messages work with and without payload

* removed commented code

* syncadd works, but i need to fix the error handling

* remove sync folder

* remove commented code, change printfs to debug or simply remove

* removed unnecessary print

* removed more prints

* removed dead var

* update error handling in add_sync_folder, fix memleak

* simplified finalize
This commit is contained in:
Levi Neely 2024-08-25 21:54:41 +02:00 committed by GitHub
parent 21aa356ed3
commit c687484707
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 1099 additions and 538 deletions

View File

@ -28,7 +28,7 @@ LIBOUT := libpcloudcc_lib.so
# Build type specific flags
ifeq ($(BUILD), debug)
CFLAGS += -g -O0 -DDEBUG -Wall
CFLAGS += -g -O0 -DDEBUG -Wall
CXXFLAGS += -g -O0 -DDEBUG -Wall
else ifeq ($(BUILD), release)
CFLAGS += -O2 -DNDEBUG

View File

@ -25,6 +25,8 @@
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include <cstring>
#include <iomanip>
#include <iostream>
#include <string>
@ -37,9 +39,9 @@
#include "control_tools.h"
#include "overlay_client.h"
#include "pclsync_lib_c.h"
#include "pclsync_lib.h"
#include "psynclib.h"
namespace cc = console_client;
@ -56,23 +58,129 @@ 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;
int rval;
errm = NULL;
errmsz = 0;
rep = NULL;
repsz = 0;
rval = 0;
result = SendCall(LISTSYNC, "", &ret, &errm, &errmsz, &rep, &repsz);
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;
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;
}
rval = ret;
}
} else {
std::cout << "No synchronized folders found." << std::endl;
rval = ret;
}
free(errm);
free(rep);
return rval;
}
int start_crypto(const char *pass) {
int ret;
char *errm;
size_t errm_size;
int result = SendCall(STARTCRYPTO, pass, &ret, &errm, &errm_size);
// in this case, it is not enough to check for result; the server
// should return (ret==0) indicating that the crypto folder was unlocked
// successfully.
int result = SendCall(STARTCRYPTO, pass, &ret, &errm, &errm_size, NULL, NULL);
if (result != 0 || ret != 0) {
std::cout << "Start Crypto failed. return is " << ret << " and message is "
<< (errm ? errm : "no message") << std::endl;
} else {
std::cout << "Crypto started. " << std::endl;
}
if (errm)
free(errm);
return ret;
@ -83,7 +191,7 @@ int stop_crypto() {
char *errm;
size_t errm_size;
int result = SendCall(STOPCRYPTO, "", &ret, &errm, &errm_size);
int result = SendCall(STOPCRYPTO, "", &ret, &errm, &errm_size, NULL, NULL);
if (result != 0) {
std::cout << "Stop Crypto failed. return is " << ret << " and message is "
<< (errm ? errm : "no message") << std::endl;
@ -96,19 +204,88 @@ int stop_crypto() {
return ret;
}
int remove_sync_folder(const char *folderid) {
int ret;
char *errm;
size_t errmsz;
int result;
int rval;
errm = NULL;
errmsz = 0;
rval = 0;
result = SendCall(STOPSYNC, folderid, &ret, &errm, &errmsz, NULL, NULL);
if (result != 0) {
std::cout << "Remove Sync Folder failed with unknown error. return is "
<< ret << " and message is " << (errm ? errm : "no message")
<< std::endl;
rval = result;
} else {
std::cout << "Successfully removed sync folder with folderid " << folderid
<< std::endl;
}
free(errm);
return rval;
}
// TODO: should add support for specifying sync type. Need a better
// CLI processing solution first.
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);
if (result != 0) {
if (result == -1) {
std::cout << "Add Sync Folders failed: remote folder " << remotepath
<< " not found." << std::endl;
} else {
std::cout << "Add Sync Folders failed with unknown error. return is "
<< ret << " and message is " << (errm ? errm : "no message")
<< 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);
return rval;
}
int finalize() {
int ret;
char *errm;
size_t errm_size;
int result = SendCall(FINALIZE, "", &ret, &errm, &errm_size);
if (result != 0) {
std::cout << "Finalize failed. return code is " << result << ", ret is "
<< ret << ", and message is " << (errm ? errm : "no message")
<< std::endl;
} else {
std::cout << "Exiting ..." << std::endl;
}
SendCall(FINALIZE, "", &ret, &errm, &errm_size, NULL, NULL);
std::cout << "Exiting ..." << std::endl;
if (errm)
free(errm);
@ -116,18 +293,29 @@ int finalize() {
return ret;
}
void process_commands() {
void help() {
std::cout << "Supported commands are:" << std::endl
<< "startcrypto <crypto pass>, "
<< "stopcrypto, "
<< "finalize, "
<< "q, quit" << std::endl;
std::cout << "> ";
<< "help(?): Show this help message" << std::endl
<< "startcrypto <crypto pass>: Unlock crypto folder" << std::endl
<< "stopcrypto: Lock crypto folder" << std::endl
<< "finalize: Kill daemon and quit" << std::endl
<< "syncls: List sync folders" << std::endl
<< "syncadd <localpath> <remotepath>: Add sync folder (full sync)"
<< std::endl
<< "syncrm <folderid>: Remove sync folder" << std::endl
<< "quit(q): Exit this program" << std::endl;
}
void process_commands() {
std::cout << "Type 'help' or '?' for a list of supported commands."
<< std::endl;
std::cout << "> ";
for (std::string line; std::getline(std::cin, line);) {
if (!line.compare("finalize")) {
finalize();
break;
} else if (!line.compare("help") || !line.compare("?")) {
help();
} else if (!line.compare("stopcrypto")) {
stop_crypto();
} else if (!line.compare(0, 11, "startcrypto", 0, 11) &&
@ -135,6 +323,13 @@ void process_commands() {
start_crypto(line.c_str() + 12);
} else if (!line.compare("q") || !line.compare("quit")) {
break;
} else if (!line.compare("syncls")) {
list_sync_folders();
} else if (!line.compare(0, 7, "syncadd", 0, 7) && (line.length() > 7)) {
auto [lpath, rpath] = split_paths(line.c_str() + 8);
add_sync_folder(lpath, rpath);
} else if (!line.compare(0, 6, "syncrm", 0, 6) && (line.length() > 6)) {
remove_sync_folder(line.c_str() + 7);
}
std::cout << "> ";
}

View File

@ -31,7 +31,6 @@
#include <boost/program_options.hpp>
#include "control_tools.h"
#include "pclsync_lib_c.h"
#include "pclsync_lib.h"

View File

@ -26,6 +26,28 @@
DAMAGE.
*/
/*
overlay_client is responsible for invoking the pCloud API and
directing the result back to the calling function. It defines the
core logic of the request-response flow:
- SendCall (this function) writes the request to the socket.
- instance_thread reads the request from the socket and calls
get_response (see poverlay.c).
- get_response invokes the appropriate callback function and
generates a response_message. The callback functions are
registered in pclsync_lib.cpp using psync_add_overlay_callback
(see poverlay.c).
- instance_thread writes the resulting response_message to the
socket (see poverlay.c).
- SendCall reads the response from the socket. It writes the
response output data back to its caller (see control_tools.cpp).
*/
#include <errno.h>
#include <netinet/in.h>
#include <stdbool.h>
@ -38,22 +60,129 @@
#include "debug.h"
#include "overlay_client.h"
#define POVERLAY_BUFSIZE 512
#include "poverlay_protocol.h"
typedef struct _message {
uint32_t type;
uint64_t length;
char value[];
} message;
#define POVERLAY_BUFSIZE 16 * 1024
const char *clsoc = "/tmp/pcloud_unix_soc.sock";
// for easier error tracing...
#define POVERLAY_SOCKET_CREATE_FAILED -100
#define POVERLAY_SOCKET_CONNECT_FAILED -101
#define POVERLAY_WRITE_SOCK_ERR -102
#define POVERLAY_WRITE_COMM_ERR -103
#define POVERLAY_READ_SOCK_ERR -104
#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) {
if (resp) {
free(resp->msg);
free(resp->payload);
free(resp);
}
}
int QueryState(pCloud_FileState *state, char *path) {
int rep = 0;
char *errm;
size_t errm_size;
if (!SendCall(4, path /*IN*/, &rep, &errm, &errm_size)) {
if (!SendCall(4, path /*IN*/, &rep, &errm, &errm_size, NULL, NULL)) {
debug(D_NOTICE, "QueryState responese rep[%d] path[%s]", rep, path);
if (errm)
debug(D_NOTICE, "The error is %s", errm);
@ -71,196 +200,214 @@ int QueryState(pCloud_FileState *state, char *path) {
return 0;
}
int SendCall(int id /*IN*/, const char *path /*IN*/, int *ret /*OUT*/,
char **out /*OUT*/, size_t *out_size) {
// socket_connect creates and connects to a unix socket at the
// specified sockpath. it may write an error message and error message
// size to out and out_size, and a "ret" value to ret (i think this is
// redundant maybe...)
int socket_connect(const char *sockpath, char **out, size_t *out_size,
int *ret) {
int fd;
struct sockaddr_un addr;
int result, rc;
uint64_t sendbytes = 0;
int fd = -1;
int sendlen = strlen(path);
int sendsize = sizeof(message) + sendlen + 1;
char sendbuf[sendsize];
char *recvbuf = NULL;
size_t recvsize = 0;
size_t recvbytes = 0;
size_t recvchunk = 32; // read response in 32-byte chunks
message *rep = NULL;
const char *error_msg;
// init output params
*out = NULL;
*out_size = 0;
*ret = 0;
result = 0;
debug(D_NOTICE, "SendCall id[%d] path[%s]\n", id, path);
// prepare socket fd
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
error_msg = "Unable to create unix socket";
*out = strdup(error_msg);
if (*out == NULL) {
debug(D_ERROR,
"on socket(): failed to allocate memory for output message");
*ret = -255;
return -255;
}
*out_size = strlen(error_msg) + 1;
*ret = -3;
return -3;
*ret = POVERLAY_SOCKET_CREATE_FAILED;
return POVERLAY_SOCKET_CREATE_FAILED;
}
// connect to socket
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, clsoc, sizeof(addr.sun_path) - 1);
strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path) - 1);
if (connect(fd, (struct sockaddr *)&addr, SUN_LEN(&addr)) == -1) {
error_msg = "Unable to connect to UNIX socket";
*out = strdup(error_msg);
if (*out == NULL) {
debug(D_ERROR,
"on connect(): failed to allocate memory for output message");
*ret = -254;
return -254;
}
*out_size = strlen(error_msg) + 1;
*ret = -4;
return -4;
*ret = POVERLAY_SOCKET_CONNECT_FAILED;
return POVERLAY_SOCKET_CONNECT_FAILED;
}
return fd;
}
debug(D_NOTICE, "SendCall: Sending message type %d, path '%s'", id, path);
// write_request writes a request_message to given socket file
// descriptor of a given type and value. it may write out an error
// message and error message size to out and out_size, and a "ret"
// value to ret (i think this is redundant, maybe...)
int write_request(int fd, int msgtype, const char *value, char **out,
size_t *out_size, int *ret) {
uint64_t bytes_written;
int rc;
int len;
int size;
char *buf;
const char *err;
request_message *request;
char *curbuf;
// prepare and send the message to the socket
message *mes = (message *)sendbuf;
memset(mes, 0, sendsize);
mes->type = id;
strncpy(mes->value, path, sendlen + 1);
mes->length = sendsize;
*ret = 0; // Initialize ret to 0
char *curbuf = (char *)mes;
while (sendbytes < mes->length) {
rc = write(fd, curbuf, (mes->length - sendbytes));
len = strlen(value);
size = sizeof(request_message) + len + 1;
buf = (char *)malloc(size);
request = (request_message *)buf;
memset(request, 0, size);
request->type = msgtype;
strncpy(request->value, value, len + 1);
request->length = size;
bytes_written = 0;
curbuf = (char *)request;
while (bytes_written < request->length && *ret == 0) {
rc = write(fd, curbuf, (request->length - bytes_written));
if (rc <= 0) {
if (errno == EINTR)
continue; // try again on interrupt
error_msg = "failed to write to socket.";
*out = strdup(error_msg);
if (*out == NULL) {
debug(D_ERROR, "failed to allocate memory for output message");
*ret = -253;
return -253;
if (errno != EINTR) {
err = "failed to write to socket.";
*out = strdup(err);
*ret = POVERLAY_WRITE_SOCK_ERR;
}
*ret = -248;
return -248;
} else {
bytes_written += rc;
curbuf += rc;
}
sendbytes += rc;
}
debug(D_NOTICE, "SendCall: Sent %lu bytes", sendbytes);
if (sendbytes != mes->length) {
error_msg = "Communication error";
if (*ret == 0 && bytes_written != request->length) {
err = "Communication error";
*out = strdup(err);
*out_size = strlen(err) + 1;
*ret = POVERLAY_WRITE_COMM_ERR;
}
free(buf);
return *ret;
}
// read_response reads a response message from a given socket. it may
// 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);
if (bytes_read <= 0) {
const char *error_msg =
(bytes_read == 0) ? "Connection closed" : strerror(errno);
*out = strdup(error_msg);
if (*out == NULL) {
debug(D_ERROR, "while checking bytes_written: failed to allocate memory "
"for output message");
*ret = -253;
return -253;
}
*out_size = strlen(error_msg) + 1;
*ret = -5;
return -5;
*ret = -1;
return -1;
}
// read the response from the socket
bool received_data = false;
for (;;) {
char *new_buf = realloc(recvbuf, recvsize + recvchunk);
if (!new_buf) {
debug(D_ERROR, "failed to allocate memory to response buffer");
*ret = -252;
result = -252;
goto cleanup;
}
recvbuf = new_buf;
rc = read(fd, recvbuf + recvsize, recvchunk);
if (rc < 0) {
debug(D_ERROR, "failed to read from socket into response buffer");
*ret = -251;
result = -251;
goto cleanup;
}
if (rc == 0) {
break; // end of response
}
received_data = true;
recvsize += rc;
recvbytes += rc;
if (recvbytes >= sizeof(message)) {
message *rep = (message *)recvbuf;
if (recvbytes >= rep->length) {
break; // entire message read
}
}
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;
}
debug(D_NOTICE, "SendCall: Received %zu bytes", recvbytes);
if (!received_data) {
*ret = 0;
*out = strdup("");
if (*out == NULL) {
debug(D_ERROR, "failed to allocate memory for empty output message");
*ret = -248;
result = -248;
goto cleanup;
}
*out_size = 1;
result = 0;
goto cleanup;
// 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;
}
if (recvbytes >= sizeof(message)) {
message *rep = (message *)recvbuf;
debug(D_NOTICE, "SendCall: Received message type: %d, length: %lu",
rep->type, rep->length);
if (recvbytes >= rep->length) {
debug(D_NOTICE, "SendCall: Entire message content: '%s'", rep->value);
}
// 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;
}
if (recvbytes < sizeof(message)) {
debug(D_ERROR, "got incomplete message from socket");
*ret = -250;
result = -250;
goto cleanup;
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;
}
rep = (message *)recvbuf;
*ret = rep->type;
size_t value_size = rep->length - sizeof(message);
*out = malloc(value_size + 1);
if (!*out) {
debug(D_ERROR, "failed to allocate memory to output buffer");
*ret = -249;
result = -249;
goto cleanup;
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, rep->value, value_size);
memcpy(*out, msg->value, value_size);
(*out)[value_size] = '\0';
*out_size = value_size + 1;
cleanup:
if (fd != -1)
close(fd);
if (recvbuf)
free(recvbuf);
*ret = msg->type;
return result;
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);
*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;
}
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) {
int result;
int sockfd;
sockfd = -1;
result = 0;
*out = NULL;
*out_size = 0;
*ret = 0;
// side effects: modify out, out_size, ret
sockfd = socket_connect(POVERLAY_SOCK_PATH, out, out_size, 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);
}
close(sockfd);
} else {
result = -1;
}
return *ret; // always 0 on success
}

View File

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

View File

@ -2978,7 +2978,7 @@ void psync_diff_wake() {
static void psync_diff_thread() {
psync_socket *sock;
binresult *res;
binresult *res = NULL;
const binresult *entries;
uint64_t newdiffid, result;
psync_socket_t exceptionsock, socks[2];
@ -2986,8 +2986,11 @@ static void psync_diff_thread() {
int sel, ret = 0;
char ex;
char *err = NULL;
int should_free_res = 0;
psync_set_status(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_CONNECTING);
psync_send_status_update();
restart:
psync_set_status(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_CONNECTING);
sock = get_connected_socket();
@ -3005,8 +3008,9 @@ restart:
P_NUM("limit", PSYNC_DIFF_LIMIT),
P_NUM("diffid", ids.diffid)};
if (!psync_do_run)
break;
goto cleanup;
res = send_command(sock, "diff", diffparams);
should_free_res = 1;
if (!res) {
psync_socket_close(sock);
goto restart;
@ -3015,7 +3019,6 @@ restart:
if (unlikely(result)) {
debug(D_ERROR, "diff returned error %u: %s", (unsigned int)result,
psync_find_result(res, "error", PARAM_STR)->str);
psync_free(res);
psync_socket_close(sock);
psync_milisleep(PSYNC_SLEEP_BEFORE_RECONNECT);
goto restart;
@ -3026,13 +3029,17 @@ restart:
debug(D_NOTICE, "processing diff with %u entries",
(unsigned)entries->length);
ids.diffid = process_entries(entries, newdiffid);
// psync_diff_refresh_fs(entries); -- don't do this for initial loading
debug(D_NOTICE, "got diff with %u entries, new diffid %lu",
(unsigned)entries->length, (unsigned long)ids.diffid);
}
result = entries->length;
psync_free(res);
if (should_free_res) {
psync_free(res);
should_free_res = 0;
res = NULL;
}
} while (result);
psync_fs_refresh_folder(0);
debug(D_NOTICE, "initial sync finished");
if (psync_diff_check_quota(sock)) {
@ -3049,7 +3056,7 @@ restart:
if (unlikely(exceptionsock == INVALID_SOCKET)) {
debug(D_ERROR, "could not create pipe");
psync_socket_close(sock);
return;
goto cleanup;
}
socks[0] = exceptionsock;
socks[1] = sock->sock;
@ -3059,6 +3066,7 @@ restart:
send_diff_command(sock, ids);
psync_milisleep(50);
last_event = 0;
while (psync_do_run) {
if (unlinked) {
unlinked = 0;
@ -3085,6 +3093,7 @@ restart:
} else if (sel == 1) {
sock->pending = 1;
res = get_result(sock);
should_free_res = 1;
if (unlikely_log(!res)) {
psync_timer_notify_exception();
handle_exception(&sock, &ids, 'r');
@ -3098,13 +3107,11 @@ restart:
if (result == 6003 || result == 6002) { // timeout or cancel
debug(D_NOTICE, "got \"%s\" from the socket",
psync_find_result(res, "error", PARAM_STR)->str);
psync_free(res);
send_diff_command(sock, ids);
continue;
}
debug(D_ERROR, "diff returned error %u: %s", (unsigned int)result,
psync_find_result(res, "error", PARAM_STR)->str);
psync_free(res);
handle_exception(&sock, &ids, 'r');
socks[1] = sock->sock;
continue;
@ -3123,18 +3130,17 @@ restart:
initialdownload = 0;
} else
debug(D_NOTICE, "diff with 0 entries, did we send a nop recently?");
psync_free(res);
} else if (entries->length == 13 &&
!strcmp(entries->str, "notifications")) {
ids.notificationid =
psync_find_result(res, "notificationid", PARAM_NUM)->num;
// do not free res
psync_notifications_notify(res);
should_free_res = 0; // Don't free res in this case
} else if (entries->length == 8 && !strcmp(entries->str, "publinks")) {
ids.publinkid = psync_find_result(res, "publinkid", PARAM_NUM)->num;
ret = cache_links(err, 256);
if (ret < 0)
debug(D_ERROR, "Cacheing links faild with err %s", err);
debug(D_ERROR, "Cacheing links failed with err %s", err);
else
psync_notify_cache_change(PACCOUNT_CHANGE_LINKS);
} else if (entries->length == 11 &&
@ -3146,7 +3152,6 @@ restart:
debug(D_ERROR, "Cacheing upload links failed with err %s", err);
else
psync_notify_cache_change(PACCOUNT_CHANGE_LINKS);
} else if (entries->length == 5 && !strcmp(entries->str, "teams")) {
cache_account_teams();
cache_ba_my_teams();
@ -3159,14 +3164,22 @@ restart:
psync_notify_cache_change(PACCOUNT_CHANGE_CONTACTS);
} else {
debug(D_NOTICE, "got no from, did we send a nop recently?");
psync_free(res);
}
send_diff_command(sock, ids);
} else {
psync_free(res);
debug(D_NOTICE, "got no from, did we send a nop recently?");
}
}
if (should_free_res) {
psync_free(res);
should_free_res = 0;
res = NULL;
}
}
cleanup:
if (should_free_res && res) {
psync_free(res);
}
psync_socket_close(sock);

View File

@ -103,6 +103,7 @@ psync_folderid_t psync_get_folderid_by_path(const char *path) {
}
} else
psync_sql_reset(res);
psync_sql_bind_uint(res, 1, cfolderid);
psync_sql_bind_lstring(res, 2, path, len);
row = psync_sql_fetch_rowint(res);
@ -878,7 +879,10 @@ psync_folder_list_t *psync_list_get_list(char *syncTypes) {
l = folders[i].locallen;
memcpy(str, folders[i].localpath, l);
psync_free(folders[i].localpath);
ret->folders[i].localpath = str;
strncpy(ret->folders[i].localpath, str,
sizeof(ret->folders[i].localpath) - 1);
ret->folders[i].localpath[sizeof(ret->folders[i].localpath) - 1] = '\0';
l--;
while (l && str[l] != PSYNC_DIRECTORY_SEPARATORC && str[l] != '/')
@ -887,13 +891,17 @@ psync_folder_list_t *psync_list_get_list(char *syncTypes) {
if ((str[l] == PSYNC_DIRECTORY_SEPARATORC || str[l] == '/') && str[l + 1])
l++;
ret->folders[i].localname = str + l;
strncpy(ret->folders[i].localname, str,
sizeof(ret->folders[i].localname) - 1);
ret->folders[i].localname[sizeof(ret->folders[i].localname) - 1] = '\0';
str += folders[i].locallen;
l = folders[i].remotelen;
memcpy(str, folders[i].remotepath, l);
psync_free(folders[i].remotepath);
ret->folders[i].remotepath = str;
strncpy(ret->folders[i].remotepath, str,
sizeof(ret->folders[i].remotepath) - 1);
ret->folders[i].remotepath[sizeof(ret->folders[i].remotepath) - 1] = '\0';
if (l)
l--;
@ -904,7 +912,9 @@ psync_folder_list_t *psync_list_get_list(char *syncTypes) {
if (str[l] == '/')
l++;
ret->folders[i].remotename = str + l;
strncpy(ret->folders[i].remotename, str + l,
sizeof(ret->folders[i].remotename) - 1);
ret->folders[i].remotename[sizeof(ret->folders[i].remotename) - 1] = '\0';
str += folders[i].remotelen;
ret->folders[i].folderid = folders[i].folderid;
ret->folders[i].syncid = folders[i].syncid;

View File

@ -26,41 +26,93 @@
DAMAGE.
*/
#include "poverlay.h"
#include "pcache.h"
#include "pcompat.h"
#include "plibs.h"
#include "ppathstatus.h"
/*
poverlay is the "overlay server" (contrast with overlay_client). It
listens for request messages generated by overlay_client on a unix
socket, invokes the appropriate callback based on the message type,
and generates a response message. It then writes the response
message back to the socket where the overlay_client will read and
act upon it.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include "pcompat.h"
#include "poverlay_protocol.h"
#include "poverlay.h"
#include "ppathstatus.h"
#include "plibs.h"
#define POVERLAY_BUFSIZE 512
int overlays_running = 1;
int callbacks_running = 1;
char *mysoc = "/tmp/pcloud_unix_soc.sock";
// 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;
void overlay_main_loop() {
// 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;
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
// debug(D_NOTICE, "Unix socket error failed to open %s", mysoc);
debug(D_ERROR, "Unix socket error failed to open %s", POVERLAY_SOCK_PATH);
return;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, mysoc, sizeof(addr.sun_path) - 1);
strncpy(addr.sun_path, POVERLAY_SOCK_PATH, sizeof(addr.sun_path) - 1);
unlink(mysoc);
unlink(POVERLAY_SOCK_PATH);
if (bind(fd, (struct sockaddr *)&addr,
strlen(mysoc) + sizeof(addr.sun_family)) == -1) {
strlen(POVERLAY_SOCK_PATH) + sizeof(addr.sun_family)) == -1) {
debug(D_ERROR, "Unix socket bind error");
return;
}
@ -75,159 +127,289 @@ void overlay_main_loop() {
debug(D_ERROR, "Unix socket accept error");
continue;
}
// handle the request in a new thread
psync_run_thread1("Pipe request handle routine",
instance_thread, // thread proc
(LPVOID)&cl // thread parameter
psync_overlay_handle_request, // thread proc
(LPVOID)&cl // thread parameter
);
}
return;
}
void instance_thread(void *lpvParam) {
int *cl, rc;
char chbuf[POVERLAY_BUFSIZE];
message *request = NULL;
char *curbuf = &chbuf[0];
int bytes_read = 0;
message *reply = (message *)psync_malloc(POVERLAY_BUFSIZE);
void psync_overlay_handle_request(void *lpvParam) {
int *sockfd; // pcloud socket file descriptor
int rc; // bytes read / written per iteration
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
memset(reply, 0, POVERLAY_BUFSIZE);
memset(chbuf, 0, POVERLAY_BUFSIZE);
request = NULL;
response = NULL;
readbytes = 0;
rqbufp = &rqbuf[0];
sockfd = (int *)lpvParam;
cl = (int *)lpvParam;
while ((rc = read(*cl, curbuf, (POVERLAY_BUFSIZE - bytes_read))) > 0) {
bytes_read += rc;
// debug(D_ERROR, "Read %u bytes: %u %s", bytes_read, rc, curbuf );
curbuf = curbuf + rc;
if (bytes_read > 12) {
request = (message *)chbuf;
if (request->length == bytes_read)
// read the request from the socket into the request buffer
memset(rqbuf, 0, POVERLAY_BUFSIZE);
while ((rc = read(*sockfd, rqbufp, (POVERLAY_BUFSIZE - readbytes))) > 0) {
readbytes += rc;
rqbufp = rqbufp + rc;
if (readbytes > 12) {
request = (request_message *)rqbuf;
if (request->length == (uint64_t)readbytes)
break;
}
}
if (rc == -1) {
// debug(D_ERROR,"Unix socket read");
close(*cl);
return;
} else if (rc == 0) {
// debug(D_NOTICE,"Message received");
close(*cl);
debug(D_ERROR, "Unix socket read error");
goto cleanup;
} else if (rc == 0 && readbytes == 0) {
debug(D_NOTICE, "Connection closed by client before sending data");
goto cleanup;
}
request = (message *)chbuf;
if (request) {
get_answer_to_request(request, reply);
if (reply) {
rc = write(*cl, reply, reply->length);
if (rc != reply->length)
debug(D_ERROR, "Unix socket reply not sent.");
}
}
if (cl) {
close(*cl);
}
// debug(D_NOTICE, "InstanceThread exitting.\n");
psync_free(reply);
return;
};
// 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;
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;
}
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);
} else {
debug(D_ERROR, "No valid request received");
}
cleanup:
if (sockfd) {
close(*sockfd);
}
if (response) {
if (response->msg) {
psync_free(response->msg);
}
if (response->payload) {
psync_free(response->payload);
}
psync_free(response);
}
debug(D_NOTICE, "InstanceThread exiting.");
}
poverlay_callback *callbacks;
static int callbacks_size = 15;
static const int calbacks_lower_band = 20;
int psync_add_overlay_callback(int id, poverlay_callback callback) {
// registers an overlay callback for a given message type.
int psync_overlay_register_callback(int msgtype, poverlay_callback callback) {
poverlay_callback *callbacks_old = callbacks;
int callbacks_size_old = callbacks_size;
if (id < calbacks_lower_band)
if (msgtype < calbacks_lower_band)
return -1;
if (id > (calbacks_lower_band + callbacks_size)) {
callbacks_size = id - calbacks_lower_band + 1;
init_overlay_callbacks();
if (msgtype > (calbacks_lower_band + callbacks_size)) {
callbacks_size = msgtype - calbacks_lower_band + 1;
psync_overlay_init_callbacks();
memcpy(callbacks, callbacks_old,
callbacks_size_old * sizeof(poverlay_callback));
psync_free(callbacks_old);
}
callbacks[id - calbacks_lower_band] = callback;
callbacks[msgtype - calbacks_lower_band] = callback;
return 0;
}
void init_overlay_callbacks() {
void psync_overlay_init_callbacks() {
callbacks = (poverlay_callback *)psync_malloc(sizeof(poverlay_callback) *
callbacks_size);
memset(callbacks, 0, sizeof(poverlay_callback) * callbacks_size);
}
void psync_stop_overlays() { overlays_running = 0; }
void psync_start_overlays() { overlays_running = 1; }
static void psync_overlay_get_status_response(request_message *request,
response_message *response,
size_t available_space) {
psync_path_status_t stat;
void psync_stop_overlay_callbacks() { callbacks_running = 0; }
void psync_start_overlay_callbacks() { callbacks_running = 1; }
stat = PSYNC_PATH_STATUS_NOT_OURS;
void get_answer_to_request(message *request, message *reply) {
psync_path_status_t stat = PSYNC_PATH_STATUS_NOT_OURS;
memcpy(reply->value, "Ok.", 4);
reply->length = sizeof(message) + 4;
if (request->type == 20 /* STARTCRYPTO, see control_tools.cpp */) {
// don't publish the crypto password to the logs in plain text...
debug(D_NOTICE, "Client Request type [%u] len [%lu] string: [%s]",
request->type, request->length, "REDACTED");
} else {
debug(D_NOTICE, "Client Request type [%u] len [%lu] string: [%s]",
request->type, request->length, request->value);
if (overlays_running) {
stat = psync_path_status_get(request->value);
}
if (request->type < 20) {
if (overlays_running)
stat = psync_path_status_get(request->value);
switch (psync_path_status_get_status(stat)) {
case PSYNC_PATH_STATUS_IN_SYNC:
reply->type = 10;
break;
case PSYNC_PATH_STATUS_IN_PROG:
reply->type = 12;
break;
case PSYNC_PATH_STATUS_PAUSED:
case PSYNC_PATH_STATUS_REMOTE_FULL:
case PSYNC_PATH_STATUS_LOCAL_FULL:
reply->type = 11;
break;
default:
reply->type = 13;
memcpy(reply->value, "No.", 4);
}
} else if ((callbacks_running) &&
(request->type < (calbacks_lower_band + callbacks_size))) {
int ind = request->type - 20;
int ret = 0;
message *rep = NULL;
if (callbacks[ind]) {
ret = callbacks[ind](request->value, rep);
if (ret == 0) {
if (rep) {
psync_free(reply);
reply = rep;
} else {
reply->type = 0;
}
} else {
reply->type = ret;
memcpy(reply->value, "No.", 4);
}
} else {
reply->type = 13;
memcpy(reply->value, "No callback with this id registered.", 37);
reply->length = sizeof(message) + 37;
}
} else {
reply->type = 13;
memcpy(reply->value, "Invalid type.", 14);
reply->length = sizeof(message) + 14;
switch (psync_path_status_get_status(stat)) {
case PSYNC_PATH_STATUS_IN_SYNC:
response->msg->type = 10;
break;
case PSYNC_PATH_STATUS_IN_PROG:
response->msg->type = 12;
break;
case PSYNC_PATH_STATUS_PAUSED:
case PSYNC_PATH_STATUS_REMOTE_FULL:
case PSYNC_PATH_STATUS_LOCAL_FULL:
response->msg->type = 11;
break;
default:
response->msg->type = 13;
snprintf(response->msg->value, available_space, "No.");
}
}
int psync_overlays_running() { return overlays_running; }
int psync_ovr_callbacks_running() { return callbacks_running; }
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,
size_t available_space) {
int cbidx; // callback index (based on message type)
int cbret; // callback return value
cbidx = request->type - 20;
cbret = 0;
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.");
debug(D_NOTICE, "Invalid request type: %u", request->type);
return;
}
if (!callbacks[cbidx]) {
response->msg->type = 13;
snprintf(response->msg->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);
if (cbret == 0) {
response->msg->type = 0;
psync_overlay_get_overlay_response_payload(request, response);
} else {
response->msg->type = cbret;
snprintf(response->msg->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) {
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;
value_avail = POVERLAY_BUFSIZE - sizeof(message);
// never print the crypto password to the logs in plain text
dbgmsg = (request->type == 20) ? "REDACTED" : request->value;
debug(D_NOTICE, "Client Request type [%u] len [%lu] string: [%s]",
request->type, request->length, dbgmsg);
if (request->type < 20) {
psync_overlay_get_status_response(request, response, value_avail);
} else {
psync_overlay_get_overlay_response(request, response, value_avail);
}
// 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.");
} else {
debug(D_WARNING,
"not updating value to Ok: response->msg->type=%d, "
"response->msg->value=%s",
response->msg->type, response->msg->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';
debug(D_WARNING, "Response message truncated to fit buffer");
}
}
void psync_overlay_stop_overlays() { overlays_running = 0; }
void psync_overlay_start_overlays() { overlays_running = 1; }
void psync_overlay_stop_overlay_callbacks() { callbacks_running = 0; }
void psync_overlay_start_overlay_callbacks() { callbacks_running = 1; }
int psync_overlay_overlays_running() { return overlays_running; }
int psync_overlay_callbacks_running() { return callbacks_running; }

View File

@ -26,6 +26,10 @@
DAMAGE.
*/
// dependencies:
// - poverlay_protocol.h
// - psynclib.h
#ifndef POVERLAY_H
#define POVERLAY_H
@ -39,26 +43,21 @@
#include "psynclib.h"
typedef struct _message {
uint32_t type;
uint64_t length;
char value[];
} message;
extern int overlays_running;
extern int callbacks_running;
void overlay_main_loop(VOID);
void instance_thread(LPVOID);
void get_answer_to_request(message *requesr /*IN*/, message *replay /*OUT*/);
void psync_stop_overlays();
void psync_start_overlays();
void psync_stop_overlay_callbacks();
void psync_start_overlay_callbacks();
int psync_overlays_running();
int psync_ovr_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_stop_overlays();
void psync_overlay_start_overlays();
void psync_overlay_stop_overlay_callbacks();
void psync_overlay_start_overlay_callbacks();
int psync_overlay_overlays_running();
int psync_overlay_callbacks_running();
void init_overlay_callbacks();
int psync_add_overlay_callback(int id, poverlay_callback callback);
void psync_overlay_init_callbacks();
int psync_overlay_register_callback(int id, poverlay_callback callback);
#endif // POVERLAY_H

View File

@ -0,0 +1,22 @@
// defines the messaging protocol for pclsync
#ifndef POVERLAY_SOCK_PATH
#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;

View File

@ -61,6 +61,9 @@
#include "pmemlock.h"
#include "pnetlibs.h"
#include "pnotifications.h"
#include "poverlay_protocol.h"
#include "poverlay.h"
#include "pp2p.h"
#include "ppagecache.h"
@ -297,8 +300,8 @@ int psync_init() {
pthread_mutex_unlock(&psync_libstate_mutex);
}
psync_run_thread("Overlay main thread", overlay_main_loop);
init_overlay_callbacks();
psync_run_thread("Overlay main thread", psync_overlay_main_loop);
psync_overlay_init_callbacks();
if (PSYNC_SSL_DEBUG_LEVEL)
psync_set_ssl_debug_callback(ssl_debug_cb);
@ -3045,7 +3048,7 @@ char *get_backup_root_name() {
char *get_pc_name() { return get_machine_name(); }
void psync_async_delete_sync(void *ptr) {
psync_syncid_t syncId = *(psync_syncid_t *)ptr;
psync_syncid_t syncId = (psync_syncid_t)(uintptr_t)ptr;
int res;
res = psync_delete_sync(syncId);
@ -3074,32 +3077,23 @@ void psync_async_ui_callback(void *ptr) {
int psync_delete_sync_by_folderid(psync_folderid_t fId) {
psync_sql_res *sqlRes;
psync_uint_row row;
psync_syncid_t *syncId;
psync_syncid_t *syncIdT;
psync_syncid_t syncId;
sqlRes =
psync_sql_query_nolock("SELECT id FROM syncfolder WHERE folderid = ?");
psync_sql_query_rdlock("SELECT id FROM syncfolder WHERE folderid = ?");
psync_sql_bind_uint(sqlRes, 1, fId);
row = psync_sql_fetch_rowint(sqlRes);
if (unlikely(!row)) {
debug(D_ERROR, "Sync to delete not found!");
psync_sql_free_result(sqlRes);
return -1;
}
// XXX: results in truncation (uint64 -> uint)
syncId = (psync_syncid_t *)row[0];
syncId = (psync_syncid_t)row[0];
psync_sql_free_result(sqlRes);
syncIdT = psync_new(psync_syncid_t);
syncIdT = syncId;
psync_run_thread1("psync_async_sync_delete", psync_async_delete_sync,
syncIdT);
(void *)(uintptr_t)syncId);
return 0;
}

View File

@ -381,6 +381,9 @@ typedef struct pstatus_struct_ {
#define PSYNC_CRYPTO_STATUS_ACTIVE 4
#define PSYNC_CRYPTO_STATUS_SETUP 5
// limitation: path length of 255, plus null terminator.
#define PSYNC_MAX_PATH_LENGTH 256
#define PSYNC_CRYPTO_INVALID_FOLDERID ((psync_folderid_t) - 1)
#define PSYNC_CRYPTO_FLAG_TEMP_PASS 1
@ -402,10 +405,10 @@ typedef struct pstatus_struct_ {
// Lib error codes end
typedef struct {
const char *localname;
const char *localpath;
const char *remotename;
const char *remotepath;
char localname[PSYNC_MAX_PATH_LENGTH];
char localpath[PSYNC_MAX_PATH_LENGTH];
char remotename[PSYNC_MAX_PATH_LENGTH];
char remotepath[PSYNC_MAX_PATH_LENGTH];
psync_folderid_t folderid;
psync_syncid_t syncid;
psync_synctype_t synctype;
@ -1791,10 +1794,21 @@ void psync_get_current_userid(psync_userid_t * /*OUT*/ ret);
void psync_get_folder_ownerid(psync_folderid_t folderid,
psync_userid_t * /*OUT*/ ret);
/* Callback to be registered to be called from file manager extension.
*/
typedef int (*poverlay_callback)(const char *path, void *rep);
// Defines the function signature of an overlay server-side
// callback. poverlay_callback implementations must satisfy the
// following:
//
// - Accepts request data as a string.
//
// - Returns 0 on success, and non-zero on failure
//
// - If the function invoked by the callback function returns data
// that can be used by the client (e.g., list_sync_folders), then
// allocate the void** pointer and write the data there. If the
// void** pointer is null, then do not write any data back out for
// the client.
//
typedef int (*poverlay_callback)(const char *, void **);
/* 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
@ -1806,11 +1820,11 @@ typedef int (*poverlay_callback)(const char *path, void *rep);
* synchronize.
*/
int psync_add_overlay_callback(int id, poverlay_callback callback);
void psync_stop_overlays();
void psync_start_overlays();
void psync_stop_overlay_callbacks();
void psync_start_overlay_callbacks();
int psync_overlay_register_callback(int id, poverlay_callback callback);
void psync_overlay_stop_overlays();
void psync_overlay_start_overlays();
void psync_overlay_stop_overlay_callbacks();
void psync_overlay_start_overlay_callbacks();
int psync_setlanguage(const char *language, char **err);

View File

@ -286,7 +286,7 @@ int backend_call(const char *binapi, const char *wsPath,
j++;
}
for (i = 0; i <= totalParCnt; i++) {
for (i = 0; i < totalParCnt; i++) {
if (localParams[i].paramtype == 0) {
continue;
}

View File

@ -30,11 +30,16 @@
#include <iostream>
#include <string>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include "pclsync_lib_c.h"
#include "poverlay_protocol.h"
#include "poverlay.h"
#include "psynclib.h"
#include "pclsync_lib.h"
@ -111,36 +116,61 @@ void clib::pclsync_lib::do_get_pass_from_console(std::string &password) {
void event_handler(psync_eventtype_t event, psync_eventdata_t eventdata) {
if (event < PEVENT_FIRST_USER_EVENT) {
if (event & PEVENT_TYPE_FOLDER) {
std::cout << "folder event=" << event
<< ", syncid=" << eventdata.folder->syncid
<< ", folderid=" << eventdata.folder->folderid
<< ", name=" << eventdata.folder->name
<< ", local=" << eventdata.folder->localpath
<< ", remote=" << eventdata.folder->remotepath << std::endl;
if (eventdata.folder) {
std::cout << "folder event=" << event
<< ", syncid=" << eventdata.folder->syncid
<< ", folderid=" << eventdata.folder->folderid << ", name="
<< (eventdata.folder->name ? eventdata.folder->name : "")
<< ", local="
<< (eventdata.folder->localpath ? eventdata.folder->localpath
: "")
<< ", remote="
<< (eventdata.folder->remotepath
? eventdata.folder->remotepath
: "")
<< std::endl;
} else {
std::cout << "folder event=" << event << " (no folder data)"
<< std::endl;
}
} else {
std::cout << "file event=" << event
<< ", syncid=" << eventdata.folder->syncid
<< ", file=" << eventdata.file->fileid
<< ", name=" << eventdata.file->name
<< ", local=" << eventdata.file->localpath
<< ", remote=" << eventdata.file->remotepath << std::endl;
if (eventdata.file) {
std::cout
<< "file event=" << event << ", syncid=" << eventdata.file->syncid
<< ", file=" << eventdata.file->fileid
<< ", name=" << (eventdata.file->name ? eventdata.file->name : "")
<< ", local="
<< (eventdata.file->localpath ? eventdata.file->localpath : "")
<< ", remote="
<< (eventdata.file->remotepath ? eventdata.file->remotepath : "")
<< std::endl;
} else {
std::cout << "file event=" << event << " (no file data)" << std::endl;
}
}
} else if (event >= PEVENT_FIRST_SHARE_EVENT) {
std::cout << "share event=" << event
<< ", folderid=" << eventdata.share->folderid
<< ", sharename=" << eventdata.share->sharename
<< ", email=" << eventdata.share->toemail
<< ", message=" << eventdata.share->message
<< ", userid=" << eventdata.share->userid
<< ", shareid=" << eventdata.share->shareid
<< ", sharerequestid=" << eventdata.share->sharerequestid
<< ", created=" << eventdata.share->created
<< ", canread=" << eventdata.share->canread
<< ", cancreate=" << eventdata.share->cancreate
<< ", canmodify=" << eventdata.share->canmodify
<< ", candelete=" << eventdata.share->candelete << std::endl;
if (eventdata.share) {
std::cout << "share event=" << event
<< ", folderid=" << eventdata.share->folderid << ", sharename="
<< (eventdata.share->sharename ? eventdata.share->sharename
: "")
<< ", email="
<< (eventdata.share->toemail ? eventdata.share->toemail : "")
<< ", message="
<< (eventdata.share->message ? eventdata.share->message : "")
<< ", userid=" << eventdata.share->userid
<< ", shareid=" << eventdata.share->shareid
<< ", sharerequestid=" << eventdata.share->sharerequestid
<< ", created=" << eventdata.share->created
<< ", canread=" << eventdata.share->canread
<< ", cancreate=" << eventdata.share->cancreate
<< ", canmodify=" << eventdata.share->canmodify
<< ", candelete=" << eventdata.share->candelete << std::endl;
} else {
std::cout << "share event=" << event << " (no share data)" << std::endl;
}
} else {
std::cout << "event" << event << std::endl;
std::cout << "event " << event << std::endl;
}
}
@ -222,9 +252,6 @@ static void status_change(pstatus_t *status) {
clib::pclsync_lib::get_lib().get_pass_from_console();
}
// std::cout << "Username: " <<
// clib::pclsync_lib::get_lib().get_username().c_str() << "| Password: " <<
// clib::pclsync_lib::get_lib().get_password().c_str() << std::endl;
psync_set_user_pass(clib::pclsync_lib::get_lib().get_username().c_str(),
clib::pclsync_lib::get_lib().get_password().c_str(),
(int)clib::pclsync_lib::get_lib().save_pass_);
@ -270,28 +297,99 @@ static void status_change(pstatus_t *status) {
psync_free(err);
}
int clib::pclsync_lib::start_crypto(const char *pass, void *rep) {
int clib::pclsync_lib::start_crypto(const char *pass, void **payload) {
(void)payload;
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 *rep) {
int res = -1;
int clib::pclsync_lib::stop_crypto(const char *path, void **payload) {
(void)payload;
(void)path;
psync_crypto_stop();
get_lib().crypto_on_ = false;
return res;
return 0;
}
int clib::pclsync_lib::finalize(const char *path, void *rep) {
int clib::pclsync_lib::finalize(const char *path, void **payload) {
(void)payload;
(void)path;
psync_destroy();
exit(0);
}
int clib::pclsync_lib::list_sync_folders(const char *path, void *rep) {
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;
}
if (path == nullptr) {
std::cerr << "Error: path is nullptr" << std::endl;
return -255;
}
const char delimiter = '|';
std::string combined(path);
size_t delimiter_pos = combined.find(delimiter);
if (delimiter_pos == std::string::npos) {
std::cerr << "Error: Invalid path format. Expected 'localpath|remotepath'"
<< std::endl;
return -255;
}
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);
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;
}
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);
}
*payload = payload_ptr;
return 0;
}
int clib::pclsync_lib::remove_sync_folder(const char *path, void **payload) {
(void)payload;
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) {
(void)path;
psync_folder_list_t *folders = psync_get_sync_list();
rep = psync_malloc(sizeof(*folders));
memcpy(rep, folders, sizeof(*folders));
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);
psync_free(folders);
return 0;
}
@ -330,10 +428,12 @@ int clib::pclsync_lib::init() {
psync_free(username_old);
}
psync_add_overlay_callback(20, &clib::pclsync_lib::start_crypto);
psync_add_overlay_callback(21, &clib::pclsync_lib::stop_crypto);
psync_add_overlay_callback(22, &clib::pclsync_lib::finalize);
psync_add_overlay_callback(23, &clib::pclsync_lib::list_sync_folders);
psync_overlay_register_callback(20, &clib::pclsync_lib::start_crypto);
psync_overlay_register_callback(21, &clib::pclsync_lib::stop_crypto);
psync_overlay_register_callback(22, &clib::pclsync_lib::finalize);
psync_overlay_register_callback(23, &clib::pclsync_lib::list_sync_folders);
psync_overlay_register_callback(24, &clib::pclsync_lib::add_sync_folder);
psync_overlay_register_callback(25, &clib::pclsync_lib::remove_sync_folder);
return 0;
}

View File

@ -36,6 +36,7 @@
#define PCLSYNC_LIB_H
struct pstatus_struct_;
typedef void (*status_callback_t)(int status, const char *stat_string);
namespace console_client {
namespace clibrary {
@ -81,10 +82,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 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);
char *get_token();
int logout();

View File

@ -1,69 +0,0 @@
/*
Copyright (c) 2013-2015 pCloud Ltd. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met: Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with
the distribution. Neither the name of pCloud Ltd nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL pCloud
Ltd BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include <string>
#include "pclsync_lib_c.h"
#include "pclsync_lib.h"
#ifdef __cplusplus
extern "C" {
#endif
namespace cc = console_client::clibrary;
int init() {
if (!cc::pclsync_lib::get_lib().was_init_)
return cc::pclsync_lib::get_lib().init();
else
return 0;
}
int start_crypto(const char *pass) {
return cc::pclsync_lib::start_crypto(pass, NULL);
}
int stop_crypto() { return cc::pclsync_lib::stop_crypto(NULL, NULL); }
int finalize() { return cc::pclsync_lib::finalize(NULL, NULL); }
void set_status_callback(status_callback_t c) {
cc::pclsync_lib::get_lib().set_status_callback(c);
}
char *get_token() { return cc::pclsync_lib::get_lib().get_token(); }
int login(const char *user, const char *pass, int save) {
return cc::pclsync_lib::get_lib().login(user, pass, save);
}
int logout() { return cc::pclsync_lib::get_lib().logout(); }
int unlinklib() { return cc::pclsync_lib::get_lib().unlink(); }
#ifdef __cplusplus
}
#endif

View File

@ -1,49 +0,0 @@
/*
Copyright (c) 2013-2015 pCloud Ltd. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met: Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with
the distribution. Neither the name of pCloud Ltd nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL pCloud
Ltd BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#ifdef __cplusplus
extern "C" {
#endif
void psync_fs_pause_until_login();
typedef void (*status_callback_t)(int status, const char *stat_string);
int init();
int start_crypto(const char *pass);
int stop_crypto();
int finalize();
char *get_token();
void set_status_callback(status_callback_t);
int logout();
int unlinklib();
int login(const char *user, const char *pass, int save);
#ifdef __cplusplus
};
#endif