diff --git a/Babakhina.Sofia/lab1/Config.txt b/Babakhina.Sofia/lab1/Config.txt index 1ce9232..b2d726b 100644 --- a/Babakhina.Sofia/lab1/Config.txt +++ b/Babakhina.Sofia/lab1/Config.txt @@ -1,3 +1,3 @@ -/home/barulina/barulina/ProjectsVSCode/OpSys/lab1/folder1 -/home/barulina/barulina/ProjectsVSCode/OpSys/lab1/folder2 -60 \ No newline at end of file +/home/barulina/ProjectsVSCode/OpSys/lab1/folder1 +/home/barulina/ProjectsVSCode/OpSys/lab1/folder2 +60 diff --git a/Babakhina.Sofia/lab2/.gitignore b/Babakhina.Sofia/lab2/.gitignore new file mode 100644 index 0000000..1899660 --- /dev/null +++ b/Babakhina.Sofia/lab2/.gitignore @@ -0,0 +1,2 @@ +build +.vscode \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/CMakeLists.txt b/Babakhina.Sofia/lab2/CMakeLists.txt new file mode 100644 index 0000000..0270ec3 --- /dev/null +++ b/Babakhina.Sofia/lab2/CMakeLists.txt @@ -0,0 +1,104 @@ + +cmake_minimum_required(VERSION 3.10) + +project(library) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror") + +# Set the path for Qt6 +set(CMAKE_PREFIX_PATH "/home/barulina/Qt/6.8.0/gcc_64/lib/cmake") + +# Include directories +include_directories(include) + +# Find Qt6 package +find_package(Qt6 REQUIRED COMPONENTS Widgets) + +# Host and Client source files for FIFO +set(HOST_FIFO_SRC_FILES + host/host.cpp + host/host_fifo.cpp + connection/conn_fifo.cpp +) + +set(CLIENT_FIFO_SRC_FILES + client/client.cpp + client/client_fifo.cpp + connection/conn_fifo.cpp +) + +# Host and Client source files for Queue +set(HOST_MQ_SRC_FILES + host/host.cpp + host/host_mq.cpp + connection/conn_mq.cpp +) + +set(CLIENT_MQ_SRC_FILES + client/client.cpp + client/client_mq.cpp + connection/conn_mq.cpp +) + +# Host and Client source files for Seg +set(HOST_SEG_SRC_FILES + host/host.cpp + host/host_seg.cpp + connection/conn_seg.cpp +) + +set(CLIENT_SEG_SRC_FILES + client/client.cpp + client/client_seg.cpp + connection/conn_seg.cpp +) + +set(SEMAPHORE + semaphore/semaphore.cpp +) + +set(GUI + gui/client_gui.cpp + gui/host_gui.cpp +) + +# Ensure Qt's moc is run on the ChatWindow header +qt6_wrap_cpp(MOC_SOURCES gui/client_gui.h) +qt6_wrap_cpp(MOC_SOURCES gui/host_gui.h) +# qt6_wrap_cpp(MOC_SOURCES_CLIENT client/client.h) + +# Add executables for FIFO communication +add_executable(host_fifo ${HOST_FIFO_SRC_FILES} ${SEMAPHORE} ${GUI} ${MOC_SOURCES}) +add_executable(client_fifo ${CLIENT_FIFO_SRC_FILES} ${SEMAPHORE} ${GUI} ${MOC_SOURCES}) + + +# Add executables for Queue communication +add_executable(host_mq ${HOST_MQ_SRC_FILES} ${SEMAPHORE} ${GUI} ${MOC_SOURCES}) +add_executable(client_mq ${CLIENT_MQ_SRC_FILES} ${SEMAPHORE} ${GUI} ${MOC_SOURCES}) + +# Add executables for Queue communication +add_executable(host_seg ${HOST_SEG_SRC_FILES} ${SEMAPHORE} ${GUI} ${MOC_SOURCES}) +add_executable(client_seg ${CLIENT_SEG_SRC_FILES} ${SEMAPHORE} ${GUI} ${MOC_SOURCES}) + +# Link Qt libraries to the GUI executable +target_link_libraries(host_fifo Qt6::Widgets) +target_link_libraries(client_fifo Qt6::Widgets) +target_link_libraries(host_mq Qt6::Widgets) +target_link_libraries(client_mq Qt6::Widgets) +target_link_libraries(host_seg Qt6::Widgets) +target_link_libraries(client_seg Qt6::Widgets) + + +# Set output directories for all executables +set_target_properties(host_fifo PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set_target_properties(client_fifo PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set_target_properties(host_mq PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set_target_properties(client_mq PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set_target_properties(host_seg PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set_target_properties(client_seg PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + + +# Custom target to build all +add_custom_target(all_targets DEPENDS host_fifo client_fifo host_mq client_mq host_seg client_seg) diff --git a/Babakhina.Sofia/lab2/book.h b/Babakhina.Sofia/lab2/book.h new file mode 100644 index 0000000..133d8a8 --- /dev/null +++ b/Babakhina.Sofia/lab2/book.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +struct Book { + std::string name; + int count; +}; + +const std::vector books = { + {"crime & punisment", 15}, + {"the idiot", 15}, + {"the karamazov brothers", 15}, + {"white nights ", 7}, + {"the gambler", } +}; \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/build.sh b/Babakhina.Sofia/lab2/build.sh new file mode 100644 index 0000000..3c61891 --- /dev/null +++ b/Babakhina.Sofia/lab2/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash +mkdir -p build +cd build +cmake .. +make + +find . -type f -name '*.o' -delete +find . -type f -name '*.cmake' -delete +find . -type f -name 'CMakeCache.txt' -delete +find . -type f -name 'Makefile' -delete +rm -rf CMakeFiles +rm -rf .qt +rm -rf gui \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/client/client.cpp b/Babakhina.Sofia/lab2/client/client.cpp new file mode 100644 index 0000000..58f5e92 --- /dev/null +++ b/Babakhina.Sofia/lab2/client/client.cpp @@ -0,0 +1,108 @@ +#include "client.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +Client::Client(std::vector books) : client_books(std::move(books)), window(client_books) { + read_host_pid(); + window.client_pid = client_pid; + semaphore = new Semaphore(host_pid, 0); +} + +void Client::read_host_pid() { + std::ifstream pid_file("host_pid.txt"); + if (!pid_file) { + std::cout << "Failed to open PID file\n"; + return; + } + pid_file >> host_pid; + pid_file.close(); + if (std::remove("host_pid.txt") != 0) { + std::cout << "Error deleting PID file\n"; + return; + } +} + +void Client::read_from_host() { + while (is_running) { + if (client_conn && client_conn->is_valid()) { + std::string message; + const size_t max_size = 1024; + semaphore->wait(); + if (client_conn->read(message, max_size)) { + bool flag = true; + std::string str; + if (message.rfind("YES", 0) == 0) { + window.success_take_book(); + str = message.substr(3); + } + else if (message.rfind("NO", 0) == 0) { + window.fail_take_book(); + window.wrap_reset_timer(); + flag = false; + str = message.substr(2); + } + int del_pos = str.find("#"); + std::string book_name = str.substr(0, del_pos); + std::string time = str.substr(del_pos + 1); + window.update_books(books, "TAKE", book_name, time, flag); + } + semaphore->post(); + } + sleep(0.5); + } +} + +void Client::write_to_host() { + QObject::connect(&window, &ClientWindow::book_selected, [this](const QString& book_name) { + auto time = std::chrono::system_clock::now(); + std::time_t time_c = std::chrono::system_clock::to_time_t(time); + std::tm* ttime = std::localtime(&time_c); + std::ostringstream oss; + oss << std::put_time(ttime, "%H:%M"); + std::string request = "TAKE " + book_name.toStdString() + "#" + client_name + "#" + oss.str(); + semaphore->wait(); + if (!host_conn->write(request)) { + std::cout << "Failed to send request\n"; + return; + } + window.wrap_stop_timer(); + semaphore->post(); + }); + + QObject::connect(&window, &ClientWindow::book_returned, [this] (const QString& book_name) { + auto time = std::chrono::system_clock::now(); + std::time_t time_c = std::chrono::system_clock::to_time_t(time); + std::tm* ttime = std::localtime(&time_c); + + std::ostringstream oss; + oss << std::put_time(ttime, "%H:%M"); + std::string request = "RETURN " + book_name.toStdString() + "#" + client_name + "#" + oss.str(); + semaphore->wait(); + + if (!host_conn->write(request)) { + std::cout << "Failed to send request\n"; + return; + } + + window.wrap_reset_timer(); + + semaphore->post(); + window.update_books(books, "RETURN", book_name.toStdString(), oss.str(), true); + }); +} + +void read_wrap(Client& client) { + client.read_from_host(); +} diff --git a/Babakhina.Sofia/lab2/client/client.h b/Babakhina.Sofia/lab2/client/client.h new file mode 100644 index 0000000..90b04ed --- /dev/null +++ b/Babakhina.Sofia/lab2/client/client.h @@ -0,0 +1,52 @@ +#pragma once + +#include "../gui/client_gui.h" +#include "../semaphore/semaphore.h" +#include "../book.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class Client{ +protected: + std::vector client_books; + + pid_t client_pid = getpid(); + pid_t host_pid; + +public: + std::string client_name = "Fryasha"; + bool is_running = true; + + Semaphore* semaphore; + + Conn* client_conn; + Conn* host_conn; + + ClientWindow window; + + Client(std::vector books); + virtual ~Client() {} + + virtual bool setup_conn() = 0; + void read_from_host(); + void write_to_host(); + void read_host_pid(); +}; + +void read_wrap(Client& client); diff --git a/Babakhina.Sofia/lab2/client/client_fifo.cpp b/Babakhina.Sofia/lab2/client/client_fifo.cpp new file mode 100644 index 0000000..f9ab4eb --- /dev/null +++ b/Babakhina.Sofia/lab2/client/client_fifo.cpp @@ -0,0 +1,47 @@ +#include "client_fifo.h" + + +bool ClientFifo::setup_conn() { + std::string client_path = "/tmp/chat_client_fifo" + std::to_string(host_pid); + std::string host_path = "/tmp/chat_host_fifo" + std::to_string(host_pid); + + client_conn = new ConnFifo(client_path, false); + if (!client_conn->is_valid()) { + std::cout << "Failed to open FIFO for writing\n"; + return false; + } + + host_conn = new ConnFifo(host_path, false); + if (!host_conn->is_valid()) { + std::cout << "Failed to open FIFO for reading\n"; + return false; + } + return true; +}; + + +ClientFifo::ClientFifo(std::vector books) : Client(std::move(books)) { + setup_conn(); +} + + +ClientFifo::~ClientFifo() { + delete client_conn; + delete host_conn; + delete semaphore; +} + +int main(int argc, char* argv[]) { + QApplication app(argc, argv); + ClientFifo client(books); + std::thread read_thread(read_wrap, std::ref(client)); + client.write_to_host(); + client.window.show(); + int res = app.exec(); + client.is_running = false; + if (read_thread.joinable()) { + read_thread.join(); + } + + return res; +}; diff --git a/Babakhina.Sofia/lab2/client/client_fifo.h b/Babakhina.Sofia/lab2/client/client_fifo.h new file mode 100644 index 0000000..24113bc --- /dev/null +++ b/Babakhina.Sofia/lab2/client/client_fifo.h @@ -0,0 +1,14 @@ +#pragma once + +#include "client.h" +#include "../connection/conn_fifo.h" + + +class ClientFifo : public Client { +public: + ClientFifo(std::vector books); + ~ClientFifo(); + + bool setup_conn() override; +}; + diff --git a/Babakhina.Sofia/lab2/client/client_mq.cpp b/Babakhina.Sofia/lab2/client/client_mq.cpp new file mode 100644 index 0000000..6d8c282 --- /dev/null +++ b/Babakhina.Sofia/lab2/client/client_mq.cpp @@ -0,0 +1,53 @@ +#include "client_mq.h" + + +bool ClientMq::setup_conn() { + std::string client_path = "/client_mq" + std::to_string(host_pid); + std::string host_path = "/host_mq" + std::to_string(host_pid); + + key_t client_key = ftok(client_path.c_str(), 1); + key_t host_key = ftok(host_path.c_str(), 1); + + client_conn = new ConnMq(client_key, false); + if (!client_conn->is_valid()) { + std::cout << "Failed to open MQ for writing\n"; + return false; + } + + host_conn = new ConnMq(host_key, false); + if (!host_conn->is_valid()) { + std::cout << "Failed to open MQ for reading\n"; + return false; + } + return true; +}; + + +ClientMq::ClientMq(std::vector books) : Client(std::move(books)) { + setup_conn(); +} + + +ClientMq::~ClientMq() { + delete client_conn; + delete host_conn; + delete semaphore; +} + + +int main(int argc, char* argv[]) { + QApplication app(argc, argv); + ClientMq client(books); + std::thread read_thread(read_wrap, std::ref(client)); + client.write_to_host(); + client.window.show(); + int res = app.exec(); + client.is_running = false; + client.client_conn->close(); + client.host_conn->close(); + if (read_thread.joinable()) { + read_thread.join(); + } + + return res; +}; diff --git a/Babakhina.Sofia/lab2/client/client_mq.h b/Babakhina.Sofia/lab2/client/client_mq.h new file mode 100644 index 0000000..7bcbb83 --- /dev/null +++ b/Babakhina.Sofia/lab2/client/client_mq.h @@ -0,0 +1,13 @@ +#pragma once + +#include "client.h" +#include "../connection/conn_mq.h" + +class ClientMq : public Client { +public: + ClientMq(std::vector books); + ~ClientMq(); + + bool setup_conn() override; +}; + diff --git a/Babakhina.Sofia/lab2/client/client_seg.cpp b/Babakhina.Sofia/lab2/client/client_seg.cpp new file mode 100644 index 0000000..44c8157 --- /dev/null +++ b/Babakhina.Sofia/lab2/client/client_seg.cpp @@ -0,0 +1,44 @@ +#include "client_seg.h" + + +bool ClientSeg::setup_conn() { + client_conn = new ConnSeg(1, false); + if (!client_conn->is_valid()) { + std::cout << "Failed to open SEG for writing\n"; + return false; + } + + host_conn = new ConnSeg(500, false); + if (!host_conn->is_valid()) { + std::cout << "Failed to open SEG for reading\n"; + return false; + } + return true; +}; + + +ClientSeg::ClientSeg(std::vector books) : Client(std::move(books)) { + setup_conn(); +} + + +ClientSeg::~ClientSeg() { + delete client_conn; + delete host_conn; + delete semaphore; +} + +int main(int argc, char* argv[]) { + QApplication app(argc, argv); + ClientSeg client(books); + std::thread read_thread(read_wrap, std::ref(client)); + client.write_to_host(); + client.window.show(); + int res = app.exec(); + client.is_running = false; + if (read_thread.joinable()) { + read_thread.join(); + } + + return res; +}; diff --git a/Babakhina.Sofia/lab2/client/client_seg.h b/Babakhina.Sofia/lab2/client/client_seg.h new file mode 100644 index 0000000..0e78d22 --- /dev/null +++ b/Babakhina.Sofia/lab2/client/client_seg.h @@ -0,0 +1,14 @@ +#pragma once + +#include "client.h" +#include "../connection/conn_seg.h" + + +class ClientSeg : public Client { +public: + ClientSeg(std::vector books); + ~ClientSeg(); + + bool setup_conn() override; +}; + diff --git a/Babakhina.Sofia/lab2/connection/conn.h b/Babakhina.Sofia/lab2/connection/conn.h new file mode 100644 index 0000000..1925a97 --- /dev/null +++ b/Babakhina.Sofia/lab2/connection/conn.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Conn { +public: + virtual ~Conn() {} + + virtual bool read(std::string& data, size_t max_size) = 0; + virtual bool write(const std::string& data) = 0; + virtual bool is_valid() const = 0; + + virtual void close() = 0; +}; diff --git a/Babakhina.Sofia/lab2/connection/conn_fifo.cpp b/Babakhina.Sofia/lab2/connection/conn_fifo.cpp new file mode 100644 index 0000000..9e730aa --- /dev/null +++ b/Babakhina.Sofia/lab2/connection/conn_fifo.cpp @@ -0,0 +1,75 @@ +#include "conn_fifo.h" + + +ConnFifo::ConnFifo(const std::string& path, bool create) : path(path), fd(-1), valid(false) { + if (create) { + if (mkfifo(path.c_str(), 0777) == -1) { + if (errno != EEXIST) { + std::cerr << "Ошибка создания FIFO: " << strerror(errno) << "\n"; + return; + } + } + } + + fd = open(path.c_str(), O_RDWR | O_NONBLOCK); + if (fd == -1) { + std::cerr << "Ошибка создания FIFO: " << strerror(errno) << "\n"; + } else { + valid = true; + } +}; + +ConnFifo::~ConnFifo() { + std::cout << "~ConnFifo" << std::endl; + close(); + if (valid) { + if (unlink(path.c_str()) == -1) { + std::cerr << "Ошибка удаления FIFO: " << strerror(errno) << "\n"; + } + } +}; + +bool ConnFifo::write(const std::string& msg) { + if (!is_valid()) { + std::cerr << "FIFO недоступен для записи\n"; + return false; + } + + ssize_t bytes_written = ::write(fd, msg.c_str(), msg.size()); + if (bytes_written == -1) { + std::cerr << "Ошибка записи в FIFO: " << strerror(errno) << "\n"; + return false; + } + return true; +} + +bool ConnFifo::read(std::string& msg, size_t max_size) { + if (!is_valid()) { + std::cerr << "FIFO недоступен для чтения\n"; + return false; + } + + char buffer[max_size]; + memset(buffer, '\0', max_size); + + ssize_t bytes_read = ::read(fd, buffer, max_size - 1); + if (bytes_read == -1) { + return false; + } + + msg.assign(buffer, bytes_read); + return true; +}; + +bool ConnFifo::is_valid() const { + return valid; +}; + +void ConnFifo::close() { + if (is_valid() && fd != -1) { + if (::close(fd) == -1) { + std::cerr << "Ошибка закрытия FIFO: " << strerror(errno) << "\n"; + } + fd = -1; + } +}; diff --git a/Babakhina.Sofia/lab2/connection/conn_fifo.h b/Babakhina.Sofia/lab2/connection/conn_fifo.h new file mode 100644 index 0000000..c457436 --- /dev/null +++ b/Babakhina.Sofia/lab2/connection/conn_fifo.h @@ -0,0 +1,21 @@ +#pragma once + +#include "conn.h" + + +class ConnFifo : public Conn { +public: + ConnFifo(const std::string& path, bool create); + ~ConnFifo(); + + bool write(const std::string& msg) override; + bool read(std::string& msg, size_t max_size) override; + bool is_valid() const override; + + void close(); + +private: + std::string path; + int fd; + bool valid; +}; \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/connection/conn_mq.cpp b/Babakhina.Sofia/lab2/connection/conn_mq.cpp new file mode 100644 index 0000000..f5926b6 --- /dev/null +++ b/Babakhina.Sofia/lab2/connection/conn_mq.cpp @@ -0,0 +1,133 @@ +#include "conn_mq.h" + + +ConnMq::ConnMq(key_t key, bool host_flag): is_host(host_flag) { + int flags = (is_host ? IPC_CREAT : 0) | 0666; + queue_id = msgget(key, flags); + + if (queue_id == -1) { + std::cout << "Failed to open message queue\n"; + } +} + +ConnMq::~ConnMq() { + if (is_valid()) { + close(); + } +} + +bool ConnMq::read(std::string& msg, size_t max_size) { + if (!is_valid()) return false; + + struct msgbuf { + long mtype; + char mtext[1024]; + }; + struct msgbuf message; + + ssize_t bytesRead = msgrcv(queue_id, &message, sizeof(message.mtext), !is_host + 1, IPC_NOWAIT); + if (bytesRead == -1) { + if (errno == ENOMSG) { + return false; + } else { + perror("msgrcv"); + return false; + } + } + + msg = message.mtext; + msg.resize(bytesRead); + return true; +} + + +bool ConnMq::write(const std::string& msg) { + if (!is_valid()) return false; + + struct msgbuf { + long mtype; + char mtext[1024]; + }; + struct msgbuf message; + + message.mtype = is_host + 1; + std::memcpy(message.mtext, msg.c_str(), std::min((size_t)sizeof(message.mtext) -1, msg.size())); + message.mtext[std::min((size_t)sizeof(message.mtext) -1, msg.size())] = '\0'; + + int result = msgsnd(queue_id, &message, std::min((size_t)sizeof(message.mtext), msg.size()), IPC_NOWAIT); + if (result == -1) { + if (errno == ENOSPC) { + return false; + } else { + perror("msgsnd"); + return false; + } + } + return true; +} + + +// bool ConnMq::read(std::string& msg, size_t max_size) { +// std::cout << "read msg: " << msg << "\n"; + +// if (!is_valid()) { +// return false; +// } + +// struct msgbuf { +// long mtype; +// char mtext[1024]; +// } message; + +// std::cout << "before msgrcv message.mtext: " << message.mtext << "\n"; +// ssize_t bytesRead = msgrcv(queue_id, &message, sizeof(message.mtext), !is_host + 1, 0); // !is_host: if host -> read client else read host +// if (bytesRead == -1) { +// return false; +// } + +// std::cout << "after msgrcv message.mtext: " << message.mtext << "\n"; +// std::cout << "after msgrcv bytesRead: " << bytesRead << "\n"; + +// msg = message.mtext; + +// msg.resize(bytesRead); +// std::cout << "after msgrcv msg.resize: " << msg << "\n"; + +// return true; +// } + +// bool ConnMq::write(const std::string& msg) { +// std::cout << "write msg: " << msg << "\n"; + +// if (!is_valid()) { +// return false; +// } + +// struct msgbuf { +// long mtype; +// char mtext[1024]; +// } message; + +// message.mtype = is_host + 1; + +// std::cout << "before memcpy message.mtext: " << message.mtext << "\n"; +// std::cout << "before memcpy msg.c_str(): " << msg.c_str() << "\n"; +// std::cout << "before memcpy msg.size(): " << msg.size() << "\n"; +// std::memcpy(message.mtext, msg.c_str(), msg.size()); +// message.mtext[msg.size()] = '\0'; +// std::cout << "after memcpy message.mtext: " << message.mtext << "\n"; +// if (msgsnd(queue_id, &message, msg.size(), 0) == -1) { +// return false; +// } + +// return true; +// } + +bool ConnMq::is_valid() const { + return (queue_id != -1); +} + +void ConnMq::close() { + msgctl(queue_id, IPC_RMID, nullptr); + queue_id = -1; +}; diff --git a/Babakhina.Sofia/lab2/connection/conn_mq.h b/Babakhina.Sofia/lab2/connection/conn_mq.h new file mode 100644 index 0000000..f2661a5 --- /dev/null +++ b/Babakhina.Sofia/lab2/connection/conn_mq.h @@ -0,0 +1,21 @@ +#pragma once + +#include "conn.h" + + +class ConnMq : public Conn { +public: + ConnMq(key_t key, bool host_flag); + ~ConnMq(); + + bool write(const std::string& msg) override; + bool read(std::string& msg, size_t max_size) override; + bool is_valid() const override; + + void close(); + +private: + int queue_id; + bool is_host; +}; + diff --git a/Babakhina.Sofia/lab2/connection/conn_seg.cpp b/Babakhina.Sofia/lab2/connection/conn_seg.cpp new file mode 100644 index 0000000..39542ec --- /dev/null +++ b/Babakhina.Sofia/lab2/connection/conn_seg.cpp @@ -0,0 +1,49 @@ +#include "conn_seg.h" + + +ConnSeg::ConnSeg(key_t key, bool isHost) { + _isHost = isHost; + int f = _isHost ? IPC_CREAT | O_EXCL | 0666 : 0666; + _shmid = shmget(key, MAX_SIZE, f); + _segptr = shmat(_shmid, 0, 0); + if (_segptr == (void*)-1) { + if (_isHost) + shmctl(_shmid, IPC_RMID, 0); + } +} + +bool ConnSeg::read(std::string& data, size_t max_size) { + if (is_valid()) { + if (max_size > MAX_SIZE) + return false; + char buf[MAX_SIZE]; + memcpy(buf, _segptr, max_size); + data = buf; + memcpy(_segptr, "lalala", 6); + if (data.substr(0, 10) == "written###") { + data = data.substr(10); + return true; + } + } + + return false; +} + +bool ConnSeg::write(const std::string& data) { + if (data.size() > MAX_SIZE) + return false; + std::string new_data = "written###" + data + '\0'; + memcpy(_segptr, new_data.c_str(), new_data.size()); + + return true; +} + +ConnSeg::~ConnSeg(void) { + shmdt(_segptr); + if (_isHost) + shmctl(_shmid, IPC_RMID, 0); +} + +bool ConnSeg::is_valid() const { + return (_segptr != nullptr); +} diff --git a/Babakhina.Sofia/lab2/connection/conn_seg.h b/Babakhina.Sofia/lab2/connection/conn_seg.h new file mode 100644 index 0000000..7929f36 --- /dev/null +++ b/Babakhina.Sofia/lab2/connection/conn_seg.h @@ -0,0 +1,21 @@ +#include "conn.h" + + +constexpr int MAX_SIZE = 1024; + +class ConnSeg : public Conn { +public: + ConnSeg(key_t key, bool isHost); + + bool read(std::string& data, size_t max_size) override; + bool write(const std::string& data) override; + bool is_valid() const; + void close(){} + + ~ConnSeg(); + +private: + bool _isHost; + void *_segptr = nullptr; + int _shmid = -1; +}; \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/gui/client_gui.cpp b/Babakhina.Sofia/lab2/gui/client_gui.cpp new file mode 100644 index 0000000..5d4cad5 --- /dev/null +++ b/Babakhina.Sofia/lab2/gui/client_gui.cpp @@ -0,0 +1,175 @@ +#include "client_gui.h" + + +ClientWindow::ClientWindow(const std::vector& books, QWidget* parent) + : QMainWindow(parent) { + stacked_widget = new QStackedWidget(this); + create_general_view(books); + create_reading_view(); + setCentralWidget(stacked_widget); + setWindowTitle("Client Control Panel"); + resize(800, 400); + stacked_widget->setCurrentIndex(0); + connect(&timer, &QTimer::timeout, this, [this]() { + if (!timer.isActive()) return; + if (--timekill <= 0) { + terminate_client(); + } + else { + timer_label->setText(QString("Time left: %1 sec...").arg(timekill)); + } + }); + connect(this, &ClientWindow::signal_reset_timer, this, &ClientWindow::reset_timer); + connect(this, &ClientWindow::signal_stop_timer, this, [this]() { + timer.stop(); + }); + + timer.setInterval(1000); + timer.start(); + +} + +ClientWindow::~ClientWindow() {} + +void ClientWindow::create_general_view(const std::vector& books) { + QWidget* general_view = new QWidget(this); + QVBoxLayout* v_layout = new QVBoxLayout(general_view); + QWidget* book_view = new QWidget(this); + QHBoxLayout* h_layout = new QHBoxLayout(book_view); + QWidget* book_list_w = new QWidget(this); + QVBoxLayout* layout1 = new QVBoxLayout(book_list_w); + book_table = new QTableWidget(this); + book_table->setColumnCount(2); + book_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + QStringList book_table_headers; + book_table_headers << "book title" << "amount"; + book_table->setHorizontalHeaderLabels(book_table_headers); + for (const auto& book : books) { + int rows = book_table->rowCount(); + book_table->insertRow (rows); + QTableWidgetItem *item_title = new QTableWidgetItem(QString::fromStdString(book.name)); + QTableWidgetItem *item_amount = new QTableWidgetItem(QString::number(book.count)); + book_table->setItem(rows, 0, item_title); + book_table->setItem(rows, 1, item_amount); + } + left_label = new QLabel("Book list", this); + select_button = new QPushButton("SELECT THE BOOK", this); + select_button->setEnabled(false); + layout1->addWidget(left_label); + layout1->addWidget(book_table); + layout1->addWidget(select_button); + QWidget* history_list_w = new QWidget(this); + QVBoxLayout* layout2 = new QVBoxLayout(history_list_w); + right_label = new QLabel("History", this); + table = new QTableWidget(this); + table->setColumnCount(3); + table->horizontalHeader()->setStretchLastSection(true); + QStringList headers; + headers << "time" << "status" << "book title"; + table->setHorizontalHeaderLabels(headers); + timer_label = new QLabel("Time left: 10 sec...", this); + timer_label->setAlignment(Qt::AlignHCenter | Qt::AlignTop); + layout2->addWidget(right_label); + layout2->addWidget(table); + h_layout->addWidget(book_list_w); + h_layout->addWidget(history_list_w); + v_layout->addWidget(timer_label); + v_layout->addWidget(book_view); + connect(book_table, &QTableWidget::itemSelectionChanged, [this]() { + select_button->setEnabled(book_table->currentItem() != nullptr); + }); + connect(select_button, &QPushButton::clicked, this, &ClientWindow::select_book); + stacked_widget->addWidget(general_view); +} + +void ClientWindow::create_reading_view() { + QWidget* readingView = new QWidget(this); + QVBoxLayout* layout = new QVBoxLayout(readingView); + reading_label = new QLabel("Reading book: ", this); + reading_label->setAlignment(Qt::AlignCenter); + layout->addWidget(reading_label); + cancel_reading_button = new QPushButton("Cancel Reading", this); + layout->addWidget(cancel_reading_button); + connect(cancel_reading_button, &QPushButton::clicked, this, &ClientWindow::cancel_reading); + stacked_widget->addWidget(readingView); +} + +void ClientWindow::select_book() { + if (book_table->currentItem()) { + QString book_name = book_table->currentItem()->text(); + reading_label->setText("NOW READING: " + book_name); + emit book_selected(book_name); + } +} + +void ClientWindow::cancel_reading() { + QString book_name = reading_label->text().split(": ").last(); + emit book_returned(book_name); + stacked_widget->setCurrentIndex(0); +} + +void ClientWindow::success_take_book() { + std::cout << "Succeded to take book\n"; + stacked_widget->setCurrentIndex(1); +} + +void ClientWindow::fail_take_book() { + std::cout << "Failed to take book\n"; +} + +void ClientWindow::update_books(const std::vector& books, std::string state, std::string book_name, std::string time, bool flag) { + if (flag) { + book_table->clear(); + QStringList book_table_headers; + book_table_headers << "book title" << "amount"; + book_table->setHorizontalHeaderLabels(book_table_headers); + book_table->setRowCount(0); + for (const auto& book : books) { + int book_table_rows = book_table->rowCount(); + book_table->insertRow(book_table_rows); + QTableWidgetItem *item_title = new QTableWidgetItem(QString::fromStdString(book.name)); + QTableWidgetItem *item_amount = new QTableWidgetItem(QString::number(book.count)); + book_table->setItem(book_table_rows, 0, item_title); + book_table->setItem(book_table_rows, 1, item_amount); + } + int table_rows = table->rowCount(); + table->insertRow(table_rows); + QTableWidgetItem *item_time = new QTableWidgetItem(QString::fromStdString(time)); + QTableWidgetItem *item_state = new QTableWidgetItem(QString::fromStdString(state)); + QTableWidgetItem *item_title = new QTableWidgetItem(QString::fromStdString(book_name)); + table->setItem(table_rows, 0, item_time); + table->setItem(table_rows, 1, item_state); + table->setItem(table_rows, 2, item_title); + } + else{ + std::string fail_state = "FAILED"; + int table_rows = table->rowCount(); + table->insertRow (table_rows); + QTableWidgetItem *item_time = new QTableWidgetItem(QString::fromStdString(time)); + QTableWidgetItem *item_state = new QTableWidgetItem(QString::fromStdString(fail_state)); + QTableWidgetItem *item_title = new QTableWidgetItem(QString::fromStdString(book_name)); + table->setItem(table_rows, 0, item_time); + table->setItem(table_rows, 1, item_state); + table->setItem(table_rows, 2, item_title); + } +} + +void ClientWindow::terminate_client() { + timer.stop(); + QMessageBox::information(this, "Terminate Client", "Client terminated."); + kill(client_pid, SIGKILL); +} + +void ClientWindow::reset_timer() { + timekill = conn_timeout; + timer_label->setText(QString("Time left: %1 sec").arg(conn_timeout)); + timer.start(); +} + +void ClientWindow::wrap_reset_timer() { + emit signal_reset_timer(); +} + +void ClientWindow::wrap_stop_timer() { + emit signal_stop_timer(); +} diff --git a/Babakhina.Sofia/lab2/gui/client_gui.h b/Babakhina.Sofia/lab2/gui/client_gui.h new file mode 100644 index 0000000..d178cc3 --- /dev/null +++ b/Babakhina.Sofia/lab2/gui/client_gui.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../book.h" +#include "../connection/conn.h" + + +class ClientWindow : public QMainWindow { + Q_OBJECT +private: + void create_general_view(const std::vector& books); + void create_reading_view(); + + QStackedWidget* stacked_widget; + + QLabel* reading_label; + QLabel* left_label; + QLabel* right_label; + QLabel* timer_label; + + QListWidget* history_list; + QTableWidget* table; + QTableWidget* book_table; + + QPushButton* select_button; + QPushButton* cancel_reading_button; + +public: + pid_t client_pid = 0; + + ClientWindow(const std::vector& books, QWidget* parent = nullptr); + ~ClientWindow(); + + void success_take_book(); + void fail_take_book(); + void update_books(const std::vector& books, std::string state, std::string book_name, std::string time, bool flag); + + void wrap_reset_timer(); + void wrap_stop_timer(); + + QTimer timer; + constexpr static int conn_timeout = 10; + int timekill = conn_timeout; + +signals: + void book_selected(const QString& book_name); + void book_returned(const QString& book_name); + + void signal_reset_timer(); + void signal_stop_timer(); + +private slots: + void select_book(); + void cancel_reading(); + + void terminate_client(); + void reset_timer(); +}; diff --git a/Babakhina.Sofia/lab2/gui/host_gui.cpp b/Babakhina.Sofia/lab2/gui/host_gui.cpp new file mode 100644 index 0000000..e7b5788 --- /dev/null +++ b/Babakhina.Sofia/lab2/gui/host_gui.cpp @@ -0,0 +1,101 @@ +#include "host_gui.h" + + +HostWindow::HostWindow(const std::vector& books, QWidget* parent) + : QMainWindow(parent) { + + QWidget* book_view = new QWidget(this); + QHBoxLayout* h_layout = new QHBoxLayout(book_view); + + QWidget* book_list_w = new QWidget(this); + QVBoxLayout* layout1 = new QVBoxLayout(book_list_w); + + book_table = new QTableWidget(this); + book_table->setColumnCount(2); + book_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); + QStringList book_table_headers; + book_table_headers << "book title" << "amount"; + book_table->setHorizontalHeaderLabels(book_table_headers); + + for (const auto& book : books) { + int rows = book_table->rowCount(); + book_table->insertRow (rows); + QTableWidgetItem *item_title = new QTableWidgetItem(QString::fromStdString(book.name)); + QTableWidgetItem *item_amount = new QTableWidgetItem(QString::number(book.count)); + book_table->setItem(rows, 0, item_title); + book_table->setItem(rows, 1, item_amount); + } + left_label = new QLabel("Book list", this); + + layout1->addWidget(left_label); + layout1->addWidget(book_table); + + + QWidget* history_list_w = new QWidget(this); + QVBoxLayout* layout2 = new QVBoxLayout(history_list_w); + + right_label = new QLabel("History list", this); + + table = new QTableWidget(this); + table->setColumnCount(4); + table->horizontalHeader()->setStretchLastSection(true); + QStringList headers; + headers << "time" << "user" << "status" << "book title"; + table->setHorizontalHeaderLabels(headers); + + layout2->addWidget(right_label); + layout2->addWidget(table); + + + h_layout->addWidget(book_list_w); + h_layout->addWidget(history_list_w); + + setCentralWidget(book_view); + setWindowTitle("Host Control Panel"); + resize(900, 400); +} + +HostWindow::~HostWindow() {} + +void HostWindow::update_books(const std::vector& books, std::string state, std::string book_name, std::string client_name, std::string time, bool flag) { + if (flag) { + book_table->clear(); + QStringList book_table_headers; + book_table_headers << "book title" << "amount"; + book_table->setHorizontalHeaderLabels(book_table_headers); + book_table->setRowCount(0); + for (const auto& book : books) { + int book_table_rows = book_table->rowCount(); + book_table->insertRow(book_table_rows); + QTableWidgetItem *item_title = new QTableWidgetItem(QString::fromStdString(book.name)); + QTableWidgetItem *item_amount = new QTableWidgetItem(QString::number(book.count)); + book_table->setItem(book_table_rows, 0, item_title); + book_table->setItem(book_table_rows, 1, item_amount); + } + + int table_rows = table->rowCount(); + table->insertRow(table_rows); + QTableWidgetItem *item_time = new QTableWidgetItem(QString::fromStdString(time)); + QTableWidgetItem *item_state = new QTableWidgetItem(QString::fromStdString(state)); + QTableWidgetItem *item_title = new QTableWidgetItem(QString::fromStdString(book_name)); + QTableWidgetItem *item_client = new QTableWidgetItem(QString::fromStdString(client_name)); + table->setItem(table_rows, 0, item_time); + table->setItem(table_rows, 1, item_client); + table->setItem(table_rows, 2, item_state); + table->setItem(table_rows, 3, item_title); + } + else{ + int table_rows = table->rowCount(); + table->insertRow (table_rows); + QTableWidgetItem *item_time = new QTableWidgetItem(QString::fromStdString(time)); + QTableWidgetItem *item_state = new QTableWidgetItem(QString::fromStdString("FAILED")); + QTableWidgetItem *item_title = new QTableWidgetItem(QString::fromStdString(book_name)); + QTableWidgetItem *item_client = new QTableWidgetItem(QString::fromStdString(client_name)); + table->setItem(table_rows, 0, item_time); + table->setItem(table_rows, 1, item_client); + table->setItem(table_rows, 2, item_state); + table->setItem(table_rows, 3, item_title); + } +} + + diff --git a/Babakhina.Sofia/lab2/gui/host_gui.h b/Babakhina.Sofia/lab2/gui/host_gui.h new file mode 100644 index 0000000..a59d217 --- /dev/null +++ b/Babakhina.Sofia/lab2/gui/host_gui.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../book.h" + +class HostWindow : public QMainWindow { + Q_OBJECT + +private: + QLabel* left_label; + QLabel* right_label; + QTableWidget* table; + QTableWidget* book_table; + +public: + HostWindow(const std::vector& books, QWidget* parent = nullptr); + virtual ~HostWindow(); + + void update_books(const std::vector& books, std::string state, std::string book_name, std::string client_name, std::string time, bool flag); +}; \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/host/host.cpp b/Babakhina.Sofia/lab2/host/host.cpp new file mode 100644 index 0000000..0a724c6 --- /dev/null +++ b/Babakhina.Sofia/lab2/host/host.cpp @@ -0,0 +1,94 @@ +#include "../host/host.h" + + +Host::Host(const std::vector& books_) : books(std::move(books_)), semaphore(pid, 1), window(books) {} + + +void Host::write_to_client(std::string response) { + if (client_conn && client_conn->is_valid()) { + if (!client_conn->write(response)) { + std::cout << "Failed to write response \n"; + return; + } + } +} + +void set_parametrs(std::string &message, std::string &client_name, std::string &book_name, std::string &time, int pos){ + std::string str = message.substr(pos); + int delimetr_pos = str.find("#"); + book_name = str.substr(0, delimetr_pos); + str = str.substr(delimetr_pos + 1); + delimetr_pos = str.find("#"); + client_name = str.substr(0, delimetr_pos); + time = str.substr(delimetr_pos + 1); +} + +void Host::read_from_client() { + while (is_running) { + if (host_conn && host_conn->is_valid()) { + std::string message; + const size_t max_size = 1024; + semaphore.wait(); + if (host_conn->read(message, max_size)) { + std::string state; + std::string client_name; + std::string book_name; + std::string time; + bool flag = true; + if (message.rfind("TAKE ", 0) == 0) { + state = "TAKE"; + set_parametrs(message, client_name, book_name, time, 5); + std::string response; + if (select_book(books, book_name, client_name)){ + response = "YES" + book_name + "#" + time; + } + else { + response = "NO" + book_name + "#" + time; + flag = false; + } + write_to_client(response); + } + else if (message.rfind("RETURN ", 0) == 0) { + state = "RETURN"; + set_parametrs(message, client_name, book_name, time, 7); + return_book(books, book_name, client_name); + } + window.update_books(books, state, book_name, client_name, time, flag); + } + semaphore.post(); + } + sleep(0.5); + } +} + +bool return_book(std::vector& books, const std::string& book_name, std::string client_name) { + for (auto& book : books) { + if (book.name == book_name) { + book.count++; + return true; + } + } + std::cout << "No such book in library: " << book_name << "\n"; + return false; +} + + +bool select_book(std::vector& books, const std::string& book_name, std::string client_name) { + for (auto& book : books) { + if (book.name == book_name) { + if (book.count > 0) { + book.count--; + return true; + } else { + std::cout << "Book is not available: " << book_name << "\n"; + return false; + } + } + } + std::cout << "No such book in library: " << book_name << "\n"; + return false; +} + +void read_wrap(Host& host) { + host.read_from_client(); +} diff --git a/Babakhina.Sofia/lab2/host/host.h b/Babakhina.Sofia/lab2/host/host.h new file mode 100644 index 0000000..0a3c910 --- /dev/null +++ b/Babakhina.Sofia/lab2/host/host.h @@ -0,0 +1,49 @@ +#pragma once + +#include "../gui/host_gui.h" +#include "../connection/conn.h" +#include "../semaphore/semaphore.h" +#include "../book.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +class Host { +protected: + pid_t pid = getpid(); + + static constexpr int timeout = 5; + + std::vector books; + + Semaphore semaphore; + + Conn* client_conn; + Conn* host_conn; + +public: + bool is_running = true; + + HostWindow window; + + Host(const std::vector& books_); + virtual ~Host() {} + + void read_from_client(); + void write_to_client(std::string response); + + virtual bool setup_conn() = 0; +}; + +bool return_book(std::vector& books, const std::string& book_name, std::string client_name); + +bool select_book(std::vector& books, const std::string& book_name, std::string client_name); + +void read_wrap(Host& host); diff --git a/Babakhina.Sofia/lab2/host/host_fifo.cpp b/Babakhina.Sofia/lab2/host/host_fifo.cpp new file mode 100644 index 0000000..17ab194 --- /dev/null +++ b/Babakhina.Sofia/lab2/host/host_fifo.cpp @@ -0,0 +1,55 @@ +#include "../connection/conn_fifo.h" +#include "../host/host_fifo.h" + + +bool HostFifo::setup_conn() { + pid_t pid = getpid(); + std::ofstream pid_file("host_pid.txt"); + if (!pid_file) { + std::cout << "Failed to open PID file for writing"; + return false; + } + pid_file << pid; + pid_file.close(); + + std::string client_path = "/tmp/chat_client_fifo" + std::to_string(pid); + std::string host_path = "/tmp/chat_host_fifo" + std::to_string(pid); + + client_conn = new ConnFifo(client_path, true); + if (!client_conn->is_valid()) { + return false; + } + + host_conn = new ConnFifo(host_path, true); + if (!host_conn->is_valid()) { + return false; + } + + return true; +} + + +HostFifo::HostFifo(const std::vector& books_) : Host(std::move(books_)) { + setup_conn(); +} + + +HostFifo::~HostFifo() { + delete client_conn; + delete host_conn; +} + + +int main(int argc, char* argv[]) { + QApplication app(argc, argv); + HostFifo host(books); + std::thread read_thread(read_wrap, std::ref(host)); + host.window.show(); + int res = app.exec(); + host.is_running = false; + if (read_thread.joinable()) { + read_thread.join(); + } + + return res; +} \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/host/host_fifo.h b/Babakhina.Sofia/lab2/host/host_fifo.h new file mode 100644 index 0000000..11dd144 --- /dev/null +++ b/Babakhina.Sofia/lab2/host/host_fifo.h @@ -0,0 +1,11 @@ +#include "../host/host.h" + + +class HostFifo : public Host { + public: + HostFifo(const std::vector& books_); + + ~HostFifo(); + + bool setup_conn() override; +}; \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/host/host_mq.cpp b/Babakhina.Sofia/lab2/host/host_mq.cpp new file mode 100644 index 0000000..987e5a2 --- /dev/null +++ b/Babakhina.Sofia/lab2/host/host_mq.cpp @@ -0,0 +1,59 @@ +#include "../connection/conn_mq.h" +#include "../host/host_mq.h" + + +bool HostMq::setup_conn() { + pid_t pid = getpid(); + std::ofstream pid_file("host_pid.txt"); + if (!pid_file) { + std::cout << "Failed to open PID file for writing"; + return false; + } + pid_file << pid; + pid_file.close(); + + std::string client_path = "/client_mq" + std::to_string(pid); + std::string host_path = "/host_mq" + std::to_string(pid); + + key_t key_client = ftok(client_path.c_str(), 1); + key_t key_host = ftok(host_path.c_str(), 1); + + client_conn = new ConnMq(key_client, true); + if (!client_conn->is_valid()) { + std::cout << "Failed to open MQ for writing\n"; + return false; + } + + host_conn = new ConnMq(key_host, true); + if (!host_conn->is_valid()) { + std::cout << "Failed to open MQ for reading\n"; + return false; + } + return true; +} + + +HostMq::HostMq(const std::vector& books_) : Host(std::move(books_)) { + setup_conn(); +} + + +HostMq::~HostMq() { + delete client_conn; + delete host_conn; +} + + +int main(int argc, char* argv[]) { + QApplication app(argc, argv); + HostMq host(books); + std::thread read_thread(read_wrap, std::ref(host)); + host.window.show(); + int res = app.exec(); + host.is_running = false; + if (read_thread.joinable()) { + read_thread.join(); + } + + return res; +} \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/host/host_mq.h b/Babakhina.Sofia/lab2/host/host_mq.h new file mode 100644 index 0000000..0af3bad --- /dev/null +++ b/Babakhina.Sofia/lab2/host/host_mq.h @@ -0,0 +1,10 @@ +#include "../host/host.h" + +class HostMq : public Host { +public: + + HostMq(const std::vector& books_); + ~HostMq(); + + bool setup_conn() override; +}; \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/host/host_seg.cpp b/Babakhina.Sofia/lab2/host/host_seg.cpp new file mode 100644 index 0000000..ed1d103 --- /dev/null +++ b/Babakhina.Sofia/lab2/host/host_seg.cpp @@ -0,0 +1,54 @@ +#include "../connection/conn_seg.h" +#include "../host/host_seg.h" + + +bool HostSeg::setup_conn() { + std::cout << "setup_conn\n"; + pid_t pid = getpid(); + std::ofstream pid_file("host_pid.txt"); + if (!pid_file) { + std::cout << "Failed to open PID file for writing"; + return false; + } + pid_file << pid; + pid_file.close(); + + client_conn = new ConnSeg(1, true); + if (!client_conn->is_valid()) { + std::cout << "Failed to open SEG for writing\n"; + return false; + } + + host_conn = new ConnSeg(500, true); + if (!host_conn->is_valid()) { + std::cout << "Failed to open SEG for reading\n"; + return false; + } + return true; +}; + + +HostSeg::HostSeg(const std::vector& books_) : Host(std::move(books_)) { + setup_conn(); +} + + +HostSeg::~HostSeg() { + delete client_conn; + delete host_conn; +} + + +int main(int argc, char* argv[]) { + QApplication app(argc, argv); + HostSeg host(books); + std::thread read_thread(read_wrap, std::ref(host)); + host.window.show(); + int res = app.exec(); + host.is_running = false; + if (read_thread.joinable()) { + read_thread.join(); + } + + return res; +} \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/host/host_seg.h b/Babakhina.Sofia/lab2/host/host_seg.h new file mode 100644 index 0000000..7b66df4 --- /dev/null +++ b/Babakhina.Sofia/lab2/host/host_seg.h @@ -0,0 +1,9 @@ +#include "../host/host.h" + +class HostSeg : public Host { +public: + HostSeg(const std::vector& books_); + ~HostSeg(); + + bool setup_conn() override; +}; \ No newline at end of file diff --git a/Babakhina.Sofia/lab2/semaphore/semaphore.cpp b/Babakhina.Sofia/lab2/semaphore/semaphore.cpp new file mode 100644 index 0000000..a93b311 --- /dev/null +++ b/Babakhina.Sofia/lab2/semaphore/semaphore.cpp @@ -0,0 +1,43 @@ +#include "semaphore.h" + + +Semaphore::Semaphore(unsigned int value, bool host_flag) { + + std::string semaphore_name = "/sem" + std::to_string(value); + if (host_flag) { + semaphore = sem_open(semaphore_name.c_str(), O_CREAT | O_EXCL, 0777, 2); + if (semaphore == SEM_FAILED) { + std::cout << "Could not open semaphore --> Terminate\n"; + exit(EXIT_FAILURE); + } + } + else { + semaphore = sem_open(semaphore_name.c_str(), 0); + if (semaphore == SEM_FAILED) { + std::cout << "Could not open semaphore --> Terminate\n"; + exit(EXIT_FAILURE); + } + } +} + +bool Semaphore::wait() { + if (sem_wait(semaphore) == -1) { + std::cout << "Semaphore wait failed" << std::endl; + return false; + } + return true; +} + +bool Semaphore::post() { + if (sem_post(semaphore) == -1) { + std::cout << "Semaphore post failed" << std::endl; + return false; + } + return true; +} + +Semaphore::~Semaphore() { + if (sem_destroy(semaphore) == -1) { + std::cout << "Semaphore destruction failed" << std::endl; + } +} diff --git a/Babakhina.Sofia/lab2/semaphore/semaphore.h b/Babakhina.Sofia/lab2/semaphore/semaphore.h new file mode 100644 index 0000000..563fff9 --- /dev/null +++ b/Babakhina.Sofia/lab2/semaphore/semaphore.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include + +class Semaphore { +public: + Semaphore(unsigned int value, bool host_flag); + bool wait(); + bool post(); + ~Semaphore(); + +private: + sem_t* semaphore; +};