diff --git a/lesson_03/ap/ap.cpp b/lesson_03/ap/ap.cpp new file mode 100644 index 0000000..b385274 --- /dev/null +++ b/lesson_03/ap/ap.cpp @@ -0,0 +1,136 @@ +/* + * ap.cpp + * + * Created on: 05 сен. 2022 г. + * Author: alexander + */ + +#include + +namespace ap +{ + +ConfigOption::ConfigOption(const std::string &longParameter, const char shortParameter, const hasArg ha) : + _longParameter(nullptr), _shortParameter(shortParameter), _ha(ha) +{ + _longParameter = new char[longParameter.length() + 1]; + strcpy(_longParameter, longParameter.c_str()); +} + +const char* ConfigOption::getLongParameter() const +{ + return _longParameter; +} + +const char& ConfigOption::getShortParameter() const +{ + return _shortParameter; +} + +const hasArg& ConfigOption::getPresenceArgument() const +{ + return _ha; +} + +Option::Option() : _set(false) +{ +} + +void Option::set() +{ + _set = true; +} + +void Option::push(const std::string &value) +{ + _values.push_back(value); +} + +std::vector& Option::getValues() +{ + return _values; +} + +bool Option::isSet() const +{ + return _set; +} + +void Hub::_createArguments(const std::vector &options, bool silence) +{ + _longOptions = new struct option[options.size() + 1]; + _sizeOptions = options.size(); + std::string temp; + if (silence) + temp.push_back(':'); + for (auto const &opt : options | boost::adaptors::indexed(0)) + { + _longOptions[opt.index()].name = opt.value().getLongParameter(); + _longOptions[opt.index()].has_arg = opt.value().getPresenceArgument(); + _longOptions[opt.index()].flag = nullptr; + _longOptions[opt.index()].val = opt.value().getShortParameter(); + + temp.push_back(opt.value().getShortParameter()); + switch (opt.value().getPresenceArgument()) + { + case hasArg::OPTIONAL: + temp.push_back(':'); + /* no break */ + case hasArg::REQUIRED: + temp.push_back(':'); + break; + case hasArg::NO: + break; + } + + _arguments[opt.value().getShortParameter()].first = false; + } + + _longOptions[options.size()].name = nullptr; + _longOptions[options.size()].has_arg = 0; + _longOptions[options.size()].flag = nullptr; + _longOptions[options.size()].val = 0; + + _shortOptions = new char[temp.size() + 1]; + strcpy(_shortOptions, temp.c_str()); +} + +Hub::Hub(const std::vector &options, bool silence) : + _longOptions(nullptr), _shortOptions(nullptr) +{ + _createArguments(options, silence); +} + +void Hub::readArguments(int argc, char *argv[], void (*_callback)()) +{ + int next_option; + while ((next_option = getopt_long(argc, argv, _shortOptions, _longOptions, nullptr)) != -1) + { + if (_arguments.count(next_option)) + { + _arguments[next_option].first = true; + _arguments[next_option].second.set(); + if (optarg) + _arguments[next_option].second.push(std::string(optarg)); + } + if (next_option == '?' && _callback) + _callback(); + } +} + +Option Hub::getOption(char key) const +{ + return _arguments.count(key) && _arguments.at(key).first ? _arguments.at(key).second : Option(); +} + +Hub::~Hub() +{ + delete[] _shortOptions; + for (size_t i = 0; i < _sizeOptions; ++i) + { + delete[] _longOptions[i].name; + } + delete[] _longOptions; +} + +} diff --git a/lesson_03/ap/ap.hpp b/lesson_03/ap/ap.hpp new file mode 100644 index 0000000..8ae0de8 --- /dev/null +++ b/lesson_03/ap/ap.hpp @@ -0,0 +1,68 @@ +/* + * ap.hpp + * + * Created on: 05 сен. 2022 г. + * Author: alexander + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ap +{ + +enum hasArg +{ + NO, REQUIRED, OPTIONAL +}; + +typedef std::vector (*_handler)(const std::vector&); + +class ConfigOption +{ +private: + char *_longParameter; + const char _shortParameter; + const hasArg _ha; +public: + ConfigOption(const std::string &longParameter, const char shortParameter, const hasArg ha); + const char* getLongParameter() const; + const char& getShortParameter() const; + const hasArg& getPresenceArgument() const; +}; + +class Option +{ +private: + std::vector _values; + bool _set; +public: + Option(); + void push(const std::string &value); + std::vector& getValues(); + void set(); + bool isSet() const; +}; + +class Hub +{ +private: + struct option *_longOptions; + size_t _sizeOptions; + char *_shortOptions; + std::map> _arguments; + void _createArguments(const std::vector &options, bool silence); +public: + Hub(const std::vector &options, bool silence = true); + void readArguments(int argc, char *argv[], void (*_callback)() = nullptr); + Option getOption(char key) const; + ~Hub(); +}; + +} diff --git a/lesson_03/header/address.hpp b/lesson_03/header/address.hpp new file mode 100644 index 0000000..4fdf301 --- /dev/null +++ b/lesson_03/header/address.hpp @@ -0,0 +1,28 @@ +/* + * address.hpp + * + * Created on: 5 сент. 2022 г. + * Author: alexander + */ + +#pragma once + +#include +#include + +namespace zh { + +class Address +{ +private: + struct sockaddr_in _addr; + unsigned int _len; +public: + Address(); + Address(const Address &address); + Address(const unsigned short int family, const unsigned int addr, const unsigned short int port); + unsigned int& size(); + struct sockaddr_in& operator*(); +}; + +} diff --git a/lesson_03/header/server.hpp b/lesson_03/header/server.hpp new file mode 100644 index 0000000..5b1f24c --- /dev/null +++ b/lesson_03/header/server.hpp @@ -0,0 +1,65 @@ +/* + * server.hpp + * + * Created on: 5 сент. 2022 г. + * Author: alexander + */ + +#pragma once + +//#include + +#include +#include +#include +#include +#include + +namespace zh +{ + +class Server // @suppress("Class has a virtual method and non-virtual destructor") +{ +protected: + std::unique_ptr _socket; + std::unique_ptr
_local, _client; + unsigned int _sizeClient; + const unsigned short int _port; + int _connfd; +public: + Server(const unsigned short int port); + virtual void bind() = 0; + virtual void listen() = 0; +}; + +typedef void (*hook)(std::string buffer, Server &s); + +class ServerTCP: public Server // @suppress("Class has a virtual method and non-virtual destructor") +{ +private: + bool _bind; + const unsigned short int _sizeBuffer; + std::unique_ptr _buffer; + + class Hook + { + private: + std::string _command; + hook _handler; + public: + Hook(std::string command, hook handler); + void execute(std::string buffer, Server &s); + }; + + std::vector _hooks; + + void chat(); +public: + ServerTCP(const unsigned short int port, const unsigned short int sizeBuffer = 1024); + void bind(); + void listen(); + void registerHook(std::string command, hook handler); +}; + +} + diff --git a/lesson_03/header/socket.hpp b/lesson_03/header/socket.hpp new file mode 100644 index 0000000..4e29363 --- /dev/null +++ b/lesson_03/header/socket.hpp @@ -0,0 +1,26 @@ +/* + * socket.hpp + * + * Created on: 5 сент. 2022 г. + * Author: alexander + */ + +#pragma once + +#include +#include +#include + +namespace zh { + +class Socket +{ +private: + int _sockfd; +public: + Socket(const int domain, const int type, const int protocol); + operator int() const; + ~Socket(); +}; + +} diff --git a/lesson_03/main.cpp b/lesson_03/main.cpp new file mode 100644 index 0000000..cf64aad --- /dev/null +++ b/lesson_03/main.cpp @@ -0,0 +1,32 @@ +/* + * main.cpp + * + * Created on: 5 сент. 2022 г. + * Author: alexander + */ + +#include +#include + +#include + +int main(int argc, char *argv[]) +{ + ap::Hub hub({{ "port", 'p', ap::REQUIRED }}); + hub.readArguments(argc, argv); + + auto optionPort = hub.getOption('p'); + if (!optionPort.isSet()) + { + std::cerr << "Порт не был установлен!" << std::endl; + exit(EXIT_FAILURE); + } + + int port = std::stoi(optionPort.getValues()[0]); + + zh::ServerTCP tcpServer(port); + tcpServer.bind(); + tcpServer.listen(); + + return 0; +} diff --git a/lesson_03/source/address.cpp b/lesson_03/source/address.cpp new file mode 100644 index 0000000..132fa77 --- /dev/null +++ b/lesson_03/source/address.cpp @@ -0,0 +1,44 @@ +/* + * address.cpp + * + * Created on: 5 сент. 2022 г. + * Author: alexander + */ + +#include + +namespace zh { + +Address::Address() +{ + memset(&_addr, 0, sizeof(_addr)); + _len = sizeof(_addr); +} + +Address::Address(const Address &address) +{ + _addr = address._addr; + _len = address._len; +} + +Address::Address(const unsigned short int family, const unsigned int addr, const unsigned short int port) +{ + memset(&_addr, 0, sizeof(_addr)); + _len = sizeof(_addr); + + _addr.sin_family = family; + _addr.sin_addr.s_addr = htonl(addr); + _addr.sin_port = htons(port); +} + +unsigned int& Address::size() +{ + return _len; +} + +struct sockaddr_in& Address::operator*() +{ + return _addr; +} + +} diff --git a/lesson_03/source/server.cpp b/lesson_03/source/server.cpp new file mode 100644 index 0000000..9872b01 --- /dev/null +++ b/lesson_03/source/server.cpp @@ -0,0 +1,113 @@ +/* + * server.cpp + * + * Created on: 5 сент. 2022 г. + * Author: alexander + */ + +#include +#include +#include + +namespace zh +{ + +#define MAX 1024 + +Server::Server(const unsigned short int port) : _port(port), _connfd(-1) +{ + _sizeClient = sizeof(*_client); +} + +ServerTCP::Hook::Hook(std::string command, hook handler) : _command(command), _handler(handler) +{ +} + +void ServerTCP::Hook::execute(std::string buffer, Server &s) +{ + if (_command == "") + { + _handler(buffer, s); + } + else + { + auto pos = buffer.find_first_of(_command); + if (pos != std::string::npos && pos == 0) + { + _handler(buffer, s); + } + } +} + +void ServerTCP::registerHook(std::string command, hook handler) +{ + _hooks.push_back({ command, handler }); +} + +ServerTCP::ServerTCP(const unsigned short int port, const unsigned short int sizeBuffer) : Server(port), _bind(false), _sizeBuffer(sizeBuffer) +{ + _socket = std::make_unique(AF_INET, SOCK_STREAM, IPPROTO_IP); + _local = std::make_unique
(AF_INET, INADDR_ANY, port); + _buffer = std::make_unique(sizeBuffer); +} + +void ServerTCP::bind() +{ + if (_bind) + { + std::cerr << "Адрес уже связан с дескриптором слушающего сокета!" << std::endl; + return; + } + + if (::bind((*_socket), reinterpret_cast(&(*_local)), (*_local).size()) != 0) + std::cerr << "Не удаётся связать адрес с дескриптором слушающего сокета!" << std::endl; + else + _bind = true; +} + +void ServerTCP::listen() +{ + if (::listen(*_socket, 0) != 0) + { + std::cerr << "Не удаётся создать очередь соединений для сокета!" << std::endl; + return; + } + + while (_bind) + { + if ((_connfd = ::accept(*_socket, reinterpret_cast(&(*_client)), &_sizeClient)) < 0) + { + std::cerr << "Не удаётся верифицировать и принять пакеты от клиента!" << std::endl; + return; + } + + // Обработка соединения с клиентом + chat(); + } +} + +void ServerTCP::chat() +{ +// char buff[MAX]; +// int n; + while (true) + { +// bzero(buff, sizeof(buff)); +// printf("Enter the string : "); +// n = 0; +// while ((buff[n++] = getchar()) != '\n') +// ; +// write(_connfd, buff, sizeof(buff)); + bzero(_buffer.get(), _sizeBuffer); + read(_connfd, _buffer.get(), _sizeBuffer); + std::cout << _buffer.get() << std::endl; +// printf("From Server : %s", *_buffer); +// if ((strncmp((*_buffer), "exit", 4)) == 0) +// { +// printf("Client Exit...\n"); +// break; +// } + } +} + +} diff --git a/lesson_03/source/socket.cpp b/lesson_03/source/socket.cpp new file mode 100644 index 0000000..ccfe2a2 --- /dev/null +++ b/lesson_03/source/socket.cpp @@ -0,0 +1,32 @@ +/* + * socket.cpp + * + * Created on: 5 сент. 2022 г. + * Author: alexander + */ + +#include +#include + +namespace zh { + +Socket::Socket(const int domain, const int type, const int protocol) +{ + if ((_sockfd = socket(domain, type, protocol)) < 0) + { + perror("socket creation failed"); + exit(EXIT_FAILURE); + } +} + +Socket::operator int() const +{ + return _sockfd; +} + +Socket::~Socket() +{ + ::close(_sockfd); +} + +}