Compare commits

..

2 Commits

Author SHA1 Message Date
Antonio Andelic
16245d7ec8 Fix tests 2022-02-11 12:42:40 +01:00
Antonio Andelic
49ad114366 PMR property value 2022-02-11 11:32:11 +01:00
563 changed files with 11937 additions and 16762 deletions

View File

@@ -1,7 +1,6 @@
---
Checks: '*,
-abseil-string-find-str-contains,
-altera-id-dependent-backward-branch,
-altera-struct-pack-align,
-altera-unroll-loops,
-android-*,

View File

@@ -16,7 +16,6 @@ tmpdir=$(mktemp -d repo-XXXXXXXX)
trap "rm -rf $tmpdir" EXIT INT
modified_files=$(git diff --cached --name-only --diff-filter=AM $against | sed -nE "/.*\.(cpp|cc|cxx|c|h|hpp)$/p")
FAIL=0
for file in $modified_files; do
echo "Checking $file..."
@@ -26,20 +25,19 @@ for file in $modified_files; do
echo "Running clang-format..."
$project_folder/tools/git-clang-format $tmpdir/$file
CODE=$?
code=$?
if [ $CODE -ne 0 ]; then
if [ $code -ne 0 ]; then
break
fi
# Do not break header checker
echo "Running header checker..."
$project_folder/tools/header-checker.py $tmpdir/$file $file --amend-year
CODE=$?
if [ $CODE -ne 0 ]; then
FAIL=1
fi
code=$?
if [ $code -ne 0 ]; then
break
fi
done;
return ${FAIL}
return $code

View File

@@ -1,49 +0,0 @@
name: Publish Docker images
on:
workflow_dispatch:
inputs:
version:
description: "Memgraph binary version to publish on Dockerhub."
required: true
jobs:
docker_publish:
runs-on: ubuntu-latest
env:
DOCKER_ORGANIZATION_NAME: memgraph
DOCKER_REPOSITORY_NAME: memgraph
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
- name: Log in to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Download memgraph binary
run: |
cd release/docker
curl -L https://download.memgraph.com/memgraph/v${{ github.event.inputs.version }}/debian-11/memgraph_${{ github.event.inputs.version }}-1_amd64.deb > memgraph-amd64.deb
curl -L https://download.memgraph.com/memgraph/v${{ github.event.inputs.version }}/debian-11-aarch64/memgraph_${{ github.event.inputs.version }}-1_arm64.deb > memgraph-arm64.deb
- name: Build & push docker images
run: |
cd release/docker
docker buildx build \
--build-arg BINARY_NAME="memgraph-" \
--build-arg EXTENSION="deb" \
--platform linux/amd64,linux/arm64 \
--tag $DOCKER_ORGANIZATION_NAME/$DOCKER_REPOSITORY_NAME:${{ github.event.inputs.version }} \
--tag $DOCKER_ORGANIZATION_NAME/$DOCKER_REPOSITORY_NAME:latest \
--file memgraph_deb.dockerfile \
--push .

View File

@@ -204,8 +204,6 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
# release flags
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -pthread")
#debug flags
set(PREFERRED_DEBUGGER "gdb" CACHE STRING
"Tunes the debug output for your preferred debugger (gdb or lldb).")

View File

@@ -1 +1 @@
* @antaljanosbenjamin @kostasrim
* @gitbuda @antonio2368 @antaljanosbenjamin @kostasrim @jbajic

View File

@@ -54,18 +54,6 @@ Memgraph is implemented in C/C++ and leverages an in-memory first architecture
to ensure that youre getting the best possible performance consistently and
without surprises. Its also ACID-compliant and highly available.
## :video_game: Memgraph Playground
You don't need to install anything to try out Memgraph. Check out
our **[Memgraph Playground](https://playground.memgraph.com/)** sandboxes in
your browser.
<p align="left">
<a href="https://playground.memgraph.com/">
<img width="450px" alt="Memgraph Playground" src="https://download.memgraph.com/asset/github/memgraph/memgraph-playground.png">
</a>
</p>
## :floppy_disk: Download & Install
### Windows

View File

@@ -11,7 +11,7 @@ TOOLCHAIN_BUILD_DEPS=(
gnupg2 # used for archive signature verification
tar gzip bzip2 xz unzip # used for archive unpacking
zlib-devel # zlib library used for all builds
expat-devel libipt libipt-devel libbabeltrace-devel xz-devel python3-devel # gdb
expat-devel libipt-devel libbabeltrace-devel xz-devel python3-devel # gdb
texinfo # gdb
libcurl-devel # cmake
curl # snappy
@@ -22,7 +22,6 @@ TOOLCHAIN_BUILD_DEPS=(
openssl-devel
gmp-devel
gperf
patch
)
TOOLCHAIN_RUN_DEPS=(
@@ -106,7 +105,7 @@ install() {
https://repo.ius.io/ius-release-el7.rpm
yum update -y
yum install -y wget python3 python3-pip
yum install -y git
yum install -y git224
for pkg in $1; do
if [ "$pkg" == libipt ]; then
if ! yum list installed libipt >/dev/null 2>/dev/null; then

View File

@@ -6,12 +6,12 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source "$DIR/../util.sh"
TOOLCHAIN_BUILD_DEPS=(
coreutils-common gcc gcc-c++ make # generic build tools
coreutils gcc gcc-c++ make # generic build tools
wget # used for archive download
gnupg2 # used for archive signature verification
tar gzip bzip2 xz unzip # used for archive unpacking
zlib-devel # zlib library used for all builds
expat-devel libipt libipt-devel libbabeltrace-devel xz-devel python36-devel texinfo # for gdb
expat-devel libipt-devel libbabeltrace-devel xz-devel python36-devel texinfo # for gdb
libcurl-devel # for cmake
curl # snappy
readline-devel # for cmake and llvm
@@ -21,7 +21,6 @@ TOOLCHAIN_BUILD_DEPS=(
openssl-devel
gmp-devel
gperf
patch
)
TOOLCHAIN_RUN_DEPS=(
@@ -117,10 +116,9 @@ install() {
# https://centos.pkgs.org
# Since 2020, there is Babeltrace2 (https://babeltrace.org). Not used
# within GDB yet (an assumption).
# http://mirror.centos.org/centos/8/PowerTools/x86_64/os/Packages/libbabeltrace-devel-1.5.4-3.el8.x86_64.rpm not working
if [ "$pkg" == libbabeltrace-devel ]; then
if ! dnf list installed libbabeltrace-devel >/dev/null 2>/dev/null; then
dnf install -y https://rpmfind.net/linux/centos/8-stream/PowerTools/x86_64/os/Packages/libbabeltrace-devel-1.5.4-3.el8.x86_64.rpm
dnf install -y http://mirror.centos.org/centos/8/PowerTools/x86_64/os/Packages/libbabeltrace-devel-1.5.4-3.el8.x86_64.rpm
fi
continue
fi

View File

@@ -1,104 +0,0 @@
#!/bin/bash
set -Eeuo pipefail
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
source "$DIR/../util.sh"
TOOLCHAIN_BUILD_DEPS=(
coreutils gcc g++ build-essential make # generic build tools
wget # used for archive download
gnupg # used for archive signature verification
tar gzip bzip2 xz-utils unzip # used for archive unpacking
zlib1g-dev # zlib library used for all builds
libexpat1-dev liblzma-dev python3-dev texinfo # for gdb
libcurl4-openssl-dev # for cmake
libreadline-dev # for cmake and llvm
libffi-dev libxml2-dev # for llvm
libedit-dev libpcre3-dev automake bison # for swig
curl # snappy
file # for libunwind
libssl-dev # for libevent
libgmp-dev
gperf # for proxygen
git # for fbthrift
)
TOOLCHAIN_RUN_DEPS=(
make # generic build tools
tar gzip bzip2 xz-utils # used for archive unpacking
zlib1g # zlib library used for all builds
libexpat1 liblzma5 python3 # for gdb
libcurl4 # for cmake
file # for CPack
libreadline8 # for cmake and llvm
libffi7 libxml2 # for llvm
libssl-dev # for libevent
)
MEMGRAPH_BUILD_DEPS=(
git # source code control
make pkg-config # build system
curl wget # for downloading libs
uuid-dev default-jre-headless # required by antlr
libreadline-dev # for memgraph console
libpython3-dev python3-dev # for query modules
libssl-dev
libseccomp-dev
netcat # tests are using nc to wait for memgraph
python3 virtualenv python3-virtualenv python3-pip # for qa, macro_benchmark and stress tests
python3-yaml # for the configuration generator
libcurl4-openssl-dev # mg-requests
sbcl # for custom Lisp C++ preprocessing
doxygen graphviz # source documentation generators
mono-runtime mono-mcs zip unzip default-jdk-headless # for driver tests
golang nodejs npm
autoconf # for jemalloc code generation
libtool # for protobuf code generation
)
list() {
echo "$1"
}
check() {
check_all_dpkg "$1"
}
install() {
cat >/etc/apt/sources.list <<EOF
deb http://deb.debian.org/debian bullseye main
deb-src http://deb.debian.org/debian bullseye main
deb http://deb.debian.org/debian-security/ bullseye-security main
deb-src http://deb.debian.org/debian-security/ bullseye-security main
deb http://deb.debian.org/debian bullseye-updates main
deb-src http://deb.debian.org/debian bullseye-updates main
EOF
cd "$DIR"
apt update
# If GitHub Actions runner is installed, append LANG to the environment.
# Python related tests doesn't work the LANG export.
if [ -d "/home/gh/actions-runner" ]; then
echo "LANG=en_US.utf8" >> /home/gh/actions-runner/.env
else
echo "NOTE: export LANG=en_US.utf8"
fi
apt install -y wget
for pkg in $1; do
if [ "$pkg" == dotnet-sdk-3.1 ]; then
if ! dpkg -s "$pkg" 2>/dev/null >/dev/null; then
wget -nv https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
dpkg -i packages-microsoft-prod.deb
apt-get update
apt-get install -y apt-transport-https dotnet-sdk-3.1
fi
continue
fi
apt install -y "$pkg"
done
}
deps=$2"[*]"
"$1" "${!deps}"

View File

@@ -0,0 +1,2 @@
31d30
< add_subdirectory(logging/example)

View File

@@ -1,41 +0,0 @@
diff -ur a/folly/CMakeLists.txt b/folly/CMakeLists.txt
--- a/folly/CMakeLists.txt 2021-12-12 23:10:42.000000000 +0100
+++ b/folly/CMakeLists.txt 2022-02-03 15:19:41.349693134 +0100
@@ -28,7 +28,6 @@
)
add_subdirectory(experimental/exception_tracer)
-add_subdirectory(logging/example)
if (PYTHON_EXTENSIONS)
# Create tree of symbolic links in structure required for successful
diff -ur a/folly/experimental/exception_tracer/ExceptionTracerLib.cpp b/folly/experimental/exception_tracer/ExceptionTracerLib.cpp
--- a/folly/experimental/exception_tracer/ExceptionTracerLib.cpp 2021-12-12 23:10:42.000000000 +0100
+++ b/folly/experimental/exception_tracer/ExceptionTracerLib.cpp 2022-02-03 15:19:11.003368891 +0100
@@ -96,6 +96,7 @@
#define __builtin_unreachable()
#endif
+#if 0
namespace __cxxabiv1 {
void __cxa_throw(
@@ -154,5 +155,5 @@
}
} // namespace std
-
+#endif
#endif // defined(__GLIBCXX__)
diff -ur a/folly/Portability.h b/folly/Portability.h
--- a/folly/Portability.h 2021-12-12 23:10:42.000000000 +0100
+++ b/folly/Portability.h 2022-02-03 15:19:11.003368891 +0100
@@ -566,7 +566,7 @@
#define FOLLY_HAS_COROUTINES 0
#elif (__cpp_coroutines >= 201703L || __cpp_impl_coroutine >= 201902L) && \
(__has_include(<coroutine>) || __has_include(<experimental/coroutine>))
-#define FOLLY_HAS_COROUTINES 1
+#define FOLLY_HAS_COROUTINES 0
// This is mainly to workaround bugs triggered by LTO, when stack allocated
// variables in await_suspend end up on a coroutine frame.
#define FOLLY_CORO_AWAIT_SUSPEND_NONTRIVIAL_ATTRIBUTES FOLLY_NOINLINE

View File

@@ -0,0 +1,2 @@
24d23
< find_dependency(mvfst)

View File

@@ -1,11 +0,0 @@
diff -ur a/cmake/proxygen-config.cmake.in b/cmake/proxygen-config.cmake.in
--- a/cmake/proxygen-config.cmake.in 2021-12-13 02:37:05.000000000 +0100
+++ b/cmake/proxygen-config.cmake.in 2022-01-27 17:14:28.284810621 +0100
@@ -21,7 +21,6 @@
find_dependency(folly)
find_dependency(wangle)
find_dependency(Fizz)
-find_dependency(mvfst)
# For now, anything that depends on Proxygen has to copy its FindZstd.cmake
# and issue a `find_package(Zstd)`. Uncommenting this won't work because
# this Zstd module exposes a library called `zstd`. The right fix is

View File

@@ -0,0 +1,16 @@
55,57c55,57
< # Disable RTTI.
< string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
< set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
---
> # # Disable RTTI.
> # string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
> # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
80,82c80,82
< # Disable RTTI.
< string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
< set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
---
> # # Disable RTTI.
> # string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
> # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")

View File

@@ -1,29 +0,0 @@
diff -ur a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt 2021-05-05 00:53:34.000000000 +0200
+++ b/CMakeLists.txt 2022-01-27 17:18:34.758302398 +0100
@@ -52,9 +52,9 @@
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHs-c-")
add_definitions(-D_HAS_EXCEPTIONS=0)
- # Disable RTTI.
- string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
+ # # Disable RTTI.
+ # string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# Use -Wall for clang and gcc.
if(NOT CMAKE_CXX_FLAGS MATCHES "-Wall")
@@ -77,9 +77,9 @@
string(REGEX REPLACE "-fexceptions" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
- # Disable RTTI.
- string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
+ # # Disable RTTI.
+ # string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make

View File

@@ -538,8 +538,7 @@ if [ ! -f $PREFIX/bin/clang ]; then
make -j$CPUS
if [[ "$for_arm" = false ]]; then
make -j$CPUS check-clang # run clang test suite
# ldd is not used
# make -j$CPUS check-lld # run lld test suite
make -j$CPUS check-lld # run lld test suite
fi
make install
popd && popd
@@ -1030,7 +1029,7 @@ if [ ! -f $PREFIX/include/snappy.h ]; then
fi
tar -xzf ../archives/snappy-$SNAPPY_VERSION.tar.gz
pushd snappy-$SNAPPY_VERSION
patch -p1 < ../../snappy.patch
patch CMakeLists.txt ../../snappy.diff
mkdir build
pushd build
cmake .. $COMMON_CMAKE_FLAGS \
@@ -1072,7 +1071,7 @@ if [ ! -d $PREFIX/include/folly ]; then
mkdir folly-$FBLIBS_VERSION
tar -xzf ../archives/folly-$FBLIBS_VERSION.tar.gz -C folly-$FBLIBS_VERSION
pushd folly-$FBLIBS_VERSION
patch -p1 < ../../folly.patch
patch folly/CMakeLists.txt ../../folly.diff
# build is used by facebook builder
mkdir _build
pushd _build
@@ -1131,7 +1130,7 @@ if [ ! -d $PREFIX/include/proxygen ]; then
mkdir proxygen-$FBLIBS_VERSION
tar -xzf ../archives/proxygen-$FBLIBS_VERSION.tar.gz -C proxygen-$FBLIBS_VERSION
pushd proxygen-$FBLIBS_VERSION
patch -p1 < ../../proxygen.patch
patch cmake/proxygen-config.cmake.in ../../proxygen.diff
# build is used by facebook builder
mkdir _build
pushd _build
@@ -1178,13 +1177,7 @@ popd
# create toolchain archive
if [ ! -f $NAME-binaries-$DISTRO.tar.gz ]; then
DISTRO_FULL_NAME=$DISTRO
if [ "$for_arm" = true ]; then
DISTRO_FULL_NAME="$DISTRO_FULL_NAME-aarch64"
else
DISTRO_FULL_NAME="$DISTRO_FULL_NAME-x86_64"
fi
tar --owner=root --group=root -cpvzf $NAME-binaries-$DISTRO_FULL_NAME.tar.gz -C /opt $NAME
tar --owner=root --group=root -cpvzf $NAME-binaries-$DISTRO.tar.gz -C /opt $NAME
fi
# output final instructions

View File

@@ -5,10 +5,6 @@ operating_system() {
sort | cut -d '=' -f 2- | sed 's/"//g' | paste -s -d '-'
}
architecture() {
uname -m
}
check_all_yum() {
local missing=""
for pkg in $1; do

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -549,8 +549,6 @@ enum mgp_error mgp_path_equal(struct mgp_path *p1, struct mgp_path *p2, int *res
struct mgp_result;
/// Represents a record of resulting field values.
struct mgp_result_record;
/// Represents a return type for magic functions
struct mgp_func_result;
/// Set the error as the result of the procedure.
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE ff there's no memory for copying the error message.
@@ -1292,9 +1290,6 @@ struct mgp_module;
/// Describes a procedure of a query module.
struct mgp_proc;
/// Describes a Memgraph magic function.
struct mgp_func;
/// Entry-point for a query module read procedure, invoked through openCypher.
///
/// Passed in arguments will not live longer than the callback's execution.
@@ -1507,84 +1502,6 @@ typedef void (*mgp_trans_cb)(struct mgp_messages *, struct mgp_graph *, struct m
enum mgp_error mgp_module_add_transformation(struct mgp_module *module, const char *name, mgp_trans_cb cb);
/// @}
/// @name Memgraph Magic Functions API
///
/// API for creating the Memgraph magic functions. It is used to create external-source stateless methods which can
/// be called by using openCypher query language. These methods should not modify the original graph and should use only
/// the values provided as arguments to the method.
///
///@{
/// Add a required argument to a function.
///
/// The order of the added arguments corresponds to the signature of the openCypher function.
/// Note, that required arguments are followed by optional arguments.
///
/// The `name` must be a valid identifier, following the same rules as the
/// function `name` in mgp_module_add_function.
///
/// Passed in `type` describes what kind of values can be used as the argument.
///
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for an argument.
/// Return MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid argument name.
/// Return MGP_ERROR_LOGIC_ERROR if the function already has any optional argument.
enum mgp_error mgp_func_add_arg(struct mgp_func *func, const char *name, struct mgp_type *type);
/// Add an optional argument with a default value to a function.
///
/// The order of the added arguments corresponds to the signature of the openCypher function.
/// Note, that required arguments are followed by optional arguments.
///
/// The `name` must be a valid identifier, following the same rules as the
/// function `name` in mgp_module_add_function.
///
/// Passed in `type` describes what kind of values can be used as the argument.
///
/// `default_value` is copied and set as the default value for the argument.
/// Don't forget to call mgp_value_destroy when you are done using
/// `default_value`. When the function is called, if this argument is not
/// provided, `default_value` will be used instead. `default_value` must not be
/// a graph element (node, relationship, path) and it must satisfy the given
/// `type`.
///
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for an argument.
/// Return MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid argument name.
/// Return MGP_ERROR_VALUE_CONVERSION if `default_value` is a graph element (vertex, edge or path).
/// Return MGP_ERROR_LOGIC_ERROR if `default_value` does not satisfy `type`.
enum mgp_error mgp_func_add_opt_arg(struct mgp_func *func, const char *name, struct mgp_type *type,
struct mgp_value *default_value);
/// Entry-point for a custom Memgraph awesome function.
///
/// Passed in arguments will not live longer than the callback's execution.
/// Therefore, you must not store them globally or use the passed in mgp_memory
/// to allocate global resources.
typedef void (*mgp_func_cb)(struct mgp_list *, struct mgp_func_context *, struct mgp_func_result *,
struct mgp_memory *);
/// Register a Memgraph magic function
///
/// The `name` must be a sequence of digits, underscores, lowercase and
/// uppercase Latin letters. The name must begin with a non-digit character.
/// Note that Unicode characters are not allowed.
///
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory for mgp_func.
/// Return MGP_ERROR_INVALID_ARGUMENT if `name` is not a valid function name.
/// RETURN MGP_ERROR_LOGIC_ERROR if a function with the same name was already registered.
enum mgp_error mgp_module_add_function(struct mgp_module *module, const char *name, mgp_func_cb cb,
struct mgp_func **result);
/// Set an error message as an output to the Magic function
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if there's no memory for copying the error message.
enum mgp_error mgp_func_result_set_error_msg(struct mgp_func_result *result, const char *error_msg,
struct mgp_memory *memory);
/// Set an output value for the Magic function
/// Return MGP_ERROR_UNABLE_TO_ALLOCATE if unable to allocate memory to copy the mgp_value to mgp_func_result.
enum mgp_error mgp_func_result_set_value(struct mgp_func_result *result, struct mgp_value *value,
struct mgp_memory *memory);
/// @}
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -40,7 +40,6 @@ class InvalidContextError(Exception):
"""
Signals using a graph element instance outside of the registered procedure.
"""
pass
@@ -48,7 +47,6 @@ class UnknownError(_mgp.UnknownError):
"""
Signals unspecified failure.
"""
pass
@@ -56,7 +54,6 @@ class UnableToAllocateError(_mgp.UnableToAllocateError):
"""
Signals failed memory allocation.
"""
pass
@@ -64,7 +61,6 @@ class InsufficientBufferError(_mgp.InsufficientBufferError):
"""
Signals that some buffer is not big enough.
"""
pass
@@ -73,7 +69,6 @@ class OutOfRangeError(_mgp.OutOfRangeError):
Signals that an index-like parameter has a value that is outside its
possible values.
"""
pass
@@ -82,7 +77,6 @@ class LogicErrorError(_mgp.LogicErrorError):
Signals faulty logic within the program such as violating logical
preconditions or class invariants and may be preventable.
"""
pass
@@ -90,7 +84,6 @@ class DeletedObjectError(_mgp.DeletedObjectError):
"""
Signals accessing an already deleted object.
"""
pass
@@ -98,7 +91,6 @@ class InvalidArgumentError(_mgp.InvalidArgumentError):
"""
Signals that some of the arguments have invalid values.
"""
pass
@@ -106,7 +98,6 @@ class KeyAlreadyExistsError(_mgp.KeyAlreadyExistsError):
"""
Signals that a key already exists in a container-like object.
"""
pass
@@ -114,7 +105,6 @@ class ImmutableObjectError(_mgp.ImmutableObjectError):
"""
Signals modification of an immutable object.
"""
pass
@@ -122,7 +112,6 @@ class ValueConversionError(_mgp.ValueConversionError):
"""
Signals that the conversion failed between python and cypher values.
"""
pass
@@ -131,14 +120,12 @@ class SerializationError(_mgp.SerializationError):
Signals serialization error caused by concurrent modifications from
different transactions.
"""
pass
class Label:
"""Label of a Vertex."""
__slots__ = ("_name",)
__slots__ = ('_name',)
def __init__(self, name: str):
self._name = name
@@ -158,22 +145,19 @@ class Label:
# Named property value of a Vertex or an Edge.
# It would be better to use typing.NamedTuple with typed fields, but that is
# not available in Python 3.5.
Property = namedtuple("Property", ("name", "value"))
Property = namedtuple('Property', ('name', 'value'))
class Properties:
"""
A collection of properties either on a Vertex or an Edge.
"""
__slots__ = (
"_vertex_or_edge",
"_len",
)
__slots__ = ('_vertex_or_edge', '_len',)
def __init__(self, vertex_or_edge):
if not isinstance(vertex_or_edge, (_mgp.Vertex, _mgp.Edge)):
raise TypeError("Expected '_mgp.Vertex' or '_mgp.Edge', got {}".format(type(vertex_or_edge)))
raise TypeError("Expected '_mgp.Vertex' or '_mgp.Edge', \
got {}".format(type(vertex_or_edge)))
self._len = None
self._vertex_or_edge = vertex_or_edge
@@ -346,8 +330,7 @@ class Properties:
class EdgeType:
"""Type of an Edge."""
__slots__ = ("_name",)
__slots__ = ('_name',)
def __init__(self, name):
self._name = name
@@ -365,7 +348,7 @@ class EdgeType:
if sys.version_info >= (3, 5, 2):
EdgeId = typing.NewType("EdgeId", int)
EdgeId = typing.NewType('EdgeId', int)
else:
EdgeId = int
@@ -377,12 +360,12 @@ class Edge:
a query. You should not globally store an instance of an Edge. Using an
invalid Edge instance will raise InvalidContextError.
"""
__slots__ = ("_edge",)
__slots__ = ('_edge',)
def __init__(self, edge):
if not isinstance(edge, _mgp.Edge):
raise TypeError("Expected '_mgp.Edge', got '{}'".format(type(edge)))
raise TypeError(
"Expected '_mgp.Edge', got '{}'".format(type(edge)))
self._edge = edge
def __deepcopy__(self, memo):
@@ -425,7 +408,7 @@ class Edge:
return EdgeType(self._edge.get_type_name())
@property
def from_vertex(self) -> "Vertex":
def from_vertex(self) -> 'Vertex':
"""
Get the source vertex.
@@ -436,7 +419,7 @@ class Edge:
return Vertex(self._edge.from_vertex())
@property
def to_vertex(self) -> "Vertex":
def to_vertex(self) -> 'Vertex':
"""
Get the destination vertex.
@@ -470,7 +453,7 @@ class Edge:
if sys.version_info >= (3, 5, 2):
VertexId = typing.NewType("VertexId", int)
VertexId = typing.NewType('VertexId', int)
else:
VertexId = int
@@ -482,12 +465,12 @@ class Vertex:
in a query. You should not globally store an instance of a Vertex. Using an
invalid Vertex instance will raise InvalidContextError.
"""
__slots__ = ("_vertex",)
__slots__ = ('_vertex',)
def __init__(self, vertex):
if not isinstance(vertex, _mgp.Vertex):
raise TypeError("Expected '_mgp.Vertex', got '{}'".format(type(vertex)))
raise TypeError(
"Expected '_mgp.Vertex', got '{}'".format(type(vertex)))
self._vertex = vertex
def __deepcopy__(self, memo):
@@ -530,7 +513,8 @@ class Vertex:
"""
if not self.is_valid():
raise InvalidContextError()
return tuple(Label(self._vertex.label_at(i)) for i in range(self._vertex.labels_count()))
return tuple(Label(self._vertex.label_at(i))
for i in range(self._vertex.labels_count()))
def add_label(self, label: str) -> None:
"""
@@ -631,8 +615,7 @@ class Vertex:
class Path:
"""Path containing Vertex and Edge instances."""
__slots__ = ("_path", "_vertices", "_edges")
__slots__ = ('_path', '_vertices', '_edges')
def __init__(self, starting_vertex_or_path: typing.Union[_mgp.Path, Vertex]):
"""Initialize with a starting Vertex.
@@ -653,7 +636,8 @@ class Path:
raise InvalidContextError()
self._path = _mgp.Path.make_with_start(vertex)
else:
raise TypeError("Expected '_mgp.Vertex' or '_mgp.Path', got '{}'".format(type(starting_vertex_or_path)))
raise TypeError("Expected '_mgp.Vertex' or '_mgp.Path', got '{}'"
.format(type(starting_vertex_or_path)))
def __copy__(self):
if not self.is_valid():
@@ -694,7 +678,8 @@ class Path:
extension.
"""
if not isinstance(edge, Edge):
raise TypeError("Expected '_mgp.Edge', got '{}'".format(type(edge)))
raise TypeError(
"Expected '_mgp.Edge', got '{}'".format(type(edge)))
if not self.is_valid() or not edge.is_valid():
raise InvalidContextError()
self._path.expand(edge._edge)
@@ -713,7 +698,8 @@ class Path:
raise InvalidContextError()
if self._vertices is None:
num_vertices = self._path.size() + 1
self._vertices = tuple(Vertex(self._path.vertex_at(i)) for i in range(num_vertices))
self._vertices = tuple(Vertex(self._path.vertex_at(i))
for i in range(num_vertices))
return self._vertices
@property
@@ -727,14 +713,14 @@ class Path:
raise InvalidContextError()
if self._edges is None:
num_edges = self._path.size()
self._edges = tuple(Edge(self._path.edge_at(i)) for i in range(num_edges))
self._edges = tuple(Edge(self._path.edge_at(i))
for i in range(num_edges))
return self._edges
class Record:
"""Represents a record of resulting field values."""
__slots__ = ("fields",)
__slots__ = ('fields',)
def __init__(self, **kwargs):
"""Initialize with name=value fields in kwargs."""
@@ -743,12 +729,12 @@ class Record:
class Vertices:
"""Iterable over vertices in a graph."""
__slots__ = ("_graph", "_len")
__slots__ = ('_graph', '_len')
def __init__(self, graph):
if not isinstance(graph, _mgp.Graph):
raise TypeError("Expected '_mgp.Graph', got '{}'".format(type(graph)))
raise TypeError(
"Expected '_mgp.Graph', got '{}'".format(type(graph)))
self._graph = graph
self._len = None
@@ -805,12 +791,12 @@ class Vertices:
class Graph:
"""State of the graph database in current ProcCtx."""
__slots__ = ("_graph",)
__slots__ = ('_graph',)
def __init__(self, graph):
if not isinstance(graph, _mgp.Graph):
raise TypeError("Expected '_mgp.Graph', got '{}'".format(type(graph)))
raise TypeError(
"Expected '_mgp.Graph', got '{}'".format(type(graph)))
self._graph = graph
def __deepcopy__(self, memo):
@@ -899,7 +885,8 @@ class Graph:
raise InvalidContextError()
self._graph.detach_delete_vertex(vertex._vertex)
def create_edge(self, from_vertex: Vertex, to_vertex: Vertex, edge_type: EdgeType) -> None:
def create_edge(self, from_vertex: Vertex, to_vertex: Vertex,
edge_type: EdgeType) -> None:
"""
Create an edge.
@@ -912,7 +899,8 @@ class Graph:
"""
if not self.is_valid():
raise InvalidContextError()
return Edge(self._graph.create_edge(from_vertex._vertex, to_vertex._vertex, edge_type.name))
return Edge(self._graph.create_edge(from_vertex._vertex,
to_vertex._vertex, edge_type.name))
def delete_edge(self, edge: Edge) -> None:
"""
@@ -930,7 +918,6 @@ class Graph:
class AbortError(Exception):
"""Signals that the procedure was asked to abort its execution."""
pass
@@ -940,12 +927,12 @@ class ProcCtx:
Access to a ProcCtx is only valid during a single execution of a procedure
in a query. You should not globally store a ProcCtx instance.
"""
__slots__ = ("_graph",)
__slots__ = ('_graph',)
def __init__(self, graph):
if not isinstance(graph, _mgp.Graph):
raise TypeError("Expected '_mgp.Graph', got '{}'".format(type(graph)))
raise TypeError(
"Expected '_mgp.Graph', got '{}'".format(type(graph)))
self._graph = Graph(graph)
def is_valid(self) -> bool:
@@ -982,7 +969,8 @@ LocalDateTime = datetime.datetime
Duration = datetime.timedelta
Any = typing.Union[bool, str, Number, Map, Path, list, Date, LocalTime, LocalDateTime, Duration]
Any = typing.Union[bool, str, Number, Map, Path,
list, Date, LocalTime, LocalDateTime, Duration]
List = typing.List
@@ -1015,7 +1003,7 @@ def _typing_to_cypher_type(type_):
Date: _mgp.type_date(),
LocalTime: _mgp.type_local_time(),
LocalDateTime: _mgp.type_local_date_time(),
Duration: _mgp.type_duration(),
Duration: _mgp.type_duration()
}
try:
return simple_types[type_]
@@ -1033,14 +1021,14 @@ def _typing_to_cypher_type(type_):
if type(None) in type_args:
types = tuple(t for t in type_args if t is not type(None)) # noqa E721
if len(types) == 1:
(type_arg,) = types
type_arg, = types
else:
# We cannot do typing.Union[*types], so do the equivalent
# with __getitem__ which does not even need arg unpacking.
type_arg = typing.Union.__getitem__(types)
return _mgp.type_nullable(_typing_to_cypher_type(type_arg))
elif complex_type == list:
(type_arg,) = type_args
type_arg, = type_args
return _mgp.type_list(_typing_to_cypher_type(type_arg))
raise UnsupportedTypingError(type_)
else:
@@ -1050,17 +1038,13 @@ def _typing_to_cypher_type(type_):
# printed the same way. `typing.List[type]` is printed as such, while
# `typing.Optional[type]` is printed as 'typing.Union[type, NoneType]'
def parse_type_args(type_as_str):
return tuple(
map(
str.strip,
type_as_str[type_as_str.index("[") + 1 : -1].split(","),
)
)
return tuple(map(str.strip,
type_as_str[type_as_str.index('[') + 1: -1].split(',')))
def fully_qualified_name(cls):
if cls.__module__ is None or cls.__module__ == "builtins":
if cls.__module__ is None or cls.__module__ == 'builtins':
return cls.__name__
return cls.__module__ + "." + cls.__name__
return cls.__module__ + '.' + cls.__name__
def get_simple_type(type_as_str):
for simple_type, cypher_type in simple_types.items():
@@ -1076,26 +1060,28 @@ def _typing_to_cypher_type(type_):
pass
def parse_typing(type_as_str):
if type_as_str.startswith("typing.Union"):
if type_as_str.startswith('typing.Union'):
type_args_as_str = parse_type_args(type_as_str)
none_type_as_str = type(None).__name__
if none_type_as_str in type_args_as_str:
types = tuple(t for t in type_args_as_str if t != none_type_as_str)
types = tuple(
t for t in type_args_as_str if t != none_type_as_str)
if len(types) == 1:
(type_arg_as_str,) = types
type_arg_as_str, = types
else:
type_arg_as_str = "typing.Union[" + ", ".join(types) + "]"
type_arg_as_str = 'typing.Union[' + \
', '.join(types) + ']'
simple_type = get_simple_type(type_arg_as_str)
if simple_type is not None:
return _mgp.type_nullable(simple_type)
return _mgp.type_nullable(parse_typing(type_arg_as_str))
elif type_as_str.startswith("typing.List"):
elif type_as_str.startswith('typing.List'):
type_arg_as_str = parse_type_args(type_as_str)
if len(type_arg_as_str) > 1:
# Nested object could be a type consisting of a list of types (e.g. mgp.Map)
# so we need to join the parts.
type_arg_as_str = ", ".join(type_arg_as_str)
type_arg_as_str = ', '.join(type_arg_as_str)
else:
type_arg_as_str = type_arg_as_str[0]
@@ -1110,11 +1096,9 @@ def _typing_to_cypher_type(type_):
# Procedure registration
class Deprecated:
"""Annotate a resulting Record's field as deprecated."""
__slots__ = ("field_type",)
__slots__ = ('field_type',)
def __init__(self, type_):
self.field_type = type_
@@ -1122,7 +1106,8 @@ class Deprecated:
def raise_if_does_not_meet_requirements(func: typing.Callable[..., Record]):
if not callable(func):
raise TypeError("Expected a callable object, got an instance of '{}'".format(type(func)))
raise TypeError("Expected a callable object, got an instance of '{}'"
.format(type(func)))
if inspect.iscoroutinefunction(func):
raise TypeError("Callable must not be 'async def' function")
if sys.version_info >= (3, 6):
@@ -1132,25 +1117,24 @@ def raise_if_does_not_meet_requirements(func: typing.Callable[..., Record]):
raise NotImplementedError("Generator functions are not supported")
def _register_proc(func: typing.Callable[..., Record], is_write: bool):
def _register_proc(func: typing.Callable[..., Record],
is_write: bool):
raise_if_does_not_meet_requirements(func)
register_func = _mgp.Module.add_write_procedure if is_write else _mgp.Module.add_read_procedure
register_func = (
_mgp.Module.add_write_procedure if is_write
else _mgp.Module.add_read_procedure)
sig = inspect.signature(func)
params = tuple(sig.parameters.values())
if params and params[0].annotation is ProcCtx:
@wraps(func)
def wrapper(graph, args):
return func(ProcCtx(graph), *args)
params = params[1:]
mgp_proc = register_func(_mgp._MODULE, wrapper)
else:
@wraps(func)
def wrapper(graph, args):
return func(*args)
mgp_proc = register_func(_mgp._MODULE, wrapper)
for param in params:
name = param.name
@@ -1165,7 +1149,8 @@ def _register_proc(func: typing.Callable[..., Record], is_write: bool):
if sig.return_annotation is not sig.empty:
record = sig.return_annotation
if not isinstance(record, Record):
raise TypeError("Expected '{}' to return 'mgp.Record', got '{}'".format(func.__name__, type(record)))
raise TypeError("Expected '{}' to return 'mgp.Record', got '{}'"
.format(func.__name__, type(record)))
for name, type_ in record.fields.items():
if isinstance(type_, Deprecated):
cypher_type = _typing_to_cypher_type(type_.field_type)
@@ -1272,22 +1257,20 @@ class InvalidMessageError(Exception):
"""
Signals using a message instance outside of the registered transformation.
"""
pass
SOURCE_TYPE_KAFKA = _mgp.SOURCE_TYPE_KAFKA
SOURCE_TYPE_PULSAR = _mgp.SOURCE_TYPE_PULSAR
class Message:
"""Represents a message from a stream."""
__slots__ = ("_message",)
__slots__ = ('_message',)
def __init__(self, message):
if not isinstance(message, _mgp.Message):
raise TypeError("Expected '_mgp.Message', got '{}'".format(type(message)))
raise TypeError(
"Expected '_mgp.Message', got '{}'".format(type(message)))
self._message = message
def __deepcopy__(self, memo):
@@ -1370,18 +1353,17 @@ class Message:
class InvalidMessagesError(Exception):
"""Signals using a messages instance outside of the registered transformation."""
pass
class Messages:
"""Represents a list of messages from a stream."""
__slots__ = ("_messages",)
__slots__ = ('_messages',)
def __init__(self, messages):
if not isinstance(messages, _mgp.Messages):
raise TypeError("Expected '_mgp.Messages', got '{}'".format(type(messages)))
raise TypeError(
"Expected '_mgp.Messages', got '{}'".format(type(messages)))
self._messages = messages
def __deepcopy__(self, memo):
@@ -1413,12 +1395,12 @@ class TransCtx:
Access to a TransCtx is only valid during a single execution of a transformation.
You should not globally store a TransCtx instance.
"""
__slots__ = "_graph"
__slots__ = ('_graph')
def __init__(self, graph):
if not isinstance(graph, _mgp.Graph):
raise TypeError("Expected '_mgp.Graph', got '{}'".format(type(graph)))
raise TypeError(
"Expected '_mgp.Graph', got '{}'".format(type(graph)))
self._graph = Graph(graph)
def is_valid(self) -> bool:
@@ -1438,76 +1420,21 @@ def transformation(func: typing.Callable[..., Record]):
params = tuple(sig.parameters.values())
if not params or not params[0].annotation is Messages:
if not len(params) == 2 or not params[1].annotation is Messages:
raise NotImplementedError("Valid signatures for transformations are (TransCtx, Messages) or (Messages)")
raise NotImplementedError(
"Valid signatures for transformations are (TransCtx, Messages) or (Messages)")
if params[0].annotation is TransCtx:
@wraps(func)
def wrapper(graph, messages):
return func(TransCtx(graph), messages)
_mgp._MODULE.add_transformation(wrapper)
else:
@wraps(func)
def wrapper(graph, messages):
return func(messages)
_mgp._MODULE.add_transformation(wrapper)
return func
class FuncCtx:
"""Context of a function being executed.
Access to a FuncCtx is only valid during a single execution of a transformation.
You should not globally store a FuncCtx instance.
"""
__slots__ = "_graph"
def __init__(self, graph):
if not isinstance(graph, _mgp.Graph):
raise TypeError("Expected '_mgp.Graph', got '{}'".format(type(graph)))
self._graph = Graph(graph)
def is_valid(self) -> bool:
return self._graph.is_valid()
def function(func: typing.Callable):
raise_if_does_not_meet_requirements(func)
register_func = _mgp.Module.add_function
sig = inspect.signature(func)
params = tuple(sig.parameters.values())
if params and params[0].annotation is FuncCtx:
@wraps(func)
def wrapper(graph, args):
return func(FuncCtx(graph), *args)
params = params[1:]
mgp_func = register_func(_mgp._MODULE, wrapper)
else:
@wraps(func)
def wrapper(graph, args):
return func(*args)
mgp_func = register_func(_mgp._MODULE, wrapper)
for param in params:
name = param.name
type_ = param.annotation
if type_ is param.empty:
type_ = object
cypher_type = _typing_to_cypher_type(type_)
if param.default is param.empty:
mgp_func.add_arg(name, cypher_type)
else:
mgp_func.add_opt_arg(name, cypher_type, param.default)
return func
def _wrap_exceptions():
def wrap_function(func):
@wraps(func)
@@ -1536,7 +1463,6 @@ def _wrap_exceptions():
raise ValueConversionError(e)
except _mgp.SerializationError as e:
raise SerializationError(e)
return wrapped_func
def wrap_prop_func(func):
@@ -1547,16 +1473,11 @@ def _wrap_exceptions():
if inspect.isfunction(obj):
setattr(cls, name, wrap_function(obj))
elif isinstance(obj, property):
setattr(
cls,
name,
property(
wrap_prop_func(obj.fget),
wrap_prop_func(obj.fset),
wrap_prop_func(obj.fdel),
obj.__doc__,
),
)
setattr(cls, name, property(
wrap_prop_func(obj.fget),
wrap_prop_func(obj.fset),
wrap_prop_func(obj.fdel),
obj.__doc__))
def defined_in_this_module(obj: object):
return getattr(obj, "__module__", "") == __name__

28
init
View File

@@ -65,14 +65,8 @@ else
fi
DISTRO=$(operating_system)
ARCHITECTURE=$(architecture)
if [ "${ARCHITECTURE}" = "arm64" ]; then
OS_SCRIPT=$DIR/environment/os/$DISTRO-arm.sh
else
OS_SCRIPT=$DIR/environment/os/$DISTRO.sh
fi
echo "ALL BUILD PACKAGES: $($OS_SCRIPT list MEMGRAPH_BUILD_DEPS)"
$OS_SCRIPT check MEMGRAPH_BUILD_DEPS
echo "ALL BUILD PACKAGES: $($DIR/environment/os/$DISTRO.sh list MEMGRAPH_BUILD_DEPS)"
$DIR/environment/os/$DISTRO.sh check MEMGRAPH_BUILD_DEPS
echo "All packages are in-place..."
# create a default build directory
@@ -111,10 +105,22 @@ if [[ "$setup_libs" == "true" ]]; then
cd ..
fi
# setup gql_behave dependencies
setup_virtualenv tests/gql_behave
# setup stress dependencies
setup_virtualenv tests/stress
# setup integration/ldap dependencies
setup_virtualenv tests/integration/ldap
# Setup tests dependencies.
cd tests
./setup.sh
cd ..
# cd tests
# ./setup.sh
# cd ..
# TODO(gitbuda): Remove setup_virtualenv, replace it with tests/ve3. Take care
# of the build order because tests/setup.py builds pymgclient which depends on
# mgclient which is build after this script by calling make.
echo "Done installing dependencies for Memgraph"

View File

@@ -107,22 +107,27 @@ declare -A primary_urls=(
["antlr4-code"]="http://$local_cache_host/git/antlr4.git"
["antlr4-generator"]="http://$local_cache_host/file/antlr-4.9.2-complete.jar"
["cppitertools"]="http://$local_cache_host/git/cppitertools.git"
["fmt"]="http://$local_cache_host/git/fmt.git"
["rapidcheck"]="http://$local_cache_host/git/rapidcheck.git"
["gbenchmark"]="http://$local_cache_host/git/benchmark.git"
["gtest"]="http://$local_cache_host/git/googletest.git"
["gflags"]="http://$local_cache_host/git/gflags.git"
["libbcrypt"]="http://$local_cache_host/git/libbcrypt.git"
["bzip2"]="http://$local_cache_host/git/bzip2.git"
["zlib"]="http://$local_cache_host/git/zlib.git"
["rocksdb"]="http://$local_cache_host/git/rocksdb.git"
["mgclient"]="http://$local_cache_host/git/mgclient.git"
["pymgclient"]="http://$local_cache_host/git/pymgclient.git"
["mgconsole"]="http://$local_cache_host/git/mgconsole.git"
["spdlog"]="http://$local_cache_host/git/spdlog"
["jemalloc"]="http://$local_cache_host/git/jemalloc.git"
["nlohmann"]="http://$local_cache_host/file/nlohmann/json/4f8fba14066156b73f1189a2b8bd568bde5284c5/single_include/nlohmann/json.hpp"
["neo4j"]="http://$local_cache_host/file/neo4j-community-3.2.3-unix.tar.gz"
["librdkafka"]="http://$local_cache_host/git/librdkafka.git"
["protobuf"]="http://$local_cache_host/git/protobuf.git"
["boost"]="http://$local_cache_host/file/boost_1_77_0.tar.gz"
["pulsar"]="http://$local_cache_host/git/pulsar.git"
["librdtsc"]="http://$local_cache_host/git/librdtsc.git"
["gqlalchemy"]="http://$local_cache_host/git/gqlalchemy.git"
)
# The goal of secondary urls is to have links to the "source of truth" of
@@ -133,22 +138,27 @@ declare -A secondary_urls=(
["antlr4-code"]="https://github.com/antlr/antlr4.git"
["antlr4-generator"]="http://www.antlr.org/download/antlr-4.9.2-complete.jar"
["cppitertools"]="https://github.com/ryanhaining/cppitertools.git"
["fmt"]="https://github.com/fmtlib/fmt.git"
["rapidcheck"]="https://github.com/emil-e/rapidcheck.git"
["gbenchmark"]="https://github.com/google/benchmark.git"
["gtest"]="https://github.com/google/googletest.git"
["gflags"]="https://github.com/memgraph/gflags.git"
["libbcrypt"]="https://github.com/rg3/libbcrypt"
["bzip2"]="https://github.com/VFR-maniac/bzip2"
["zlib"]="https://github.com/madler/zlib.git"
["rocksdb"]="https://github.com/facebook/rocksdb.git"
["mgclient"]="https://github.com/memgraph/mgclient.git"
["pymgclient"]="https://github.com/memgraph/pymgclient.git"
["mgconsole"]="http://github.com/memgraph/mgconsole.git"
["spdlog"]="https://github.com/gabime/spdlog"
["jemalloc"]="https://github.com/jemalloc/jemalloc.git"
["nlohmann"]="https://raw.githubusercontent.com/nlohmann/json/4f8fba14066156b73f1189a2b8bd568bde5284c5/single_include/nlohmann/json.hpp"
["neo4j"]="https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/neo4j-community-3.2.3-unix.tar.gz"
["librdkafka"]="https://github.com/edenhill/librdkafka.git"
["protobuf"]="https://github.com/protocolbuffers/protobuf.git"
["boost"]="https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.tar.gz"
["pulsar"]="https://github.com/apache/pulsar.git"
["librdtsc"]="https://github.com/gabrieleara/librdtsc.git"
["gqlalchemy"]="http://github.com/memgraph/gqlalchemy.git"
)
# antlr
@@ -201,8 +211,8 @@ git apply ../rocksdb.patch
popd
# mgclient
mgclient_tag="v1.3.0" # (2022-02-08)
repo_clone_try_double "${primary_urls[mgclient]}" "${secondary_urls[mgclient]}" "mgclient" "$mgclient_tag"
mgclient_tag="v1.3.0" # (2021-09-23)
repo_clone_try_double "${primary_urls[mgclient]}" "${secondary_urls[mgclient]}" "mgclient" "$mgclient_tag" true
sed -i 's/\${CMAKE_INSTALL_LIBDIR}/lib/' mgclient/src/CMakeLists.txt
# pymgclient
@@ -240,10 +250,3 @@ repo_clone_try_double "${primary_urls[librdtsc]}" "${secondary_urls[librdtsc]}"
pushd librdtsc
git apply ../librdtsc.patch
popd
#gqlalchemy
gqlalchemy_tag="v1.2.0"
repo_clone_try_double "${primary_urls[gqlalchemy]}" "${secondary_urls[gqlalchemy]}" "gqlalchemy" "$gqlalchemy_tag" true
pushd gqlalchemy
git apply ../gqlalchemy.patch
popd

View File

@@ -36,7 +36,7 @@ ADDITIONAL USE GRANT: You may use the Licensed Work in accordance with the
3. using the Licensed Work to create a work or solution
which competes (or might reasonably be expected to
compete) with the Licensed Work.
CHANGE DATE: 2026-18-02
CHANGE DATE: 2025-12-08
CHANGE LICENSE: Apache License, Version 2.0
For information about alternative licensing arrangements, please visit: https://memgraph.com/legal.

View File

@@ -10,14 +10,6 @@ set(CPACK_PACKAGE_VENDOR "Memgraph Ltd.")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY
"High performance, in-memory, transactional graph database")
# Setting arhitecture extension for deb packages
set(MG_ARCH_EXTENSION_DEB "all")
if (${MG_ARCH} STREQUAL "x86_64")
set(MG_ARCH_EXTENSION_DEB "amd64")
elseif (${MG_ARCH} STREQUAL "ARM64")
set(MG_ARCH_EXTENSION_DEB "arm64")
endif()
# DEB specific
# Instead of using "name <email>" format, we use "email (name)" to prevent
# errors due to full stop, '.' at the end of "Ltd". (See: RFC 822)
@@ -25,7 +17,7 @@ set(CPACK_DEBIAN_PACKAGE_MAINTAINER "tech@memgraph.com (Memgraph Ltd.)")
set(CPACK_DEBIAN_PACKAGE_SECTION non-free/database)
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE https://memgraph.com)
set(CPACK_DEBIAN_PACKAGE_VERSION "${MEMGRAPH_VERSION_DEB}")
set(CPACK_DEBIAN_FILE_NAME "memgraph_${MEMGRAPH_VERSION_DEB}_${MG_ARCH_EXTENSION_DEB}.deb")
set(CPACK_DEBIAN_FILE_NAME "memgraph_${MEMGRAPH_VERSION_DEB}_amd64.deb")
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
"${CMAKE_CURRENT_SOURCE_DIR}/debian/conffiles;"
"${CMAKE_CURRENT_SOURCE_DIR}/debian/copyright;"
@@ -43,18 +35,19 @@ set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
# We also depend on `python3` because we embed it in Memgraph.
set(CPACK_DEBIAN_PACKAGE_DEPENDS "openssl (>= 1.1.0), python3 (>= 3.5.0)")
# Setting arhitecture extension for rpm packages
set(MG_ARCH_EXTENSION_RPM "noarch")
# RPM specific
set(MG_ARCH_EXTENSION "noarch")
if (${MG_ARCH} STREQUAL "x86_64")
set(MG_ARCH_EXTENSION_RPM "x86_64")
set(MG_ARCH_EXTENSION "x86_64")
elseif (${MG_ARCH} STREQUAL "ARM64")
set(MG_ARCH_EXTENSION_RPM "aarch64")
set(MG_ARCH_EXTENSION "aarch64")
endif()
# RPM specific
set(CPACK_RPM_PACKAGE_URL https://memgraph.com)
set(CPACK_RPM_PACKAGE_VERSION "${MEMGRAPH_VERSION_RPM}")
set(CPACK_RPM_FILE_NAME "memgraph-${MEMGRAPH_VERSION_RPM}-1.${MG_ARCH_EXTENSION_RPM}.rpm")
set(CPACK_RPM_FILE_NAME "memgraph-${MEMGRAPH_VERSION_RPM}-1.${MG_ARCH_EXTENSION}.rpm")
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
/var /var/lib /var/log /etc/logrotate.d
/lib /lib/systemd /lib/systemd/system /lib/systemd/system/memgraph.service)

View File

@@ -1,21 +1,19 @@
FROM debian:bullseye
# NOTE: If you change the base distro update release/package as well.
ARG BINARY_NAME
ARG EXTENSION
ARG TARGETARCH
ARG release
RUN apt-get update && apt-get install -y \
openssl libcurl4 libssl1.1 libseccomp2 python3 libpython3.9 python3-pip \
--no-install-recommends \
openssl libcurl4 libssl1.1 libseccomp2 python3 libpython3.9 python3-pip \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN pip3 install networkx==2.4 numpy==1.21.4 scipy==1.7.3
COPY "${BINARY_NAME}${TARGETARCH}.${EXTENSION}" /
COPY ${release} /
# Install memgraph package
RUN dpkg -i "${BINARY_NAME}${TARGETARCH}.deb"
RUN dpkg -i ${release}
# Memgraph listens for Bolt Protocol on this port by default.
EXPOSE 7687

View File

@@ -55,10 +55,7 @@ image_name="memgraph:${version}"
image_package_name="memgraph-${version}-docker.tar.gz"
# Build docker image.
docker build -t ${image_name} ${tag_latest} -f ${dockerfile_path} \
--build-arg BINARY_NAME=${package_name} \
--build-arg EXTENSION=${extension} \
--build-arg TARGETARCH="" .
docker build -t ${image_name} ${tag_latest} -f ${dockerfile_path} --build-arg release=${package_name}.${extension} .
docker save ${image_name} ${latest_image} | gzip > ${image_package_name}
rm "${package_name}.${extension}"
echo "Built Docker image at '${working_dir}/${image_package_name}'"

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
@@ -18,7 +18,7 @@
#include "utils/logging.hpp"
#include "utils/string.hpp"
namespace memgraph::audit {
namespace audit {
// Helper function that converts a `storage::PropertyValue` to `nlohmann::json`.
inline nlohmann::json PropertyValueToJson(const storage::PropertyValue &pv) {
@@ -143,4 +143,4 @@ void Log::Flush() {
log_.Sync();
}
} // namespace memgraph::audit
} // namespace audit

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
@@ -17,7 +17,7 @@
#include "utils/file.hpp"
#include "utils/scheduler.hpp"
namespace memgraph::audit {
namespace audit {
const uint64_t kBufferSizeDefault = 100000;
const uint64_t kBufferFlushIntervalMillisDefault = 200;
@@ -71,4 +71,4 @@ class Log {
std::mutex lock_;
};
} // namespace memgraph::audit
} // namespace audit

View File

@@ -11,7 +11,7 @@ find_package(gflags REQUIRED)
add_library(mg-auth STATIC ${auth_src_files})
target_link_libraries(mg-auth json libbcrypt gflags fmt::fmt)
target_link_libraries(mg-auth mg-utils mg-kvstore mg-license )
target_link_libraries(mg-auth mg-utils mg-kvstore)
target_link_libraries(mg-auth ${Seccomp_LIBRARIES})
target_include_directories(mg-auth SYSTEM PRIVATE ${Seccomp_INCLUDE_DIRS})

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
@@ -42,7 +42,8 @@ DEFINE_VALIDATED_int32(auth_module_timeout_ms, 10000,
"response from the auth module.",
FLAG_IN_RANGE(100, 1800000));
namespace memgraph::auth {
namespace auth {
const std::string kUserPrefix = "user:";
const std::string kRolePrefix = "role:";
const std::string kLinkPrefix = "link:";
@@ -315,4 +316,4 @@ std::vector<auth::User> Auth::AllUsersForRole(const std::string &rolename_orig)
return ret;
}
} // namespace memgraph::auth
} // namespace auth

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
@@ -18,7 +18,8 @@
#include "kvstore/kvstore.hpp"
#include "utils/settings.hpp"
namespace memgraph::auth {
namespace auth {
/**
* This class serves as the main Authentication/Authorization storage.
* It provides functions for managing Users, Roles and Permissions.
@@ -162,4 +163,4 @@ class Auth final {
kvstore::KVStore storage_;
auth::Module module_;
};
} // namespace memgraph::auth
} // namespace auth

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
@@ -12,7 +12,8 @@
#include "auth/exceptions.hpp"
namespace memgraph::auth {
namespace auth {
const std::string EncryptPassword(const std::string &password) {
char salt[BCRYPT_HASHSIZE];
char hash[BCRYPT_HASHSIZE];
@@ -39,4 +40,4 @@ bool VerifyPassword(const std::string &password, const std::string &hash) {
return ret == 0;
}
} // namespace memgraph::auth
} // namespace auth

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
@@ -10,11 +10,12 @@
#include <string>
namespace memgraph::auth {
namespace auth {
/// @throw AuthException if unable to encrypt the password.
const std::string EncryptPassword(const std::string &password);
/// @throw AuthException if unable to verify the password.
bool VerifyPassword(const std::string &password, const std::string &hash);
} // namespace memgraph::auth
} // namespace auth

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -13,7 +13,8 @@
#include "utils/exceptions.hpp"
namespace memgraph::auth {
namespace auth {
/**
* This exception class is thrown for all exceptions that can occur when dealing
* with the Auth library.
@@ -22,4 +23,4 @@ class AuthException : public utils::BasicException {
public:
using utils::BasicException::BasicException;
};
} // namespace memgraph::auth
} // namespace auth

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
@@ -22,23 +22,13 @@
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
DEFINE_bool(auth_password_permit_null, true, "Set to false to disable null passwords.");
inline constexpr std::string_view default_password_regex = ".+";
constexpr std::string_view default_password_regex = ".+";
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
DEFINE_string(auth_password_strength_regex, default_password_regex.data(),
"The regular expression that should be used to match the entire "
"entered password to ensure its strength.");
namespace memgraph::auth {
namespace {
// Constant list of all available permissions.
const std::vector<Permission> kPermissionsAll = {
Permission::MATCH, Permission::CREATE, Permission::MERGE, Permission::DELETE,
Permission::SET, Permission::REMOVE, Permission::INDEX, Permission::STATS,
Permission::CONSTRAINT, Permission::DUMP, Permission::AUTH, Permission::REPLICATION,
Permission::DURABILITY, Permission::READ_FILE, Permission::FREE_MEMORY, Permission::TRIGGER,
Permission::CONFIG, Permission::STREAM, Permission::MODULE_READ, Permission::MODULE_WRITE,
Permission::WEBSOCKET};
} // namespace
namespace auth {
std::string PermissionToString(Permission permission) {
switch (permission) {
@@ -78,12 +68,6 @@ std::string PermissionToString(Permission permission) {
return "AUTH";
case Permission::STREAM:
return "STREAM";
case Permission::MODULE_READ:
return "MODULE_READ";
case Permission::MODULE_WRITE:
return "MODULE_WRITE";
case Permission::WEBSOCKET:
return "WEBSOCKET";
}
}
@@ -302,4 +286,4 @@ bool operator==(const User &first, const User &second) {
return first.username_ == second.username_ && first.password_hash_ == second.password_hash_ &&
first.permissions_ == second.permissions_ && first.role_ == second.role_;
}
} // namespace memgraph::auth
} // namespace auth

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
@@ -13,35 +13,41 @@
#include <json/json.hpp>
namespace memgraph::auth {
namespace auth {
// These permissions must have values that are applicable for usage in a
// bitmask.
// clang-format off
enum class Permission : uint64_t {
MATCH = 1,
CREATE = 1U << 1U,
MERGE = 1U << 2U,
DELETE = 1U << 3U,
SET = 1U << 4U,
REMOVE = 1U << 5U,
INDEX = 1U << 6U,
STATS = 1U << 7U,
CONSTRAINT = 1U << 8U,
DUMP = 1U << 9U,
REPLICATION = 1U << 10U,
DURABILITY = 1U << 11U,
READ_FILE = 1U << 12U,
FREE_MEMORY = 1U << 13U,
TRIGGER = 1U << 14U,
CONFIG = 1U << 15U,
AUTH = 1U << 16U,
STREAM = 1U << 17U,
MODULE_READ = 1U << 18U,
MODULE_WRITE = 1U << 19U,
WEBSOCKET = 1U << 20U
MATCH = 1,
CREATE = 1U << 1U,
MERGE = 1U << 2U,
DELETE = 1U << 3U,
SET = 1U << 4U,
REMOVE = 1U << 5U,
INDEX = 1U << 6U,
STATS = 1U << 7U,
CONSTRAINT = 1U << 8U,
DUMP = 1U << 9U,
REPLICATION = 1U << 10U,
DURABILITY = 1U << 11U,
READ_FILE = 1U << 12U,
FREE_MEMORY = 1U << 13U,
TRIGGER = 1U << 14U,
CONFIG = 1U << 15U,
AUTH = 1U << 16U,
STREAM = 1U << 17U
};
// clang-format on
// Constant list of all available permissions.
const std::vector<Permission> kPermissionsAll = {Permission::MATCH, Permission::CREATE, Permission::MERGE,
Permission::DELETE, Permission::SET, Permission::REMOVE,
Permission::INDEX, Permission::STATS, Permission::CONSTRAINT,
Permission::DUMP, Permission::AUTH, Permission::REPLICATION,
Permission::DURABILITY, Permission::READ_FILE, Permission::FREE_MEMORY,
Permission::TRIGGER, Permission::CONFIG, Permission::STREAM};
// Function that converts a permission to its string representation.
std::string PermissionToString(Permission permission);
@@ -153,4 +159,4 @@ class User final {
};
bool operator==(const User &first, const User &second);
} // namespace memgraph::auth
} // namespace auth

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
@@ -153,7 +153,7 @@ int Target(void *arg) {
// process and something really bad could happen.
// Get a pointer to the passed arguments.
auto *ta = reinterpret_cast<memgraph::auth::TargetArguments *>(arg);
auto *ta = reinterpret_cast<auth::TargetArguments *>(arg);
// Redirect `stdin` to `/dev/null`.
int fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
@@ -312,7 +312,8 @@ nlohmann::json GetData(int fd, int timeout_millisec) {
} // namespace
namespace memgraph::auth {
namespace auth {
Module::Module(const std::filesystem::path &module_executable_path) {
if (!module_executable_path.empty()) {
module_executable_path_ = std::filesystem::absolute(module_executable_path);
@@ -446,4 +447,4 @@ void Module::Shutdown() {
Module::~Module() { Shutdown(); }
} // namespace memgraph::auth
} // namespace auth

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Licensed as a Memgraph Enterprise file under the Memgraph Enterprise
// License (the "License"); by using this file, you agree to be bound by the terms of the License, and you may not use
@@ -16,7 +16,8 @@
#include <json/json.hpp>
namespace memgraph::auth {
namespace auth {
struct TargetArguments {
std::filesystem::path module_executable_path;
int pipe_to_module{-1};
@@ -69,4 +70,4 @@ class Module final {
int pipe_from_module_[2] = {-1, -1};
};
} // namespace memgraph::auth
} // namespace auth

View File

@@ -2,10 +2,6 @@ find_package(fmt REQUIRED)
find_package(gflags REQUIRED)
set(communication_src_files
websocket/auth.cpp
websocket/server.cpp
websocket/listener.cpp
websocket/session.cpp
bolt/v1/value.cpp
buffer.cpp
client.cpp
@@ -13,10 +9,8 @@ set(communication_src_files
helpers.cpp
init.cpp)
find_package(Boost REQUIRED)
add_library(mg-communication STATIC ${communication_src_files})
target_link_libraries(mg-communication Boost::headers Threads::Threads mg-utils mg-io mg-auth fmt::fmt gflags)
target_link_libraries(mg-communication Threads::Threads mg-utils mg-io fmt::fmt gflags)
find_package(OpenSSL REQUIRED)
target_link_libraries(mg-communication ${OPENSSL_LIBRARIES})

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -21,7 +21,7 @@
#include "utils/exceptions.hpp"
#include "utils/logging.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
/// This exception is thrown whenever an error occurs during query execution
/// that isn't fatal (eg. mistyped query or some transient error occurred).
@@ -315,4 +315,4 @@ class Client final {
ChunkedEncoderBuffer<communication::ClientOutputStream> encoder_buffer_{output_stream_};
ClientEncoder<ChunkedEncoderBuffer<communication::ClientOutputStream>> encoder_{encoder_buffer_};
};
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -13,10 +13,10 @@
#include <cstdint>
namespace memgraph::communication::bolt {
namespace communication::bolt {
inline constexpr uint8_t kPreamble[4] = {0x60, 0x60, 0xB0, 0x17};
inline constexpr uint8_t kProtocol[4] = {0x00, 0x00, 0x00, 0x01};
static constexpr uint8_t kPreamble[4] = {0x60, 0x60, 0xB0, 0x17};
static constexpr uint8_t kProtocol[4] = {0x00, 0x00, 0x00, 0x01};
enum class Signature : uint8_t {
Noop = 0x00,
@@ -95,9 +95,9 @@ enum class Marker : uint8_t {
Struct16 = 0xDD,
};
inline constexpr uint8_t MarkerString = 0, MarkerList = 1, MarkerMap = 2;
inline constexpr Marker MarkerTiny[3] = {Marker::TinyString, Marker::TinyList, Marker::TinyMap};
inline constexpr Marker Marker8[3] = {Marker::String8, Marker::List8, Marker::Map8};
inline constexpr Marker Marker16[3] = {Marker::String16, Marker::List16, Marker::Map16};
inline constexpr Marker Marker32[3] = {Marker::String32, Marker::List32, Marker::Map32};
} // namespace memgraph::communication::bolt
static constexpr uint8_t MarkerString = 0, MarkerList = 1, MarkerMap = 2;
static constexpr Marker MarkerTiny[3] = {Marker::TinyString, Marker::TinyList, Marker::TinyMap};
static constexpr Marker Marker8[3] = {Marker::String8, Marker::List8, Marker::Map8};
static constexpr Marker Marker16[3] = {Marker::String16, Marker::List16, Marker::Map16};
static constexpr Marker Marker32[3] = {Marker::String32, Marker::List32, Marker::Map32};
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -14,22 +14,22 @@
#include <cstddef>
#include <cstdint>
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* Sizes related to the chunk defined in Bolt protocol.
*/
inline constexpr size_t kChunkHeaderSize = 2;
inline constexpr size_t kChunkMaxDataSize = 65535;
inline constexpr size_t kChunkWholeSize = kChunkHeaderSize + kChunkMaxDataSize;
static constexpr size_t kChunkHeaderSize = 2;
static constexpr size_t kChunkMaxDataSize = 65535;
static constexpr size_t kChunkWholeSize = kChunkHeaderSize + kChunkMaxDataSize;
/**
* Handshake size defined in the Bolt protocol.
*/
inline constexpr size_t kHandshakeSize = 20;
static constexpr size_t kHandshakeSize = 20;
inline constexpr uint16_t kSupportedVersions[] = {0x0100, 0x0400, 0x0401, 0x0403};
static constexpr uint16_t kSupportedVersions[] = {0x0100, 0x0400, 0x0401, 0x0403};
inline constexpr int kPullAll = -1;
inline constexpr int kPullLast = -1;
} // namespace memgraph::communication::bolt
static constexpr int kPullAll = -1;
static constexpr int kPullLast = -1;
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -20,7 +20,7 @@
#include "communication/bolt/v1/constants.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* This class is used as the return value of the GetChunk function of the
@@ -136,4 +136,4 @@ class ChunkedDecoderBuffer {
std::vector<uint8_t> data_;
size_t pos_{0};
};
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -22,7 +22,7 @@
#include "utils/logging.hpp"
#include "utils/temporal.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* Bolt Decoder.
@@ -591,4 +591,4 @@ class Decoder {
return true;
}
};
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -22,7 +22,7 @@ static_assert(std::is_same_v<std::uint8_t, char> || std::is_same_v<std::uint8_t,
"communication::bolt::Encoder requires uint8_t to be "
"implemented as char or unsigned char.");
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* Bolt BaseEncoder. Has public interfaces for writing Bolt encoded data.
@@ -273,4 +273,4 @@ class BaseEncoder {
}
};
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -18,7 +18,7 @@
#include "communication/bolt/v1/constants.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* @brief ChunkedEncoderBuffer
@@ -123,4 +123,4 @@ class ChunkedEncoderBuffer {
// Amount of data in chunk array.
size_t have_{0};
};
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -14,7 +14,7 @@
#include "communication/bolt/v1/codes.hpp"
#include "communication/bolt/v1/encoder/base_encoder.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* Bolt Client Encoder.
@@ -169,4 +169,4 @@ class ClientEncoder : private BaseEncoder<Buffer> {
return buffer_.Flush();
}
};
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -14,7 +14,7 @@
#include "communication/bolt/v1/codes.hpp"
#include "communication/bolt/v1/encoder/base_encoder.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* Bolt Encoder.
@@ -158,4 +158,4 @@ class Encoder : private BaseEncoder<Buffer> {
return buffer_.Flush();
}
};
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -17,7 +17,7 @@
#include "utils/exceptions.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* Used to indicate something is wrong with the client but the transaction is
@@ -83,4 +83,4 @@ class VerboseError : public utils::BasicException {
std::string code_;
};
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -27,7 +27,7 @@
#include "utils/exceptions.hpp"
#include "utils/logging.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* Bolt Session Exception
@@ -195,4 +195,4 @@ class Session {
}
};
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -13,7 +13,7 @@
#include <cstdint>
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* This class represents states in execution of the Bolt protocol.
@@ -55,4 +55,4 @@ enum class State : uint8_t {
*/
Close
};
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -20,7 +20,7 @@
#include "utils/likely.hpp"
#include "utils/logging.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
/**
* Error state run function
@@ -95,4 +95,4 @@ State StateErrorRun(TSession &session, State state) {
return state;
}
}
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -26,7 +26,7 @@
#include "utils/logging.hpp"
#include "utils/message.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
template <typename TSession>
State RunHandlerV1(Signature signature, TSession &session, State state, Marker marker) {
@@ -118,4 +118,4 @@ State StateExecutingRun(TSession &session, State state) {
return State::Close;
}
}
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -24,7 +24,7 @@
#include "utils/logging.hpp"
#include "utils/message.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
// TODO: Revise these error messages
inline std::pair<std::string, std::string> ExceptionToErrorMessage(const std::exception &e) {
if (const auto *verbose = dynamic_cast<const VerboseError *>(&e)) {
@@ -415,4 +415,4 @@ State HandleRoute(TSession &session) {
}
return State::Error;
}
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -22,7 +22,7 @@
#include "utils/likely.hpp"
#include "utils/logging.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
inline bool CopyProtocolInformationIfSupported(uint16_t version, uint8_t *protocol) {
const auto *supported_version = std::find(std::begin(kSupportedVersions), std::end(kSupportedVersions), version);
@@ -110,4 +110,4 @@ State StateHandshakeRun(TSession &session) {
return State::Init;
}
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -21,7 +21,7 @@
#include "utils/likely.hpp"
#include "utils/logging.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
namespace details {
template <typename TSession>
@@ -212,4 +212,4 @@ State StateInitRun(TSession &session) {
spdlog::trace("Unsupported bolt version:{}.{})!", session.version_.major, session.version_.minor);
return State::Close;
}
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -14,7 +14,7 @@
#include "utils/algorithm.hpp"
#include "utils/string.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
#define DEF_GETTER_BY_VAL(type, value_type, field) \
value_type &Value::Value##type() { \
@@ -461,4 +461,4 @@ std::ostream &operator<<(std::ostream &os, const Value::Type type) {
return os << "duration";
}
}
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -20,7 +20,7 @@
#include "utils/exceptions.hpp"
#include "utils/temporal.hpp"
namespace memgraph::communication::bolt {
namespace communication::bolt {
/** Forward declaration of Value class. */
class Value;
@@ -282,4 +282,4 @@ std::ostream &operator<<(std::ostream &os, const UnboundedEdge &edge);
std::ostream &operator<<(std::ostream &os, const Path &path);
std::ostream &operator<<(std::ostream &os, const Value &value);
std::ostream &operator<<(std::ostream &os, const Value::Type type);
} // namespace memgraph::communication::bolt
} // namespace communication::bolt

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -13,7 +13,7 @@
#include "utils/logging.hpp"
namespace memgraph::communication {
namespace communication {
Buffer::Buffer() : data_(kBufferInitialSize, 0), read_end_(this), write_end_(this) {}
@@ -77,4 +77,4 @@ void Buffer::Resize(size_t len) {
void Buffer::Clear() { have_ = 0; }
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -15,7 +15,7 @@
#include "io/network/stream_buffer.hpp"
namespace memgraph::communication {
namespace communication {
/**
* @brief Buffer
@@ -171,4 +171,4 @@ class Buffer final {
ReadEnd read_end_;
WriteEnd write_end_;
};
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -14,7 +14,7 @@
#include "communication/helpers.hpp"
#include "utils/logging.hpp"
namespace memgraph::communication {
namespace communication {
Client::Client(ClientContext *context) : context_(context) {}
@@ -239,4 +239,4 @@ bool ClientOutputStream::Write(const uint8_t *data, size_t len, bool have_more)
}
bool ClientOutputStream::Write(const std::string &str, bool have_more) { return client_.Write(str, have_more); }
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -21,14 +21,14 @@
#include "io/network/endpoint.hpp"
#include "io/network/socket.hpp"
namespace memgraph::communication {
namespace communication {
/**
* This class implements a generic network Client.
* It uses blocking sockets and provides an API that can be used to receive/send
* data over the network connection.
*
* NOTE: If you use this client you **must** create `memgraph::communication::SSLInit`
* NOTE: If you use this client you **must** create `communication::SSLInit`
* from the `main` function before using the client!
*/
class Client final {
@@ -167,4 +167,4 @@ class ClientOutputStream final {
Client &client_;
};
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -10,13 +10,10 @@
// licenses/APL.txt.
#include "communication/context.hpp"
#include <boost/asio/ssl/context.hpp>
#include <boost/asio/ssl/verify_mode.hpp>
#include <boost/system/detail/error_code.hpp>
#include "utils/logging.hpp"
namespace memgraph::communication {
namespace communication {
ClientContext::ClientContext(bool use_ssl) : use_ssl_(use_ssl), ctx_(nullptr) {
if (use_ssl_) {
@@ -76,62 +73,80 @@ SSL_CTX *ClientContext::context() { return ctx_; }
bool ClientContext::use_ssl() { return use_ssl_; }
ServerContext::ServerContext() : use_ssl_(false), ctx_(nullptr) {}
ServerContext::ServerContext(const std::string &key_file, const std::string &cert_file, const std::string &ca_file,
bool verify_peer) {
ctx_.emplace(boost::asio::ssl::context::tls_server);
ctx_->set_default_verify_paths();
// TODO: add support for encrypted private keys
// TODO: add certificate revocation list (CRL)
boost::system::error_code ec;
ctx_->use_certificate_chain_file(cert_file, ec);
MG_ASSERT(!ec, "Couldn't load server certificate from file: {}", cert_file);
ctx_->use_private_key_file(key_file, boost::asio::ssl::context::pem, ec);
MG_ASSERT(!ec, "Couldn't load server private key from file: {}", key_file);
bool verify_peer)
: use_ssl_(true),
#if OPENSSL_VERSION_NUMBER < 0x10100000L
ctx_(SSL_CTX_new(SSLv23_server_method()))
#else
ctx_(SSL_CTX_new(TLS_server_method()))
#endif
{
// TODO (mferencevic): add support for encrypted private keys
// TODO (mferencevic): add certificate revocation list (CRL)
MG_ASSERT(SSL_CTX_use_certificate_file(ctx_, cert_file.c_str(), SSL_FILETYPE_PEM) == 1,
"Couldn't load server certificate from file: {}", cert_file);
MG_ASSERT(SSL_CTX_use_PrivateKey_file(ctx_, key_file.c_str(), SSL_FILETYPE_PEM) == 1,
"Couldn't load server private key from file: {}", key_file);
ctx_->set_options(SSL_OP_NO_SSLv3, ec);
MG_ASSERT(!ec, "Setting options to SSL context failed!");
// Disable legacy SSL support. Other options can be seen here:
// https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_options.html
SSL_CTX_set_options(ctx_, SSL_OP_NO_SSLv3);
if (!ca_file.empty()) {
if (ca_file != "") {
// Load the certificate authority file.
boost::system::error_code ec;
ctx_->load_verify_file(ca_file, ec);
MG_ASSERT(!ec, "Couldn't load certificate authority from file: {}", ca_file);
MG_ASSERT(SSL_CTX_load_verify_locations(ctx_, ca_file.c_str(), nullptr) == 1,
"Couldn't load certificate authority from file: {}", ca_file);
if (verify_peer) {
// Add the CA to list of accepted CAs that is sent to the client.
STACK_OF(X509_NAME) *ca_names = SSL_load_client_CA_file(ca_file.c_str());
MG_ASSERT(ca_names != nullptr, "Couldn't load certificate authority from file: {}", ca_file);
// `ca_names` doesn' need to be free'd because we pass it to
// `SSL_CTX_set_client_CA_list`:
// https://mta.openssl.org/pipermail/openssl-users/2015-May/001363.html
SSL_CTX_set_client_CA_list(ctx_, ca_names);
// Enable verification of the client certificate.
// NOLINTNEXTLINE(hicpp-signed-bitwise)
ctx_->set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert, ec);
MG_ASSERT(!ec, "Setting SSL verification mode failed!");
SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
}
}
}
ServerContext::ServerContext(ServerContext &&other) noexcept { std::swap(ctx_, other.ctx_); }
ServerContext::ServerContext(ServerContext &&other) noexcept : use_ssl_(other.use_ssl_), ctx_(other.ctx_) {
other.use_ssl_ = false;
other.ctx_ = nullptr;
}
ServerContext &ServerContext::operator=(ServerContext &&other) noexcept {
if (this == &other) return *this;
// destroy my objects
if (use_ssl_) {
SSL_CTX_free(ctx_);
}
// move other objects to self
ctx_ = std::move(other.ctx_);
use_ssl_ = other.use_ssl_;
ctx_ = other.ctx_;
// reset other objects
other.ctx_.reset();
other.use_ssl_ = false;
other.ctx_ = nullptr;
return *this;
}
ServerContext::~ServerContext() {}
SSL_CTX *ServerContext::context() {
MG_ASSERT(ctx_);
return ctx_->native_handle();
ServerContext::~ServerContext() {
if (use_ssl_) {
SSL_CTX_free(ctx_);
}
}
boost::asio::ssl::context &ServerContext::context_clone() {
MG_ASSERT(ctx_);
return *ctx_;
}
SSL_CTX *ServerContext::context() { return ctx_; }
bool ServerContext::use_ssl() const { return ctx_.has_value(); }
bool ServerContext::use_ssl() { return use_ssl_; }
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -11,13 +11,11 @@
#pragma once
#include <optional>
#include <string>
#include <openssl/ssl.h>
#include <boost/asio/ssl/context.hpp>
namespace memgraph::communication {
namespace communication {
/**
* This class represents a context that should be used with network clients. One
@@ -71,7 +69,11 @@ class ClientContext final {
*/
class ServerContext final {
public:
ServerContext() = default;
/**
* This constructor constructs a ServerContext that doesn't use SSL.
*/
ServerContext();
/**
* This constructor constructs a ServerContext that uses SSL. The parameters
* `key_file` and `cert_file` can't be "" because when setting up a server it
@@ -93,15 +95,16 @@ class ServerContext final {
ServerContext(ServerContext &&other) noexcept;
ServerContext &operator=(ServerContext &&other) noexcept;
// Destructor that handles ownership of the SSL object.
~ServerContext();
SSL_CTX *context();
boost::asio::ssl::context &context_clone();
bool use_ssl() const;
bool use_ssl();
private:
std::optional<boost::asio::ssl::context> ctx_;
bool use_ssl_;
SSL_CTX *ctx_;
};
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -13,7 +13,7 @@
#include "utils/exceptions.hpp"
namespace memgraph::communication {
namespace communication {
/**
* This exception is thrown to indicate to the communication stack that the
@@ -22,4 +22,4 @@ namespace memgraph::communication {
class SessionClosedException : public utils::BasicException {
using utils::BasicException::BasicException;
};
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -13,7 +13,7 @@
#include "communication/helpers.hpp"
namespace memgraph::communication {
namespace communication {
const std::string SslGetLastError() {
char buff[2048];
@@ -21,4 +21,4 @@ const std::string SslGetLastError() {
ERR_error_string_n(err, buff, sizeof(buff));
return std::string(buff);
}
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -13,11 +13,11 @@
#include <string>
namespace memgraph::communication {
namespace communication {
/**
* This function reads and returns a string describing the last OpenSSL error.
*/
const std::string SslGetLastError();
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -20,7 +20,7 @@
#include "utils/signals.hpp"
#include "utils/spin_lock.hpp"
namespace memgraph::communication {
namespace communication {
namespace {
// OpenSSL before 1.1 did not have a out-of-the-box multithreading support
@@ -72,4 +72,4 @@ SSLInit::SSLInit() {
}
SSLInit::~SSLInit() { Cleanup(); }
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -11,7 +11,7 @@
#pragma once
namespace memgraph::communication {
namespace communication {
/**
* Create this object in each `main` file that uses the Communication stack. It
@@ -36,4 +36,4 @@ struct SSLInit {
~SSLInit();
};
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -28,7 +28,7 @@
#include "utils/spin_lock.hpp"
#include "utils/thread.hpp"
namespace memgraph::communication {
namespace communication {
/**
* This class listens to events on an epoll object and processes them.
@@ -273,4 +273,4 @@ class Listener final {
const std::string service_name_;
const size_t workers_count_;
};
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -29,7 +29,7 @@
*/
class ResultStreamFaker {
public:
explicit ResultStreamFaker(memgraph::storage::Storage *store) : store_(store) {}
explicit ResultStreamFaker(storage::Storage *store) : store_(store) {}
ResultStreamFaker(const ResultStreamFaker &) = delete;
ResultStreamFaker &operator=(const ResultStreamFaker &) = delete;
@@ -38,25 +38,25 @@ class ResultStreamFaker {
void Header(const std::vector<std::string> &fields) { header_ = fields; }
void Result(const std::vector<memgraph::communication::bolt::Value> &values) { results_.push_back(values); }
void Result(const std::vector<communication::bolt::Value> &values) { results_.push_back(values); }
void Result(const std::vector<memgraph::query::TypedValue> &values) {
std::vector<memgraph::communication::bolt::Value> bvalues;
void Result(const std::vector<query::TypedValue> &values) {
std::vector<communication::bolt::Value> bvalues;
bvalues.reserve(values.size());
for (const auto &value : values) {
auto maybe_value = memgraph::glue::ToBoltValue(value, *store_, memgraph::storage::View::NEW);
auto maybe_value = glue::ToBoltValue(value, *store_, storage::View::NEW);
MG_ASSERT(maybe_value.HasValue());
bvalues.push_back(std::move(*maybe_value));
}
results_.push_back(std::move(bvalues));
}
void Summary(const std::map<std::string, memgraph::communication::bolt::Value> &summary) { summary_ = summary; }
void Summary(const std::map<std::string, communication::bolt::Value> &summary) { summary_ = summary; }
void Summary(const std::map<std::string, memgraph::query::TypedValue> &summary) {
std::map<std::string, memgraph::communication::bolt::Value> bsummary;
void Summary(const std::map<std::string, query::TypedValue> &summary) {
std::map<std::string, communication::bolt::Value> bsummary;
for (const auto &item : summary) {
auto maybe_value = memgraph::glue::ToBoltValue(item.second, *store_, memgraph::storage::View::NEW);
auto maybe_value = glue::ToBoltValue(item.second, *store_, storage::View::NEW);
MG_ASSERT(maybe_value.HasValue());
bsummary.insert({item.first, std::move(*maybe_value)});
}
@@ -119,17 +119,17 @@ class ResultStreamFaker {
// output the summary
os << "Query summary: {";
memgraph::utils::PrintIterable(os, results.GetSummary(), ", ",
[&](auto &stream, const auto &kv) { stream << kv.first << ": " << kv.second; });
utils::PrintIterable(os, results.GetSummary(), ", ",
[&](auto &stream, const auto &kv) { stream << kv.first << ": " << kv.second; });
os << "}" << std::endl;
return os;
}
private:
memgraph::storage::Storage *store_;
storage::Storage *store_;
// the data that the record stream can accept
std::vector<std::string> header_;
std::vector<std::vector<memgraph::communication::bolt::Value>> results_;
std::map<std::string, memgraph::communication::bolt::Value> summary_;
std::vector<std::vector<communication::bolt::Value>> results_;
std::map<std::string, communication::bolt::Value> summary_;
};

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -27,7 +27,7 @@
#include "utils/message.hpp"
#include "utils/thread.hpp"
namespace memgraph::communication {
namespace communication {
/**
* Communication server.
@@ -37,10 +37,10 @@ namespace memgraph::communication {
* that has `num_workers` threads. It is started automatically on constructor,
* and stopped at destructor.
*
* Current Server architecture:
* Current Server achitecture:
* incoming connection -> server -> listener -> session
*
* NOTE: If you use this server you **must** create communication::SSLInit`
* NOTE: If you use this server you **must** create `communication::SSLInit`
* from the `main` function before using the server!
*
* @tparam TSession the server can handle different Sessions, each session
@@ -161,4 +161,4 @@ class Server final {
const std::string service_name_;
};
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -33,7 +33,7 @@
#include "utils/on_scope_exit.hpp"
#include "utils/spin_lock.hpp"
namespace memgraph::communication {
namespace communication {
/**
* This is used to provide input to user sessions. All sessions used with the
@@ -327,4 +327,4 @@ class Session final {
SSL *ssl_{nullptr};
BIO *bio_{nullptr};
}; // namespace communication
} // namespace memgraph::communication
} // namespace communication

View File

@@ -1,30 +0,0 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "communication/websocket/auth.hpp"
#include <string>
namespace memgraph::communication::websocket {
bool SafeAuth::Authenticate(const std::string &username, const std::string &password) const {
return auth_->Lock()->Authenticate(username, password).has_value();
}
bool SafeAuth::HasUserPermission(const std::string &username, const auth::Permission permission) const {
if (const auto user = auth_->ReadLock()->GetUser(username); user) {
return user->GetPermissions().Has(permission) == auth::PermissionLevel::GRANT;
}
return false;
}
bool SafeAuth::HasAnyUsers() const { return auth_->ReadLock()->HasUsers(); }
} // namespace memgraph::communication::websocket

View File

@@ -1,44 +0,0 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#pragma once
#include <string>
#include "auth/auth.hpp"
#include "utils/spin_lock.hpp"
#include "utils/synchronized.hpp"
namespace memgraph::communication::websocket {
class AuthenticationInterface {
public:
virtual bool Authenticate(const std::string &username, const std::string &password) const = 0;
virtual bool HasUserPermission(const std::string &username, auth::Permission permission) const = 0;
virtual bool HasAnyUsers() const = 0;
};
class SafeAuth : public AuthenticationInterface {
public:
explicit SafeAuth(utils::Synchronized<auth::Auth, utils::WritePrioritizedRWLock> *auth) : auth_{auth} {}
bool Authenticate(const std::string &username, const std::string &password) const override;
bool HasUserPermission(const std::string &username, auth::Permission permission) const override;
bool HasAnyUsers() const override;
private:
utils::Synchronized<auth::Auth, utils::WritePrioritizedRWLock> *auth_;
};
} // namespace memgraph::communication::websocket

View File

@@ -1,90 +0,0 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "communication/websocket/listener.hpp"
namespace memgraph::communication::websocket {
namespace {
void LogError(boost::beast::error_code ec, const std::string_view what) {
spdlog::warn("Websocket listener failed on {}: {}", what, ec.message());
}
} // namespace
void Listener::Run() { DoAccept(); }
void Listener::WriteToAll(std::shared_ptr<std::string> message) {
auto sessions_ptr = sessions_.Lock();
for (auto &session : *sessions_ptr) {
session->Write(message);
}
}
boost::asio::ip::tcp::endpoint Listener::GetEndpoint() const { return acceptor_.local_endpoint(); };
Listener::Listener(boost::asio::io_context &ioc, ServerContext *context, tcp::endpoint endpoint,
AuthenticationInterface &auth)
: ioc_(ioc), context_(context), acceptor_(ioc), auth_(auth) {
boost::beast::error_code ec;
// Open the acceptor
acceptor_.open(endpoint.protocol(), ec);
if (ec) {
LogError(ec, "open");
return;
}
// Allow address reuse
acceptor_.set_option(boost::asio::socket_base::reuse_address(true), ec);
if (ec) {
LogError(ec, "set_option");
return;
}
// Bind to the server address
acceptor_.bind(endpoint, ec);
if (ec) {
LogError(ec, "bind");
return;
}
acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec);
if (ec) {
LogError(ec, "listen");
return;
}
spdlog::info("WebSocket server is listening on {}:{}", endpoint.address(), endpoint.port());
}
void Listener::DoAccept() {
acceptor_.async_accept(
ioc_, [shared_this = shared_from_this()](auto ec, auto socket) { shared_this->OnAccept(ec, std::move(socket)); });
}
void Listener::OnAccept(boost::beast::error_code ec, tcp::socket socket) {
if (ec) {
return LogError(ec, "accept");
}
auto session = Session::Create(std::move(socket), *context_, auth_);
if (session->Run()) {
auto sessions_ptr = sessions_.Lock();
// Clean disconnected clients
std::erase_if(*sessions_ptr, [](const auto &elem) { return !elem->IsConnected(); });
sessions_ptr->emplace_back(std::move(session));
}
DoAccept();
}
} // namespace memgraph::communication::websocket

View File

@@ -1,57 +0,0 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#pragma once
#define BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT
#include <list>
#include <memory>
#include <spdlog/spdlog.h>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
#include <boost/beast/core.hpp>
#include "communication/context.hpp"
#include "communication/websocket/session.hpp"
#include "utils/spin_lock.hpp"
#include "utils/synchronized.hpp"
namespace memgraph::communication::websocket {
class Listener : public std::enable_shared_from_this<Listener> {
using tcp = boost::asio::ip::tcp;
public:
template <typename... Args>
static std::shared_ptr<Listener> Create(Args &&...args) {
return std::shared_ptr<Listener>{new Listener(std::forward<Args>(args)...)};
}
// Start accepting incoming connections
void Run();
void WriteToAll(std::shared_ptr<std::string> message);
tcp::endpoint GetEndpoint() const;
private:
Listener(boost::asio::io_context &ioc, ServerContext *context, tcp::endpoint endpoint, AuthenticationInterface &auth);
void DoAccept();
void OnAccept(boost::beast::error_code ec, tcp::socket socket);
boost::asio::io_context &ioc_;
ServerContext *context_;
tcp::acceptor acceptor_;
utils::Synchronized<std::list<std::shared_ptr<Session>>, utils::SpinLock> sessions_;
AuthenticationInterface &auth_;
};
} // namespace memgraph::communication::websocket

View File

@@ -1,84 +0,0 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "communication/websocket/server.hpp"
#include <spdlog/pattern_formatter.h>
namespace memgraph::communication::websocket {
Server::~Server() {
MG_ASSERT(!background_thread_ || (ioc_.stopped() && !background_thread_->joinable()),
"Server wasn't shutdown properly");
}
void Server::Start() {
MG_ASSERT(!background_thread_, "The server was already started!");
listener_->Run();
background_thread_.emplace([this] { ioc_.run(); });
}
void Server::Shutdown() { ioc_.stop(); }
void Server::AwaitShutdown() {
if (background_thread_ && background_thread_->joinable()) {
background_thread_->join();
}
}
bool Server::IsRunning() const { return background_thread_ && !ioc_.stopped(); }
boost::asio::ip::tcp::endpoint Server::GetEndpoint() const { return listener_->GetEndpoint(); };
namespace {
class QuoteEscapeFormatter : public spdlog::custom_flag_formatter {
public:
void format(const spdlog::details::log_msg &msg, const std::tm & /*time*/, spdlog::memory_buf_t &dest) override {
for (const auto c : msg.payload) {
if (c == '"') {
static constexpr std::string_view escaped_quote = "\\\"";
dest.append(escaped_quote.data(), escaped_quote.data() + escaped_quote.size());
} else if (c == '\n') {
static constexpr std::string_view escaped_newline = "\\n";
dest.append(escaped_newline.data(), escaped_newline.data() + escaped_newline.size());
} else {
dest.push_back(c);
}
}
}
std::unique_ptr<custom_flag_formatter> clone() const override {
return spdlog::details::make_unique<QuoteEscapeFormatter>();
}
};
}; // namespace
void Server::LoggingSink::sink_it_(const spdlog::details::log_msg &msg) {
const auto listener = listener_.lock();
if (!listener) {
return;
}
using memory_buf_t = fmt::basic_memory_buffer<char, 250>;
memory_buf_t formatted;
base_sink<std::mutex>::formatter_->format(msg, formatted);
listener->WriteToAll(std::make_shared<std::string>(formatted.data(), formatted.size()));
}
std::shared_ptr<Server::LoggingSink> Server::GetLoggingSink() {
auto formatter = std::make_unique<spdlog::pattern_formatter>();
formatter->add_flag<QuoteEscapeFormatter>('*').set_pattern(
R"json({"event": "log", "level": "%l", "message": "%*"})json");
auto sink = std::make_shared<LoggingSink>(listener_);
sink->set_formatter(std::move(formatter));
return sink;
}
} // namespace memgraph::communication::websocket

View File

@@ -1,68 +0,0 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#pragma once
#define BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT
#include <thread>
#include <spdlog/sinks/base_sink.h>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include "communication/websocket/listener.hpp"
#include "io/network/endpoint.hpp"
namespace memgraph::communication::websocket {
class Server final {
using tcp = boost::asio::ip::tcp;
public:
explicit Server(io::network::Endpoint endpoint, ServerContext *context, AuthenticationInterface &auth)
: listener_{Listener::Create(
ioc_, context, tcp::endpoint{boost::asio::ip::make_address(endpoint.address), endpoint.port}, auth)} {}
Server(const Server &) = delete;
Server(Server &&) = delete;
Server &operator=(const Server &) = delete;
Server &operator=(Server &&) = delete;
~Server();
void Start();
void Shutdown();
void AwaitShutdown();
bool IsRunning() const;
tcp::endpoint GetEndpoint() const;
class LoggingSink : public spdlog::sinks::base_sink<std::mutex> {
public:
explicit LoggingSink(std::weak_ptr<Listener> listener) : listener_(listener) {}
private:
void sink_it_(const spdlog::details::log_msg &msg) override;
void flush_() override {}
std::weak_ptr<Listener> listener_;
};
std::shared_ptr<LoggingSink> GetLoggingSink();
private:
boost::asio::io_context ioc_;
std::shared_ptr<Listener> listener_;
std::optional<std::thread> background_thread_;
};
} // namespace memgraph::communication::websocket

View File

@@ -1,235 +0,0 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "communication/websocket/session.hpp"
#include <functional>
#include <memory>
#include <string>
#include <fmt/format.h>
#include <spdlog/spdlog.h>
#include <boost/asio/bind_executor.hpp>
#include <boost/beast/core/buffers_to_string.hpp>
#include <boost/beast/core/stream_traits.hpp>
#include <json/json.hpp>
#include "communication/context.hpp"
#include "communication/websocket/auth.hpp"
#include "utils/logging.hpp"
namespace memgraph::communication::websocket {
namespace {
void LogError(const boost::beast::error_code ec, const std::string_view what) {
spdlog::warn("Websocket session failed on {}: {}", what, ec.message());
}
} // namespace
std::variant<Session::PlainWebSocket, Session::SSLWebSocket> Session::CreateWebSocket(tcp::socket &&socket,
ServerContext &context) {
if (context.use_ssl()) {
ssl_context_.emplace(context.context_clone());
return Session::SSLWebSocket{std::move(socket), *ssl_context_};
}
return Session::PlainWebSocket{std::move(socket)};
}
Session::Session(tcp::socket &&socket, ServerContext &context, AuthenticationInterface &auth)
: ws_(CreateWebSocket(std::move(socket), context)), strand_{boost::asio::make_strand(GetExecutor())}, auth_{auth} {}
bool Session::Run() {
ExecuteForWebsocket([](auto &&ws) {
ws.set_option(boost::beast::websocket::stream_base::timeout::suggested(boost::beast::role_type::server));
ws.set_option(boost::beast::websocket::stream_base::decorator([](boost::beast::websocket::response_type &res) {
res.set(boost::beast::http::field::server, "Memgraph WS");
}));
});
if (auto *ssl_ws = std::get_if<SSLWebSocket>(&ws_); ssl_ws != nullptr) {
try {
boost::beast::get_lowest_layer(*ssl_ws).expires_after(std::chrono::seconds(30));
ssl_ws->next_layer().handshake(boost::asio::ssl::stream_base::server);
} catch (const boost::system::system_error &e) {
spdlog::warn("Failed on SSL handshake: {}", e.what());
return false;
}
}
auto result = ExecuteForWebsocket([](auto &&ws) -> bool {
// Accept the websocket handshake
boost::beast::error_code ec;
ws.accept(ec);
if (ec) {
LogError(ec, "accept");
return false;
}
return true;
});
if (!result) {
return false;
}
authenticated_ = !auth_.HasAnyUsers();
connected_.store(true, std::memory_order_relaxed);
// run on the strand
boost::asio::dispatch(strand_, [shared_this = shared_from_this()] { shared_this->DoRead(); });
return true;
}
void Session::Write(std::shared_ptr<std::string> message) {
boost::asio::dispatch(strand_, [message = std::move(message), shared_this = shared_from_this()]() mutable {
if (!shared_this->connected_.load(std::memory_order_relaxed)) {
return;
}
if (!shared_this->IsAuthenticated()) {
return;
}
shared_this->messages_.push_back(std::move(message));
if (shared_this->messages_.size() > 1) {
return;
}
shared_this->DoWrite();
});
}
bool Session::IsConnected() const { return connected_.load(std::memory_order_relaxed); }
void Session::DoWrite() {
ExecuteForWebsocket([this](auto &&ws) {
auto next_message = messages_.front();
ws.async_write(boost::asio::buffer(*next_message),
boost::asio::bind_executor(
strand_, [message_string = std::move(next_message), shared_this = shared_from_this()](
boost::beast::error_code ec, const size_t bytes_transferred) {
shared_this->OnWrite(ec, bytes_transferred);
}));
});
}
void Session::OnWrite(boost::beast::error_code ec, size_t /*bytes_transferred*/) {
messages_.pop_front();
if (close_) {
DoShutdown();
return;
}
if (ec) {
close_ = true;
return LogError(ec, "write");
}
if (!messages_.empty()) {
DoWrite();
}
}
void Session::DoRead() {
ExecuteForWebsocket([this](auto &&ws) {
ws.async_read(buffer_, boost::asio::bind_executor(strand_, std::bind_front(&Session::OnRead, shared_from_this())));
});
;
}
void Session::DoClose() {
ExecuteForWebsocket([this](auto &&ws) mutable {
ws.async_close(boost::beast::websocket::close_code::normal,
boost::asio::bind_executor(strand_, [shared_this = shared_from_this()](boost::beast::error_code ec) {
shared_this->OnClose(ec);
}));
});
}
void Session::OnClose(boost::beast::error_code ec) {
connected_.store(false, std::memory_order_relaxed);
if (ec) {
return LogError(ec, "close");
}
}
utils::BasicResult<std::string> Session::Authorize(const nlohmann::json &creds) {
if (!auth_.Authenticate(creds.at("username").get<std::string>(), creds.at("password").get<std::string>())) {
return {"Authentication failed!"};
}
#ifdef MG_ENTERPRISE
if (!auth_.HasUserPermission(creds.at("username").get<std::string>(), auth::Permission::WEBSOCKET)) {
return {"Authorization failed!"};
}
#endif
return {};
}
void Session::OnRead(const boost::beast::error_code ec, const size_t /*bytes_transferred*/) {
if (ec == boost::beast::websocket::error::closed) {
DoShutdown();
return;
}
if (!IsAuthenticated()) {
auto response = nlohmann::json();
auto auth_failed = [this, &response](const std::string &message) {
response["success"] = false;
response["message"] = message;
MG_ASSERT(messages_.empty());
messages_.push_back(std::make_shared<std::string>(response.dump()));
close_ = true;
DoWrite();
};
try {
const auto creds = nlohmann::json::parse(boost::beast::buffers_to_string(buffer_.data()));
buffer_.consume(buffer_.size());
if (const auto result = Authorize(creds); result.HasError()) {
std::invoke(auth_failed, result.GetError());
return;
}
response["success"] = true;
response["message"] = "User has been successfully authenticated!";
MG_ASSERT(messages_.empty());
authenticated_ = true;
messages_.push_back(std::make_shared<std::string>(response.dump()));
DoWrite();
} catch (const nlohmann::json::out_of_range &out_of_range) {
const auto err_msg = fmt::format("Invalid JSON for authentication received: {}!", out_of_range.what());
spdlog::error(err_msg);
std::invoke(auth_failed, err_msg);
return;
} catch (const nlohmann::json::parse_error &parse_error) {
const auto err_msg = fmt::format("Cannot parse JSON for WebSocket authentication: {}!", parse_error.what());
spdlog::error(err_msg);
std::invoke(auth_failed, err_msg);
return;
}
}
DoRead();
}
bool Session::IsAuthenticated() const { return authenticated_; }
void Session::DoShutdown() {
std::visit(utils::Overloaded{[this](SSLWebSocket &ssl_ws) {
boost::beast::get_lowest_layer(ssl_ws).expires_after(std::chrono::seconds(30));
ssl_ws.next_layer().async_shutdown(
[shared_this = shared_from_this()](boost::beast::error_code ec) {
if (ec) {
LogError(ec, "shutdown");
}
shared_this->DoClose();
});
},
[this](auto && /* plain_ws */) { DoClose(); }},
ws_);
}
} // namespace memgraph::communication::websocket

View File

@@ -1,91 +0,0 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#pragma once
#define BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT
#include <deque>
#include <memory>
#include <optional>
#include <variant>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/strand.hpp>
#include <boost/beast/core/tcp_stream.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/websocket.hpp>
#include <json/json.hpp>
#include "communication/context.hpp"
#include "communication/websocket/auth.hpp"
#include "utils/result.hpp"
#include "utils/synchronized.hpp"
#include "utils/variant_helpers.hpp"
namespace memgraph::communication::websocket {
class Session : public std::enable_shared_from_this<Session> {
using tcp = boost::asio::ip::tcp;
public:
template <typename... Args>
static std::shared_ptr<Session> Create(Args &&...args) {
return std::shared_ptr<Session>{new Session{std::forward<Args>(args)...}};
}
bool Run();
void Write(std::shared_ptr<std::string> message);
bool IsConnected() const;
private:
using PlainWebSocket = boost::beast::websocket::stream<boost::beast::tcp_stream>;
using SSLWebSocket = boost::beast::websocket::stream<boost::beast::ssl_stream<boost::beast::tcp_stream>>;
explicit Session(tcp::socket &&socket, ServerContext &context, AuthenticationInterface &auth);
void DoWrite();
void OnWrite(boost::beast::error_code ec, size_t bytes_transferred);
void DoRead();
void OnRead(boost::beast::error_code ec, size_t bytes_transferred);
void DoClose();
void OnClose(boost::beast::error_code ec);
bool IsAuthenticated() const;
utils::BasicResult<std::string> Authorize(const nlohmann::json &creds);
void DoShutdown();
auto GetExecutor() {
return std::visit(utils::Overloaded{[](auto &&ws) { return ws.get_executor(); }}, ws_);
}
template <typename F>
decltype(auto) ExecuteForWebsocket(F &&fn) {
return std::visit(utils::Overloaded{std::forward<F>(fn)}, ws_);
}
std::variant<PlainWebSocket, SSLWebSocket> CreateWebSocket(tcp::socket &&socket, ServerContext &context);
std::optional<std::reference_wrapper<boost::asio::ssl::context>> ssl_context_;
std::variant<PlainWebSocket, SSLWebSocket> ws_;
boost::beast::flat_buffer buffer_;
std::deque<std::shared_ptr<std::string>> messages_;
boost::asio::strand<PlainWebSocket::executor_type> strand_;
std::atomic<bool> connected_{false};
bool authenticated_{false};
bool close_{false};
AuthenticationInterface &auth_;
};
} // namespace memgraph::communication::websocket

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -49,7 +49,7 @@ class RingBuffer {
void emplace(TArgs &&...args) {
while (true) {
{
std::lock_guard<memgraph::utils::SpinLock> guard(lock_);
std::lock_guard<utils::SpinLock> guard(lock_);
if (size_ < capacity_) {
buffer_[write_pos_++] = TElement(std::forward<TArgs>(args)...);
write_pos_ %= capacity_;
@@ -70,7 +70,7 @@ class RingBuffer {
* empty, nullopt is returned.
*/
std::optional<TElement> pop() {
std::lock_guard<memgraph::utils::SpinLock> guard(lock_);
std::lock_guard<utils::SpinLock> guard(lock_);
if (size_ == 0) return std::nullopt;
size_--;
std::optional<TElement> result(std::move(buffer_[read_pos_++]));
@@ -80,7 +80,7 @@ class RingBuffer {
/** Removes all elements from the buffer. */
void clear() {
std::lock_guard<memgraph::utils::SpinLock> guard(lock_);
std::lock_guard<utils::SpinLock> guard(lock_);
read_pos_ = 0;
write_pos_ = 0;
size_ = 0;
@@ -89,7 +89,7 @@ class RingBuffer {
private:
int capacity_;
std::unique_ptr<TElement[]> buffer_;
memgraph::utils::SpinLock lock_;
utils::SpinLock lock_;
int read_pos_{0};
int write_pos_{0};
int size_{0};

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -11,7 +11,7 @@
#include "glue/auth.hpp"
namespace memgraph::glue {
namespace glue {
auth::Permission PrivilegeToPermission(query::AuthQuery::Privilege privilege) {
switch (privilege) {
@@ -51,12 +51,6 @@ auth::Permission PrivilegeToPermission(query::AuthQuery::Privilege privilege) {
return auth::Permission::AUTH;
case query::AuthQuery::Privilege::STREAM:
return auth::Permission::STREAM;
case query::AuthQuery::Privilege::MODULE_READ:
return auth::Permission::MODULE_READ;
case query::AuthQuery::Privilege::MODULE_WRITE:
return auth::Permission::MODULE_WRITE;
case query::AuthQuery::Privilege::WEBSOCKET:
return auth::Permission::WEBSOCKET;
}
}
} // namespace memgraph::glue
} // namespace glue

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -12,7 +12,7 @@
#include "auth/models.hpp"
#include "query/frontend/ast/ast.hpp"
namespace memgraph::glue {
namespace glue {
/**
* This function converts query::AuthQuery::Privilege to its corresponding
@@ -20,4 +20,4 @@ namespace memgraph::glue {
*/
auth::Permission PrivilegeToPermission(query::AuthQuery::Privilege privilege);
} // namespace memgraph::glue
} // namespace glue

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -20,14 +20,14 @@
#include "storage/v2/vertex_accessor.hpp"
#include "utils/temporal.hpp"
using memgraph::communication::bolt::Value;
using communication::bolt::Value;
namespace memgraph::glue {
namespace glue {
query::TypedValue ToTypedValue(const Value &value) {
switch (value.type()) {
case Value::Type::Null:
return {};
return query::TypedValue();
case Value::Type::Bool:
return query::TypedValue(value.ValueBool());
case Value::Type::Int:
@@ -238,7 +238,7 @@ Value ToBoltValue(const storage::PropertyValue &value) {
case storage::PropertyValue::Type::Double:
return Value(value.ValueDouble());
case storage::PropertyValue::Type::String:
return Value(value.ValueString());
return Value(std::string{value.ValueString()});
case storage::PropertyValue::Type::List: {
const auto &values = value.ValueList();
std::vector<Value> vec;
@@ -271,4 +271,4 @@ Value ToBoltValue(const storage::PropertyValue &value) {
}
}
} // namespace memgraph::glue
} // namespace glue

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -18,13 +18,13 @@
#include "storage/v2/result.hpp"
#include "storage/v2/view.hpp"
namespace memgraph::storage {
namespace storage {
class EdgeAccessor;
class Storage;
class VertexAccessor;
} // namespace memgraph::storage
} // namespace storage
namespace memgraph::glue {
namespace glue {
/// @param storage::VertexAccessor for converting to
/// communication::bolt::Vertex.
@@ -65,4 +65,4 @@ communication::bolt::Value ToBoltValue(const storage::PropertyValue &value);
storage::PropertyValue ToPropertyValue(const communication::bolt::Value &value);
} // namespace memgraph::glue
} // namespace glue

View File

@@ -14,12 +14,10 @@
#include <chrono>
#include <string>
namespace memgraph::integrations {
inline constexpr int64_t kDefaultCheckBatchLimit{1};
inline constexpr std::chrono::milliseconds kDefaultCheckTimeout{30000};
inline constexpr std::chrono::milliseconds kMinimumInterval{1};
inline constexpr int64_t kMinimumSize{1};
namespace integrations {
constexpr int64_t kDefaultCheckBatchLimit{1};
constexpr std::chrono::milliseconds kDefaultCheckTimeout{30000};
constexpr std::chrono::milliseconds kMinimumInterval{1};
constexpr int64_t kMinimumSize{1};
const std::string kReducted{"<REDUCTED>"};
} // namespace memgraph::integrations
} // namespace integrations

View File

@@ -27,7 +27,7 @@
#include "utils/on_scope_exit.hpp"
#include "utils/thread.hpp"
namespace memgraph::integrations::kafka {
namespace integrations::kafka {
namespace {
utils::BasicResult<std::string, std::vector<Message>> GetBatch(RdKafka::KafkaConsumer &consumer,
@@ -185,10 +185,8 @@ Consumer::Consumer(ConsumerInfo info, ConsumerFunction consumer_function)
std::inserter(topic_names_from_metadata, topic_names_from_metadata.begin()),
[](const auto topic_metadata) { return topic_metadata->topic(); });
static constexpr size_t max_topic_name_length = 249;
static constexpr auto is_valid_topic_name = [](const auto c) {
return std::isalnum(c) || c == '.' || c == '_' || c == '-';
};
constexpr size_t max_topic_name_length = 249;
constexpr auto is_valid_topic_name = [](const auto c) { return std::isalnum(c) || c == '.' || c == '_' || c == '-'; };
for (const auto &topic_name : info_.topics) {
if (topic_name.size() > max_topic_name_length ||
@@ -353,7 +351,7 @@ void Consumer::StartConsuming() {
}
thread_ = std::thread([this] {
static constexpr auto kMaxThreadNameSize = utils::GetMaxThreadNameSize();
constexpr auto kMaxThreadNameSize = utils::GetMaxThreadNameSize();
const auto full_thread_name = "Cons#" + info_.consumer_name;
utils::ThreadSetName(full_thread_name.substr(0, kMaxThreadNameSize));
@@ -450,4 +448,4 @@ void Consumer::ConsumerRebalanceCb::rebalance_cb(RdKafka::KafkaConsumer *consume
}
}
void Consumer::ConsumerRebalanceCb::set_offset(int64_t offset) { offset_ = offset; }
} // namespace memgraph::integrations::kafka
} // namespace integrations::kafka

View File

@@ -26,7 +26,7 @@
#include <librdkafka/rdkafkacpp.h>
#include "utils/result.hpp"
namespace memgraph::integrations::kafka {
namespace integrations::kafka {
/// Wraps the message returned from librdkafka.
///
@@ -183,4 +183,4 @@ class Consumer final : public RdKafka::EventCb {
std::thread thread_;
ConsumerRebalanceCb cb_;
};
} // namespace memgraph::integrations::kafka
} // namespace integrations::kafka

View File

@@ -15,7 +15,7 @@
#include "utils/exceptions.hpp"
namespace memgraph::integrations::kafka {
namespace integrations::kafka {
class KafkaStreamException : public utils::BasicException {
using utils::BasicException::BasicException;
};
@@ -64,4 +64,4 @@ class TopicNotFoundException : public KafkaStreamException {
TopicNotFoundException(const std::string_view consumer_name, const std::string_view topic_name)
: KafkaStreamException("Kafka consumer {} cannot find topic {}", consumer_name, topic_name) {}
};
} // namespace memgraph::integrations::kafka
} // namespace integrations::kafka

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -26,7 +26,7 @@
#include "utils/result.hpp"
#include "utils/thread.hpp"
namespace memgraph::integrations::pulsar {
namespace integrations::pulsar {
namespace {
@@ -231,7 +231,7 @@ void Consumer::StartConsuming() {
is_running_.store(true);
thread_ = std::thread([this] {
static constexpr auto kMaxThreadNameSize = utils::GetMaxThreadNameSize();
constexpr auto kMaxThreadNameSize = utils::GetMaxThreadNameSize();
const auto full_thread_name = "Cons#" + info_.consumer_name;
utils::ThreadSetName(full_thread_name.substr(0, kMaxThreadNameSize));
@@ -284,4 +284,4 @@ void Consumer::StopConsuming() {
}
}
} // namespace memgraph::integrations::pulsar
} // namespace integrations::pulsar

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -17,7 +17,7 @@
#include <pulsar/Client.h>
namespace memgraph::integrations::pulsar {
namespace integrations::pulsar {
namespace pulsar_client = ::pulsar;
@@ -79,4 +79,4 @@ class Consumer final {
pulsar_client::MessageId last_message_id_{pulsar_client::MessageId::earliest()};
std::thread thread_;
};
} // namespace memgraph::integrations::pulsar
} // namespace integrations::pulsar

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -15,7 +15,7 @@
#include "utils/exceptions.hpp"
namespace memgraph::integrations::pulsar {
namespace integrations::pulsar {
class PulsarStreamException : public utils::BasicException {
using utils::BasicException::BasicException;
};
@@ -55,4 +55,4 @@ class TopicNotFoundException : public PulsarStreamException {
TopicNotFoundException(const std::string &consumer_name, const std::string &topic_name)
: PulsarStreamException("Pulsar consumer {} cannot find topic {}", consumer_name, topic_name) {}
};
} // namespace memgraph::integrations::pulsar
} // namespace integrations::pulsar

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -9,52 +9,34 @@
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "io/network/addrinfo.hpp"
#include <netdb.h>
#include <cstring>
#include <concepts>
#include <iterator>
#include "io/network/addrinfo.hpp"
#include "io/network/network_error.hpp"
namespace memgraph::io::network {
namespace io::network {
static_assert(std::forward_iterator<AddrInfo::Iterator> && std::equality_comparable<AddrInfo::Iterator>);
AddrInfo::AddrInfo(struct addrinfo *info) : info(info) {}
AddrInfo::AddrInfo(const Endpoint &endpoint) : AddrInfo(endpoint.address, endpoint.port) {}
AddrInfo::~AddrInfo() { freeaddrinfo(info); }
AddrInfo AddrInfo::Get(const char *addr, const char *port) {
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; // IPv4 and IPv6
hints.ai_socktype = SOCK_STREAM; // TCP socket
hints.ai_flags = AI_PASSIVE;
struct addrinfo *result;
auto status = getaddrinfo(addr, port, &hints, &result);
AddrInfo::AddrInfo(const std::string &addr, uint16_t port) : info_{nullptr, nullptr} {
addrinfo hints{
.ai_flags = AI_PASSIVE,
.ai_family = AF_UNSPEC, // IPv4 and IPv6
.ai_socktype = SOCK_STREAM // TCP socket
};
addrinfo *info = nullptr;
auto status = getaddrinfo(addr.c_str(), std::to_string(port).c_str(), &hints, &info);
if (status != 0) throw NetworkError(gai_strerror(status));
info_ = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>(info, &freeaddrinfo);
return AddrInfo(result);
}
AddrInfo::Iterator::Iterator(addrinfo *p) noexcept : ptr_(p) {}
AddrInfo::Iterator::reference AddrInfo::Iterator::operator*() const noexcept { return *ptr_; }
AddrInfo::Iterator::pointer AddrInfo::Iterator::operator->() const noexcept { return ptr_; }
// NOLINTNEXTLINE(cert-dcl21-cpp)
AddrInfo::Iterator AddrInfo::Iterator::operator++(int) noexcept {
auto it = *this;
++(*this);
return it;
}
AddrInfo::Iterator &AddrInfo::Iterator::operator++() noexcept {
ptr_ = ptr_->ai_next;
return *this;
}
bool operator==(const AddrInfo::Iterator &lhs, const AddrInfo::Iterator &rhs) noexcept { return lhs.ptr_ == rhs.ptr_; };
bool operator!=(const AddrInfo::Iterator &lhs, const AddrInfo::Iterator &rhs) noexcept { return !(lhs == rhs); };
void swap(AddrInfo::Iterator &lhs, AddrInfo::Iterator &rhs) noexcept { std::swap(lhs.ptr_, rhs.ptr_); };
} // namespace memgraph::io::network
AddrInfo::operator struct addrinfo *() { return info; }
} // namespace io::network

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -11,53 +11,23 @@
#pragma once
#include <netdb.h>
#include <iterator>
#include <memory>
#include <string>
#include "io/network/endpoint.hpp"
namespace memgraph::io::network {
namespace io::network {
/**
* Wrapper class for getaddrinfo.
* see: man 3 getaddrinfo
*/
class AddrInfo {
explicit AddrInfo(struct addrinfo *info);
public:
struct Iterator {
using iterator_category = std::forward_iterator_tag;
using value_type = addrinfo;
using difference_type = std::ptrdiff_t;
using pointer = addrinfo *;
using reference = addrinfo &;
~AddrInfo();
Iterator() = default;
Iterator(const Iterator &) = default;
explicit Iterator(addrinfo *p) noexcept;
Iterator &operator=(const Iterator &) = default;
reference operator*() const noexcept;
pointer operator->() const noexcept;
Iterator operator++(int) noexcept;
Iterator &operator++() noexcept;
static AddrInfo Get(const char *addr, const char *port);
friend bool operator==(const Iterator &lhs, const Iterator &rhs) noexcept;
friend bool operator!=(const Iterator &lhs, const Iterator &rhs) noexcept;
friend void swap(Iterator &lhs, Iterator &rhs) noexcept;
private:
addrinfo *ptr_{nullptr};
};
AddrInfo(const std::string &addr, uint16_t port);
explicit AddrInfo(const Endpoint &endpoint);
auto begin() const noexcept { return Iterator(info_.get()); }
auto end() const noexcept { return Iterator{nullptr}; }
operator struct addrinfo *();
private:
std::unique_ptr<addrinfo, void (*)(addrinfo *)> info_;
struct addrinfo *info;
};
} // namespace memgraph::io::network
} // namespace io::network

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -21,7 +21,7 @@
#include "utils/message.hpp"
#include "utils/string.hpp"
namespace memgraph::io::network {
namespace io::network {
Endpoint::IpFamily Endpoint::GetIpFamily(const std::string &ip_address) {
in_addr addr4;
@@ -110,4 +110,4 @@ std::ostream &operator<<(std::ostream &os, const Endpoint &endpoint) {
return os << endpoint.address << ":" << endpoint.port;
}
} // namespace memgraph::io::network
} // namespace io::network

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -17,7 +17,7 @@
#include <optional>
#include <string>
namespace memgraph::io::network {
namespace io::network {
/**
* This class represents a network endpoint that is used in Socket.
@@ -55,4 +55,4 @@ struct Endpoint {
static IpFamily GetIpFamily(const std::string &ip_address);
};
} // namespace memgraph::io::network
} // namespace io::network

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -21,7 +21,7 @@
#include "utils/likely.hpp"
#include "utils/logging.hpp"
namespace memgraph::io::network {
namespace io::network {
/**
* Wrapper class for epoll.
@@ -104,4 +104,4 @@ class Epoll {
private:
const int epoll_fd_;
};
} // namespace memgraph::io::network
} // namespace io::network

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -13,10 +13,10 @@
#include "utils/exceptions.hpp"
namespace memgraph::io::network {
namespace io::network {
class NetworkError : public utils::StacktraceException {
public:
using utils::StacktraceException::StacktraceException;
};
} // namespace memgraph::io::network
} // namespace io::network

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -14,18 +14,18 @@
#include "io/network/endpoint.hpp"
#include "slk/serialization.hpp"
namespace memgraph::slk {
namespace slk {
inline void Save(const io::network::Endpoint &endpoint, Builder *builder) {
Save(endpoint.address_, builder);
Save(endpoint.port_, builder);
Save(endpoint.family_, builder);
inline void Save(const io::network::Endpoint &endpoint, slk::Builder *builder) {
slk::Save(endpoint.address_, builder);
slk::Save(endpoint.port_, builder);
slk::Save(endpoint.family_, builder);
}
inline void Load(io::network::Endpoint *endpoint, Reader *reader) {
Load(&endpoint->address_, reader);
Load(&endpoint->port_, reader);
Load(&endpoint->family_, reader);
inline void Load(io::network::Endpoint *endpoint, slk::Reader *reader) {
slk::Load(&endpoint->address_, reader);
slk::Load(&endpoint->port_, reader);
slk::Load(&endpoint->family_, reader);
}
} // namespace memgraph::slk
} // namespace slk

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2021 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -9,25 +9,39 @@
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "io/network/socket.hpp"
#include <cstdio>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <poll.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include "io/network/addrinfo.hpp"
#include "io/network/socket.hpp"
#include "utils/likely.hpp"
#include "utils/logging.hpp"
namespace memgraph::io::network {
namespace io::network {
Socket::Socket(Socket &&other) noexcept : socket_(other.socket_), endpoint_(std::move(other.endpoint_)) {
Socket::Socket(Socket &&other) {
socket_ = other.socket_;
endpoint_ = std::move(other.endpoint_);
other.socket_ = -1;
}
Socket &Socket::operator=(Socket &&other) noexcept {
Socket &Socket::operator=(Socket &&other) {
if (this != &other) {
if (socket_ != -1) close(socket_);
socket_ = other.socket_;
endpoint_ = std::move(other.endpoint_);
other.socket_ = -1;
@@ -35,8 +49,9 @@ Socket &Socket::operator=(Socket &&other) noexcept {
return *this;
}
Socket::~Socket() noexcept {
if (socket_ != -1) close(socket_);
Socket::~Socket() {
if (socket_ == -1) return;
close(socket_);
}
void Socket::Close() {
@@ -55,27 +70,33 @@ bool Socket::IsOpen() const { return socket_ != -1; }
bool Socket::Connect(const Endpoint &endpoint) {
if (socket_ != -1) return false;
for (const auto &it : AddrInfo{endpoint}) {
int sfd = socket(it.ai_family, it.ai_socktype, it.ai_protocol);
auto info = AddrInfo::Get(endpoint.address.c_str(), std::to_string(endpoint.port).c_str());
for (struct addrinfo *it = info; it != nullptr; it = it->ai_next) {
int sfd = socket(it->ai_family, it->ai_socktype, it->ai_protocol);
if (sfd == -1) continue;
if (connect(sfd, it.ai_addr, it.ai_addrlen) == 0) {
if (connect(sfd, it->ai_addr, it->ai_addrlen) == 0) {
socket_ = sfd;
endpoint_ = endpoint;
break;
} else {
// If the connect failed close the file descriptor to prevent file
// descriptors being leaked
close(sfd);
}
// If the connect failed close the file descriptor to prevent file
// descriptors being leaked
close(sfd);
}
return !(socket_ == -1);
if (socket_ == -1) return false;
return true;
}
bool Socket::Bind(const Endpoint &endpoint) {
if (socket_ != -1) return false;
for (const auto &it : AddrInfo{endpoint}) {
int sfd = socket(it.ai_family, it.ai_socktype, it.ai_protocol);
auto info = AddrInfo::Get(endpoint.address.c_str(), std::to_string(endpoint.port).c_str());
for (struct addrinfo *it = info; it != nullptr; it = it->ai_next) {
int sfd = socket(it->ai_family, it->ai_socktype, it->ai_protocol);
if (sfd == -1) continue;
int on = 1;
@@ -86,13 +107,14 @@ bool Socket::Bind(const Endpoint &endpoint) {
continue;
}
if (bind(sfd, it.ai_addr, it.ai_addrlen) == 0) {
if (bind(sfd, it->ai_addr, it->ai_addrlen) == 0) {
socket_ = sfd;
break;
} else {
// If the bind failed close the file descriptor to prevent file
// descriptors being leaked
close(sfd);
}
// If the bind failed close the file descriptor to prevent file
// descriptors being leaked
close(sfd);
}
if (socket_ == -1) return false;
@@ -100,7 +122,7 @@ bool Socket::Bind(const Endpoint &endpoint) {
// detect bound port, used when the server binds to a random port
struct sockaddr_in6 portdata;
socklen_t portdatalen = sizeof(portdata);
if (getsockname(socket_, reinterpret_cast<sockaddr *>(&portdata), &portdatalen) < 0) {
if (getsockname(socket_, (struct sockaddr *)&portdata, &portdatalen) < 0) {
// If the getsockname failed close the file descriptor to prevent file
// descriptors being leaked
close(socket_);
@@ -114,35 +136,36 @@ bool Socket::Bind(const Endpoint &endpoint) {
}
void Socket::SetNonBlocking() {
const unsigned flags = fcntl(socket_, F_GETFL);
constexpr unsigned o_nonblock = O_NONBLOCK;
int flags = fcntl(socket_, F_GETFL, 0);
MG_ASSERT(flags != -1, "Can't get socket mode");
MG_ASSERT(fcntl(socket_, F_SETFL, flags | o_nonblock) != -1, "Can't set socket nonblocking");
flags |= O_NONBLOCK;
MG_ASSERT(fcntl(socket_, F_SETFL, flags) != -1, "Can't set socket nonblocking");
}
void Socket::SetKeepAlive() {
int optval = 1;
MG_ASSERT(!setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)), "Can't set socket keep alive");
socklen_t optlen = sizeof(optval);
MG_ASSERT(!setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen), "Can't set socket keep alive");
optval = 20; // wait 20s before sending keep-alive packets
MG_ASSERT(!setsockopt(socket_, SOL_TCP, TCP_KEEPIDLE, (void *)&optval, sizeof(optval)),
"Can't set socket keep alive");
MG_ASSERT(!setsockopt(socket_, SOL_TCP, TCP_KEEPIDLE, (void *)&optval, optlen), "Can't set socket keep alive");
optval = 4; // 4 keep-alive packets must fail to close
MG_ASSERT(!setsockopt(socket_, SOL_TCP, TCP_KEEPCNT, (void *)&optval, sizeof(optval)), "Can't set socket keep alive");
MG_ASSERT(!setsockopt(socket_, SOL_TCP, TCP_KEEPCNT, (void *)&optval, optlen), "Can't set socket keep alive");
optval = 15; // send keep-alive packets every 15s
MG_ASSERT(!setsockopt(socket_, SOL_TCP, TCP_KEEPINTVL, (void *)&optval, sizeof(optval)),
"Can't set socket keep alive");
MG_ASSERT(!setsockopt(socket_, SOL_TCP, TCP_KEEPINTVL, (void *)&optval, optlen), "Can't set socket keep alive");
}
void Socket::SetNoDelay() {
int optval = 1;
MG_ASSERT(!setsockopt(socket_, SOL_TCP, TCP_NODELAY, (void *)&optval, sizeof(optval)), "Can't set socket no delay");
socklen_t optlen = sizeof(optval);
MG_ASSERT(!setsockopt(socket_, SOL_TCP, TCP_NODELAY, (void *)&optval, optlen), "Can't set socket no delay");
}
// NOLINTNEXTLINE(readability-make-member-function-const)
void Socket::SetTimeout(int64_t sec, int64_t usec) {
void Socket::SetTimeout(long sec, long usec) {
struct timeval tv;
tv.tv_sec = sec;
tv.tv_usec = usec;
@@ -153,7 +176,7 @@ void Socket::SetTimeout(int64_t sec, int64_t usec) {
}
int Socket::ErrorStatus() const {
int optval = 0;
int optval;
socklen_t optlen = sizeof(optval);
auto status = getsockopt(socket_, SOL_SOCKET, SO_ERROR, &optval, &optlen);
MG_ASSERT(!status, "getsockopt failed");
@@ -166,22 +189,21 @@ std::optional<Socket> Socket::Accept() {
sockaddr_storage addr;
socklen_t addr_size = sizeof addr;
char addr_decoded[INET6_ADDRSTRLEN];
void *addr_src;
unsigned short port;
int sfd = accept(socket_, reinterpret_cast<sockaddr *>(&addr), &addr_size);
int sfd = accept(socket_, (struct sockaddr *)&addr, &addr_size);
if (UNLIKELY(sfd == -1)) return std::nullopt;
void *addr_src = nullptr;
uint16_t port = 0;
if (addr.ss_family == AF_INET) {
addr_src = &reinterpret_cast<sockaddr_in &>(addr).sin_addr;
port = ntohs(reinterpret_cast<sockaddr_in &>(addr).sin_port);
addr_src = (void *)&(((sockaddr_in *)&addr)->sin_addr);
port = ntohs(((sockaddr_in *)&addr)->sin_port);
} else {
addr_src = &reinterpret_cast<sockaddr_in6 &>(addr).sin6_addr;
port = ntohs(reinterpret_cast<sockaddr_in6 &>(addr).sin6_port);
addr_src = (void *)&(((sockaddr_in6 *)&addr)->sin6_addr);
port = ntohs(((sockaddr_in6 *)&addr)->sin6_port);
}
inet_ntop(addr.ss_family, addr_src, addr_decoded, sizeof(addr_decoded));
inet_ntop(addr.ss_family, addr_src, addr_decoded, INET6_ADDRSTRLEN);
Endpoint endpoint(addr_decoded, port);
@@ -191,11 +213,9 @@ std::optional<Socket> Socket::Accept() {
bool Socket::Write(const uint8_t *data, size_t len, bool have_more) {
// MSG_NOSIGNAL is here to disable raising a SIGPIPE signal when a
// connection dies mid-write, the socket will only return an EPIPE error.
constexpr unsigned msg_nosignal = MSG_NOSIGNAL;
constexpr unsigned msg_more = MSG_MORE;
const unsigned flags = msg_nosignal | (have_more ? msg_more : 0);
int flags = MSG_NOSIGNAL | (have_more ? MSG_MORE : 0);
while (len > 0) {
auto written = send(socket_, data, len, static_cast<int>(flags));
auto written = send(socket_, data, len, flags);
if (written == -1) {
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
// Terminal error, return failure.
@@ -233,8 +253,7 @@ bool Socket::WaitForReadyRead() {
// event occurs.
int ret = poll(&p, 1, -1);
if (ret < 1) return false;
constexpr unsigned pollin = POLLIN;
return static_cast<unsigned>(p.revents) & pollin;
return p.revents & POLLIN;
}
bool Socket::WaitForReadyWrite() {
@@ -246,8 +265,7 @@ bool Socket::WaitForReadyWrite() {
// event occurs.
int ret = poll(&p, 1, -1);
if (ret < 1) return false;
constexpr unsigned pollout = POLLOUT;
return static_cast<unsigned>(p.revents) & pollout;
return p.revents & POLLOUT;
}
} // namespace memgraph::io::network
} // namespace io::network

Some files were not shown because too many files have changed in this diff Show More