aboutsummaryrefslogtreecommitdiff
path: root/works/life/computer-network-experiment
diff options
context:
space:
mode:
Diffstat (limited to 'works/life/computer-network-experiment')
-rw-r--r--works/life/computer-network-experiment/.gitignore5
-rw-r--r--works/life/computer-network-experiment/.vscode/launch.json16
-rw-r--r--works/life/computer-network-experiment/Base.hpp59
-rw-r--r--works/life/computer-network-experiment/CMakeLists.txt23
-rw-r--r--works/life/computer-network-experiment/Common.cpp142
-rw-r--r--works/life/computer-network-experiment/Common.h54
-rw-r--r--works/life/computer-network-experiment/IO.cpp81
-rw-r--r--works/life/computer-network-experiment/IO.h68
-rw-r--r--works/life/computer-network-experiment/PreConfig.hpp6
-rw-r--r--works/life/computer-network-experiment/ReadWriteLock.cpp97
-rw-r--r--works/life/computer-network-experiment/ReadWriteLock.h45
-rw-r--r--works/life/computer-network-experiment/StringUtil.cpp355
-rw-r--r--works/life/computer-network-experiment/StringUtil.hpp158
-rw-r--r--works/life/computer-network-experiment/TODO.md6
-rw-r--r--works/life/computer-network-experiment/client.cpp103
-rw-r--r--works/life/computer-network-experiment/server.cpp261
16 files changed, 0 insertions, 1479 deletions
diff --git a/works/life/computer-network-experiment/.gitignore b/works/life/computer-network-experiment/.gitignore
deleted file mode 100644
index 502724c..0000000
--- a/works/life/computer-network-experiment/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-*.exe
-*.pdb
-.cache
-build
-compile_commands.json \ No newline at end of file
diff --git a/works/life/computer-network-experiment/.vscode/launch.json b/works/life/computer-network-experiment/.vscode/launch.json
deleted file mode 100644
index 882a540..0000000
--- a/works/life/computer-network-experiment/.vscode/launch.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- // Use IntelliSense to learn about possible attributes.
- // Hover to view descriptions of existing attributes.
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
- "version": "0.2.0",
- "configurations": [
- {
- "name": "Launch server.",
- "type": "gdb",
- "request": "launch",
- "target": "${workspaceRoot}/build/server",
- "cwd": "${workspaceRoot}",
- "valuesFormatting": "parseText"
- }
- ]
-} \ No newline at end of file
diff --git a/works/life/computer-network-experiment/Base.hpp b/works/life/computer-network-experiment/Base.hpp
deleted file mode 100644
index b1ad55c..0000000
--- a/works/life/computer-network-experiment/Base.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-#include "PreConfig.hpp"
-
-#include <exception>
-#include <stdexcept>
-#include <gsl/gsl>
-
-#define CRU_UNUSED(entity) static_cast<void>(entity);
-
-#define CRU__CONCAT(a, b) a##b
-#define CRU_MAKE_UNICODE_LITERAL(str) CRU__CONCAT(u, #str)
-
-#define CRU_DEFAULT_COPY(classname) \
- classname(const classname&) = default; \
- classname& operator=(const classname&) = default;
-
-#define CRU_DEFAULT_MOVE(classname) \
- classname(classname&&) = default; \
- classname& operator=(classname&&) = default;
-
-#define CRU_DELETE_COPY(classname) \
- classname(const classname&) = delete; \
- classname& operator=(const classname&) = delete;
-
-#define CRU_DELETE_MOVE(classname) \
- classname(classname&&) = delete; \
- classname& operator=(classname&&) = delete;
-
-namespace cru {
-class Object {
- public:
- Object() = default;
- CRU_DEFAULT_COPY(Object)
- CRU_DEFAULT_MOVE(Object)
- virtual ~Object() = default;
-};
-
-struct Interface {
- Interface() = default;
- CRU_DELETE_COPY(Interface)
- CRU_DELETE_MOVE(Interface)
- virtual ~Interface() = default;
-};
-
-[[noreturn]] inline void UnreachableCode() { std::terminate(); }
-
-using Index = gsl::index;
-
-// https://www.boost.org/doc/libs/1_54_0/doc/html/hash/reference.html#boost.hash_combine
-template <class T>
-inline void hash_combine(std::size_t& s, const T& v) {
- std::hash<T> h;
- s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
-}
-
-#define CRU_DEFINE_CLASS_LOG_TAG(tag) \
- private: \
- constexpr static std::u16string_view log_tag = tag;
-} // namespace cru
diff --git a/works/life/computer-network-experiment/CMakeLists.txt b/works/life/computer-network-experiment/CMakeLists.txt
deleted file mode 100644
index 2ffd481..0000000
--- a/works/life/computer-network-experiment/CMakeLists.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-cmake_minimum_required(VERSION 3.20)
-
-set(CMAKE_TOOLCHAIN_FILE $ENV{VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake
- CACHE STRING "Vcpkg toolchain file")
-
-project(network-experiment)
-
-set(CMAKE_CXX_STANDARD 17)
-
-find_package(fmt CONFIG REQUIRED)
-find_package(Microsoft.GSL CONFIG REQUIRED)
-add_library(base STATIC Common.cpp StringUtil.cpp IO.cpp ReadWriteLock.cpp)
-target_link_libraries(base PUBLIC Microsoft.GSL::GSL fmt::fmt Folly::folly)
-if(WIN32)
-target_link_libraries(base PUBLIC Ws2_32)
-endif()
-
-add_executable(client client.cpp)
-target_link_libraries(client PRIVATE base)
-
-add_executable(server server.cpp)
-find_package(folly CONFIG REQUIRED)
-target_link_libraries(server PRIVATE base)
diff --git a/works/life/computer-network-experiment/Common.cpp b/works/life/computer-network-experiment/Common.cpp
deleted file mode 100644
index 1df4d56..0000000
--- a/works/life/computer-network-experiment/Common.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-#include "Common.h"
-
-#include "IO.h"
-#include <memory>
-
-#ifdef WIN32
-#include <Windows.h>
-#include <winsock.h>
-#else
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/unistd.h>
-#endif
-
-#include <string>
-
-[[noreturn]] void PrintErrorMessageAndExit(StringView message,
- bool print_last_error) {
-
- SendOutput(CRUT("{}\n"), message);
-
- if (print_last_error) {
-#ifdef WIN32
- auto error_code = WSAGetLastError();
- SendOutput(OutputType::Error, CRUT("Error code is {}.\n"), error_code);
- wchar_t buffer[500];
- if (!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_ARGUMENT_ARRAY |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- nullptr, error_code, 0, buffer, 500, nullptr)) {
- SendOutput(OutputType::Error, CRUT("Failed to format error message.\n"));
- } else {
- SendOutput(OutputType::Error, CRUT("{}\n"), buffer);
- }
-#else
-#endif
- }
-
- BeforeExit();
-
- std::exit(1);
-}
-
-#ifdef WIN32
-namespace {
-void InitWSA() {
- WSADATA wsa_data;
-
- if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) { // initialize wsa
- PrintErrorMessageAndExit(CRUT("Failed to initialize wsa."));
- }
-}
-} // namespace
-
-#endif
-
-int CloseSocket(int socket) {
-#ifdef WIN32
- return closesocket(socket);
-#else
- return close(socket);
-#endif
-}
-
-void BeforeExit() {
-#ifdef WIN32
- WSACleanup();
-#endif
-
- SignalAndWaitForOutputThreadStop();
-}
-
-bool SafeSend(int socket, std::string_view buffer) {
- const int total_byte_count = buffer.size();
- int byte_count_sent = 0;
- int retry_count = 0;
-
- while (true) {
- // Now we have sent all data.
- if (byte_count_sent == total_byte_count)
- return true;
-
- auto byte_actually_sent = send(socket, buffer.data() + byte_count_sent,
- buffer.size() - byte_count_sent, 0);
-
- // send failed
- if (byte_actually_sent == -1) {
- return false;
- }
-
- byte_count_sent += byte_actually_sent;
- }
-}
-
-bool SafeReadUntil(int socket, char c, std::string &data, std::string &rest) {
- data = rest;
-
- const int buffer_size = 100;
- char buffer[buffer_size];
-
- while (true) {
- int received_number = recv(socket, buffer, buffer_size, 0);
-
- if (received_number == -1) {
- return false;
- }
-
- bool end = false;
-
- for (int i = 0; i < received_number; i++) {
- if (buffer[i] == c) {
- data.append(buffer, i);
- rest = std::string(buffer + i + 1, received_number - i - 1);
- end = true;
- break;
- }
- }
-
- if (end)
- return true;
-
- data.append(buffer, received_number);
- }
-}
-
-int main() {
-#ifdef WIN32
- HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
- DWORD mode;
- GetConsoleMode(h, &mode);
- mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
- SetConsoleMode(h, mode);
-
- InitWSA();
-#endif
-
- int c = Main();
-
- BeforeExit();
- return c;
-}
diff --git a/works/life/computer-network-experiment/Common.h b/works/life/computer-network-experiment/Common.h
deleted file mode 100644
index 1e6c277..0000000
--- a/works/life/computer-network-experiment/Common.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#pragma once
-#include "StringUtil.hpp"
-
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <string_view>
-
-#ifdef WIN32
-using Char = wchar_t;
-using String = std::wstring;
-using StringView = std::wstring_view;
-using StringStream = std::wstringstream;
-inline auto &input_stream = std::wcin;
-inline auto &output_stream = std::wcout;
-inline auto &error_stream = std::wcerr;
-#define CRUT(string_literal) L##string_literal
-
-inline String ConvertCharString(std::string_view s) {
- return cru::ToUtf16WString(s);
-}
-
-inline std::string ConvertCharStringBack(StringView s) {
- return cru::ToUtf8(s);
-}
-#else
-using Char = char;
-using String = std::string;
-using StringView = std::string_view;
-using StringStream = std::stringstream;
-inline auto &input_stream = std::cin;
-inline auto &output_stream = std::cout;
-inline auto &error_stream = std::cerr;
-#define CRUT(string_literal) string_literal
-
-inline String ConvertCharString(std::string_view s) { return String(s); }
-inline std::string ConvertCharStringBack(StringView s) {
- return std::string(s);
-}
-#endif
-
-int Main();
-
-[[noreturn]] void PrintErrorMessageAndExit(StringView message,
- bool print_last_error = true);
-
-int CloseSocket(int socket);
-
-void BeforeExit();
-
-// Return false for error.
-bool SafeSend(int socket, std::string_view buffer);
-// Return false for error.
-bool SafeReadUntil(int socket, char c, std::string &data, std::string &rest);
diff --git a/works/life/computer-network-experiment/IO.cpp b/works/life/computer-network-experiment/IO.cpp
deleted file mode 100644
index 5d3fe12..0000000
--- a/works/life/computer-network-experiment/IO.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-#include "IO.h"
-
-#include <folly/CancellationToken.h>
-
-#include <mutex>
-#include <ostream>
-#include <thread>
-#include <type_traits>
-
-folly::MPMCQueue<Output> output_queue(100);
-
-namespace {
-folly::CancellationSource cancellation_source;
-std::thread io_thread;
-}
-
-void PrintOutput(const Output &output) {
- std::basic_ostream<Char> *stream;
-
- switch (output.type) {
- case OutputType::Error:
- stream = &error_stream;
- break;
- default:
- stream = &output_stream;
- break;
- }
-
- switch (output.color) {
- case OutputColor::Normal:
- (*stream) << output.message;
- break;
- case OutputColor::Green:
- (*stream) << CRUT("\x1b[32m") << output.message << CRUT("\x1b[39m")
- << std::flush;
- break;
- case OutputColor::Red:
- (*stream) << CRUT("\x1b[31m") << output.message << CRUT("\x1b[39m")
- << std::flush;
- break;
- case OutputColor::Yellow:
- (*stream) << CRUT("\x1b[33m") << output.message << CRUT("\x1b[39m")
- << std::flush;
- break;
- }
-}
-
-String ReadInputLine() {
- String line;
- std::getline(input_stream, line);
- return line;
-}
-
-void IOThread() {
- while (true) {
- if (cancellation_source.isCancellationRequested()) {
- while (true) {
- Output output;
- if (output_queue.readIfNotEmpty(output)) {
- PrintOutput(output);
- } else {
- return;
- }
- }
- }
-
- Output output;
- while (output_queue.readIfNotEmpty(output))
- PrintOutput(output);
-
- PrintOutput({CRUT("> ")});
- OnInputLine(ReadInputLine());
- }
-}
-
-void SignalAndWaitForOutputThreadStop() {
- cancellation_source.requestCancellation();
- io_thread.join();
-}
-
-void StartIOThread() { io_thread = std::thread(IOThread); }
diff --git a/works/life/computer-network-experiment/IO.h b/works/life/computer-network-experiment/IO.h
deleted file mode 100644
index 1658b78..0000000
--- a/works/life/computer-network-experiment/IO.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#pragma once
-#include "Common.h"
-#include "StringUtil.hpp"
-
-#include <fmt/format.h>
-#include <folly/CancellationToken.h>
-#include <folly/MPMCPipeline.h>
-#include <folly/MPMCQueue.h>
-
-#include <iostream>
-#include <thread>
-
-enum class OutputType { Normal, Error };
-enum class OutputColor { Normal, Green, Red, Yellow };
-
-struct Output {
- Output() = default;
- Output(String message, OutputType type = OutputType::Normal)
- : message(std::move(message)), type(type),
- color(type == OutputType::Error ? OutputColor::Red
- : OutputColor::Normal) {}
-
- Output(String message, OutputColor color)
- : message(std::move(message)), type(OutputType::Normal), color(color) {}
-
- Output(String message, OutputType type, OutputColor color)
- : message(std::move(message)), type(type), color(color) {}
-
- CRU_DEFAULT_COPY(Output)
- CRU_DEFAULT_MOVE(Output)
- ~Output() = default;
-
- String message;
- OutputType type;
- OutputColor color;
-};
-
-extern folly::MPMCQueue<Output> output_queue;
-
-inline void SendOutput(Output output) {
- output_queue.blockingWrite(std::move(output));
-}
-
-inline void SendOutput(String output) { SendOutput(Output{std::move(output)}); }
-
-template <typename... Args> void SendOutput(StringView format, Args &&...args) {
- output_queue.blockingWrite(fmt::format(format, std::forward<Args>(args)...));
-}
-
-template <typename... Args>
-void SendOutput(OutputType type, StringView format, Args &&...args) {
- output_queue.blockingWrite(
- Output{fmt::format(format, std::forward<Args>(args)...), type});
-}
-
-template <typename... Args>
-void SendOutput(OutputColor color, StringView format, Args &&...args) {
- output_queue.blockingWrite(
- Output{fmt::format(format, std::forward<Args>(args)...), color});
-}
-
-void SignalAndWaitForOutputThreadStop();
-
-void OnInputLine(StringView line);
-
-void StartIOThread();
-
-String ReadInputLine(); \ No newline at end of file
diff --git a/works/life/computer-network-experiment/PreConfig.hpp b/works/life/computer-network-experiment/PreConfig.hpp
deleted file mode 100644
index d78292c..0000000
--- a/works/life/computer-network-experiment/PreConfig.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-#ifdef _MSC_VER
-// disable the unnecessary warning about multi-inheritance
-#pragma warning(disable : 4250)
-#endif
diff --git a/works/life/computer-network-experiment/ReadWriteLock.cpp b/works/life/computer-network-experiment/ReadWriteLock.cpp
deleted file mode 100644
index 46d2857..0000000
--- a/works/life/computer-network-experiment/ReadWriteLock.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-#include "ReadWriteLock.h"
-
-#include <cassert>
-#include <memory>
-
-namespace cru {
-ReadWriteLock::ReadWriteLock() {
-#ifdef WIN32
- lock_ = std::make_unique<SRWLOCK>();
- InitializeSRWLock(lock_.get());
-#else
- lock_.reset(new pthread_rwlock_t(PTHREAD_RWLOCK_INITIALIZER));
- pthread_rwlock_init(lock_.get(), nullptr);
-#endif
-}
-
-ReadWriteLock::ReadWriteLock(ReadWriteLock &&other)
- : lock_(std::move(other.lock_)) {}
-
-ReadWriteLock &ReadWriteLock::operator=(ReadWriteLock &&other) {
- if (this != &other) {
- Destroy();
- lock_ = std::move(other.lock_);
- }
- return *this;
-}
-
-ReadWriteLock::~ReadWriteLock() { Destroy(); }
-
-void ReadWriteLock::ReadLock() {
- assert(lock_);
-#ifdef WIN32
- AcquireSRWLockShared(lock_.get());
-#else
- pthread_rwlock_rdlock(lock_.get());
-#endif
-}
-
-void ReadWriteLock::WriteLock() {
- assert(lock_);
-#ifdef WIN32
- AcquireSRWLockExclusive(lock_.get());
-#else
- pthread_rwlock_wrlock(lock_.get());
-#endif
-}
-
-bool ReadWriteLock::ReadTryLock() {
- assert(lock_);
-#ifdef WIN32
- return TryAcquireSRWLockShared(lock_.get()) != 0;
-#else
- return pthread_rwlock_tryrdlock(lock_.get()) == 0;
-#endif
-}
-
-bool ReadWriteLock::WriteTryLock() {
- assert(lock_);
-#ifdef WIN32
- return TryAcquireSRWLockExclusive(lock_.get()) != 0;
-#else
- return pthread_rwlock_trywrlock(lock_.get()) == 0;
-#endif
-}
-
-void ReadWriteLock::ReadUnlock() {
- assert(lock_);
-#ifdef WIN32
- ReleaseSRWLockShared(lock_.get());
-#else
- pthread_rwlock_unlock(lock_.get());
-#endif
-}
-
-void ReadWriteLock::WriteUnlock() {
- assert(lock_);
-#ifdef WIN32
- ReleaseSRWLockExclusive(lock_.get());
-#else
- pthread_rwlock_unlock(lock_.get());
-#endif
-}
-
-void ReadWriteLock::Destroy() {
-#ifndef WIN32
- if (lock_ != nullptr)
- pthread_rwlock_destroy(lock_.get());
-#endif
-}
-
-void swap(ReadWriteLock &left, ReadWriteLock &right) {
- auto temp = std::move(left.lock_);
- left.lock_ = std::move(right.lock_);
- right.lock_ = std::move(temp);
-}
-
-} // namespace cru \ No newline at end of file
diff --git a/works/life/computer-network-experiment/ReadWriteLock.h b/works/life/computer-network-experiment/ReadWriteLock.h
deleted file mode 100644
index ee40ac0..0000000
--- a/works/life/computer-network-experiment/ReadWriteLock.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-#include "Common.h"
-
-#include <memory>
-
-#ifdef WIN32
-#include <Windows.h>
-#else
-#include <pthread.h>
-#endif
-
-namespace cru {
-class ReadWriteLock {
- friend void swap(ReadWriteLock &left, ReadWriteLock &right);
-public:
- ReadWriteLock();
-
- ReadWriteLock(ReadWriteLock &&other);
- ReadWriteLock &operator=(ReadWriteLock &&other);
-
- ~ReadWriteLock();
-
-public:
- void ReadLock();
- void WriteLock();
-
- bool ReadTryLock();
- bool WriteTryLock();
-
- void ReadUnlock();
- void WriteUnlock();
-
-private:
- void Destroy();
-
-private:
-#ifdef WIN32
- std::unique_ptr<SRWLOCK> lock_;
-#else
- std::unique_ptr<pthread_rwlock_t> lock_;
-#endif
-};
-
-void swap(ReadWriteLock &left, ReadWriteLock &right);
-} // namespace cru
diff --git a/works/life/computer-network-experiment/StringUtil.cpp b/works/life/computer-network-experiment/StringUtil.cpp
deleted file mode 100644
index 6bf906d..0000000
--- a/works/life/computer-network-experiment/StringUtil.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-#include "StringUtil.hpp"
-#include "Base.hpp"
-#include <string>
-
-namespace cru {
-namespace {
-template <typename UInt, int number_of_bit, typename ReturnType>
-inline std::enable_if_t<std::is_unsigned_v<UInt>, ReturnType>
-ExtractBits(UInt n) {
- return static_cast<ReturnType>(n & ((1u << number_of_bit) - 1));
-}
-} // namespace
-
-CodePoint Utf8NextCodePoint(std::string_view str, Index current,
- Index *next_position) {
- CodePoint result;
-
- if (current >= static_cast<Index>(str.length())) {
- result = k_invalid_code_point;
- } else {
- const auto cu0 = static_cast<std::uint8_t>(str[current++]);
-
- auto read_next_folowing_code = [&str, &current]() -> CodePoint {
- if (current == static_cast<Index>(str.length()))
- throw TextEncodeException(
- "Unexpected end when read continuing byte of multi-byte code "
- "point.");
-
- const auto u = static_cast<std::uint8_t>(str[current]);
- if (!(u & (1u << 7)) || (u & (1u << 6))) {
- throw TextEncodeException(
- "Unexpected bad-format (not 0b10xxxxxx) continuing byte of "
- "multi-byte code point.");
- }
-
- return ExtractBits<std::uint8_t, 6, CodePoint>(str[current++]);
- };
-
- if ((1u << 7) & cu0) {
- if ((1u << 6) & cu0) { // 2~4-length code point
- if ((1u << 5) & cu0) { // 3~4-length code point
- if ((1u << 4) & cu0) { // 4-length code point
- if (cu0 & (1u << 3)) {
- throw TextEncodeException(
- "Unexpected bad-format begin byte (not 0b11110xxx) of 4-byte"
- "code point.");
- }
-
- const CodePoint s0 = ExtractBits<std::uint8_t, 3, CodePoint>(cu0)
- << (6 * 3);
- const CodePoint s1 = read_next_folowing_code() << (6 * 2);
- const CodePoint s2 = read_next_folowing_code() << 6;
- const CodePoint s3 = read_next_folowing_code();
- result = s0 + s1 + s2 + s3;
- } else { // 3-length code point
- const CodePoint s0 = ExtractBits<std::uint8_t, 4, CodePoint>(cu0)
- << (6 * 2);
- const CodePoint s1 = read_next_folowing_code() << 6;
- const CodePoint s2 = read_next_folowing_code();
- result = s0 + s1 + s2;
- }
- } else { // 2-length code point
- const CodePoint s0 = ExtractBits<std::uint8_t, 5, CodePoint>(cu0)
- << 6;
- const CodePoint s1 = read_next_folowing_code();
- result = s0 + s1;
- }
- } else {
- throw TextEncodeException(
- "Unexpected bad-format (0b10xxxxxx) begin byte of a code point.");
- }
- } else {
- result = static_cast<CodePoint>(cu0);
- }
- }
-
- if (next_position != nullptr)
- *next_position = current;
- return result;
-}
-
-CodePoint Utf16NextCodePoint(std::u16string_view str, Index current,
- Index *next_position) {
- CodePoint result;
-
- if (current >= static_cast<Index>(str.length())) {
- result = k_invalid_code_point;
- } else {
- const auto cu0 = str[current++];
-
- if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point
- result = static_cast<CodePoint>(cu0);
- } else if (IsUtf16SurrogatePairLeading(cu0)) { // 2-length code point
- if (current >= static_cast<Index>(str.length())) {
- throw TextEncodeException(
- "Unexpected end when reading second code unit of surrogate pair.");
- }
- const auto cu1 = str[current++];
-
- if (!IsUtf16SurrogatePairTrailing(cu1)) {
- throw TextEncodeException(
- "Unexpected bad-range second code unit of surrogate pair.");
- }
-
- const auto s0 = ExtractBits<std::uint16_t, 10, CodePoint>(cu0) << 10;
- const auto s1 = ExtractBits<std::uint16_t, 10, CodePoint>(cu1);
-
- result = s0 + s1 + 0x10000;
-
- } else {
- throw TextEncodeException(
- "Unexpected bad-range first code unit of surrogate pair.");
- }
- }
-
- if (next_position != nullptr)
- *next_position = current;
- return result;
-}
-
-CodePoint Utf16PreviousCodePoint(std::u16string_view str, Index current,
- Index *previous_position) {
- CodePoint result;
- if (current <= 0) {
- result = k_invalid_code_point;
- } else {
- const auto cu0 = str[--current];
-
- if (!IsUtf16SurrogatePairCodeUnit(cu0)) { // 1-length code point
- result = static_cast<CodePoint>(cu0);
- } else if (IsUtf16SurrogatePairTrailing(cu0)) { // 2-length code point
- if (current <= 0) {
- throw TextEncodeException(
- "Unexpected end when reading first code unit of surrogate pair.");
- }
- const auto cu1 = str[--current];
-
- if (!IsUtf16SurrogatePairLeading(cu1)) {
- throw TextEncodeException(
- "Unexpected bad-range first code unit of surrogate pair.");
- }
-
- const auto s0 = ExtractBits<std::uint16_t, 10, CodePoint>(cu1) << 10;
- const auto s1 = ExtractBits<std::uint16_t, 10, CodePoint>(cu0);
-
- result = s0 + s1 + 0x10000;
-
- } else {
- throw TextEncodeException(
- "Unexpected bad-range second code unit of surrogate pair.");
- }
- }
-
- if (previous_position != nullptr)
- *previous_position = current;
- return result;
-}
-
-void Utf8EncodeCodePointAppend(CodePoint code_point, std::string &str) {
- auto write_continue_byte = [&str](std::uint8_t byte6) {
- str.push_back((1u << 7) + (((1u << 6) - 1) & byte6));
- };
-
- if (code_point >= 0 && code_point <= 0x007F) {
- str.push_back(static_cast<char>(code_point));
- } else if (code_point >= 0x0080 && code_point <= 0x07FF) {
- std::uint32_t unsigned_code_point = code_point;
- str.push_back(static_cast<char>(ExtractBits<std::uint32_t, 5, std::uint8_t>(
- (unsigned_code_point >> 6)) +
- 0b11000000));
- write_continue_byte(
- ExtractBits<std::uint32_t, 6, std::uint8_t>(unsigned_code_point));
- } else if (code_point >= 0x0800 && code_point <= 0xFFFF) {
- std::uint32_t unsigned_code_point = code_point;
- str.push_back(static_cast<char>(ExtractBits<std::uint32_t, 4, std::uint8_t>(
- (unsigned_code_point >> (6 * 2))) +
- 0b11100000));
- write_continue_byte(
- ExtractBits<std::uint32_t, 6, std::uint8_t>(unsigned_code_point >> 6));
- write_continue_byte(
- ExtractBits<std::uint32_t, 6, std::uint8_t>(unsigned_code_point));
- } else if (code_point >= 0x10000 && code_point <= 0x10FFFF) {
- std::uint32_t unsigned_code_point = code_point;
- str.push_back(static_cast<char>(ExtractBits<std::uint32_t, 3, std::uint8_t>(
- (unsigned_code_point >> (6 * 3))) +
- 0b11110000));
- write_continue_byte(ExtractBits<std::uint32_t, 6, std::uint8_t>(
- unsigned_code_point >> (6 * 2)));
- write_continue_byte(
- ExtractBits<std::uint32_t, 6, std::uint8_t>(unsigned_code_point >> 6));
- write_continue_byte(
- ExtractBits<std::uint32_t, 6, std::uint8_t>(unsigned_code_point));
- } else {
- throw TextEncodeException("Code point out of range.");
- }
-}
-
-void Utf16EncodeCodePointAppend(CodePoint code_point, std::u16string &str) {
- if ((code_point >= 0 && code_point <= 0xD7FF) ||
- (code_point >= 0xE000 && code_point <= 0xFFFF)) {
- str.push_back(static_cast<char16_t>(code_point));
- } else if (code_point >= 0x10000 && code_point <= 0x10FFFF) {
- std::uint32_t u = code_point - 0x10000;
- str.push_back(static_cast<char16_t>(
- ExtractBits<std::uint32_t, 10, std::uint32_t>(u >> 10) + 0xD800u));
- str.push_back(static_cast<char16_t>(
- ExtractBits<std::uint32_t, 10, std::uint32_t>(u) + 0xDC00u));
- } else {
- throw TextEncodeException("Code point out of range.");
- }
-}
-
-std::string ToUtf8(std::u16string_view s) {
- std::string result;
- for (CodePoint cp : Utf16CodePointIterator{s}) {
- Utf8EncodeCodePointAppend(cp, result);
- }
- return result;
-}
-
-std::u16string ToUtf16(std::string_view s) {
- std::u16string result;
- for (CodePoint cp : Utf8CodePointIterator{s}) {
- Utf16EncodeCodePointAppend(cp, result);
- }
- return result;
-}
-
-#ifdef WIN32
-std::string ToUtf8(std::wstring_view s) {
- std::u16string_view string{reinterpret_cast<const char16_t *>(s.data()),
- s.size()};
- std::string result;
- for (CodePoint cp : Utf16CodePointIterator{string}) {
- Utf8EncodeCodePointAppend(cp, result);
- }
- return result;
-}
-std::wstring ToUtf16WString(std::string_view s) {
- std::u16string result;
- for (CodePoint cp : Utf8CodePointIterator{s}) {
- Utf16EncodeCodePointAppend(cp, result);
- }
-
- std::wstring r(result.cbegin(), result.cend());
- return r;
-}
-#endif
-
-bool Utf16IsValidInsertPosition(std::u16string_view s, gsl::index position) {
- if (position < 0)
- return false;
- if (position > static_cast<gsl::index>(s.size()))
- return false;
- if (position == 0)
- return true;
- if (position == static_cast<gsl::index>(s.size()))
- return true;
- return !IsUtf16SurrogatePairTrailing(s[position]);
-}
-
-gsl::index Utf16BackwardUntil(std::u16string_view str, gsl::index position,
- const std::function<bool(CodePoint)> &predicate) {
- if (position <= 0)
- return position;
- while (true) {
- gsl::index p = position;
- auto c = Utf16PreviousCodePoint(str, p, &position);
- if (predicate(c))
- return p;
- if (c == k_invalid_code_point)
- return p;
- }
- UnreachableCode();
-}
-
-gsl::index Utf16ForwardUntil(std::u16string_view str, gsl::index position,
- const std::function<bool(CodePoint)> &predicate) {
- if (position >= static_cast<gsl::index>(str.size()))
- return position;
- while (true) {
- gsl::index p = position;
- auto c = Utf16NextCodePoint(str, p, &position);
- if (predicate(c))
- return p;
- if (c == k_invalid_code_point)
- return p;
- }
- UnreachableCode();
-}
-
-inline bool IsSpace(CodePoint c) { return c == 0x20 || c == 0xA; }
-
-gsl::index Utf16PreviousWord(std::u16string_view str, gsl::index position,
- bool *is_space) {
- if (position <= 0)
- return position;
- auto c = Utf16PreviousCodePoint(str, position, nullptr);
- if (IsSpace(c)) { // TODO: Currently only test against 0x20(space).
- if (is_space)
- *is_space = true;
- return Utf16BackwardUntil(str, position,
- [](CodePoint c) { return !IsSpace(c); });
- } else {
- if (is_space)
- *is_space = false;
- return Utf16BackwardUntil(str, position, IsSpace);
- }
-}
-
-gsl::index Utf16NextWord(std::u16string_view str, gsl::index position,
- bool *is_space) {
- if (position >= static_cast<gsl::index>(str.size()))
- return position;
- auto c = Utf16NextCodePoint(str, position, nullptr);
- if (IsSpace(c)) { // TODO: Currently only test against 0x20(space).
- if (is_space)
- *is_space = true;
- return Utf16ForwardUntil(str, position,
- [](CodePoint c) { return !IsSpace(c); });
- } else {
- if (is_space)
- *is_space = false;
- return Utf16ForwardUntil(str, position, IsSpace);
- }
-}
-
-char16_t ToLower(char16_t c) {
- if (c >= u'A' && c <= u'Z') {
- return c - u'A' + u'a';
- }
- return c;
-}
-
-char16_t ToUpper(char16_t c) {
- if (c >= u'a' && c <= u'z') {
- return c - u'a' + u'A';
- }
- return c;
-}
-
-std::u16string ToLower(std::u16string_view s) {
- std::u16string result;
- for (auto c : s)
- result.push_back(ToLower(c));
- return result;
-}
-
-std::u16string ToUpper(std::u16string_view s) {
- std::u16string result;
- for (auto c : s)
- result.push_back(ToUpper(c));
- return result;
-}
-} // namespace cru
diff --git a/works/life/computer-network-experiment/StringUtil.hpp b/works/life/computer-network-experiment/StringUtil.hpp
deleted file mode 100644
index b0ca675..0000000
--- a/works/life/computer-network-experiment/StringUtil.hpp
+++ /dev/null
@@ -1,158 +0,0 @@
-#pragma once
-#include "Base.hpp"
-
-#include <functional>
-#include <string>
-#include <string_view>
-
-namespace cru {
-using CodePoint = std::int32_t;
-constexpr CodePoint k_invalid_code_point = -1;
-
-class TextEncodeException : public std::runtime_error {
- public:
- using runtime_error::runtime_error;
-};
-
-inline bool IsUtf16SurrogatePairCodeUnit(char16_t c) {
- return c >= 0xD800 && c <= 0xDFFF;
-}
-
-inline bool IsUtf16SurrogatePairLeading(char16_t c) {
- return c >= 0xD800 && c <= 0xDBFF;
-}
-
-inline bool IsUtf16SurrogatePairTrailing(char16_t c) {
- return c >= 0xDC00 && c <= 0xDFFF;
-}
-
-CodePoint Utf8NextCodePoint(std::string_view str, Index current,
- Index* next_position);
-
-CodePoint Utf16NextCodePoint(std::u16string_view str, Index current,
- Index* next_position);
-CodePoint Utf16PreviousCodePoint(std::u16string_view str, Index current,
- Index* previous_position);
-
-template <typename StringType>
-using NextCodePointFunctionType = CodePoint (*)(StringType, Index, Index*);
-
-template <typename StringType,
- NextCodePointFunctionType<StringType> NextCodePointFunction>
-class CodePointIterator {
- public:
- using difference_type = Index;
- using value_type = CodePoint;
- using pointer = void;
- using reference = value_type;
- using iterator_category = std::forward_iterator_tag;
-
- public:
- struct past_end_tag_t {};
-
- explicit CodePointIterator(StringType string)
- : string_(std::move(string)), position_(0) {}
- explicit CodePointIterator(StringType string, past_end_tag_t)
- : string_(std::move(string)), position_(string_.size()) {}
-
- CRU_DEFAULT_COPY(CodePointIterator)
- CRU_DEFAULT_MOVE(CodePointIterator)
-
- ~CodePointIterator() = default;
-
- public:
- StringType GetString() const { return string_; }
- Index GetPosition() const { return position_; }
-
- bool IsPastEnd() const {
- return position_ == static_cast<Index>(string_.size());
- }
-
- public:
- CodePointIterator begin() const { return *this; }
- CodePointIterator end() const {
- return CodePointIterator{string_, past_end_tag_t{}};
- }
-
- public:
- bool operator==(const CodePointIterator& other) const {
- // You should compare iterator that iterate on the same string.
- Expects(this->string_.data() == other.string_.data() &&
- this->string_.size() == other.string_.size());
- return this->position_ == other.position_;
- }
- bool operator!=(const CodePointIterator& other) const {
- return !this->operator==(other);
- }
-
- CodePointIterator& operator++() {
- Expects(!IsPastEnd());
- Forward();
- return *this;
- }
-
- CodePointIterator operator++(int) {
- Expects(!IsPastEnd());
- CodePointIterator old = *this;
- Forward();
- return old;
- }
-
- CodePoint operator*() const {
- return NextCodePointFunction(string_, position_, &next_position_cache_);
- }
-
- private:
- void Forward() {
- if (next_position_cache_ > position_) {
- position_ = next_position_cache_;
- } else {
- NextCodePointFunction(string_, position_, &position_);
- }
- }
-
- private:
- StringType string_;
- Index position_;
- mutable Index next_position_cache_;
-};
-
-using Utf8CodePointIterator =
- CodePointIterator<std::string_view, &Utf8NextCodePoint>;
-
-using Utf16CodePointIterator =
- CodePointIterator<std::u16string_view, &Utf16NextCodePoint>;
-
-void Utf8EncodeCodePointAppend(CodePoint code_point, std::string& str);
-void Utf16EncodeCodePointAppend(CodePoint code_point, std::u16string& str);
-
-std::string ToUtf8(std::u16string_view s);
-std::u16string ToUtf16(std::string_view s);
-
-#ifdef WIN32
-std::string ToUtf8(std::wstring_view s);
-std::wstring ToUtf16WString(std::string_view s);
-#endif
-
-// If given s is not a valid utf16 string, return value is UD.
-bool Utf16IsValidInsertPosition(std::u16string_view s, gsl::index position);
-
-// Return position after the character making predicate returns true or 0 if no
-// character doing so.
-gsl::index Utf16BackwardUntil(std::u16string_view str, gsl::index position,
- const std::function<bool(CodePoint)>& predicate);
-// Return position before the character making predicate returns true or
-// str.size() if no character doing so.
-gsl::index Utf16ForwardUntil(std::u16string_view str, gsl::index position,
- const std::function<bool(CodePoint)>& predicate);
-
-gsl::index Utf16PreviousWord(std::u16string_view str, gsl::index position,
- bool* is_space = nullptr);
-gsl::index Utf16NextWord(std::u16string_view str, gsl::index position,
- bool* is_space = nullptr);
-
-char16_t ToLower(char16_t c);
-char16_t ToUpper(char16_t c);
-std::u16string ToLower(std::u16string_view s);
-std::u16string ToUpper(std::u16string_view s);
-} // namespace cru
diff --git a/works/life/computer-network-experiment/TODO.md b/works/life/computer-network-experiment/TODO.md
deleted file mode 100644
index 248a2d7..0000000
--- a/works/life/computer-network-experiment/TODO.md
+++ /dev/null
@@ -1,6 +0,0 @@
-1. Apply read-write lock to connections. ✅
-2. Remove dead connection from connection list. ✅
-3. Handle SIGINT gracefully.
-4. Add close method to protocol.
-5. Add help and exit command.
-6. Use multiprocess to show output.
diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp
deleted file mode 100644
index 73ae52f..0000000
--- a/works/life/computer-network-experiment/client.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/** Created by crupest.
- * This is the client program.
- */
-
-#include "Common.h"
-#include "IO.h"
-
-#include <folly/CancellationToken.h>
-#include <folly/ProducerConsumerQueue.h>
-
-#ifdef WIN32
-#include <Windows.h>
-#include <winsock.h>
-#else
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#endif
-
-const auto connect_address = "127.0.0.1"; // control connect address
-const u_short port = 1234; // control connect port
-
-namespace {
-folly::ProducerConsumerQueue<std::string> send_queue(100);
-folly::CancellationSource cancellation_source;
-} // namespace
-
-void PrintHelp() {
- SendOutput(CRUT("Input anything to send to server. Or just enter to receive "
- "lastest messages from server.\n"));
-}
-
-void OnInputLine(StringView line) {
- if (line.empty()) {
- return;
- } else {
- send_queue.write(ConvertCharStringBack(line) + '\n');
- }
-}
-
-int Main() {
- int client_socket;
-
- if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- PrintErrorMessageAndExit(CRUT("Failed to create socket!\n"));
- }
-
- sockaddr_in server_address;
-
- server_address.sin_family = AF_INET;
- server_address.sin_port = htons(port);
- server_address.sin_addr.s_addr = inet_addr(connect_address);
- memset(&(server_address.sin_zero), 0, sizeof(server_address.sin_zero));
-
- if (connect(client_socket, (sockaddr *)&server_address, sizeof(sockaddr)) ==
- -1) {
- PrintErrorMessageAndExit(CRUT("Failed to connect!"));
- }
-
- output_stream << CRUT("Please input your name:\n> ");
- String name = ReadInputLine();
-
- PrintHelp();
-
- StartIOThread();
-
- name.push_back(CRUT('\n'));
- auto name_data = ConvertCharStringBack(name);
- SafeSend(client_socket, name_data);
-
- std::thread receive_thread([client_socket] {
- std::string rest;
- while (true) {
- if (cancellation_source.isCancellationRequested()) {
- break;
- }
-
- std::string data;
- if (!SafeReadUntil(client_socket, '\n', data, rest)) {
- PrintErrorMessageAndExit(CRUT("Failed to receive message.\n"));
- }
-
- SendOutput(CRUT("Recived a message:\n{}\n"), ConvertCharString(data));
- }
- });
- receive_thread.detach();
-
- while (true) {
- if (cancellation_source.isCancellationRequested()) {
- break;
- }
-
- std::string s;
- if (send_queue.read(s)) {
- if (!SafeSend(client_socket, s)) {
- PrintErrorMessageAndExit(CRUT("Failed to send message to server."));
- }
- }
- }
-
- CloseSocket(client_socket);
- return 0;
-}
diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp
deleted file mode 100644
index 065687c..0000000
--- a/works/life/computer-network-experiment/server.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/** Created by crupest.
- * This is the server program.
- */
-
-#include "Common.h"
-#include "IO.h"
-#include "ReadWriteLock.h"
-
-#include <folly/CancellationToken.h>
-#include <folly/ProducerConsumerQueue.h>
-
-#include <algorithm>
-#include <memory>
-#include <optional>
-#include <stdint.h>
-#include <thread>
-
-#ifdef WIN32
-#include <Windows.h>
-#include <winsock.h>
-#else
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#endif
-
-const auto bind_address = "127.0.0.1"; // control bind address
-const u_short port = 1234; // control bind port
-
-namespace {
-void PrintHelp() {
- SendOutput(CRUT(
- "Input and run one of following command:\n\t> NOTHING -> Continue and "
- "print new messages.\n\t> list -> List all connected client.\n\t> send "
- "[i] [message] -> Send messages to client with number i.\n"));
-}
-} // namespace
-
-struct Connection {
- int id;
- std::thread thread;
- std::thread receive_thread;
- int socket;
- sockaddr_in address;
- String address_string;
- String name;
- folly::ProducerConsumerQueue<std::string> send_queue{100};
- folly::CancellationSource cancellation_source;
-};
-
-namespace {
-cru::ReadWriteLock connections_lock;
-std::vector<std::unique_ptr<Connection>> connections;
-
-void RemoveConnection(int id) {
- connections_lock.WriteLock();
- connections.erase(
- std::remove_if(connections.begin(), connections.end(),
- [id](const std::unique_ptr<Connection> &connection) {
- return connection->id == id;
- }),
- connections.end());
-
- connections_lock.WriteUnlock();
-}
-
-void PrintConnections() {
- connections_lock.ReadLock();
- if (connections.empty()) {
- SendOutput(CRUT("Currently there is no connection.\n"));
- }
-
- String s;
- for (const auto &connection : connections) {
- s += fmt::format(CRUT("{}: {}({})\n"), connection->id, connection->name,
- connection->address_string);
- }
- SendOutput(s);
- connections_lock.ReadUnlock();
-}
-} // namespace
-
-void ResponseThreadProc(Connection *connection) {
- auto host = ConvertCharString(inet_ntoa(connection->address.sin_addr));
- auto port = htons(connection->address.sin_port);
- connection->address_string = fmt::format(CRUT("{}:{}"), host, port);
-
- std::string rest;
- std::string name_data;
- if (!SafeReadUntil(connection->socket, '\n', name_data, rest)) {
- SendOutput(OutputType::Error, CRUT("Failed to read name of {}.\n"),
- connection->address_string);
- CloseSocket(connection->socket);
- return;
- }
-
- connection->name = ConvertCharString(name_data);
- SendOutput(OutputColor::Green, CRUT("Connected to {}, whose name is {}.\n"),
- connection->address_string, connection->name);
-
- connection->receive_thread = std::thread(
- [](Connection *connection) {
- std::string rest;
- while (true) {
- if (connection->cancellation_source.isCancellationRequested()) {
- break;
- }
-
- std::string data;
-
- if (!SafeReadUntil(connection->socket, '\n', data, rest)) {
- SendOutput(OutputType::Error,
- CRUT("Failed read data from socket of {}({}).\n"),
- connection->name, connection->address_string);
- connection->cancellation_source.requestCancellation();
- return;
- }
-
- SendOutput(CRUT("{}({}) send a message:\n{}\n"), connection->name,
- connection->address_string, ConvertCharString(data));
- }
- },
- connection);
- connection->receive_thread.detach();
-
- while (true) {
- if (connection->cancellation_source.isCancellationRequested()) {
- break;
- }
-
- std::string s;
- if (connection->send_queue.read(s)) {
- if (!SafeSend(connection->socket, s)) {
- SendOutput(OutputType::Error, CRUT("Failed send data to {}({}).\n"),
- connection->name, connection->address_string);
- connection->cancellation_source.requestCancellation();
- break;
- }
- }
- }
-
- CloseSocket(connection->socket);
-
- RemoveConnection(connection->id);
-}
-
-void OnInputLine(StringView line) {
- StringStream ss{String(line)};
-
- ss >> std::ws;
- if (ss.eof())
- return;
-
- String command;
- ss >> command;
-
- if (command == CRUT("list")) {
- if (!ss.eof()) {
- SendOutput(OutputType::Error,
- CRUT("List command can't have arguments!\n"));
- PrintHelp();
- } else {
- PrintConnections();
- }
- return;
- } else if (command == CRUT("send")) {
- int id;
- ss >> id;
- if (!ss) {
- SendOutput(OutputType::Error, CRUT("Send format error!\n"));
- PrintHelp();
- return;
- }
-
- String message;
- getline(ss, message);
-
- if (message.empty()) {
- SendOutput(OutputType::Error, CRUT("Send message can't be empty.!\n"));
- PrintHelp();
- return;
- }
-
- auto i = std::find_if(
- connections.begin(), connections.end(),
- [id](const std::unique_ptr<Connection> &c) { return c->id == id; });
-
- if (i == connections.end()) {
- SendOutput(OutputType::Error, CRUT("No connection with such id.\n"));
- return;
- }
-
- (*i)->send_queue.write(ConvertCharStringBack(message) + "\n");
- return;
- } else {
- SendOutput(OutputType::Error, CRUT("Unkown command!\n"));
- PrintHelp();
- return;
- }
-}
-
-int Main() {
- int server_socket;
-
- if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- PrintErrorMessageAndExit(CRUT("Failed to create socket."));
- }
-
- sockaddr_in server_address;
-
- server_address.sin_family = AF_INET;
- server_address.sin_port = htons(port);
- server_address.sin_addr.s_addr = inet_addr(bind_address);
- memset(&(server_address.sin_zero), 0, sizeof(server_address.sin_zero));
-
- if (bind(server_socket, reinterpret_cast<sockaddr *>(&server_address),
- sizeof(sockaddr_in)) == -1) {
- PrintErrorMessageAndExit(CRUT("Failed to bind."));
- }
-
- if (listen(server_socket, SOMAXCONN) == -1) {
- PrintErrorMessageAndExit(CRUT("Failed to listen."));
- }
-
- SendOutput(OutputColor::Green,
- CRUT("Now start to accept incoming connection.\n"));
-
- PrintHelp();
-
- StartIOThread();
-
- int current_id = 1;
-
- while (true) {
- sockaddr_in client_address;
- int client_socket;
- unsigned sin_size = sizeof(sockaddr_in);
- client_socket =
- accept(server_socket, reinterpret_cast<sockaddr *>(&client_address),
-#ifdef WIN32
- reinterpret_cast<int *>
-#endif
- (&sin_size));
-
- if (client_socket == -1) {
- PrintErrorMessageAndExit(CRUT("Failed to accecpt."));
- }
-
- connections_lock.WriteLock();
- connections.push_back(std::make_unique<Connection>());
- const std::unique_ptr<Connection> &connection = connections.back();
-
- connection->id = current_id++;
- connection->socket = client_socket;
- connection->address = client_address;
- connection->thread =
- std::thread(ResponseThreadProc, connections.back().get());
- connection->thread.detach();
- connections_lock.WriteUnlock();
- }
-}