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:
parent
21aa356ed3
commit
c687484707
2
Makefile
2
Makefile
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 << "> ";
|
||||
}
|
||||
|
|
|
|||
1
main.cpp
1
main.cpp
|
|
@ -31,7 +31,6 @@
|
|||
#include <boost/program_options.hpp>
|
||||
|
||||
#include "control_tools.h"
|
||||
#include "pclsync_lib_c.h"
|
||||
|
||||
#include "pclsync_lib.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
184
pclsync_lib.cpp
184
pclsync_lib.cpp
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue