diff --git a/clients/cpu_temp/src/cpu_temp.c b/clients/cpu_temp/src/cpu_temp.c index 079c5cf337fbf398f732d12ef4f660b34c64c4c4..5f126f10e00e3e0c33b39960f21f82a246964d5e 100644 --- a/clients/cpu_temp/src/cpu_temp.c +++ b/clients/cpu_temp/src/cpu_temp.c @@ -6,6 +6,7 @@ #include <unistd.h> #include <string.h> #include "../../../common/include/protocol.h" +#include "../../../common/include/userspace_comm.h" int main(int argc, char* argv[]) { if (argc < 3 || argc > 3) { @@ -13,9 +14,9 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; } - int pipe_fd = open(DAEMON_PIPE_NAME, O_WRONLY); - if (pipe_fd == -1) { - perror("Failed to open pipe"); + send_t send; + if (send_init(&send) == -1) { + perror("Failed to open message queue"); return EXIT_FAILURE; } @@ -46,15 +47,12 @@ int main(int argc, char* argv[]) { memcpy(&packet.data, &cpu_temp, sizeof(cpu_temp)); - if (write(pipe_fd, &packet, DAEMON_PACKET_HEADER_SIZE + packet.length) == -1) { - perror("Failed to write pipe"); - continue; - } + send_send(&send, packet); usleep(sleep_ms * 1000); } - close(pipe_fd); + send_destroy(&send); close(file_fd); return EXIT_SUCCESS; diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 6e1ec404f5b9be2272309b20601ef731ec856bd2..94f58803b5619a086c95548aa9a5243b1d3532b6 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -1,5 +1,6 @@ add_library(common src/protocol.c + src/userspace_comm.c src/communication.c ) target_include_directories(common diff --git a/common/include/protocol.h b/common/include/protocol.h index 35c47001d90ac2418b2ee7a3cd588bd7f79c2e6f..b20646a46a413607ac7a26f28e00eb9c4153623d 100644 --- a/common/include/protocol.h +++ b/common/include/protocol.h @@ -1,20 +1,19 @@ #pragma once #include <stdint.h> -#include <linux/limits.h> +#include <sys/ipc.h> -#define MAX_DAEMON_PACKET_SIZE PIPE_BUF -#define DAEMON_PACKET_HEADER_SIZE sizeof(uint8_t) + sizeof(daemon_measurement_datatype_t) + sizeof(uint16_t) -#define MAX_DAEMON_PACKET_DATA_SIZE MAX_DAEMON_PACKET_SIZE - DAEMON_PACKET_HEADER_SIZE +#define MAX_DAEMON_PACKET_DATA_SIZE 4096 -#define DAEMON_PIPE_NAME "/var/run/sibyl" +#define MSG_QUEUE_KEY "/var/run/sibyl" +#define MSG_QUEUE_PROJ_ID 69 /** * typedef daemon_measurement_datatype_t - Enum of possible datatypes for `daemon_measurement_t`. */ typedef enum { CHAR, - UINT64, INT64, + UINT64, FLOAT64 } __attribute__ ((__packed__)) daemon_measurement_datatype_t; @@ -48,3 +47,10 @@ int daemon_measurement_datatype_size(daemon_measurement_datatype_t datatype); * Returns 0 on success, -1 on error. */ int daemon_measurement_check(daemon_measurement_t* daemon_measurement); + +/** + * msg_queue_key() - Return the message queue key for the userspace communication. + * + * Returns the key of the message queue or -1 on error. + */ +key_t msg_queue_key(); diff --git a/common/include/userspace_comm.h b/common/include/userspace_comm.h new file mode 100644 index 0000000000000000000000000000000000000000..6540dd12def65990721585b4927f3c82acade609 --- /dev/null +++ b/common/include/userspace_comm.h @@ -0,0 +1,48 @@ +#pragma once +#include "protocol.h" + +#define MESSAGE_MEASUREMENT_ID 1 + +/** + * typedef send_t - Holds the a handle to the message queue. + * @msg_queue_id: Id of the message queue. + */ +typedef struct { + int msg_queue_id; +} send_t; + +/** + * typedef message_t - Wrapper around `daemon_measurement_t` to make it sendable over a message queue. + * @message_type: The messages' type. + * @measurement: The measurement. + */ +typedef struct { + // required by the message queue api in order to work + long message_type; + daemon_measurement_t measurement; +} message_t; + +/** + * send_init() - Initializes the send module. + * @arg1: The send module. + * + * Tries to get a handle to a message queue. + * Errors if the message queue doesn't exist. + * + * Returns 0 on success, -1 on error. + */ +int send_init(send_t* send); +/** + * send_send() - Sends a message over the message queue. + * + * Returns 0 on success, -1 on error. + */ +int send_send(send_t* send, daemon_measurement_t measurement); +/** + * send_destroy() - Destroys the message queue handle. + * + * Currently this is a dummy function that doesn't do anything. + * + * Always returns 0. + */ +int send_destroy(send_t* send); diff --git a/common/src/protocol.c b/common/src/protocol.c index 8bf232e50674aed3e84c192abf78dac452db87c9..0ce57442e8b0a2491342823bcc60f55366788831 100644 --- a/common/src/protocol.c +++ b/common/src/protocol.c @@ -4,8 +4,8 @@ int daemon_measurement_datatype_size(daemon_measurement_datatype_t datatype) { switch (datatype) { case CHAR: return 1; - case UINT64: case INT64: + case UINT64: case FLOAT64: return 8; } @@ -20,3 +20,7 @@ int daemon_measurement_check(daemon_measurement_t* daemon_measurement) { return 0; } + +key_t msg_queue_key() { + return ftok(MSG_QUEUE_KEY, MSG_QUEUE_PROJ_ID); +} diff --git a/common/src/userspace_comm.c b/common/src/userspace_comm.c new file mode 100644 index 0000000000000000000000000000000000000000..14e2786bbae13bf2497464356bc4a4b8106b0d4e --- /dev/null +++ b/common/src/userspace_comm.c @@ -0,0 +1,34 @@ +#include "../include/protocol.h" +#include "../include/userspace_comm.h" +#include <sys/ipc.h> +#include <sys/msg.h> + +int send_init(send_t* send) { + int key; + int msg_queue_id; + + if ((key = msg_queue_key()) == -1) { + return -1; + } + if ((msg_queue_id = msgget(key, IPC_NOWAIT)) == -1) { + return -1; + } + + send->msg_queue_id = msg_queue_id; + + return 0; +} + +int send_send(send_t *send, daemon_measurement_t measurement) { + message_t message = { + .message_type = MESSAGE_MEASUREMENT_ID, + .measurement = measurement, + }; + + msgsnd(send->msg_queue_id, &message, sizeof(daemon_measurement_t), 0); + return 0; +} + +int send_destroy(send_t *send) { + return 0; +} diff --git a/daemon/include/receive.h b/daemon/include/receive.h index 550a1724339181a41dbadb888f67ab5e4eb1c9e7..d6a116c283ce4b1e07a4842e4d9167f111c02ef3 100644 --- a/daemon/include/receive.h +++ b/daemon/include/receive.h @@ -1,24 +1,27 @@ #pragma once #include "../../common/include/protocol.h" +#include <sys/ipc.h> /** * typedef receive_t - The receive module. + * @msg_id: Id of the message queue that is used internally to communicate. */ -typedef struct {} receive_t; +typedef struct { + int msg_queue_id; +} receive_t; /** * receive_init() - Initializes the receive module. * @arg1: The receive module. * - * Creates a lockfile and a named pipe at DAEMON_PIPE_NAME. - * It will fail if the lockfile already exists. - * It will not fail if the lockfile is missing but the pipe exists. In this case, the pipe is reused. + * Creates a file at `MSG_QUEUE_KEY` and a message queue with `MSG_QUEUE_KEY` as key and `MSG_QUEUE_PROJ_ID` as project id. + * It will fail if the file or message queue already exists. * * Returns 0 on success, -1 on error. */ int receive_init(receive_t* receive); /** - * receive_read() - Reads a measurement from the pipe. + * receive_read() - Reads a measurement from the message queue. * @arg1: The receive module. * @arg2: The struct to store the read measurement in. * @@ -34,4 +37,4 @@ int receive_read(receive_t* receive, daemon_measurement_t* daemon_measurement); * * Always returns 0. */ -int receive_deinit(receive_t* receive); +int receive_destroy(receive_t* receive); diff --git a/daemon/src/main.c b/daemon/src/main.c index 57832c3d9407b67be95b586262635733a8e6e891..9b74fd7738e1355f69f6472a400bee5a2785a982 100644 --- a/daemon/src/main.c +++ b/daemon/src/main.c @@ -8,18 +8,44 @@ #include <unistd.h> #include <signal.h> -#define LOCKFILE "/tmp/.sibyl-daemon.lock" - receive_t receive; void signal_handler(int sig) { - receive_deinit(&receive); + receive_destroy(&receive); exit(1); } +void print_measurement_data(daemon_measurement_t* measurement) { + int datatype_size = daemon_measurement_datatype_size(measurement->datatype); + for (int i = 0; i < datatype_size / measurement->length; i++) { + uint8_t buf[datatype_size]; + for (int j = 0; j < datatype_size; j++) { + buf[j] = measurement->data[(i * datatype_size) + j]; + } + + switch (measurement->datatype) { + case CHAR: + printf("%c", *(char*)buf); + break; + case INT64: + printf("%ld", *(int64_t*)buf); + break; + case UINT64: + printf("%ld", *(uint64_t*)buf); + break; + case FLOAT64: + printf("%f", *(double*)buf); + break; + } + + if (measurement->datatype != CHAR && i != measurement->length - 1) { + printf(" "); + } + } +} + int main() { if (receive_init(&receive) != 0) { - receive_deinit(&receive); - perror("Failed to open pipe"); + perror("Failed to create receive module"); return EXIT_FAILURE; } @@ -37,10 +63,12 @@ int main() { continue; } - printf("Received data from %d with length %d\n", daemon_measurement.measurement_id, daemon_measurement.length); + printf("Received data from %d with length %d: ", daemon_measurement.measurement_id, daemon_measurement.length); + print_measurement_data(&daemon_measurement); + printf("\n"); } - receive_deinit(&receive); + receive_destroy(&receive); return EXIT_SUCCESS; } diff --git a/daemon/src/receive.c b/daemon/src/receive.c index b2654121a598f6c86a3718194ad288930ff57d97..839986e9fda4d9ffd1e037e9801db8914600ef92 100644 --- a/daemon/src/receive.c +++ b/daemon/src/receive.c @@ -1,96 +1,66 @@ #include "../../common/include/protocol.h" +#include "../../common/include/userspace_comm.h" #include "../include/receive.h" -#include <errno.h> #include <stddef.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <sys/stat.h> +#include <sys/ipc.h> +#include <sys/msg.h> +#include <sys/types.h> #include <unistd.h> -#define LOCKFILE "/tmp/.sibyl-daemon.lock" - -// create lockfile -int lock() { - int lockfile_fd; +int create_run_file() { + int fd; - if ((lockfile_fd = open(LOCKFILE, O_CREAT | O_EXCL)) < 0) { - if (errno == EEXIST) { - perror("Lockfile already exists. Maybe another process is already using it?"); - } else { - perror("Cannot open lockfile"); - } + if ((fd = open(MSG_QUEUE_KEY, O_CREAT | O_EXCL)) == -1) { return -1; } - close(lockfile_fd); - return 0; + return close(fd); } -// delete lockfile -int unlock() { - remove(LOCKFILE); - return 0; +int remove_run_file() { + return remove(MSG_QUEUE_KEY); } int receive_init(receive_t* receive) { - if (lock() != 0) { + if (create_run_file() == -1) { return -1; } - /* create the fifo file or reuses the existing one, if existing */ - if (mkfifo(DAEMON_PIPE_NAME, 0666) != 0) { - struct stat file_stat; - if (stat(DAEMON_PIPE_NAME, &file_stat) < 0 || !S_ISFIFO(file_stat.st_mode)) { - return -1; - } + key_t key = msg_queue_key(); + if (key == -1) { + return -1; } + int msg_queue_id = msgget(key, IPC_CREAT | IPC_EXCL | IPC_NOWAIT); + if (msg_queue_id == -1) { + return -1; + } + + receive->msg_queue_id = msg_queue_id; + return 0; } int receive_read(receive_t* receive, daemon_measurement_t* daemon_measurement) { - int fd; + message_t message; - // open pipe in read mode - if ((fd = open(DAEMON_PIPE_NAME, O_RDONLY)) < 0) { - errno = EIO; - close(fd); + ssize_t read = msgrcv(receive->msg_queue_id, &message, sizeof(daemon_measurement_t), MESSAGE_MEASUREMENT_ID, 0); + if (read == -1) { return -1; } - /* read first 4 bytes as packet header */ - uint8_t header[DAEMON_PACKET_HEADER_SIZE]; - size_t bytes_read = read(fd, header, DAEMON_PACKET_HEADER_SIZE); - if (bytes_read != DAEMON_PACKET_HEADER_SIZE) { - close(fd); - /* only set custom errno if error is size related */ - if (bytes_read >= 0) { - errno = EINVAL; - } - return -1; - } - - /* assemble daemon measurement id and size from packet header */ - daemon_measurement->measurement_id = header[0]; - daemon_measurement->datatype = header[1]; - daemon_measurement->length = header[2] | (header[3] << 8); - - /* read measurement data */ - bytes_read = read(fd, &daemon_measurement->data, daemon_measurement_datatype_size(daemon_measurement->datatype) * daemon_measurement->length); - if (bytes_read <= 0) { - close(fd); - /* only set custom errno if error is size related */ - if (bytes_read >= 0) { - errno = EINVAL; - } - return -1; - } + *daemon_measurement = message.measurement; return 0; } -int receive_deinit(receive_t* receive) { - remove(DAEMON_PIPE_NAME); - return unlock(); +int receive_destroy(receive_t* receive) { + remove_run_file(); + msgctl(receive->msg_queue_id, IPC_RMID, NULL); + + return 0; }