diff --git a/.gitignore b/.gitignore index a41b8ef..8beba9a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ compile_commands.json /cmd/pcloudcc/build/ /.cache/ +/lib/poverlay_linux/overlay_client diff --git a/Makefile b/Makefile index 7c77ff5..e453885 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ all: make -C ./lib/pclsync fs - cmake -H./lib/mbedtls -B./lib/mbedtls/build + cmake -DCMAKE_BUILD_TYPE=Debug -H./lib/mbedtls -B./lib/mbedtls/build make -C ./lib/mbedtls/build mkdir -p ./cmd/pcloudcc/build - cmake -H. -B./cmd/pcloudcc/build + cmake -DCMAKE_BUILD_TYPE=Debug -H. -B./cmd/pcloudcc/build make -C ./cmd/pcloudcc/build clean: diff --git a/cmd/pcloudcc/control_tools.cpp b/cmd/pcloudcc/control_tools.cpp index 245ed82..80c6cc1 100644 --- a/cmd/pcloudcc/control_tools.cpp +++ b/cmd/pcloudcc/control_tools.cpp @@ -59,45 +59,56 @@ enum command_ids_ { int start_crypto(const char *pass) { int ret; char *errm; + size_t errm_size; - if (SendCall(STARTCRYPTO, pass, &ret, &errm)) { + int result = SendCall(STARTCRYPTO, pass, &ret, &errm, &errm_size); + if (result != 0) { std::cout << "Start Crypto failed. return is " << ret << " and message is " - << errm << std::endl; + << (errm ? errm : "no message") << std::endl; } else { std::cout << "Crypto started. " << std::endl; } - free(errm); + if (errm) + free(errm); return ret; } int stop_crypto() { int ret; char *errm; + size_t errm_size; - if (SendCall(STOPCRYPTO, "", &ret, &errm)) { + int result = SendCall(STOPCRYPTO, "", &ret, &errm, &errm_size); + if (result != 0) { std::cout << "Stop Crypto failed. return is " << ret << " and message is " - << errm << std::endl; + << (errm ? errm : "no message") << std::endl; } else { std::cout << "Crypto Stopped. " << std::endl; } - free(errm); + if (errm) + free(errm); return ret; } int finalize() { int ret; char *errm; + size_t errm_size; - if (SendCall(FINALIZE, "", &ret, &errm)) { - std::cout << "Finalize failed. return is " << ret << " and message is " - << errm << std::endl; + 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; } - free(errm); + if (errm) + free(errm); + return ret; } diff --git a/lib/poverlay_linux/overlay_client.c b/lib/poverlay_linux/overlay_client.c index 7f20b6f..6c7fd0a 100644 --- a/lib/poverlay_linux/overlay_client.c +++ b/lib/poverlay_linux/overlay_client.c @@ -26,7 +26,9 @@ DAMAGE. */ +#include #include +#include #include #include #include @@ -62,7 +64,9 @@ const char *clsoc = "/tmp/pcloud_unix_soc.sock"; int QueryState(pCloud_FileState *state, char *path) { int rep = 0; char *errm; - if (!SendCall(4, path /*IN*/, &rep, &errm)) { + size_t errm_size; + + if (!SendCall(4, path /*IN*/, &rep, &errm, &errm_size)) { debug(D_NOTICE, "QueryState responese rep[%d] path[%s]", rep, path); if (errm) debug(D_NOTICE, "The error is %s", errm); @@ -81,73 +85,199 @@ int QueryState(pCloud_FileState *state, char *path) { } int SendCall(int id /*IN*/, const char *path /*IN*/, int *ret /*OUT*/, - char **out /*OUT*/) { + char **out /*OUT*/, size_t *out_size) { struct sockaddr_un addr; - int fd, rc; - int path_size = strlen(path); - int mess_size = sizeof(message) + path_size + 1; - int bytes_writen = 0; - char *curbuf = NULL; - char *buf = NULL; - uint32_t bufflen = 0; - char sendbuf[mess_size]; - int bytes_read = 0; + 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) { - *out = strndup("Unable to create UNIX socket", 27); + 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; } + + // connect to socket memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, clsoc, sizeof(addr.sun_path) - 1); - if (connect(fd, (struct sockaddr *)&addr, SUN_LEN(&addr)) == -1) { - *out = strndup("Unable to connect to UNIX socket", 32); + 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; } + debug(D_NOTICE, "SendCall: Sending message type %d, path '%s'", id, path); + + // prepare and send the message to the socket message *mes = (message *)sendbuf; - memset(mes, 0, mess_size); + memset(mes, 0, sendsize); mes->type = id; - strncpy(mes->value, path, path_size); - mes->length = mess_size; - curbuf = (char *)mes; - while ((rc = write(fd, curbuf, (mes->length - bytes_writen))) > 0) { - bytes_writen += rc; - curbuf = curbuf + rc; + strncpy(mes->value, path, sendlen); + mes->length = sendsize; + + char *curbuf = (char *)mes; + while (sendbytes < mes->length) { + rc = write(fd, curbuf, (mes->length - sendbytes)); + if (rc <= 0) { + if (errno == EINTR) + continue; // try again on interrupt + + sprintf((char *)error_msg, "failed to write to socket. errno: %d", errno); + *out = strdup(error_msg); + if (*out == NULL) { + debug(D_ERROR, "failed to allocate memory for output message"); + *ret = -253; + return -253; + } + *ret = -248; + return -248; + } + sendbytes += rc; } - debug(D_NOTICE, "QueryState bytes send[%d]\n", bytes_writen); - if (bytes_writen != mes->length) { - *out = strndup("Communication error", 19); - close(fd); + debug(D_NOTICE, "SendCall: Sent %lu bytes", sendbytes); + + if (sendbytes != mes->length) { + sprintf((char *)error_msg, + "Communication error: sendbytes=%lu, mes->length=%lu", sendbytes, + mes->length); + *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; } - bufflen = read_x_bytes(fd, 4, buf); + // 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; - if (bufflen <= 0) { - debug(D_NOTICE, "Message size could not be read![%d]\n", bufflen); - return -6; + 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 + } + } } - buf = (char *)malloc(bufflen); - rep = (message *)buf; - rep->length = bufflen; - read_x_bytes(fd, bufflen - 4, buf + 4); + 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; + } + + 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); + } + } + + if (recvbytes < sizeof(message)) { + debug(D_ERROR, "got incomplete message from socket"); + *ret = -250; + result = -250; + goto cleanup; + } + + rep = (message *)recvbuf; *ret = rep->type; - *out = strndup(rep->value, rep->length - sizeof(message)); - close(fd); + 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; + } + memcpy(*out, rep->value, value_size); + (*out)[value_size] = '\0'; + *out_size = value_size + 1; - return 0; +cleanup: + if (fd != -1) + close(fd); + if (recvbuf) + free(recvbuf); + + return result; } #ifdef PCLOUD_TESTING @@ -155,6 +285,7 @@ int main(int arc, char **argv) { int i, j = 0; pCloud_FileState state; char *errm; + size_t errm_size; for (i = 1; i < arc; ++i) { QueryState(&state, argv[i]); @@ -168,14 +299,13 @@ int main(int arc, char **argv) { printf("File %s FileStateInvalid\n", argv[i]); else printf("Not valid state returned for file %s\n", argv[i]); - SendCall(20, argv[i], &j, &errm); + SendCall(20, argv[i], &j, &errm, &errm_size); printf("Call 20 returned %d msg %s \n", j, errm); - SendCall(21, argv[i], &j, &errm); + SendCall(21, argv[i], &j, &errm, &errm_size); printf("Call 21 returned %d msg %s \n", j, errm); - SendCall(22, argv[i], &j, &errm); + SendCall(22, argv[i], &j, &errm, &errm_size); printf("Call 22 returned %d msg %s \n", j, errm); - - SendCall(23, argv[i], &j, &errm); + SendCall(23, argv[i], &j, &errm, &errm_size); printf("Call 22 returned %d msg %s \n", j, errm); } return 0; diff --git a/lib/poverlay_linux/overlay_client.h b/lib/poverlay_linux/overlay_client.h index 265c43b..af1b2ee 100644 --- a/lib/poverlay_linux/overlay_client.h +++ b/lib/poverlay_linux/overlay_client.h @@ -26,6 +26,11 @@ DAMAGE. */ +/* +Dependencies: + - stddef.h + */ + #ifndef OVERLAY_CLIENT_H #define OVERLAY_CLIENT_H @@ -44,7 +49,7 @@ 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*/); + char **out /*OUT*/, size_t *out_size); #ifdef __cplusplus } #endif